自动白平衡---灰度世界算法
白平衡的概念
白平衡,字面上的理解是白色的平衡。白平衡是描述显示器中红、绿、蓝三基色混合生成后白色精确度的一项指标。白平衡是电视摄像领域一个非常重要的概念,通过它可以解决色彩还原和色调处理的一系列问题。白平衡的英文为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