1. 程式人生 > >Local Color Correction 區域性顏色較正論文C++復現

Local Color Correction 區域性顏色較正論文C++復現

前言

\quad 偶然見到了這篇paper,雖然之前復現的一些paper已經可以較好的處理低照度下的色彩恢復,然而在光度強度很大的情況下怎麼恢復還不清楚,並且如果出現圖片中既有很亮的部分,又有很暗的部分,又不知道怎麼處理了。這篇paper,正式為了解決這一問題,他的局步顏色矯正,和He KaiMing的暗通道去霧有相似的想法,值得借鑑。

演算法原理

首先對與太亮和太暗的影象,我們可以使用Gamma校正來提高對比度。
在這裡插入圖片描述圖片表示:較暗影象,Gamma係數為0.5的Gamma校正,直方圖均衡化
在這裡插入圖片描述

代表較亮的原始影象,Gamma係數為2.5的Gamma校正,直方圖均衡化
在這裡插入圖片描述代表原始影象,Gamma係數為0.5,2.5,0.75,1.5的Gamma校正影象

使用Gamma校正後可以提高影象的動態範圍,實際上作者講這麼多實際是要說,如果當影象既有較亮又有較暗的區域時,如果僅僅使用一個Gamma矯正輸出的影象效果反而會變差,這是因為Gamma矯正是全域性的方法,某一部分相近的畫素將被對映到相同的灰度值,並沒有考慮待到畫素鄰域的資訊。對於普通的過亮和過暗的影象,當影象的平均灰度大於127.5使用 γ >

1 \gamma >1 ,對影象的亮度進行抑制;當影象的灰度資訊均值小於127.5時使用 γ < 1 \gamma <1
對影象亮度進行增強。這裡我們假設影象用無符號8bit表示,那麼 γ = 2 u 127.5 127.5 \gamma = 2^{\frac{u-127.5}{127.5}} 。在既有較暗又有較亮的區域的影象中,全域性Gamma失效,這時候作者就提出了利用影象鄰域的資訊,進行Gamma矯正。對較暗的區域進行增加亮度,對較亮的區域降低亮度。區域性顏色校正的方法可以根據鄰域內畫素的灰度值情況,把統一輸入畫素值,對映成不同水平的畫素灰度值。

演算法步驟

  • 根據輸入影象計算出掩膜影象
  • 結合輸入影象和掩模影象計算出最終結果
    掩膜影象一般根據彩色影象各個通道的影象灰度值獲得。假設RGB影象各個通道的畫素灰度值為R,G,B,則掩膜影象可以表示為 I = ( R + G + B ) / 3 I = (R + G + B) / 3 ,之後對掩膜影象進行高斯濾波: M ( x , y ) = ( G a u s s i a n ( 255 I ) ) ( x , y ) M(x,y) = (Gaussian*(255-I))(x,y) ,高斯濾波時,選取較大值進行濾波,以保證對比度不會沿著邊緣方向過度減小。上述的輸出結果表明:影象哪部分需要提亮,哪部分需要減暗。最後輸出影象為: O u t p u t ( x , y ) = 255 ( I n p u t ( x , y ) 255 ) 2 128 M ( x , y ) 128 Output(x, y)=255(\frac{Input(x,y)}{255})^{2^{\frac{128-M(x,y)}{128}}} ,如果掩膜影象大於128,將得到一個大於1的指數,並對影象該點的亮度移植,反之增加亮度。如果等於128,則不改變該畫素點亮度。

C++程式碼

Mat LCC(const Mat &src){
    int rows = src.rows;
    int cols = src.cols;
    int **I;
    I = new int *[rows];
    for(int i = 0; i < rows; i++){
        I[i] = new int [cols];
    }
    int **inv_I;
    inv_I = new int *[rows];
    for(int i = 0; i < rows; i++){
        inv_I[i] = new int [cols];
    }
    Mat Mast(rows, cols, CV_8UC1);
    for(int i = 0; i < rows; i++){
        uchar *data = Mast.ptr<uchar>(i);
        for(int j = 0; j < cols; j++){
            I[i][j] = (src.at<Vec3b>(i, j)[0] + src.at<Vec3b>(i, j)[1] + src.at<Vec3b>(i, j)[1]) / 3.0;
            inv_I[i][j] = 255;
            *data = inv_I[i][j] - I[i][j];
            data++;
        }
    }
    GaussianBlur(Mast, Mast, Size(41, 41), BORDER_DEFAULT);
    Mat dst(rows, cols, CV_8UC3);
    for(int i = 0; i < rows; i++){
        uchar *data = Mast.ptr<uchar>(i);
        for(int j = 0; j < cols; j++){
            for(int k = 0; k < 3; k++){
                float Exp = pow(2, (128 - data[j]) / 128.0);
                int value = int(255 * pow(src.at<Vec3b>(i, j)[k] / 255.0, Exp));
                dst.at<Vec3b>(i, j)[k] = value;
            }
        }
    }
    return dst;
}

效果

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述在這裡插入圖片描述在這裡插入圖片描述在這裡插入圖片描述
所有的圖片均為未處理和處理後的順序