刷博客的时候,无意中看到一篇介绍图像去雾的博客,讲到何凯明的《Single Image Haze Removal Using Dark Channel Prior》这篇文章,2009年CVPR的最佳论文,简单看了下介绍,瞬间就对作者佩服的五体投地,感叹这才叫做研究。 论文《Single Image Haze Removal Using Dark Channel Prior》可以在这里下载到,并且里面还有论文相关的幻灯片和其他参考论文等信息。
1. 论文的主要介绍※
1.1 暗通道先验※
暗通道先验是基于户外无雾图像的观察,在大部分不包含天空的图像中,在r,g,b三个通道中,至少有一个通道的最小灰度值非常小。用公式表示为,图像的暗通道J定义为:
\(J^{dark}(x)=\min_{y\in{r,g,b}}(\min_{y\in\Omega(x)}(J^c(y))\)
其中,$J^c$表示J的颜色通道,$\Omega(x)$表示以x为中心的窗口。 观察发现,对于户外无雾图片,$J^{dark}$值是非常小的,由此,称这个统计规律为暗通道先验。
1.2 图像去雾※
在计算机视觉和计算机图形学中,通常使用下面的模型描述有雾图像:
$$ I(x)=J(x)t(x) + A(1-t(x)) $$
其中,I(x)就是观察到的含雾图像,J(x)是不包含雾的图像,A是全球大气光成分系数,t(x)表示透射率。图像去雾的问题实际上是根据已知的I(x)来求J(x)。
1.3 计算透射率※
首先,假设大气光成分系数A是已知的,进一步的,假设在图像的一个小窗口内$\Omega(x)$,透射率t(x)是一个常数,对有雾图像模型的窗口内,使用min操作,得到:
$$ \min_{y\in\Omega(x)}(I^c(y)) = \tilde{t}(x)\min_{y\in\Omega(x)}(J^c(y))+(1-\tilde{t}(x))A^c $$
min操作是在三个色彩通道上独立进行的,所以等式可以化简为:
$$ \min_{y\in\Omega(x)}(\frac{I^c(y)}{A^c}) = \tilde{t}(x)\min_{y\in\Omega(x)}(\frac{J^c(y)}{A^c})+(1-\tilde{t}(x)) $$
对上面等式中三个色彩通道使用min操作,得到
$$ \min_c(\min_{y\in\Omega(x)}(\frac{I^c(y)}{A^c})) = \tilde{t} \min_c( (x)\min_{y\in\Omega(x)}(\frac{J^c(y)}{A^c})) + (1-\tilde{t}(x)) \tag{公式8} $$
根据暗通道先验,无雾图像J的暗通道$J^{dark}$趋向于0:
$$ J^{dark}(x) = \min_c( \min_{y\in\Omega(x)}(J^c(y))) = 0 $$
$A^c$一直是一个正数,可得:
$$ \min_c(\min_{y\in\Omega(x)}(\frac{I^c(y)}{A^c})) = 0 \tag{公式10} $$
\(\min_c(\min_{y\in\Omega(x)}(\frac{I^c(y)}{A^c})) = 0 \)
将公式10代入公式8中,得到:
$$ \tilde{t}(x) = 1 - \min_c(\min_{y\in\Omega(x)}(\frac{I^c(y)}{A^c})) \tag{公式11} $$ 由此,得到透射率$\tilde{t}(x)$。
前面有说道,暗通道先验在天空的区域效果不好,不过幸运的是,有雾图像中天空的颜色通常都跟大气光成分A非常相似,由此,在天空区域有: $$ \min_c(\min_{y\in\Omega(x)}(\frac{I^c(y)}{A^c})) \rightarrow 1 \text{, and } \tilde{t}(x) \rightarrow 0, $$
在天空区域,图像的透射率趋向于0,这样,公式11就很好的概况了没有天空区域和有天空区域。
在现实生活中,图像中少量的雾能够反映物体的深度信息,所以,我们可以保留一点雾来让图像更加自然一些。 $$ \tilde{t}(x) = 1 - \omega\min_c(\min_{y\in\Omega(x)}(\frac{I^c(y)}{A^c})) $$ $\omega$一般取0.95。
1.4 大气光成分系数※
大气光成分系数一般是借助暗通道图获得的,首先在暗通道图中找出前0.1%的像素位置,再在这些位置中找出最高亮度的点作为大气光成分系数A。
1.5 恢复无雾图像※
现在,I、A、T都已知,则无雾图像为: $$ J(x) = \frac{I(x) - A}{max(t(x), t_0)} + A $$ 其中,$max(t(x), t_0)$主要是防止t值很小时,J值偏大,使得图像过白,一般设置$t_0$为0.1。
2. 我的一个实现※
看我文章后,我自己用Python写了一个程序简单实现下。程序放在Github了。同时,我用Flask搭了一个简单的服务,可以直接上传有雾图片得到去雾后的图片,感兴趣的可以去http://tools.pfchai.com看看。