白平衡的概念
白平衡,字面上的理解是白色的平衡。白平衡是描述顯示器中紅、綠、藍三基色混合生成后白色精確度的一項指標。白平衡是電視攝像領域一個非常重要的概念,通過它可以解決色彩還原和色調處理的一系列問題。白平衡的英文為White Balance,其基本概念是“不管在任何光源下,都能將白色物體還原為白色”,對在特定光源下拍攝時出現的偏色現象,通過加強對應的補色來進行補償。
白平衡---灰度世界算法
原理
先驗:白光RGB分量為(R=G=B=255);灰色光RGB分量(R=G=B)。
人的視覺系統具有顏色恆常性,能從變化的光照環境和成像條件下獲取物體表面顏色的不變特性,但成像設備並不具有這樣的調節功能,不同的光照環境會導致采集到的圖像顏色與真實顏色存在一定程度的偏差,需要選擇合適的顏色平衡算法去消除光照環境對顏色顯示的影響。
灰度世界算法以灰度世界假設為基礎,假設為:對於一幅有着大量色彩變化的圖像,RGB三個分量的平均值趨於同一個灰度值$\overline{Gray} = \frac{\overline{R} + \overline{G} + \overline{B}}{3}$。從物理意思上講,灰度世界算法假設自然界景物對於光線的平均反射的均值在整體上是一個定值,這個定值近似為“灰色”。顏色平衡算法將這一假設強制應用於待處理的圖像,可以從圖像中消除環境光的影響,獲得原始場景圖像。
算法步驟及代碼實現
- 確定 $\overline{Gray}$
方法一:取固定值,比如圖像最亮灰度值的一半(這里的一半是指各個通道最大值的一半?!)
方法二:計算圖像R,G,B三個通道的$\overline{R}$,$\overline{G}$,$\overline{B}$,取$\overline{Gray} = \frac{\overline{R} + \overline{G} + \overline{B}}{3}$。(這里選用方法二)
- 計算R,G,B三個通道的增益系數:$k_r = \frac{\overline{Gray}}{\overline{R}}$,$k_g = \frac{\overline{Gray}}{\overline{G}}$,$k_b = \frac{\overline{Gray}}{\overline{B}}$
- 根據Von Kries對角模型,對於圖像中的每個像素C,調整其R,G,B分量,C(R') = C(R)*k_r,C(G') = C(G)*k_g,C(B') = C(B)*k_b.
OpenCv代碼實現Demo
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "iostream"
#include "algorithm"
#include "vector"
#include "stdio.h"
#include "map"
#include "unordered_map"
using namespace std;
using namespace cv;
Mat GrayWorld(const Mat &src){
vector <Mat> bgr;
cv::split(src, bgr);
double B = 0;
double G = 0;
double R = 0;
int row = src.rows;
int col = src.cols;
Mat dst(row, col, CV_8UC3);
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
B += 1.0 * src.at<Vec3b>(i, j)[0];
G += 1.0 * src.at<Vec3b>(i, j)[1];
R += 1.0 * src.at<Vec3b>(i, j)[2];
}
}
B /= (row * col);
G /= (row * col);
R /= (row * col);
printf("%.5f %.5f %.5f\n", B, G, R);
double GrayValue = (B + G + R) / 3;
printf("%.5f\n", GrayValue);
double kr = GrayValue / R;
double kg = GrayValue / G;
double kb = GrayValue / B;
printf("%.5f %.5f %.5f\n", kb, kg, kr);
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
dst.at<Vec3b>(i, j)[0] = (int)(kb * src.at<Vec3b>(i, j)[0]);
dst.at<Vec3b>(i, j)[1] = (int)(kg * src.at<Vec3b>(i, j)[1]);
dst.at<Vec3b>(i, j)[2] = (int)(kr * src.at<Vec3b>(i, j)[2]);
for(int k = 0; k < 3; k++){
if(dst.at<Vec3b>(i, j)[k] > 255){
dst.at<Vec3b>(i, j)[k] = 255;
}
}
}
}
return dst;
}
int main(){
Mat src = cv::imread("../test.jpg");
Mat dst = GrayWorld(src);
cv::imshow("origin", src);
cv::imshow("result", dst);
cv::imwrite("../testResult.jpg", dst);
cv::waitKey(0);
return 0;
}
測試結果
左圖為原圖,右圖為灰度世界算法處理后的結果圖。

算法優缺點
- 對於上式,計算中可能會存在溢出(>255,不會出現小於0的)現象,處理方式有兩種。
a、 直接將像素設置為255,這可能會造成圖像整體偏白。
b、 計算所有Rnew、Gnew、Bnew的最大值,然后利用該最大值將將計算后數據重新線性映射到[0,255]內。實踐證明這種方式將會使圖像整體偏暗,建議采用第一種方案。
- 此算法簡單快速,但是當圖像場景顏色並不豐富時,尤其詩出現大量單色物體時,該算法會失效。
---------------------------------------------------------------------------------------------------------------------------------------------
參考
https://blog.csdn.net/just_sort/article/details/85638420
https://www.cnblogs.com/Imageshop/archive/2013/04/20/3032062.html
