自动白平衡--完美反射算法(Perfect Reflector Assumption)

44 篇文章 33 订阅

自动白平衡–完美反射算法(Perfect Reflector Assumption)

微信公众号:幼儿园的学霸

目录

理论详解

完美反射算法解释:参考文献:Color balancing of digital photos using simple image statistics

Perfect reflection color correction. The object itself has no color; it shows color through a different wavelength of light absorption, reflection, and projection. If the object is white, all the light is reflected. The white object or area is called the perfect reflector. Perfect reflection theory is based on the hypothesis that it consider the perfect reflector as a standard white in an image. No matter what light it is, a white object, the R, G, and B of its image are of great value. Based on the perfect reflector, it corrects other colors.

完美反射算法假设图片中最亮的点就是一面镜子(因此,完美反射算法也有叫镜面法的),完美地反射了外部光照,因此,如果图像中存在一个“镜面”的话,那么在特定光源下,可以将所获得的"镜面"的色彩信息认为是当前光源的信息。那么在这个假设下,图像中就一定存在一个纯白色的的像素或者最亮的点,并根据这些白点为参考,对图像进行白平衡。最亮点定义为(R,G,B)中的最大值让这些白点的RGB三个通道按照比例拉伸到255,并将其他的点的三个通道按照同样比例拉伸,超过255的设为255。显然只是用一个点作为标准来进行校验的话明显不足,因此通常是用图像上最亮的一部分点的均值作为参考,对图像进行矫正。本文使用Ratio来进行不同比率的矫正。

算法步骤如下:

  • 遍历图像每一个像素点,1)计算各点R+G+B像素和,2)同时找到图像中的最亮点,并保存
  • 按照像素和值的大小计算出其前10%或其他Ratio的参考点的阈值T
  • 再次遍历图像中的每个点,计算R+G+B大于T的所有点的R、G、B分量的累积和、均值
  • 根据最亮点的值和上一步计算的R、G、B均值,计算图像各通道的增益系数
  • 根据增益系数,将图像每个像素各通道进行处理,同时保证量化在[0,255]区间

核心公式如下:
1)增益:
{ g a i n R = M a x V a l / R ˉ g a i n G = M a x V a l / G ˉ g a i n B = M a x V a l / B ˉ \begin{cases} gain_R={MaxVal}/{\bar{R}} \\ gain_G={MaxVal}/{\bar{G}} \\ gain_B={MaxVal}/{\bar{B}} \end{cases} gainR=MaxVal/RˉgainG=MaxVal/GˉgainB=MaxVal/Bˉ

MaxVal是所有像素点中的R,G,B的最大值.
R ˉ 、 G ˉ 、 B ˉ {\bar{R}}、{\bar{G}}、{\bar{B}} RˉGˉBˉ是为像素点R+G+B分量和大于 r o w ∗ c o l ∗ R a t i o row*col*Ratio rowcolRatio下各通道的像素点的均值

2)矫正
{ R ′ = g a i n R ∗ R G ′ = g a i n G ∗ G B ′ = g a i n B ∗ B \begin{cases} R^{'}=gain_R * R \\ G^{'}=gain_G * G \\ B^{'}=gain_B * B \end{cases} R=gainRRG=gainGGB=gainBB

代码实现

//自动白平衡完美反射算法
//Input Param:src--输入图像,3 channels
//            ratio--白色像素比例因子
//Output Param:dst--归一化后的图像,type as src
//Return:   null
void PerfectReflectionAlgorithm(const cv::Mat& src,cv::Mat& dst,float ratio)
{
    assert(CV_8UC3==src.type());

    const int row = src.rows;
    const int col = src.cols;
    dst.create(row,col,CV_8UC3);

    cv::Mat sumMat(row,col,CV_32SC1);//每个位置的像素值和,防止重复计算

    int HistRGB[767] = { 0 };//像素和的数量
    int maxVal = 0;
    auto sumIter = sumMat.begin<int>();
    for(auto iter=src.begin<cv::Vec3b>();iter!=src.end<cv::Vec3b>(); ++iter,++sumIter)
    {
        //找到图像中最亮的点,且定义为最大值
        maxVal = std::max(maxVal, (int)((*iter)[0]));
        maxVal = std::max(maxVal, (int)((*iter)[1]));
        maxVal = std::max(maxVal, (int)((*iter)[2]));

        //计算像素和
        int sum = (*iter)[0] + (*iter)[1] + (*iter)[2];
        *sumIter = sum;

        //保存像素和的数量
        HistRGB[sum]++;
    }


    //计算阈值T
    //float ratio = 0.05;
    ratio = row * col * ratio;//按照的值的大小计算出其前 5% 或其他 Ratio 的白色参考点的阈值 T。

    int Threshold = 0;
    int sum = 0;
    for (int i = 766; i >= 0; i--)
    {
        sum += HistRGB[i];
        //按照的值的大小计算出其前 10% 或其他 Ratio 的白色参考点的阈值 T。
        if (sum > ratio) {
            Threshold = i;
            break;
        }
    }


    int sumB = 0;
    int sumG = 0;
    int sumR = 0;
    int cnt = 0;
    sumIter = sumMat.begin<int>();
    for(auto iter=src.begin<cv::Vec3b>();iter!=src.end<cv::Vec3b>(); ++iter,++sumIter)
    {
        if( *sumIter > Threshold )
        {
            sumB += (*iter)[0];
            sumG += (*iter)[1];
            sumR += (*iter)[2];
            ++cnt;
        }
    }


    //计算R+G+BR+G+B大于 T 的所有点的R、G、B分量的累积和的平均值
    float avgB = sumB *1.0f/cnt;
    float avgG = sumG *1.0f / cnt;
    float avgR = sumR *1.0f/ cnt;
    float gain_B = maxVal*1.0f/avgB;
    float gain_G = maxVal*1.0f/avgG;
    float gain_R = maxVal*1.0f/avgR;

    //将每一个像素量化到[0,255]
    auto dstIter = dst.begin<cv::Vec3b>();
    for(auto iter=src.begin<cv::Vec3b>();iter!=src.end<cv::Vec3b>(); ++iter,++dstIter)
    {
        int b = (*iter)[0] * gain_B;
        int g = (*iter)[1] * gain_G;
        int r = (*iter)[2] * gain_R;

        if(b>255)b=255;
        else if( b<0) b=0;

        if(g>255)g=255;
        else if( g<0) g=0;

        if(r>255)r=255;
        else if( r<0) r=0;

        (*dstIter)[0] = b;
        (*dstIter)[1] = g;
        (*dstIter)[2] = r;
    }
}

利用该算法和上一篇文章介绍的灰度世界算法,对图像进行自动白平衡处理,效果如下:

输入图片灰度世界算法完美反射算法
输入1灰度世界完美反射
输入2灰度世界完美反射

从效果上看,该算法应该比灰度世界的效果要好些,但是也还是受到Ratio这个参数的影响。部分情况下,过高的Ration导致图片过于泛白。

如果查看opencv_contrib中封装的完美反射算法的实现,可以看到其采用了固定的ratio值。感兴趣的话可以阅读源码,了解下该值具体是多少。一点提示:opencv中,完美反射算法函数名称为cv::xphoto::createSimpleWB()

参考资料

1.Color sensors and their applications based on real-time color image segmentation for cyber physical systems
2.图像自动白平衡算法C++实现之全反射理论算法PR(Perfect Reflector Assumption)
3.自动白平衡之完美反射算法原理及 C++实现
4.白平衡之完美反射算法



下面的是我的公众号二维码图片,按需关注。
图注:幼儿园的学霸

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值