暗通道优先的图像去雾算法

11.1  暗通道优先的图像去雾算法

图像增强与图像修复二者之间有一定交叉,尽管它们一个强调客观标准,一个强调主观标准,但毕竟最终的结果都改善了图像的质量。图像去雾就是这两种技术彼此交叉领域中最典型的代表。如果将雾霾看作是一种噪声,那么去除雾霾的标准显然是非常客观的,也就是要将图像恢复至没有雾霾下所获取的情况。但是如果将在雾霾环境下拍摄的照片就看作是一种图像本来的面貌,那么去雾显然就是人们为了改善主观视觉质量而对图像所进行的一种增强。早期图像去雾的研究并没有得到应有的重视,很多人认为它的实际意义不大,甚至觉得所谓的去雾算法多是些华而不实的花拳绣腿,缺乏学术上的价值。然而,斗转星移,时易世变。一方面随着大气污染的日益严重,设法改善自动获取的图像质量其意义不言而喻。另一方面,随着数码设备的普及,消费类电子产品的市场也催生出许多新的需求,其中人们对所拍照片质量的修正和优化就是一个显而易见的需求。说到图像去雾,就不得不提到由何恺明博士等人提出的基于暗通道的图像去雾算法。这个算法因其新颖的思路和理想的效果而广受关注,相关论文也曾于2009年荣获CVPR最佳论文奖,同时也是该奖设立以来,首次由亚洲学者获颁此殊荣。

 

 

现在结果已经比较细腻了,但是显然图像有些暗。何博士在论文中也有提及直接暗通道算法的结果会是比较暗的。下一篇文章中,我们将给出在MATLAB中实现的源代码,并对过暗的图像增加曝光和自动色阶,从而得到完美的去雾图像。


我们已经了解了暗通道图像去雾算法的基本原理,下面我们来编程实现,然后对结果再做一些讨论。

上述代码中调用了几个函数,限于篇幅这里仅给出其中的暗通道处理函数,其余函数读者可以尝试自己写写看,当然其中最关键的就是暗通道处理函数,这也是算法的核心内容。

 

 1 %darkchannel.m
 2 %求一幅图像的暗通道图像,窗口大小为15*15
 3 imageRGB = imread('D:\\tmppic\\1.jpg');
 4 imageRGB = double(imageRGB);
 5 imageRGB = imageRGB./255;
 6 dark = darkfunction(imageRGB);
 7 imshow(dark);
 8 %选取通道中最亮的0.1%像素,从而求得大气光
 9 [m, n, ~] = size(imageRGB);
10 imsize = m*n;
11 numpx = floor(imsize/1000);
12 JDarkVec = reshape(dark, imsize,1);
13 ImVec = reshape(imageRGB, imsize, 3);
14 imshow(ImVec);
15 [JDarkVec, indices] = sort(JDarkVec);
16 indices = indices(imsize-numpx+1:end);
17 
18 atmSum = zeros(1, 3);
19 for ind = 1:numpx
20     atmSum = atmSum + ImVec(indices(ind),:);
21 end
22 atmospheric = atmSum / numpx;
23 %求解透射率,并通过omega参数来选择保留一定程度雾霾,一面损坏真实感
24 omega = 0.95;
25 im = zeros(size(imageRGB));
26 
27 for ind = 1:3
28     im(:,:,ind) = imageRGB(:,:,ind)./atmospheric(ind);
29 end
30 
31 dark_2 = darkfunction(im);
32 t = 1- omega*dark_2;
33 
34 %通过导向滤波来获得更为精细的投射率图
35 % r = 60;
36 % eps = 10^-6;
37 % refined_t = guidedfilter_color(imageRGB, t, r, eps);
38 % 
39 % refinedRadiance = getRadiance(atmospheric, imageRGB, refined_t);
40 disp(atmospheric);
41 %disp(t);
42 
43 for i = 1:m;
44     for j = 1:n;
45         for c = 1:3
46             imageRGB(i,j,c) = (imageRGB(i,j,c) - atmospheric(c))/max(t(i,j),0.1) + atmospheric(c);
47         end
48     end
49 end
50 
51 imshow(imageRGB);

 

 1 %函数
 2 function [dark] = darkfunction(imRGB)
 3 
 4 r = imRGB(:,:,1);
 5 g = imRGB(:,:,2);
 6 b = imRGB(:,:,3);
 7 
 8 [m n] = size(r);
 9 a = zeros(m,n);
10 for i = 1:m;
11     for j = 1:n;
12         a(i,j) = min(r(i,j),g(i,j));
13         a(i,j) = min(a(i,j),b(i,j));
14     end
15 end
16 
17 d = ones(15,15);
18 fun = @(block_struct)min(min(block_struct.data))*d;
19 dark = blockproc(a, [15 15], fun);
20 dark = dark(1:m, 1:n);
21 
22 end

 

另外,代码里我们使用了导向滤波函数,导向滤波代码来自何恺明博士,读者可以访问他的网页获得源码,已经论文的原文,链接如下:

http://research.microsoft.com/en-us/um/people/kahe/

另外,下面这个博客里有一些关于导向滤波的比较通俗的讨论,可以作为阅读论文原文时的辅助材料:

http://blog.csdn.net/aichipmunk/article/details/20704681

 

最后一个小讨论,我们所采用的方法英文叫 Dark Channel Prior,很多人困惑 Prior该怎么翻译,我标题里采用了优先这个叫法,这个是一个比较常见的叫法,我也随世流俗了,因为Prior在英文里确实有这个意思。但是这个通常的叫法其实欠妥,最好翻成 “先验”。在上一篇文章中,我们讨论过这个算法的原理,其实算法是把 暗通道的有关结论作为一个先验条件来使用的,就像我们以前做 数学证明题,会有一些 结论或者定理 即使题目中没给我们也可以直接用,那些结论或者定理就是 先验的 条件,是不需要直接给出也可以使用的。

posted @ 2016-03-15 19:15  何人之名  阅读(10052)  评论(0编辑  收藏  举报