何恺明的暗通道先验( dark channel prior)去雾算法是CV界去雾领域很有名的算法,关于该算法的论文"Single lmage Haze Removal Using Dark Channel Prior"一举获得2009年CVPR最佳论文。作者统计了大量的无雾图像,发现一条规律:每一幅图像的每个像素的RGB3三个颜色通道中,总有一个通道的灰度值很低。基于这个几乎可以视作是定理的先验知识,作者提出暗通道先验的去雾算法。
暗通道去雾模型如下:
I ( x ) = J ( x ) t ( x ) + A ( 1 − t ( x ) ) I(x)=J(x)t(x)+A(1-t(x)) I(x)=J(x)t(x)+A(1−t(x))
对于任意一副输入图像,定义其暗通道的数学表达式为:
J d a r k ( x ) = m i n y ∈ Ω ( x ) ( m i n c ∈ r , g , b J ( c ) ( y ) ) = 0 J^{dark}(x)= \mathop{min}\limits_{y\in \Omega(x)}(\mathop{min}\limits_{c \in {r,g,b}}J^{(c)}(y))=0 Jdark(x)=y∈Ω(x)min(c∈r,g,bminJ(c)(y))=0
其中c表示rgb三通道中的某一通道。上式表示在一 幅输入图像中,先取图像中每一个像素的三通道中的灰度值的最小值,得到一幅灰度图像,再在这幅灰度图像中,以每一个像素为中心取一定大小的矩形窗口,取矩形窗口中灰度值最小值代替中心像素灰度值(最小值滤波)从而得到该露天图像的暗通道图像。暗通道图像为灰度图像,通过大量统计并观察发现,暗通道图像的灰度值是很低的,所以将整幅暗通道图像中所有像素的灰度值近似为0,即:
J d a r k ⇒ 0 J^{dark}\Rightarrow 0 Jdark⇒0
对应的matlab代码为:
I=imread(filename);
figure();
imshow(I);
title('原始图像');
[h,w,s]=size(I);
min_I=zeros(h,w);
%下面取得暗影通道图像
for i=1:h
for j=1:w
dark_I(i,j)=min(I(i,j,:));
end
end
figure();
imshow(dark_I);
title('dark channnel的图形');
作者在文中假设大气光 A A A为已知量,以便节省篇幅介绍传输函数的求解方法。本次实验中求解大气光的方法是取暗通道灰度值的最大值。
对应matlab代码为:
atmosphere_light = double(max(max(dark_I)))
对于成像模型,将其归一化,即两边同时除以每个通道的大气光值:
I c ( x ) A c = t ( x ) J c ( x ) A c + 1 − t ( x ) \frac{I^c(x)}{A^c}=t(x)\frac{J^c(x)}{A^c}+1-t(x) AcIc(x)=t(x)AcJc(x)+1−t(x)
传输函数 t ( x ) t(x) t(x)的值为定值,对上式两边用最小化算子作最小化运算:
m i n c I c ( y ) A c = t ( x ) m i n c J c ( y ) A c + 1 − t ( x ) \mathop{min}\limits_c\frac{I^c(y)}{A^c}=t(x)\mathop{min}\limits_c\frac{J^c(y)}{A^c}+1-t(x) cminAcIc(y)=t(x)cminAcJc(y)+1−t(x)
由于 t ( x ) t(x) t(x)为定值,故将其拿出运算符外部。由于场景辐射事无雾图像,将暗通道先验应用于 J J J,则有:
J d a r k ( x ) = m i n c ∈ r , g , b J c ( y ) = 0 J^{dark}(x)=\mathop{min}\limits_{c\in{r,g,b}}J^c(y)=0 Jdark(x)=c∈r,g,bminJc(y)=0
由于 A c > 0 A^c >0 Ac>0,则当 m i n c ∈ r , g , b J c ( y ) A c = 0 \mathop{min}\limits_{c\in{{r,g,b}}}\frac{J^c(y)}{A^c}=0 c∈r,g,bminAcJc(y)=0时,可以得到传输函数的估计值为:
t ( x ) = 1 − m i n c I c ( y ) A c t(x)=1-\mathop{min}\limits_c\frac{I^c(y)}{A^c} t(x)=1−cminAcIc(y)
为了防止去雾太过彻底,恢复得不自然,引入参数 w w w,重新定义传输函数为:
t ( x ) = 1 − w m i n c I c ( y ) A c t(x)=1-w\mathop{min}\limits_c\frac{I^c(y)}{A^c} t(x)=1−wcminAcIc(y)
matlab代码为:
dark_channel=double(dark_I);
t=1-w0*(dark_channel/atmosphere_light); %取得传输函数分布率图
figure();
T=uint8(t*255);
imshow(T);
title('传输函数t的图形');
最后计算出 J ( x ) J(x) J(x)三个通道的值,最后可以得到去雾后的图像。
J ( x ) = I ( x ) − A ( 1 − t ( x ) ) t ( x ) J(x)=\frac{I(x)-A(1-t(x))}{t(x)} J(x)=t(x)I(x)−A(1−t(x))
代码如下:
t = max(t,t0);
I1=double(I);
J(:,:,1) = uint8((I1(:,:,1) - (1-t)*atmosphere_light)./t);
J(:,:,2) = uint8((I1(:,:,2) - (1-t)*atmosphere_light)./t);
J(:,:,3) =uint8((I1(:,:,3) - (1-t)*atmosphere_light)./t);
figure();
imshow(J);
title('去雾后的图像');