dehaze paper reading 1

基礎出發點:

I(x) = J(x) * t(x) + (1 - t(x)) *A (1)
編程

I(x):咱們觀測的圖像。ide

J(x):就是那個客觀存在的圖像,對於去霧的案例,能夠認爲是沒有被霧擋住的圖像。函數

t:爲大氣的傳輸過程。spa

A:爲空氣中的光。
get

x:爲像素的位置。
string

就是說咱們看到的圖像是空氣的光線和真實圖像的混合。這個混合的比例爲t。it

去霧就是在已知觀測圖像I(x)下恢復真實圖像J(x)。io

樸素的想法:opencv

J(x) = (I(x)-A)/t(x)  + A
pdf

所以問題就變成要估計t(x)和A。

先處理t(x)。

這個是一個隨空間位置變化的量。對於一個具體點,能夠假設附近的點上t(x)取常數。這個固然是不真實的,但能夠解決一些問題。

I(x) = J(x) * t + (1 - t) * A

分紅r,g,b三個通道(顏色)的方式:

Ic(x) = Jc(x) * t + (1 - t) * Ac         c = r, g, b

min_omega( Ic(y)) = t * min_omega(Jc(y)) + ( 1 - t) * Ac 


min_omega( Ic(y)) / Ac = t * min_omega(Jc(y))  / Ac + ( 1 - t)

min_omega函數表示,以x爲中心的一個矩形區域中全部像素的最小值。能夠用OpenCV實現爲。論文中patch_size = 15。

double min_omega(Mat& I, int patch_size) {

            Mat tmp_img;

            getRectSubPix(I, Size(patch_size, patch_size), Point(x,y), tmp_img);
            minMaxLoc(tmp_img, &tmpmin);

            return tmpmin;

}

再作一步:

min_c(  min_omega(Ic(y) ) ) /Ac = t * min_c( min_omega(Jc(y))) + (1 - t)                                               (2)

min_c是對三個通道求最小:

uchar min_c(uchar r, uchar g, char b) {

       return std::min(r ,std:: min(g,b));

}

方程(2)是沒法編程實現的。由於 Jc(y)是不知道的。

幸運的事情發生了,

min_c( min_omega(Jc(y))) = dark_channle( . ) = 0

因此。t = 1 - min_c(min_omega(Ic(y)))/Ac。這樣就獲得了t。

dark_channle( .) 是論文中核心和要害。就是說對於天然的圖像,尤爲是戶外的圖像,任何一個像素,他附近的的全部通道中總存在一個接近於0的點。

好比說一個單色的圖像,其餘兩個通道都會爲0。 在陰影中像素也是這樣的。dark_channel是一個剛開始讓人以爲很詫異的東西,仔細一想也是天然的。

這樣能夠定義從新寫一下公式:

t = 1 - dark_channel(I)/A

當A已知那麼,t就是能夠經過原來的圖像計算出來。

#include </to/path/opencv>

#include </to/path/std ...>

//using C++ 11 feature, Visual Studio 2013 or GCC

Mat recover(const Mat& I, float A, const Mat& t) {

    Mat J(I.size(), CV_32FC3);
    auto it_dst = J.begin<Vec3f>();
    auto it = t.begin<float>();
    const float t0 = 0.1f;
    for (auto it_src = I.begin<Vec3b>(); it_src != I.end<Vec3b>(); ++it_src, ++it, ++it_dst){
            float tx = std::max(*it, t0);

            float r_tx =  1 /tx;

            float t1 = A *(r_tx - 1)

            
            (*it_dst)[0] = ((*it_src)[0] )*r_tx - t1;
            (*it_dst)[1] = ((*it_src)[1] )*r_tx - t1;
            (*it_dst)[2] = ((*it_src)[2] )*r_tx - t1;
    }

    return std::move(J); //C++ 11 move semantics
}

Mat dark_channel(const Mat& I, int patch_size);


Mat dehaze(const Mat& I, int patch_size, uchar A) {

   auto dc = dark_channel(I, patch_size);

   Mat ones = Mat::ones(I.size(), CV_32F);

    Mat t(ones.size(), ones.type());

     cv::divide(ones, dc/A, t);

   return recover(I, A, t);

}


int main(int argc, char *argv[]) {

    uchar A = 220;

    string in_file (argv[1]);

    auto I = imread(in_file); //C++11 auto

    Mat&& dst = dehaze(I, 15, A);  

    imwrite("out_" + in_file, dst);

}


uchar min_omega(const Mat& dc, int patch_size, int x, int y) {
    double tmp_min;
    Mat tmp_img;
    getRectSubPix(dc, Size(patch_size, patch_size), Point(x, y), tmp_img);
    minMaxLoc(tmp_img, &tmp_min);
    return (uchar)tmp_min;
}

uchar min_c(uchar a, uchar b, uchar c) {
    return std::min(a,min(b,c));
}
    
Mat dark_channel(const Mat& I, int patch_size){
    Mat dc;
    dc.create(I.size(), CV_8U);
    for (int y = 0; y < dc.rows; ++y) {
        const uchar *p = I.ptr<uchar>(y);
        for (int x = 0; x < dc.cols; ++x) {
            dc.at<uchar>(y, x) = min_c(p[3*x],p[3*x+1], p[3*x+2]);
        }
    }
    
    Mat dc2;
    dc2.create(dc.size(), dc.type());
    for (int y = 0; y < dc.row; y++){
        for (int x = 0; x < dc.cols; x++){
            uchar tmpmin = min_omega(dc, patch_size, x, y);
            dc2.at<uchar>(y, x) = (uchar)tmpmin;      
        }
    }
    return std::move(dc2);
}


    


    



Paper download

相關文章
相關標籤/搜索