数字图像处理(十一)白平衡算法


前言

  当一副彩色图像数字化后,在显示时颜色有时会看起来有些不正常。这是因为颜色通道中不同的敏感度、增光因子、偏移量等,导致数字化中的三个图像分量(R,G,B)出现不同的变换,使结果图像的三原色"不平衡",从而使景物中所有物体的颜色都偏离了其原有的真实色彩。彩色平衡处理的目的就是将有色偏的图像进行颜色校正,获得正常颜色的图像。白平衡方法使一种常见的彩色平衡处理方法。


一、白平衡算法原理

  白平衡原理是,如果原始场景中的某些像素点应该是白色的(即R=G=B=255),但是由于图像存在色偏,这些点的R、G、B三个分量的值不再保持相同,通过调整这三个颜色分量的值,使之达到平衡,由此获得对整幅图像的彩色平衡映射关系,通过该映射关系对整幅图像进行处理,即可达到彩色平衡的目的。

二、算法具体步骤

  实现白平衡的算法有很多,这里介绍一种基本的白平衡方法。

  1. 对拍摄到的有色偏的图像,按照下式计算该图像的亮度分量。 Y = 0.299 × R + 0.587 × G + 0.114 × B Y=0.299\times R+0.587\times G+0.114\times B Y=0.299×R+0.587×G+0.114×B由于存在色偏,即现实场景中白色的点,在图像中也可能不是理想状态的白色,即 Y ≠ 255 Y\neq255 Y=255。但是可以肯定的是,白色的亮度为图像中的最大亮度。所以需要求出图像中的最大亮度 Y m a x Y_{max} Ymax和平均亮度 Y ˉ \bar{Y} Yˉ
  2. 考虑对环境光照的适应性,寻找图像中所有亮度 ≤ 0.95 ⋅ Y m a x \le 0.95 \cdot Y_{max} 0.95Ymax的像素点。将这些点假设为原始场景中的白色点,即设这些点所构成的像素点集为白色点集 { f ( i , j ) ∈ Ω w h i t e } \{f(i,j)\in\Omega_{white}\} {f(i,j)Ωwhite}
  3. 计算白色点集 Ω w h i t e \Omega_{white} Ωwhite中所有像素的R、G、B三个颜色分量的均值 R ˉ \bar{R} Rˉ G ˉ \bar{G} Gˉ B ˉ \bar{B} Bˉ
  4. 按照下式计算颜色均衡调整参数: k R = Y ˉ G ˉ k_R=\frac{\bar{Y}}{\bar{G}} kR=GˉYˉ k G = Y ˉ G ˉ k_G=\frac{\bar{Y}}{\bar{G}} kG=GˉYˉ k B = Y ˉ B ˉ k_B=\frac{\bar{Y}}{\bar{B}} kB=BˉYˉ
  5. 对整幅图像的R、G、B三个颜色分量,进行彩色平衡调整如下: R ∗ = k R ⋅ R R^*=k_R\cdot R R=kRR G ∗ = k G ⋅ G G^*=k_G\cdot G G=kGG B ∗ = k B ⋅ B B^*=k_B\cdot B B=kBB

三、C++代码

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.数字图像处理基础.朱虹

  • 1
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
白平衡是一种用于调整图像颜色的方法,它可以使图像中的白色看起来更加真实和自然。在数字图像处理中,常用的白平衡算法有基于灰度世界假设的算法。 灰度世界算法假设整个图像中的颜色分布是均匀的,因此平均颜色应该是灰色。该算法的步骤如下: 1. 计算整个图像的 RGB 三个通道的平均值。 2. 计算每个通道的增益因子,使得每个通道的平均值等于整个图像的平均值。 3. 将每个像素的 RGB 值乘以对应通道的增益因子,以实现白平衡。 以下是使用 EmguCv 库实现灰度世界算法的 C# 代码示例: ```csharp using Emgu.CV; using Emgu.CV.Structure; public static Image<Bgr, byte> GrayWorld(Image<Bgr, byte> img) { // 计算图像的平均 B、G、R 值 double avgB = 0, avgG = 0, avgR = 0; int pixelCount = img.Width * img.Height; for (int y = 0; y < img.Height; y++) { for (int x = 0; x < img.Width; x++) { Bgr color = img[y, x]; avgB += color.Blue; avgG += color.Green; avgR += color.Red; } } avgB /= pixelCount; avgG /= pixelCount; avgR /= pixelCount; // 计算每个通道的增益因子 double[] gain = new double[3]; gain[0] = avgG / avgB; // 蓝色通道的增益因子 gain[1] = 1.0; // 绿色通道的增益因子 gain[2] = avgG / avgR; // 红色通道的增益因子 // 对每个像素应用增益因子 for (int y = 0; y < img.Height; y++) { for (int x = 0; x < img.Width; x++) { Bgr color = img[y, x]; byte newB = (byte)(color.Blue * gain[0]); byte newG = (byte)(color.Green * gain[1]); byte newR = (byte)(color.Red * gain[2]); img[y, x] = new Bgr(newB, newG, newR); } } return img; } ``` 使用方法: ```csharp Image<Bgr, byte> img = new Image<Bgr, byte>("image.jpg"); img = GrayWorld(img); img.Save("result.jpg"); ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值