暗通道先验法

大气散射模型

\[ I(x)=I_{\infty}r(x)e^{-kd(x)}+I_{\infty}(1-e^{-kd(x)}) \]

其中\(r(x)\)为反射率, \(I_{\infty}\)为无穷远处天空辐射强度, \(I_{\infty}r(x)\)为没有任何干扰情况下的图像, 有雾的情况下大气透射率为\(e^{-kd(x)}\), \(k\)为散射系数

简化为:

\[ I(x)=J(x)t(x)+A[1-t(x)] \]

\(A\)为环境光, \(J(x)\)为无雾图像对应的场景辐射, \(t(x)\)为大气透射率\(0\le t(x)\le 1\)

得到恢复原图像的公式:

\[ J(x)=A-\frac{A-I(x)}{t(x)} \]

暗通道先验

暗通道为RGB通道中值最小的, 对于每个像素取最小值, 取其中最亮的0.1%的均值为环境光的估计, 因为一般天空为最亮, 代入公式天空是正好吸收和反射补偿了, 但是对于没有天空或者有灯光干扰的情况估计值就会偏小或者偏大

对于上式取最小值运算

\[ \min_{y\in N(x)}\left[\min_{C\in \{R,G,B\}}\frac{I_{C}(y)}{A_{C}}\right]=\left[1-t^{N}(x)\right]+\min_{y\in N(x)}\left[\min_{C\in \{R,G,B\}}\frac{I_C(y)}{A_C}\right]t^N(x) \]

可以得到\(N_r(x)\)邻域大气透射率的估计值\(t^N(x)\):

\[ t^N(x)=1-\min_{y\in N(x)}\left[\min_{C\in \{R,G,B\}}\frac{I_C(y)}{A_C}\right] \]

MATLAB实现代码:

close all;
clearvars;

fog = imread('fog1.jpg');

figure
imshow(fog)
% find darkness channel

darkness = min(fog, [], 3);
array_size = size(darkness);
after = fog;
after = double(after);
tN = zeros(array_size, 'double');
pixel_count = array_size(1,1) * array_size(1,2);
reshaped_array = reshape(darkness, [1, pixel_count]);
sorted_array = sort(reshaped_array, 'descend');
sample_count = round(pixel_count * 0.001);
average_gray = sum(sorted_array(1, 1:sample_count))./sample_count;

window_width = floor(min(array_size, [], "all")/16/2)*2+1;
window_height = window_width;
half_window_width = floor(window_width/2);
half_window_height = floor(window_height/2);

figure
imshow(darkness);

for r=1:array_size(1,1)
    for c=1:array_size(1,2)
        y_start = max(r - half_window_height, 1);
        y_end = min(r + half_window_height, array_size(1,1));
        x_start = max(c - half_window_width, 1);
        x_end = min(c + half_window_height, array_size(1,2));
        tN(r,c) = min(darkness(y_start:y_end, x_start:x_end), [], 'all');
    end
end
figure
imshow(uint8(tN));
tN = 1 - 0.95.*tN./average_gray;
after(:,:,1) = floor(average_gray - (average_gray - after(:,:,1))./tN);
after(:,:,2) = floor(average_gray - (average_gray - after(:,:,2))./tN);
after(:,:,3) = floor(average_gray - (average_gray - after(:,:,3))./tN);
figure
imshow(uint8(after));

算法结果: {% gi 6 3-3 %} fog1.png dark1.png after1.png fog2.png dark1.png after2.png {% endgi %}

第一组的效果比较好, 第二组在不同景深交界处会出现明显的光晕