基于opencv的单张图像去雾算法(三)

来源:互联网 发布:cocos2d 源码 编辑:程序博客网 时间:2024/06/05 00:23

http://blog.csdn.net/cfqcfqcfqcfqcfq/article/details/52870799

导向滤波算法基本已取得不错的效果,保留完整细节信息。观察去雾后的图像其亮度要比原图要低。那是因为物体光线的亮度通常不及大气光线。看一些论文里提到了自动色阶算法。查阅资料发现其就是RGB三通道进行灰度拉伸。

     实现过程中使用opencv的通道分离和和合并函数并结合普通的灰度拉伸函数就可以实现 RGB三通道灰度拉伸


实现代码:

[cpp] view plain copy
  1. int main()  
  2. {  
  3. //[6] --自动色阶(rgb三通道灰度拉伸)  
  4.     cv::Mat channels[3];  
  5.     split(deFog1,channels);//不知道什么原因vector无法使用 只能用数组来表示  
  6.     for(int c=0;c<3;c++)  
  7.         channels[c]= grayStretch(channels[c],0.001,0.5); //根据实验 暗色像素的比例应该设置的较小效果会比较好  
  8.     merge(channels,3,deFog1);  
  9.     imshow("autoLevels",deFog1);  
  10.     //[6]  
  11. }  
  12. //图像灰度拉伸  
  13. //src 灰度图图  
  14. //lowcut、highcut为百分比的值 如lowcut=3表示3%  
  15. //lowcut表示暗色像素个数的最小比例,大于该比例的灰度级作为最小亮度  
  16. //highcut为高亮像素个数的最小比例,大于该比例的灰度级作为最大亮度  
  17. cv::Mat grayStretch(cv::Mat src,double lowcut,double highcut)  
  18. {  
  19.     //[1]--统计各通道的直方图  
  20.     //参数  
  21.     const int bins = 256;  
  22.     int hist_size=bins;  
  23.     float range[]={0,255};  
  24.     const float* ranges[]={range};  
  25.     MatND desHist;  
  26.     int channels=0;  
  27.     //计算直方图  
  28.     calcHist(&src,1,&channels,Mat(),desHist,1,&hist_size,ranges,true,false);  
  29.     //[1]  
  30.   
  31.     //[2] --计算上下阈值  
  32.     int pixelAmount=src.rows*src.cols; //像素总数  
  33.     float Sum=0;  
  34.     int minValue,maxValue;  
  35.     //求最小值  
  36.     for(int i=0;i<bins;i++)  
  37.     {  
  38.         Sum=Sum+desHist.at<float>(i);  
  39.         if(Sum>=pixelAmount*lowcut*0.01)  
  40.         {  
  41.             minValue=i;  
  42.             qDebug()<<"minValue"<<minValue;  
  43.             break;  
  44.         }  
  45.     }  
  46.   
  47.     //求最大值  
  48.     Sum=0;  
  49.     for(int i=bins-1;i>=0;i--)  
  50.     {  
  51.         Sum=Sum+desHist.at<float>(i);  
  52.         if(Sum>=pixelAmount*highcut*0.01)  
  53.         {  
  54.             maxValue=i;  
  55.             qDebug()<<"maxValue"<<maxValue;  
  56.             break;  
  57.         }  
  58.     }  
  59.     //[2]  
  60.   
  61.     //[3] --对各个通道进行线性拉伸  
  62.     Mat dst=src;  
  63.     //判定是否需要拉伸  
  64.     if(minValue>maxValue)  
  65.         return src;  
  66.   
  67.     for(int i=0;i<src.rows;i++)  
  68.         for(int j=0;j<src.cols;j++)  
  69.         {  
  70.             if(src.at<uchar>(i,j)<minValue)  
  71.                 dst.at<uchar>(i,j)=0;  
  72.             if(src.at<uchar>(i,j)>maxValue)  
  73.                 dst.at<uchar>(i,j)=255;  
  74.             else  
  75.             {  
  76.                 //注意这里做除法要使用double类型  
  77.                 double pixelValue=((src.at<uchar>(i,j)-minValue)/  
  78.                                    (double)(maxValue-minValue))*255;  
  79.                 dst.at<uchar>(i,j)=(int)pixelValue;  
  80.             }  
  81.         }  
  82.     //[3]  
  83.   
  84.     return dst;  
  85. }  


结果:

    



注意事项:

   1、opencv的通道分离函数spilt()和merge()   其channels变量类型可以去数组或vector容器两种类型。但实际操作时 使用vector容器会提示指针访问越界的错误。参考文献一给出解释是说容器初始化使没有分配其容量。但我尝试reszie(3)仍然不行 所以就改用数组。在使用数组类型时候 merge函数标签应该为merge(Mat *mv,size_t cpunt ,OutputArray dst);必须要指明第二个参数 通道个数。

  2、graystrech函数中第二个参数值要取得小一点,第三个参数可以适当大一点。因为图像是整体偏暗 所以当然是希望往高亮度范围内拉伸,而不是往低亮度方向拉伸


图像去雾方法总结:

      1、不管是暗原色先验还是导向滤波,当图像中出现大面积天等白色物体区域去雾效果都不理想。因为白色物体暗原色先验的条件是基本不成立的。

      2、并不是一张图像上的雾能去除,向下面这张图:

      

基本上图像近处的物体轮廓比较清洗 能够分出前景(一层薄雾)和目标。在往远处看 基本上是一片白 除了两个车灯其他的根本分不出前景和目标。

远景那一块肉眼都看不到有没有物体 所以很难通过现有算法让计算机帮你准确分离出目标。

      所以我理解的图像去雾基本上是指那种蒙着的一层薄雾,那种没有能见度的大雾个人感觉现有算法肯定去除不了。

参考文献:

  1、自动色阶

   2、spilt 报错


原创粉丝点击