暗通道算法是由何恺明在CVPR论文《Single ImageHaze Removalusing Dark Channel Prior》中提出的。
图像去雾的模型:
我们分析以上模型:
【已知条件】
:observerd intensity,即输入图像(待去雾的图像)
【未知条件】
scene radiance,即还原图像(去雾以后的图像)
medium transmission
global atmospheric light
【目标】
求出这三个未知条件、、,而根据去雾模型,我们只需要计算出其中两个未知条件,就可以求出第三个。文中先通过求出、,然后通过去雾模型的转换计算
【问题】
【问题的解决办法】
也就是我们先求出darkChannel.
darkChannel的定义:
代码如下:
- #include<iostream>
- #include<vector>
- #include<algorithm>
- using namespace std;
- #include<opencv2\core\core.hpp>
- #include<opencv2\highgui\highgui.hpp>
- #include<opencv2\imgproc\imgproc.hpp>
- using namespace cv;
- int main(int argc,char*argv[])
- {
- Mat image=imread(argv[1],1);
- CV_Assert(!image.empty() && image.channels() == 3);
-
- Mat fImage;
- image.convertTo(fImage,CV_32FC3,1.0/255,0);
-
- int hPatch = 15;
- int vPatch = 15;
-
- Mat fImageBorder;
- copyMakeBorder(fImage,fImageBorder,vPatch/2,vPatch/2,hPatch/2,hPatch/2,BORDER_REPLICATE);
-
- vector<Mat> fImageBorderVector(3);
- split(fImageBorder,fImageBorderVector);
-
- Mat darkChannel(image.rows,image.cols,CV_32FC1);
- double minTemp ,minPixel;
-
- for(unsigned int r = 0;r < darkChannel.rows;r++)
- {
- for(unsigned int c = 0;c < darkChannel.cols;c++)
- {
- minPixel = 1.0;
- for(vector<Mat>::iterator it = fImageBorderVector.begin() ;it != fImageBorderVector.end();it++)
- {
- Mat roi(*it,Rect(c,r,hPatch,vPatch));
- minMaxLoc(roi,&minTemp);
- minPixel = min(minPixel,minTemp);
- }
- darkChannel.at<float>(r,c) = float(minPixel);
- }
- }
- namedWindow("darkChannel",1);
- imshow("darkChannel",darkChannel);
- Mat darkChannel8U;
- darkChannel.convertTo(darkChannel8U,CV_8UC1,255,0);
- imwrite("darkChannel.jpg",darkChannel8U);
- return 0;
- }
先给出一些运行结果:
第二步:通过暗通道来实现A的过程,
-
-
- float top = 0.001;
- float numberTop = top*darkChannel.rows*darkChannel.cols;
- Mat darkChannelVector;
- darkChannelVector = darkChannel.reshape(1,1);
- Mat_<int> darkChannelVectorIndex;
- sortIdx(darkChannelVector,darkChannelVectorIndex,CV_SORT_EVERY_ROW + CV_SORT_DESCENDING);
-
- Mat mask(darkChannelVectorIndex.rows,darkChannelVectorIndex.cols,CV_8UC1);
- for(unsigned int r = 0;r < darkChannelVectorIndex.rows;r++)
- {
- for(unsigned int c = 0;c < darkChannelVectorIndex.cols;c++)
- {
- if(darkChannelVectorIndex.at<int>(r,c) <= numberTop)
- mask.at<uchar>(r,c) = 1;
- else
- mask.at<uchar>(r,c) = 0;
- }
- }
- Mat darkChannelIndex = mask.reshape(1,darkChannel.rows);
- vector<double> A(3);
- vector<double>::iterator itA = A.begin();
- vector<Mat>::iterator it = fImageBorderVector.begin();
-
- vector<Mat> fImageBorderVectorA(3);
- vector<Mat>::iterator itAA = fImageBorderVectorA.begin();
- for( ;it != fImageBorderVector.end() && itA != A.end() && itAA != fImageBorderVectorA.end();it++,itA++,itAA++)
- {
- Mat roi(*it,Rect(hPatch/2,vPatch/2,darkChannel.cols,darkChannel.rows));
- minMaxLoc(roi,0,&(*itA),0,0,darkChannelIndex);
- (*itAA) = (*it)/(*itA);
- }
第三步:通过暗通道来实现t(x)的过程:
-
- Mat darkChannelA(darkChannel.rows,darkChannel.cols,CV_32FC1);
- float omega = 0.95;
-
- for(unsigned int r = 0;r < darkChannel.rows;r++)
- {
- for(unsigned int c = 0;c < darkChannel.cols;c++)
- {
- minPixel = 1.0;
- for(itAA = fImageBorderVectorA.begin() ;itAA != fImageBorderVectorA.end();itAA++)
- {
- Mat roi(*itAA,Rect(c,r,hPatch,vPatch));
- minMaxLoc(roi,&minTemp);
- minPixel = min(minPixel,minTemp);
- }
- darkChannelA.at<float>(r,c) = float(minPixel);
- }
- }
- Mat tx = 1.0 - omega*darkChannelA;
文中,给出了一个tx的优化,我们后面使用guiderFilter进行优化。
第四步:既然A和t(x)已经求出,就可以求j(x);
-
- float t0 = 0.1;
- Mat jx(image.rows,image.cols,CV_32FC3);
- for(size_t r = 0;r < jx.rows;r++)
- {
- for(size_t c =0;c<jx.cols;c++)
- {
- jx.at<Vec3f>(r,c) = Vec3f((fImage.at<Vec3f>(r,c)[0] - A[0])/max(tx.at<float>(r,c),t0)+A[0],(fImage.at<Vec3f>(r,c)[1] - A[1])/max(tx.at<float>(r,c),t0)+A[1],(fImage.at<Vec3f>(r,c)[2] - A[2])/max(tx.at<float>(r,c),t0)+A[2]);
- }
- }
- namedWindow("jx",1);
- imshow("jx",jx);
- Mat jx8U;
- jx.convertTo(jx8U,CV_8UC3,255,0);
- imwrite("jx.jpg",jx8U);
结果:
文中的代码还没有优化,代码重复率比较高
转自:http://blog.csdn.net/zhangping1987/article/details/51178103