在开始之前,先看一组去雾的效果图。
1. 关于去雾的意义及算法
去雾在视频监控、航拍、遥感、自动/辅助驾驶等需要在室外复杂、恶劣天气下运行的视觉系统,都可能需要运用到这一技术。
目前去雾算法主要有两个思路,一个是基于图像增强的图像去雾处理方法,另一个是基于物理成像模型的图像去雾处理方法。基于图像增强的去雾算法的典型代表就是(全局/局部)直方图和Retinex算法。而基于物理成像模型的图像去雾算法的典型代表就是何凯明等提出的基于暗通道的图像去雾和Jin-Hwan Kim等提出的去雾算法,这两种算法的去雾效果都比较好,计算效率也都比较高,可以达到实时的效果。特别值得一提的是,由于思路的不同,Jin-Hwan Kim的去雾算法对天空的处理效果更为自然。
这里主要是对基于暗通道的图像去雾算法进行小结,如果对Jin-Hwan Kim的去雾算法感兴趣可以阅读原文&代码,也可以参考对其进行解读的博客优化的对比度增强算法用于有雾图像的清晰化处理。
2.暗通道先验
暗通道先验就是基于这样一个假设:在绝大多数非天空的局部区域里,某一些像素总会有至少一个颜色通道具有很低的值。而这个假设是作者基于大量图片的观察得到了。关于暗通道先验去雾的相关理论推导可以参考作者原文《Single Image Haze Removal Using Dark Channel Prior》,也可以参考一些讲解博客,比如下面两篇博客讲解的都很清晰明了。
2.《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果(速度可实时)
其计算流程
3.基于预估透射率图的去雾
基于预估投射率图的计算流程如上面的流程图所示。下面是通过该方法对一副带雾的图像进行滤波后的效果图。其中src为原图,dehazedImg为去雾后的效果图,而darkChannelImg为暗通道图像,transmissionImage为预估图射率图。可以发现去雾的效果并不是很理想,可以看到很多边缘有明显的白边,主要原因是由于预估透射率图太过粗糙,导致滤波结果不够精细。在何凯明的论文中,提到可以通过soft matting的办法来改进,但这个方法较为繁琐,后来他又提出了guided filter,该算法同样可以改进去雾效果。
上面滤波的代码如下:
#include<opencv.hpp>
#include<iostream>
using namespace cv;
const double w = 0.95;
const int r = 7;
//计算全球大气光强A
//src为输入的带雾图像,darkChannelImg为暗通道图像,r为最小值滤波的窗口半径
Mat getDarkChannelImg(const Mat src, const int r)
{
int height = src.rows;
int width = src.cols;
Mat darkChannelImg(src.size(), CV_8UC1);
Mat darkTemp(darkChannelImg.size(), darkChannelImg.type());
//求取src中每个像素点三个通道中的最小值,将其赋值给暗通道图像中对应的像素点
for (int i = 0; i < height; i++)
{
const uchar* srcPtr = src.ptr<uchar>(i);
uchar* dstPtr = d