赞
踩
之前学习了ISP自动白平衡 - 灰度世界算法,这里继续跟大家分享下第二个经典算法 - 完美反射算法。
完美反射算法是选取图像中R/G/B三通道中像素值最大的点作为白点,以此来更新图像,实现图像白平衡。
算法步骤:
#include <iostream> #include <opencv2\imgcodecs.hpp> #include <opencv2\imgproc.hpp> #include <opencv2\core.hpp> #include <opencv2\highgui.hpp> #include <vector> using namespace cv; // Auto White Balance - Gray World Algorithm int AWB_GrayWorld(InputArray src, OutputArray dst) { CV_Assert(src.channels() == 3, "AWB_GrayWorld() input image must be 3 channels!"); Mat mSrc = src.getMat(); if (mSrc.empty()) { std::cout << "AWB_GrayWorld() input image is empty!" << std::endl; return -1; } dst.create(mSrc.size(), mSrc.type()); Mat mDst = dst.getMat(); if (mDst.empty()) { std::cout << "AWB_GrayWorld() create dst image failed!" << std::endl; return -1; } //对输入src图像进行RGB分离 std::vector<Mat> splitedBGR; splitedBGR.reserve(3); split(mSrc, splitedBGR); //分别计算R/G/B图像像素值均值 double meanR = 0, meanG = 0, meanB = 0; meanB = mean(splitedBGR[0])[0]; meanG = mean(splitedBGR[1])[0]; meanR = mean(splitedBGR[2])[0]; //计算R/G/B图像的增益 double gainR = 0, gainG = 0, gainB = 0; gainR = (meanR + meanG + meanB) / (3 * meanR); gainG = (meanR + meanG + meanB) / (3 * meanG); gainB = (meanR + meanG + meanB) / (3 * meanB); //计算增益后R/G/B图像 splitedBGR[0] = splitedBGR[0] * gainB; splitedBGR[1] = splitedBGR[1] * gainG; splitedBGR[2] = splitedBGR[2] * gainR; //将三个单通道图像合成一个三通道图像 merge(splitedBGR, mDst); return 0; } int AWB_PerfectReflect(InputArray src, OutputArray dst) { CV_Assert_2(src.channels() == 3, "AWB_PerfectReflect() src image must has 3 channels!"); Mat mSrc = src.getMat(); if (mSrc.empty()) { std::cout << "AWB_PerfectReflect() src image can't be empty!" << std::endl; return -1; } dst.create(mSrc.size(), mSrc.type()); Mat mDst = dst.getMat(); int sumHist[766] = { 0 };//max(R+G+B) = 255*3 = 765, 0~765->766 int maxVal = 0; for (int i = 0; i < mSrc.rows; i++) { for (int j = 0; j < mSrc.cols; j++) { Vec3b p = mSrc.at<Vec3b>(i, j); int sum = p[0] + p[1] + p[2]; sumHist[sum]++; maxVal = maxVal > p[0] ? maxVal : p[0]; maxVal = maxVal > p[1] ? maxVal : p[1]; maxVal = maxVal > p[2] ? maxVal : p[2]; } } int totalPixels = 0; for (int i = 765; i >= 0; i--) { totalPixels += sumHist[i]; } CV_Assert_2(totalPixels == mSrc.rows*mSrc.cols, "sumHist pixels number isn't equal with image size!"); float ratio = 0.1; int cumPixel = 0; int threshold = 0; for (int i = 765; i >= 0; i--) { cumPixel += sumHist[i]; if (cumPixel >= ratio * mSrc.rows* mSrc.cols) { threshold = i; break; } } int avgB = 0, avgG = 0, avgR = 0; int countPixels = 0; for (int i = 0; i < mSrc.rows; i++) { for (int j = 0; j < mSrc.cols; j++) { Vec3b p = mSrc.at<Vec3b>(i, j); int sum = p[0] + p[1] + p[2]; if (sum > threshold) { countPixels++; avgB += p[0]; avgG += p[1]; avgR += p[2]; } } } avgB /= countPixels; avgG /= countPixels; avgR /= countPixels; for (int i = 0; i < mSrc.rows; i++) { for (int j = 0; j < mSrc.cols; j++) { Vec3b p = mSrc.at<Vec3b>(i, j); int B = p[0] * maxVal / avgB; B = B > 255 ? 255 : B; mDst.at<Vec3b>(i, j)[0] = (uchar)B; int G = p[1] * maxVal / avgG; G = G > 255 ? 255 : G; mDst.at<Vec3b>(i, j)[1] = (uchar)G; int R = p[2] * maxVal / avgR; R = R > 255 ? 255 : R; mDst.at<Vec3b>(i, j)[2] = (uchar)R; } } return 0; } int main() { std::string imgPath = "C:\\Temp\\common\\Workspace\\Opencv\\images\\awb_grayworld.jpg"; Mat src = imread(imgPath); Mat dstGW; int status = AWB_GrayWorld(src, dstGW); if (status != 0) goto EXIT; imshow("src", src); imshow("AWB GrayWorld", dstGW); waitKey(0); { Mat dstPR; status = AWB_PerfectReflect(src, dstPR); if (status != 0) goto EXIT; imshow("AWB PerfectReflect", dstPR); waitKey(0); } EXIT: system("pause"); destroyAllWindows(); return 0; }
原图:
灰度世界算法结果:
完美反射算法结果:
从结果来看,完美反射算法结果要好一些,但是如果图像最亮点不是白点的话,效果不佳。
https://www.cnblogs.com/Imageshop/archive/2013/04/20/3032062.html
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。