Single Image Haze Removal Using Dark Channel Prior
【由于周五写的很匆忙,导致文中内容不详细,周末又仔细的整理和汇总了下,做了大量的修改,因此把原文删除重新发布了】。
在图像去雾这个领域,几乎没有人不知道《Single Image Haze Removal Using Dark Channel Prior》这篇文章,该文是2009年CVPR最佳论文。作者何凯明博士,2007年清华大学毕业,2011年香港中文大学博士毕业,可谓是功力深厚,感叹于国内一些所谓博士的水平,何这样的博士才可以真正叫做Doctor。
关于何博士的一些资料和论文,大家可以访问这里:http://research.microsoft.com/en-us/um/people/kahe/
最开始接触何的这篇论文是在2011年,说实在的那个时候,只是随便浏览了下,看到里面的soft matting过程比较复杂,并且执行速度非常慢,就没有什么大的兴趣。最近又偶尔拾起,仔细研读,觉得论文的推理步骤特别清晰,讲解很到位。恰好适逢浏览到其另外一篇文章《Guided Image Filtering》 ,其中提到了可以用导向滤波来代替soft matting的过程,且速度很快,因此,我对去雾的兴趣算法又大大提高了。
本文主要上是对《Single Image Haze Removal Using Dark Channel Prior》的翻译、整理、及部分解释。如果您的英文水平好,建议看原文可能来的更爽些。
一、论文思想的简单描述
首先看看暗通道先验是什么:
在绝大多数非天空的局部区域里,某一些像素总会有至少一个颜色通道具有很低的值。换言之,该区域光强度的最小值是个很小的数。
我们给暗通道一个数学定义,对于任意的输入图像J,其暗通道可以用下式表达:
式中Jc表示彩色图像的每个通道 ,Ω(x)表示以像素X为中心的一个窗口。
式(5)的意义用代码表达也很简单,首先求出每个像素RGB分量中的最小值,存入一副和原始图像大小相同的灰度图中,然后再对这幅灰度图进行最小值滤波,滤波的半径由窗口大小决定,一般有WindowSize = 2 * Radius + 1;
暗通道先验的理论指出:
实际生活中造成暗原色中低通道值主要有三个因素:a)汽车、建筑物和城市中玻璃窗户的阴影,或者是树叶、树与岩石等自然景观的投影;b)色彩鲜艳的物体或表面,在RGB的三个通道中有些通道的值很低(比如绿色的草地/树/植物,红色或黄色的花朵/叶子,或者蓝色的水面);c)颜色较暗的物体或者表面,例如灰暗色的树干和石头。总之,自然景物中到处都是阴影或者彩色,这些景物的图像的暗原色总是很灰暗的。
我们抛开论文中列举的那些例子,自己从网上找几幅没有雾的风景照,看看结果如下:
一些无雾的图片 其暗通道
在看看一些有雾的图的暗通道:
一些有雾的图片 其暗通道
上述暗通道图像均使用的窗口大小为15*15,即最小值滤波的半径为7像素。
由上述几幅图像,可以明显的看到暗通道先验理论的普遍性。在作者的论文中,统计了5000多副图像的特征,也都基本符合这个先验,因此,我们可以认为其实一条定理。
有了这个先验,接着就需要进行一些数学方面的推导来最终解决问题。
首先,在计算机视觉和计算机图形中,下述方程所描述的雾图形成模型被广泛使用:
其中,I(X)就是我们现在已经有的图像(待去雾的图像),J(x)是我们要恢复的无雾的图像,A是全球大气光成分, t(x)为透射率。现在的已知条件就是I(X),要求目标值J(x),显然,这是个有无数解的方程,因此,就需要一些先验了。
将式(1)稍作处理,变形为下式:
如上所述,上标C表示R/G/B三个通道的意思。
首先假设在每一个窗口内透射率t(x)为常数,定义他为,并且A值已经给定,然后对式(7)两边求两次最小值运算,得到下式:
上式中,J是待求的无雾的图像,根据前述的暗原色先验理论有:
因此,可推导出:
把式(10)带入式(8)中,得到:
这就是透射率的预估值。
在现实生活中,即使是晴天白云,空气中也存在着一些颗粒,因此,看远处的物体还是能感觉到雾的影响,另外,雾的存在让人类感到景深的存在,因此,有必要在去雾的时候保留一定程度的雾,这可以通过在式(11)中引入一个在[0,1] 之间的因子,则式(11)修正为:
本文中所有的测试结果依赖于: ω=0.95。
上述推论中都是假设全球达气光A值时已知的,在实际中,我们可以借助于暗通道图来从有雾图像中获取该值。具体步骤如下:
1) 从暗通道图中按照亮度的大小取前0.1%的像素。
2) 在这些位置中,在原始有雾图像I中寻找对应的具有最高亮度的点的值,作为A值。
到这一步,我们就可以进行无雾图像的恢复了。由式(1)可知: J = ( I - A)/t + A
现在I,A,t都已经求得了,因此,完全可以进行J的计算。
当投射图t 的值很小时,会导致J的值偏大,从而使淂图像整体向白场过度,因此一般可设置一阈值T0,当t值小于T0时,令t=T0,本文中所有效果图均以T0=0.1为标准计算。
因此,最终的恢复公式如下:
当直接用上述理论进行恢复时,去雾的效果其实也是很明显的,比如下面一些例子:
有雾图 去雾图
注意到第一幅图的原图两个字的周围明显有一块不协调的地方,而第二图顶部水平方向似乎有一块没有进行去雾处理,这些都是由于我们的透射率图过于粗糙了。
要获得更为精细的透射率图,何博士在文章中提出了了soft matting方法,能得到非常细腻的结果。但是他的一个致命的弱点就是速度特慢,不使用于实际使用。在2011年,何博士又除了一片论文,其中提到了导向滤波的方式来获得较好的透射率图。该方法的主要过程集中于简单的方框模糊,而方框模糊有多重和半径无关的快速算法。因此,算法的实用性特强,关于这个导向滤波算法大家在何博士的网站可以自己去研习下,除了在去雾方面外,还有着其他多方面的应用,这部分本文不多述。
使用了导向滤波后的去雾效果:
使用原始的预估透射率图 使用导向滤波后的透射率图
(a) 原图 (b) 去雾结果图
(c) 暗通道图 (d) 导向图 (原始图像的灰度图)
(e) 预估透射率图 (f) 使用导向滤波后的透射率图
二、各参数对去雾结果的影响
第一:窗口的大小。这个对结果来说是个关键的参数,窗口越大,其包含暗通道的概率越大,暗通道也就越黑。我们不去从理论角度分析,从实践的效果来看,似乎窗口越大,去雾的效果越不明显,如下图所示:
(a) 原始图像 (b) 窗口大小=11
(c) 窗口大小=21 (d) 窗口大小=101
我的建议是窗口大小在11-51之间,即半径在5-25之间。
式(12)中的ω具有着明显的意义,其值越小,去雾效果越不明显,举例如下:
(a) 原始图像 (b) ω=0.5
(c) ω=0.8 (d) ω=1
三:编码的步骤
如果你仔细的分析了原文的细路,加上适当的参考,编码其实并不是很困难。
1)根据原始图像求暗通道,参考代码如下:
for (Y = 0, DarkPt = DarkChannel; Y < Height; Y++)
{
ImgPt = Scan0 + Y * Stride;
for (X = 0; X < Width; X++)
{
Min = *ImgPt;
if (Min > *(ImgPt + 1)) Min = *(ImgPt + 1);
if (Min > *(ImgPt + 2)) Min = *(ImgPt + 2);
*DarkPt = Min;
ImgPt += 3;
DarkPt++;
}
} MinFilter(DarkChannel, Width, Height, Radius);
这里需要注意的是MinFilter算法的快速实现,提供一篇论文供有需要的朋友学习:STREAMING MAXIMUM-MINIMUM FILTER USING NO MORE THAN THREE COMPARISONS PER ELEMENT 。这个算法的时间复杂度是O(1)的。
2)按文中所描述的算法自动获得全球大气光的值。
这里说明一点,原始论文中的A最终是取原始像素中的某一个点的像素,我实际上是取的符合条件的所有点的平均值作为A的值,我这样做是因为,如果是取一个点,则各通道的A值很有可能全部很接近255,这样的话会造成处理后的图像偏色和出现大量色斑。原文作者说这个算法对天空部分不需特备处理,我实际发现该算法对有天空的图像的效果一般都不好。天空会出现明显的过渡区域。作为解决方案,我增加了一个参数,最大全球大气光值,当计算的值大于该值时,则就取该值。
原图 未对A值做限定 最大A值限定为220
3) 按式(12)计算预估的透射率图。
在式(12)中,每个通道的数据都需要除以对应的A值,即归一化,这样做,还存在一个问题,由于A的选取过程,并不能保证每个像素分量值除以A值后都小于1,从而导致t的值可能小于0,而这是不容许的,原文作者并没有交代这一点是如何处理的。我在实际的编码中发现,如果真的这样做了,其效果也并不是很理想 ,因此,我最后的办法是在式(12)中,不考虑A的计算。
4)计算导向滤波图。
这里可以直接用原始的图像做导向图,当然也可以用其灰度图,但是用RGB导向图在下一步的计算中会占用比较大的时间。
5)按照《Guided Image Filtering》论文中的公式(5)、(6)、(8)编码计算获得精细的透射率图。
网络上有这个算法的 matlab代码可下载的,这里贴部分代码:
function q = guidedfilter(I, p, r, eps)
% GUIDEDFILTER O(1) time implementation of guided filter.
%
% - guidance image: I (should be a gray-scale/single channel image)
% - filtering input image: p (should be a gray-scale/single channel image)
% - local window radius: r
% - regularization parameter: eps [hei, wid] = size(I);
N = boxfilter(ones(hei, wid), r); % the size of each local patch; N=(2r+1)^2 except for boundary pixels. % imwrite(uint8(N), 'N.jpg');
% figure,imshow(N,[]),title('N');
mean_I = boxfilter(I, r) ./ N;
mean_p = boxfilter(p, r) ./ N;
mean_Ip = boxfilter(I.*p, r) ./ N;
cov_Ip = mean_Ip - mean_I .* mean_p; % this is the covariance of (I, p) in each local patch. mean_II = boxfilter(I.*I, r) ./ N;
var_I = mean_II - mean_I .* mean_I; a = cov_Ip ./ (var_I + eps); % Eqn. (5) in the paper;
b = mean_p - a .* mean_I; % Eqn. (6) in the paper; mean_a = boxfilter(a, r) ./ N;
mean_b = boxfilter(b, r) ./ N; q = mean_a .* I + mean_b; % Eqn. (8) in the paper;
end
由上面的代码,可见,主要的工作量在均值模糊上,而均值模糊是个很快速的算法,关于均值模糊的优化可参考我以前的文章:彩色图像高速模糊之懒惰算法。
还有一点就是,上述计算需要在[0,1]范围内进行,也就是说导向图和预估的透射率图都必须从[0,255]先映射到[0,1]在进行计算。
关于guidedfilter中的半径r值,因为在前面进行最小值后暗通道的图像成一块一块的,为了使透射率图更加精细,建议这个r的取值不小于进行最小值滤波的半径的4倍,如下图所示:
(a) r=最小值滤波半径的2倍 (b) r=最小值滤波半径的8倍
可以看到,当r比较小的时候,在透射率图中基本看不到什么细节信息,因此恢复处的图像边缘处不明显。
参数eps的取值也有所讲究,他主要是为了防止计算中除以0的错误以及为了使得某些计算结果不至于过大,一般建议取值0.001或者更小。
如果使用的彩色RGB图做导向图,计算时间上会增加不少,所的到的透射率图的边缘会比灰度图所处理的保留了更多的细节,效果上略微比灰度图好,如下所示:
(a) 原图 (b)预估的透射率图
(c)使用灰度图为导向图得到的透射率图 (d)使用RGB图为导向图得到的透射率图
(e)灰度图为导向图对应的去雾效果 (f)RGB图导向图对应的去雾效果
以RGB图为导向图的计算中,涉及到3*3部分矩阵求逆的过程,如果用非matlab语言写,可以先借助于matlab的符号计算功能,以及其中的符号计算命令simple,把计算结果算出来,然后再再其他高级语言中实现。
(6) 按式(22)进行无雾图像的恢复。
四、其他一些去雾效果图
原图 去雾效果图 透射率图
上图中最后一副图我连续做了两次去雾的处理。
在原文中,有这样一段话:
Since the scene radiance is usually not as bright as the atmospheric light, the image after haze removal looks dim. So we increase the exposure of J(x) for
display.
意思就是说直接去雾后的图像会比原始的暗,因此在处理完后需要进行一定的曝光增强,但作者没有说明其是如何增强的, 因此,这里的图和他论文的效果有所不同时正常的。一般在去雾处理后再用自动色剂之类的算法增强下会获得比较满意的结果,如下图:
原图 去雾后 +自动色阶
去雾算法目前也有着众多其他的方式,不过我所接触的,很多都是以这个为基础,因此,先弄会这个为研究其他的去雾算法能奠定坚实的基础。
网络上有一些比较好的暗原色先验去雾的matlab代码:比如和本文基本对应的matlab资源:http://files.cnblogs.com/Imageshop/cvpr09defog%28matlab%29.rar
后记:稍微有看了几篇去雾的文章,基本上都是围绕着获得透视率图做文章,比如一些文章讲用联合双边滤波方式获得精细的透射率,从我个人浅薄的认识中,我觉得去雾已基本上跳不出暗原色这个范畴了。
我对双边滤波算法那也做了实验,发现这个的效果也还行,就是速度慢了很多,双边滤波的快速算法其实快不起来的,所以这个的实用性不高,我选择了一些图像做比较:
(a) 原图 (b) 联合双边滤波去雾图
(c) 导向滤波获得透射率图 (d)联合双边滤波透射率图(Sigmad=SigmaR=100)
上图可以很明显的看出联合双边滤波的透射率图没有导向滤波的精细,但比原始的粗糙的透射率图还是好很多,过渡很光滑,因此,也能获得不错的视觉去雾效果。
联合双边滤波器中的算法是参考了OpenCv中相关函数写的。
和平常一样,提供一个可供大家测试效果的程序: 基于暗原色先验的图像去雾演示程序
我分别用VB6和C#做了个程序,两个程序都已经通过各自的语言方式进行了优化,算法部分编码是一样的,C#运行速度大约是VB6的1.8倍。
在处理速度上,比 matalb的快了很多倍,在I3的笔记本电脑上,一副1024*768的图像去雾时间大约在150ms内(以灰度图为导向图)。
Single Image Haze Removal Using Dark Channel Prior的更多相关文章
- 《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果(速度可实时)
最新的效果见 :http://video.sina.com.cn/v/b/124538950-1254492273.html 可处理视频的示例:视频去雾效果 在图像去雾这个领域,几乎没有人不知道< ...
- paper 105: 《Single Image Haze Removal Using Dark Channel Prior》一文中图像去雾算法的原理、实现、效果及其他
在图像去雾这个领域,几乎没有人不知道<Single Image Haze Removal Using Dark Channel Prior>这篇文章,该文是2009年CVPR最佳论文.作者 ...
- Single Image Haze Removal Using Dark Channel Prior翻译
这段时间在回顾以前做的去雾,顺便就把这篇文章翻译了一下,看看有没有同行交流.由于是用LaTex排版的,所以只能转为图片传上来了.另外,英语水平有限,大部分都是靠词典,所以只能勉强着看了.
- Single Image Haze Removal(图像去雾)-CVPR’09 Best Paper
公式推导 paper闪光点 找到了一个很简洁的假设. paper不足 代码跑起来很慢.据说2010年的ECCV那篇是改进的.
- 基于暗通道优先算法的去雾应用(Matlab/C++)
基于暗通道优先的单幅图像去雾算法(Matlab/C++) 算法原理: 参见论文:Single Image Haze Removal Using Dark Channel Pri ...
- 一种可实时处理 O(1)复杂度图像去雾算法的实现。
在我博文的一系列的文章,有不少算法都于去雾有关,比如限制对比度自适应直方图均衡化算法原理.实现及效果.局部自适应自动色阶/对比度算法在图像增强上的应用这两个增强算法都有一定的去雾能力,而最直接的就是& ...
- CVPR历年Best Papers
作者:我爱机器学习原文链接:CVPR历年Best Papers CVPR (Computer Vision)(2000-2016) 年份 标题 一作 一作单位 2016 Deep Residual L ...
- paper 100:何恺明经典去雾算法
一:由简至美的最佳论文(作者:何恺明 视觉计算组) [视觉机器人:个人感觉学习他的经典算法固然很重要,但是他的解决问题的思路也是非常值得我们学习的] 那是2009年4月24日的早上,我收到了一封不同 ...
- OpenCV导向滤波(引导滤波)实现(Guided Filter)代码,以及使用颜色先验算法去雾
论文下载地址:http://research.microsoft.com/en-us/um/people/jiansun/papers/GuidedFilter_ECCV10.pdf 本文主要介绍导向 ...
随机推荐
- Linux下df与du两个命令的差别?
Linux下df与du两个命令的差别? 一.df显示文件系统的使用情况,与du比較,就是更全盘化. 最经常使用的就是 df -T,显示文件系统的使用情况并显示文件系统的类型. 举比例如以下: [roo ...
- 微信原生支付 Native扫码支付( V3.3.7 版本)
原文:微信原生支付 Native扫码支付( V3.3.7 版本) [尊重别人的劳动成果,转载请注明出处:一缕晨光工作室,www.wispdawn.com] 前言 辛苦研究三天,遇到各种困难,最终还是克 ...
- 通过扩展改善ASP.NET MVC的验证机制[实现篇]
原文:通过扩展改善ASP.NET MVC的验证机制[实现篇] 在<使用篇>中我们谈到扩展的验证编程方式,并且演示了本解决方案的三大特性:消息提供机制的分离.多语言的支持和多验证规则的支持, ...
- Linux之ftp命令使用
一:前言 在达内參加暑期社会实践,达内公司免费教授了一星期的课,当时认为老师用ftp命令用的非常爽.所以回来学学了. 二:分类 有关FTP(client,server搭建这里不讲)有非常多,大体分为命 ...
- .net使用cefsharp开源库开发chrome
.net使用cefsharp开源库开发chrome 离上篇写介绍pc端的混合开发和为什么以cefsharp入手研究混合开发已经有好几天,一直忙,抽不出时间继续写怎么搭建cefsharp开发环境.其实没 ...
- php连接sql server 2008数据库
原文:php连接sql server 2008数据库 关于php连接sql server 2008的问题,2000的版本可以直接通过php中的配置文件修改,2005以上的版本就不行了,需要使用微软公司 ...
- LibVLC audio controls
原文 http://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc__audio.html LibVLC audio co ...
- NET Socket服务编程
smark https://github.com/IKende/ .NET Socket服务编程之-高效连接接入编 在.NET上编写网络服务深入都有2,3年了,而这些时间时如何在.NET里实现网络服务 ...
- LINUX下FD_SET介绍
刚刚了解了linux下select系统调用,函数原型是 #include <sys/select.h> #include <sys/time.h> int select(int ...
- 安装Windows操作系统的驱动程序(驱动精灵版) - 进阶者系列 - 学习者系列文章
安装完操作系统之后,就需要安装对应的驱动程序了.下面就简要介绍下驱动程序的安装.以驱动精灵驱动安装软件为例. 1. 下载驱动精灵. 从http://www.drivergenius.com/网站下载 ...