C++?OpenCV實(shí)現(xiàn)白平衡之完美反射算法
實(shí)現(xiàn)原理
白平衡的意義在于,對在特定光源下拍攝時出現(xiàn)的偏色現(xiàn)象,通過加強(qiáng)對應(yīng)的補(bǔ)色來進(jìn)行補(bǔ)償,使白色物體能還原為白色。
完美反射算法是白平衡各種算法中較常見的一種,比灰度世界算法更優(yōu)。它假設(shè)圖像世界中最亮的白點(diǎn)是一個鏡面,能完美反射光照;基于白點(diǎn),將三通道的數(shù)值進(jìn)行適當(dāng)?shù)卣{(diào)整,以達(dá)到白平衡效果;除此之外,還需要統(tǒng)計最亮的一定區(qū)間的三通道均值,該均值與該通道最大值的差距決定了該通道調(diào)整的力度。
通俗的講,若圖像中綠色分量最大值是255,但是綠色最亮的前百分之10個點(diǎn)的平均值只有80,說明原圖的綠色分量整體較低,需要對其加強(qiáng);若最大值只有100,那么加強(qiáng)的系數(shù)就較低,白平衡的效果就不達(dá)預(yù)期。這就是完美反射算法比較依賴圖像中存在白點(diǎn)的原因,白點(diǎn)的三通道灰度值接近【255,255,255】。最下方將用實(shí)際圖像作進(jìn)一步說明,以幫助讀者理解。
完美反射算法的實(shí)現(xiàn)流程如下:
1.計算圖像RGB三通道各自的灰度最大值Rmax、Gmax、Bmax。
2.利用三通道數(shù)值和,確定圖像最亮區(qū)間的下限T。
3.計算圖像三通道數(shù)值和大于T的點(diǎn)的三通道均值Rm、Gm、Bm。
4.計算三通道的補(bǔ)償系數(shù),即單通道最大值除以單通道亮區(qū)平均值。
功能函數(shù)代碼
// 白平衡-完美反射
cv::Mat WhiteBalcane_PRA(cv::Mat src)
{
cv::Mat result = src.clone();
if (src.channels() != 3)
{
cout << "The number of image channels is not 3." << endl;
return result;
}
// 通道分離
vector<cv::Mat> Channel;
cv::split(src, Channel);
// 定義參數(shù)
int row = src.rows;
int col = src.cols;
int RGBSum[766] = { 0 };
uchar maxR, maxG, maxB;
// 計算單通道最大值
for (int i = 0; i < row; ++i)
{
uchar *b = Channel[0].ptr<uchar>(i);
uchar *g = Channel[1].ptr<uchar>(i);
uchar *r = Channel[2].ptr<uchar>(i);
for (int j = 0; j < col; ++j)
{
int sum = b[j] + g[j] + r[j];
RGBSum[sum]++;
maxB = max(maxB, b[j]);
maxG = max(maxG, g[j]);
maxR = max(maxR, r[j]);
}
}
// 計算最亮區(qū)間下限T
int T = 0;
int num = 0;
int K = static_cast<int>(row * col * 0.1);
for (int i = 765; i >= 0; --i)
{
num += RGBSum[i];
if (num > K)
{
T = i;
break;
}
}
// 計算單通道亮區(qū)平均值
double Bm = 0.0, Gm = 0.0, Rm = 0.0;
int count = 0;
for (int i = 0; i < row; ++i)
{
uchar *b = Channel[0].ptr<uchar>(i);
uchar *g = Channel[1].ptr<uchar>(i);
uchar *r = Channel[2].ptr<uchar>(i);
for (int j = 0; j < col; ++j)
{
int sum = b[j] + g[j] + r[j];
if (sum > T)
{
Bm += b[j];
Gm += g[j];
Rm += r[j];
count++;
}
}
}
Bm /= count;
Gm /= count;
Rm /= count;
// 通道調(diào)整
Channel[0] *= maxB / Bm;
Channel[1] *= maxG / Gm;
Channel[2] *= maxR / Rm;
// 合并通道
cv::merge(Channel, result);
return result;
}C++測試代碼
#include <iostream>
#include <opencv.hpp>
using namespace std;
// 白平衡-完美反射
cv::Mat WhiteBalcane_PRA(cv::Mat src)
{
cv::Mat result = src.clone();
if (src.channels() != 3)
{
cout << "The number of image channels is not 3." << endl;
return result;
}
// 通道分離
vector<cv::Mat> Channel;
cv::split(src, Channel);
// 定義參數(shù)
int row = src.rows;
int col = src.cols;
int RGBSum[766] = { 0 };
uchar maxR, maxG, maxB;
// 計算單通道最大值
for (int i = 0; i < row; ++i)
{
uchar *b = Channel[0].ptr<uchar>(i);
uchar *g = Channel[1].ptr<uchar>(i);
uchar *r = Channel[2].ptr<uchar>(i);
for (int j = 0; j < col; ++j)
{
int sum = b[j] + g[j] + r[j];
RGBSum[sum]++;
maxB = max(maxB, b[j]);
maxG = max(maxG, g[j]);
maxR = max(maxR, r[j]);
}
}
// 計算最亮區(qū)間下限T
int T = 0;
int num = 0;
int K = static_cast<int>(row * col * 0.1);
for (int i = 765; i >= 0; --i)
{
num += RGBSum[i];
if (num > K)
{
T = i;
break;
}
}
// 計算單通道亮區(qū)平均值
double Bm = 0.0, Gm = 0.0, Rm = 0.0;
int count = 0;
for (int i = 0; i < row; ++i)
{
uchar *b = Channel[0].ptr<uchar>(i);
uchar *g = Channel[1].ptr<uchar>(i);
uchar *r = Channel[2].ptr<uchar>(i);
for (int j = 0; j < col; ++j)
{
int sum = b[j] + g[j] + r[j];
if (sum > T)
{
Bm += b[j];
Gm += g[j];
Rm += r[j];
count++;
}
}
}
Bm /= count;
Gm /= count;
Rm /= count;
// 通道調(diào)整
Channel[0] *= maxB / Bm;
Channel[1] *= maxG / Gm;
Channel[2] *= maxR / Rm;
// 合并通道
cv::merge(Channel, result);
return result;
}
int main()
{
// 載入原圖
cv::Mat src = cv::imread("test21.jpg");
// 白平衡-完美反射
cv::Mat result = WhiteBalcane_PRA(src);
// 顯示
cv::imshow("src", src);
cv::imshow("result", result);
cv::waitKey(0);
return 0;
}測試效果

圖1 原圖

圖2 白平衡后圖像
如圖1所示,是傍晚的一張圖像,眾所周知,傍晚的色溫是較低的,此時采用高于傍晚色溫的色溫值拍照,就會得到一張暖色系的圖片,偏黃;對其進(jìn)行白平衡,使圖片顏色回歸真實(shí)的環(huán)境色溫,就得到如圖2的效果。
如果你用過灰度世界算法,你會發(fā)現(xiàn)完美反射算法的效果更亮些;這是因?yàn)樗{(lán)通道最大值和藍(lán)通道亮區(qū)平均值的差距較大,因而補(bǔ)償?shù)膹?qiáng)度很強(qiáng);若原圖中不存在白色區(qū),那藍(lán)通道的補(bǔ)償就會較弱,達(dá)不到較好的預(yù)期,因此該算法所處理的圖像中最好有較白的點(diǎn)。

圖3 單色原圖

圖4 單色圖白平衡效果
如圖3所示,是一張色彩相對一致的圖像,整體呈粉色系?;叶仁澜绶▽⑷ǖ罃?shù)值進(jìn)行平均再補(bǔ)償,就會使三通道的數(shù)值趨近一致,進(jìn)而呈現(xiàn)灰色;而完美反射算法,計算的是三通道各自數(shù)值最大值和其亮區(qū)平均值的差距,再進(jìn)行補(bǔ)償,因此三通道的數(shù)值都會適當(dāng)加強(qiáng),使光感更強(qiáng),即圖片更亮。
接下來做個有趣的測試,將原本粉色的墻紙設(shè)為較純的綠色。

圖5 調(diào)色后的圖像

圖6 白平衡效果圖
如圖5所示,因?yàn)閳D像中存在色調(diào)相沖的兩個部分,完美反射算法的優(yōu)勢在這種場景下體現(xiàn)的很明顯。因?yàn)榫G色區(qū)域較大,灰度世界算法中單純的計算均值再平衡,會無腦地將整圖的綠色分量降低,紅色分量提高,使得結(jié)果異?;欢昝婪瓷渌惴?,因?yàn)閳D中有白值,三通道的最大值均在250左右,對綠色分量而言,其最亮區(qū)的均值接近于230,而紅色分量和藍(lán)色分量而言,其最亮區(qū)的均值也接近于200多,因此三通道的平衡結(jié)果就是整體提亮,而不是被無腦平均。
灰度世界算法效果圖見:
C++ OpenCV實(shí)現(xiàn)白平衡之灰度世界算法
到此這篇關(guān)于C++ OpenCV實(shí)現(xiàn)白平衡之完美反射算法的文章就介紹到這了,更多相關(guān)C++ OpenCV完美反射算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VS2019使用Windows桌面應(yīng)用程序模塊創(chuàng)建Win32窗口
這篇文章主要介紹了VS2019使用Windows桌面應(yīng)用程序模塊創(chuàng)建Win32窗口,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
c++帶有string的結(jié)構(gòu)體賦值和清零問題
這篇文章主要介紹了c++帶有string的結(jié)構(gòu)體賦值和清零問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01
Qt連接數(shù)據(jù)庫并實(shí)現(xiàn)數(shù)據(jù)庫增刪改查的圖文教程
QT連接數(shù)據(jù)庫是應(yīng)用開發(fā)的常用基礎(chǔ)操作,經(jīng)過實(shí)驗(yàn)我總結(jié)了一些例程,下面這篇文章主要給大家介紹了關(guān)于Qt連接數(shù)據(jù)庫并實(shí)現(xiàn)數(shù)據(jù)庫增刪改查的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04
C++中一維數(shù)組與指針的關(guān)系詳細(xì)總結(jié)
以下是對C++中一維數(shù)組與指針的關(guān)系進(jìn)行了詳細(xì)的總結(jié)介紹,需要的朋友可以過來參考下2013-09-09
VC++中HTControl控件類的CHTSlider控制桿控件類簡介
這篇文章主要介紹了VC++中HTControl控件類的CHTSlider控制桿控件類,需要的朋友可以參考下2014-08-08
關(guān)于C語言函數(shù)strstr()的分析以及實(shí)現(xiàn)
以下是對C語言中strstr()函數(shù)的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以參考下2013-07-07
C++11 學(xué)習(xí)筆記之std::function和bind綁定器
這篇文章主要介紹了C++11 學(xué)習(xí)筆記之std::function和bind綁定器,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-07-07
簡單總結(jié)C語言中的運(yùn)算符優(yōu)先級
這篇文章主要介紹了C語言中的運(yùn)算符優(yōu)先級,文中簡單總結(jié)了一些常用運(yùn)算符的優(yōu)先級順序以及記憶技巧,需要的朋友可以參考下2016-05-05

