opencv-dark channel -实现暗通道去雾详解

1.暗通道的概念和含义


暗通道算法是由何恺明在CVPR论文《Single ImageHaze Removalusing Dark Channel Prior》中提出的。


图像去雾的模型:

  
我们分析以上模型:

【已知条件】
:observerd intensity,即输入图像(待去雾的图像)
【未知条件】
 scene radiance,即还原图像(去雾以后的图像)
 medium transmission
 global atmospheric light
【目标】
求出这三个未知条件,而根据去雾模型,我们只需要计算出其中两个未知条件,就可以求出第三个。文中先通过求出,然后通过去雾模型的转换计算

【问题】
怎么只通过,来计算出呢?
【问题的解决办法】

也就是我们先求出darkChannel.

darkChannel的定义:

代码如下:
  1. #include<iostream>  
  2. #include<vector>  
  3. #include<algorithm>  
  4. using namespace std;  
  5. #include<opencv2\core\core.hpp>  
  6. #include<opencv2\highgui\highgui.hpp>  
  7. #include<opencv2\imgproc\imgproc.hpp>  
  8. using namespace cv;  
  9. int main(int argc,char*argv[])  
  10. {  
  11.     Mat image=imread(argv[1],1);  
  12.     CV_Assert(!image.empty() && image.channels() == 3);  
  13.     //图片的归一化  
  14.     Mat fImage;  
  15.     image.convertTo(fImage,CV_32FC3,1.0/255,0);  
  16.     //规定patch的大小,且均为奇数  
  17.     int hPatch = 15;  
  18.     int vPatch = 15;  
  19.     //给归一化的图片添加边界  
  20.     Mat fImageBorder;  
  21.     copyMakeBorder(fImage,fImageBorder,vPatch/2,vPatch/2,hPatch/2,hPatch/2,BORDER_REPLICATE);  
  22.     //分离通道  
  23.     vector<Mat> fImageBorderVector(3);  
  24.     split(fImageBorder,fImageBorderVector);  
  25.     //创建darkChannel  
  26.     Mat darkChannel(image.rows,image.cols,CV_32FC1);  
  27.     double minTemp ,minPixel;  
  28.     //根据darkChannel的定义  
  29.     for(unsigned int r = 0;r < darkChannel.rows;r++)  
  30.     {  
  31.         for(unsigned int c = 0;c < darkChannel.cols;c++)  
  32.         {  
  33.             minPixel = 1.0;  
  34.             for(vector<Mat>::iterator it = fImageBorderVector.begin() ;it != fImageBorderVector.end();it++)  
  35.             {  
  36.                 Mat roi(*it,Rect(c,r,hPatch,vPatch));  
  37.                 minMaxLoc(roi,&minTemp);  
  38.                 minPixel = min(minPixel,minTemp);  
  39.             }  
  40.             darkChannel.at<float>(r,c) = float(minPixel);  
  41.         }  
  42.     }  
  43.     namedWindow("darkChannel",1);  
  44.     imshow("darkChannel",darkChannel);  
  45.     Mat darkChannel8U;  
  46.     darkChannel.convertTo(darkChannel8U,CV_8UC1,255,0);  
  47.     imwrite("darkChannel.jpg",darkChannel8U);  
  48. return 0;  
  49. }  

先给出一些运行结果:
               
   

第二步:通过暗通道来实现A的过程,

  1. /*第2步:求出 A(global atmospheric light)*/  
  2. //2.1 计算出darkChannel中,前top个亮的值,论文中取值为0.1%  
  3. float top = 0.001;  
  4. float numberTop = top*darkChannel.rows*darkChannel.cols;  
  5. Mat darkChannelVector;  
  6. darkChannelVector = darkChannel.reshape(1,1);  
  7. Mat_<int> darkChannelVectorIndex;  
  8. sortIdx(darkChannelVector,darkChannelVectorIndex,CV_SORT_EVERY_ROW + CV_SORT_DESCENDING);  
  9. //制作掩码  
  10. Mat mask(darkChannelVectorIndex.rows,darkChannelVectorIndex.cols,CV_8UC1);//注意mask的类型必须是CV_8UC1  
  11. for(unsigned int r = 0;r < darkChannelVectorIndex.rows;r++)  
  12. {  
  13.     for(unsigned int c = 0;c < darkChannelVectorIndex.cols;c++)  
  14.     {  
  15.         if(darkChannelVectorIndex.at<int>(r,c) <= numberTop)  
  16.             mask.at<uchar>(r,c) = 1;  
  17.         else   
  18.             mask.at<uchar>(r,c) = 0;  
  19.     }  
  20. }  
  21. Mat darkChannelIndex = mask.reshape(1,darkChannel.rows);  
  22. vector<double> A(3);//分别存取A_b,A_g,A_r  
  23. vector<double>::iterator itA = A.begin();  
  24. vector<Mat>::iterator it = fImageBorderVector.begin();  
  25. //2.2在求第三步的t(x)时,会用到以下的矩阵,这里可以提前求出  
  26. vector<Mat> fImageBorderVectorA(3);  
  27. vector<Mat>::iterator itAA = fImageBorderVectorA.begin();  
  28. for( ;it != fImageBorderVector.end() && itA != A.end() && itAA != fImageBorderVectorA.end();it++,itA++,itAA++)  
  29. {  
  30.     Mat roi(*it,Rect(hPatch/2,vPatch/2,darkChannel.cols,darkChannel.rows));  
  31.     minMaxLoc(roi,0,&(*itA),0,0,darkChannelIndex);//  
  32.     (*itAA) = (*it)/(*itA); //[注意:这个地方有除号,但是没有判断是否等于0]  
  33. }  

第三步:通过暗通道来实现t(x)的过程:

  1. /*第三步:求t(x)*/  
  2. Mat darkChannelA(darkChannel.rows,darkChannel.cols,CV_32FC1);  
  3. float omega = 0.95;//0<w<=1,论文中取值为0.95  
  4. //代码和求darkChannel的时候,代码差不多  
  5. for(unsigned int r = 0;r < darkChannel.rows;r++)  
  6. {  
  7.     for(unsigned int c = 0;c < darkChannel.cols;c++)  
  8.     {  
  9.         minPixel = 1.0;  
  10.         for(itAA = fImageBorderVectorA.begin() ;itAA != fImageBorderVectorA.end();itAA++)  
  11.         {  
  12.             Mat roi(*itAA,Rect(c,r,hPatch,vPatch));  
  13.             minMaxLoc(roi,&minTemp);  
  14.             minPixel = min(minPixel,minTemp);  
  15.         }  
  16.         darkChannelA.at<float>(r,c) = float(minPixel);  
  17.     }  
  18. }  
  19. Mat tx = 1.0 - omega*darkChannelA;  
文中,给出了一个tx的优化,我们后面使用guiderFilter进行优化。

第四步:既然A和t(x)已经求出,就可以求j(x);

  1. /*第四步:我们可以求J(x)*/  
  2. float t0  = 0.1;//论文中取t0 = 0.1  
  3. Mat jx(image.rows,image.cols,CV_32FC3);  
  4. for(size_t r = 0;r < jx.rows;r++)  
  5. {  
  6.     for(size_t c =0;c<jx.cols;c++)  
  7.     {  
  8.         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]);  
  9.     }  
  10. }  
  11. namedWindow("jx",1);  
  12. imshow("jx",jx);  
  13. Mat jx8U;  
  14. jx.convertTo(jx8U,CV_8UC3,255,0);  
  15. imwrite("jx.jpg",jx8U);  
结果:
 
     
   


文中的代码还没有优化,代码重复率比较高
参考:http://blog.csdn.net/zhangping1987/article/details/51178103
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值