原理
图像白化(whitening)可用于对过分曝光或低曝光的图片进行处理,处理的方式就是改变图像的平均像素值为 0 ,改变图像的方差为单位方差 1。咱们须要先计算原图像的均值和方差,而后对原图像的每一个像素值作变换。假设图像 P 有 I 行 J 列,每一个像素的值为 pij, 均值和方差的计算公式以下。函数
变换后新图像的每一个像素值 xij 为spa
OpenCV 实现
用 OpenCV 的内置函数计算均值和方差,而后对遍历每一个像素值并对每一个像素作变换。这里须要注意的是变换后的像素值确定是有一部分会是负值(小于均值的那部分),咱们须要把变换后的像素值从新映射到 [0, 255] 的范围内。由于 OpenCV 中的 normalize 函数没法实现这种任意范围内的映射,咱们须要本身去实现这类映射。咱们须要找出变换后图像中的最小 min 和最大像素值 max, 假设须要映射的范围为 [a, b]。 该映射可用函数(b-a)*(xij-min)/(max-min) 实现。关键部分实现代码以下所示:3d
1 void whitening() { 2 Mat image = imread("test.jpg",IMREAD_GRAYSCALE); 3 4 double mean, stddev; 5 Mat temp_m, temp_sd; 6 meanStdDev(image, temp_m, temp_sd); 7 mean = temp_m.at<double>(0, 0)/255.0; 8 stddev = temp_sd.at<double>(0, 0)/255.0; 9 Mat temp_image( image.rows, image.cols, CV_64F); 10 for (int i = 0; i < image.rows; i++) 11 for (int j = 0; j < image.cols; j++) { 12 double pixelVal = image.at<uchar>(i, j)/255.0; 13 double temp = (pixelVal - mean) / stddev; 14 temp_image.at<double>(i, j) = temp; 15 } 16 17 double max, min; 18 minMaxLoc(temp_image, &min, &max); 19 for (int i = 0; i < image.rows; i++) 20 for (int j = 0; j < image.cols; j++) { 21 double pixelVal = temp_image.at<double>(i, j); 22 image.at<uchar>(i, j) = (uchar)round(255.0 * (pixelVal - min) / (max - min)); 23 } 24 25 imshow("New Image", image); 26 waitKey(0); 27 }
结果
以下图所示,能够看到对左边过分曝光的图片通过白化处理后图片的曝光程度减弱了。再看图像直方图,白化变换彷佛是对原来的直方图作了一个横向的拉伸,使得像素值的分布更加的均匀,而不是集中在一个有限的(高曝光的)范围内。code
参考
[1] Computer vision: models, learning and inference, Simon J. D. Prince.orm