白平衡之完美反射算法

一、算法背景

  白平衡是圖像處理比較常見的一個概念,在採集圖像的過程中,相機的感光元件或者鏡頭會對原始色彩造成影響,而白平衡技術通常可以用來校正這種光線和鏡頭對顏色影響。所以現在先記錄一個白平衡算法,叫做完美反射算法,這個算法原理也不是有多複雜,但是效果還是挺好的,而且基本也不需要調節參數就有效果了。完美反射算法很多博客都有介紹,而且實際上也還是就幾個公式,所以我也是簡單記錄重要的公式和實現代碼而已。

二、算法原理

  完美反射算法(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;

四、算法結果

  原圖、結果,這個算法比灰度世界稍微複雜一丟丟丟,效果還是挺好的,與灰度世界算法各有優勢吧。

在這裏插入圖片描述在這裏插入圖片描述

在這裏插入圖片描述在這裏插入圖片描述

在這裏插入圖片描述在這裏插入圖片描述

在這裏插入圖片描述在這裏插入圖片描述

朝發披香殿,夕濟汾陰河。
於茲懷九逝,自此斂雙蛾。
沾妝如湛露,繞臆狀流波。
日見奔沙起,稍覺轉蓬多。
朔風犯肌骨,非直傷綺羅。
銜涕試南望,關山鬱嵯峨。
始作陽春曲,終成苦寒歌。
惟有三五夜,明月暫經過。
– 南北朝 沈約 《昭君辭》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章