白平衡之完美反射算法

一、算法背景

  白平衡是图像处理比较常见的一个概念,在采集图像的过程中,相机的感光元件或者镜头会对原始色彩造成影响,而白平衡技术通常可以用来校正这种光线和镜头对颜色影响。所以现在先记录一个白平衡算法,叫做完美反射算法,这个算法原理也不是有多复杂,但是效果还是挺好的,而且基本也不需要调节参数就有效果了。完美反射算法很多博客都有介绍,而且实际上也还是就几个公式,所以我也是简单记录重要的公式和实现代码而已。

二、算法原理

  完美反射算法(perfect Reflector, 也有叫镜面法的)认为,一幅彩色图像中,"镜面"是可以完全发射光源照射在物体上面的光线,因此,如果图像中存在一个“镜面”的话,那么在特定光源下,可以将所获得的"镜面"的色彩信息认为是当前光源的信息[1],那么在这个假设下,图像中就一定存在一个纯白色的的像素或者最亮的点,在对图像进行白平衡调整的时候会以该点作为参考来校准图像的像素。完美反射算法流程如下:
  (1)、遍历原始图像,统计RGB三通道之和的直方图;
  (2)、遍历原始图像,找到RGB三通道各自的最大值BmaxGmaxRmax
  (3)、设定比例 r ,对RGB之和的直方图进行倒叙遍历,找到使白点像素个数超过总像素个数比例的阈值,T
  (4)、遍历原始图像,计算RGB之和大于 T 的像素,各个通道取平均,得到BavgGavgRavg
  (5)、遍历原始图像,分别计算RGB三通道的调整值Aout=A / Aavg * Amax
  (6)、防溢出处理,这里可以采用简单的截断即可。

三、主要代码

  代码也没优化,就这样哈。

int histRGBSum[255 * 3 + 1] = { 0 };

//统计R+G+B
uchar maxValue[3] = { 0 };
for (int i = 0; i < src.rows; i++)
{
    const uchar *ptrSrc = src.ptr<uchar>(i);
    for (int j = 0; j < src.cols; j++)
    {
        int sum = *(ptrSrc + 3 * j) + *(ptrSrc + 3 * j + 1) + *(ptrSrc + 3 * j + 2);
        histRGBSum[sum]++;
        maxValue[0] = std::max(maxValue[0], *(ptrSrc + 3 * j));
        maxValue[1] = std::max(maxValue[1], *(ptrSrc + 3 * j + 1));
        maxValue[2] = std::max(maxValue[2], *(ptrSrc + 3 * j + 2));
    }
}

//计算R+G+B的数量超过像素总数的ratio的像素值
double sum = 0.0;
int thresholdValue = 0;
for (int i = 765; i >= 0; i--)
{
    sum += histRGBSum[i];
    if (sum > src.rows * src.cols * ratio)
    {
        thresholdValue = i;
        break;
    }
}

//计算R+G+B大于阈值的所有点的均值
double avgB = 0.0;
double avgG = 0.0;
double avgR = 0.0;
int pixCount = 0;
for (int i = 0; i < src.rows; i++)
{
    const uchar *ptrSrc = src.ptr<uchar>(i);
    for (int j = 0; j < src.cols; j++)
    {
        int sum = *(ptrSrc + 3 * j) + *(ptrSrc + 3 * j + 1) + *(ptrSrc + 3 * j + 2);
        if (sum > thresholdValue)
        {
            avgB += *(ptrSrc + 3 * j);
            avgG += *(ptrSrc + 3 * j + 1);
            avgR += *(ptrSrc + 3 * j + 2);
            pixCount++;
        }
    }
}
avgB /= pixCount;
avgG /= pixCount;
avgR /= pixCount;

//量化0-255
cv::Mat dst = cv::Mat::zeros(src.size(), src.type());
for (int i = 0; i < src.rows; i++)
{
    const uchar *ptrSrc = src.ptr<uchar>(i);
    uchar *ptrDst = dst.ptr<uchar>(i);
    for (int j = 0; j < src.cols; j++)
    {
        double blue = (double)*(ptrSrc + 3 * j) / avgB * maxValue[0];
        double green = (double)*(ptrSrc + 3 * j + 1) / avgG * maxValue[1];
        double red = (double)*(ptrSrc + 3 * j + 2) / avgR * maxValue[2];
        blue = std::min(std::max((double)0, blue), (double)255);
        green = std::min(std::max((double)0, green), (double)255);
        red = std::min(std::max((double)0, red), (double)255);
        *(ptrDst + 3 * j) = (uchar)blue;
        *(ptrDst + 3 * j + 1) = (uchar)green;
        *(ptrDst + 3 * j + 2) = (uchar)red;
    }
}
return dst;

四、算法结果

  原图、结果,这个算法比灰度世界稍微复杂一丢丢丢,效果还是挺好的,与灰度世界算法各有优势吧。

白平衡之完美反射算法_第1张图片白平衡之完美反射算法_第2张图片

白平衡之完美反射算法_第3张图片白平衡之完美反射算法_第4张图片

白平衡之完美反射算法_第5张图片白平衡之完美反射算法_第6张图片

白平衡之完美反射算法_第7张图片白平衡之完美反射算法_第8张图片

朝发披香殿,夕济汾阴河。
于兹怀九逝,自此敛双蛾。
沾妆如湛露,绕臆状流波。
日见奔沙起,稍觉转蓬多。
朔风犯肌骨,非直伤绮罗。
衔涕试南望,关山郁嵯峨。
始作阳春曲,终成苦寒歌。
惟有三五夜,明月暂经过。
– 南北朝 沈约 《昭君辞》

你可能感兴趣的:(DIP,计算机视觉,opencv)