当一副彩色图像数字化后,在显示时颜色有时会看起来有些不正常。这是因为颜色通道中不同的敏感度、增光因子、偏移量等,导致数字化中的三个图像分量(R,G,B)出现不同的变换,使结果图像的三原色"不平衡",从而使景物中所有物体的颜色都偏离了其原有的真实色彩。彩色平衡处理的目的就是将有色偏的图像进行颜色校正,获得正常颜色的图像。白平衡方法使一种常见的彩色平衡处理方法。
白平衡原理是,如果原始场景中的某些像素点应该是白色的(即R=G=B=255),但是由于图像存在色偏,这些点的R、G、B三个分量的值不再保持相同,通过调整这三个颜色分量的值,使之达到平衡,由此获得对整幅图像的彩色平衡映射关系,通过该映射关系对整幅图像进行处理,即可达到彩色平衡的目的。
实现白平衡的算法有很多,这里介绍一种基本的白平衡方法。
int main()
{
cv::Mat img = cv::imread("LenaRGB.bmp");
int width= img.cols;
int height = img.rows;
cv::Mat Y = cv::Mat::zeros(height, width, CV_32FC1);
cv::Mat R = cv::Mat::zeros(height, width, CV_8UC1);
cv::Mat G = cv::Mat::zeros(height, width, CV_8UC1);
cv::Mat B = cv::Mat::zeros(height, width, CV_8UC1);
for (int row = 0; row < height; row++)
{
cv::Vec3b * current_ptr = img.ptr<cv::Vec3b>(row);
for (int col = 0; col < width; col++)
{
R.at<uchar>(row, col) = (*(current_ptr + col))[2];
G.at<uchar>(row, col) = (*(current_ptr + col))[1];
B.at<uchar>(row, col) = (*(current_ptr + col))[0];
Y.at<float>(row, col) = 0.299*(*(current_ptr + col))[2]+0.587*(*(current_ptr + col))[1]+
0.144*(*(current_ptr + col))[0];
}
}
//求取Ymax
double minValue, Y_max;
cv::minMaxLoc(Y, &minValue, &Y_max);
float Y_value=0.0, R_value=0.0, G_value=0.0, B_value=0.0;
int num = 0;
for (int row = 0; row < height; row++)
{
float * current_ptr = Y.ptr<float>(row);
for (int col = 0; col < width; col++)
{
if (*(current_ptr + col) >= 0.95*Y_max)
{
num += 1;
Y_value += Y.at<float>(row, col);
R_value += R.at<uchar>(row, col);
G_value += G.at<uchar>(row, col);
B_value += B.at<uchar>(row, col);
}
}
}
Y_value = Y_value / num;
R_value = R_value / num;
G_value = G_value / num;
B_value = B_value / num;
//调整系数
float k_R = Y_value / R_value;
float k_G = Y_value / G_value;
float k_B = Y_value / B_value;
cv::Mat output_image = cv::Mat::zeros(height, width, CV_32FC3);
for (int row = 0; row < height; row++)
{
cv::Vec3b * img_ptr = img.ptr<cv::Vec3b>(row);
cv::Vec3f * output_ptr = output_image.ptr<cv::Vec3f>(row);
for (int col = 0; col < width; col++)
{
(*(output_ptr + col))[2] = k_R*(*(img_ptr + col))[2];
(*(output_ptr + col))[1] = k_G * (*(img_ptr + col))[1];
(*(output_ptr + col))[0] = k_B * (*(img_ptr + col))[0];
}
}
cv::convertScaleAbs(output_image, output_image);
cv::imshow("input_image", img);
cv::imshow("output_image", output_image);
return 0;
}
1.数字图像处理基础.朱虹