(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图为导向图得到的透射率图