参考论文:Single Image Haze Removal Using Dark Channel Prior
在计算机视觉当中,通常使用下面这个模型去描述一幅有雾的图像:
对于这个模型,我是这样理解的,I(x)是我们观察到的灰度,J(x)是场景在无雾时的实际光照,而A是全局大气光照强度,t(x)是透射率。去雾的目标是通过I(x)来恢复J(x)和A。如果我们稍微的把这个模型变换一下:
从上面这条公式可以看出,如果我们能够求出大气光照和透射率的话,那我们就可以还原图像在没有雾的时候实际光照了,这就实现了图像的去雾。当t(x)的值非常小的时候,公式1中的J(x)*t(x)也会非常小,如果这样直接把图像J(x)恢复出来的话,虽然能有更好的去雾效果,但是会存在非常多的噪点,所以为了限制噪点的数量,我们把t的最小值限制在0.1,这也意味着会有少量的雾保留在图中。
这个去雾算法叫暗通道先验法,大多数无雾室外图像中的局部图像中包含一些像素,这些像素在至少一个颜色通道中具有非常低的灰度,我们把这些像素称之为暗通道像素。经过观察,75%的暗通道像素灰度为0,90%的暗通道像素灰度都在25以下。在有雾图像中我们优先利用这个特点,我们可以估计雾的浓度然后把图像还原成高质量的去雾图像。
我们首先提取暗通道中灰度小于50的像素,根据这些像素占总像素的比例来选择合适的参数,然后这些像素中找到灰度最高的像素就被选择作为大气光照强度。再计算出图像的透射率,最后利用公式②来回复图像。
程序和流程图如下。
close all
clear all
clc
w0=0.6;
t0=0.1;
%I=imread('D:\Matlab\dehaze\初始图像\有雾图像样本1.jpg'); %读取需要处理的图像样本
I=imread('D:\Matlab\dehaze\初始图像\有雾图像样本2.jpg');
subplot(3,2,1); %表示3(行数)*2(列数)的图像,1代表所画图形的序号
%subplot(2,2,1);
imshow(I); %显示读取到的图像
title('原始图像:'); %给读取到的图像添加标题
subplot(3,2,3); %在读取到的图像下面添加图像
%subplot(2,2,3);
grayI=rgb2gray(I); %将RGB图像转换为灰度图
imshow(grayI,[]); %将原始图像转换的灰度图展示在原始图像的下方
title('原图像灰度图:')
subplot(3,2,4); %在第四个位置显示原始图像的直方图
imhist(grayI,256); %计算灰度图像的直方图
title('原图像灰度直方图:')
%统计<50的像素所占的比例
[COUNT,x]=imhist(grayI); %返回初始图像直方图每一级的像素个数
under_50=0;
for i=0:50 %统计有多少像素的灰度级别小于50
under_50=under_50+COUNT(x==i);
end
under_50
total=size(I,1)*size(I,2)*size(I,3); %I是读取的图像样本,这个方程是计算图像大小?
percent=under_50/total %计算深色像素在所有像素中占的比例
if(percent>0.02) %灰度小于50的像素的比例大于2%就不需要去雾。灰度值越小,图像越黑
error('This image need not Haze-Free-Proprocessing.');
else if(percent<0.001) %w0这个参数用于保留远处物体的雾,从而使图像看起来更自然,保留更多的深度信息
w0=0.6; %w0=0不去雾,w0=1去掉全部的雾,不过最好不要超过0.7,不然过饱和
else if (percent>0.01)
w0=0.3;
else
w0=0.45;
end
end
end
[h,w,s]=size(I); %返回三个维度的大小(高,宽,颜色)
for i=1:h
for j=1:w
dark_I(i,j)=min(I(i,j,:)); %取每个点的像素为RGB分量中最低的那个通道的值,组成矩阵
end
end
Max_dark_channel=double(max(max(dark_I))) %在找到所有像素RGB分量最低的那个通道的值后,再在这些值中找到最亮那个,作为大气光线的估计值
dark_channel=double(dark_I); %把矩阵里面的元素转换为双精度类型
t=1-w0*(dark_channel/Max_dark_channel); %计算透射率 t
t=max(t,t0); %t0初始值为0.1
I1=double(I);
J(:,:,1) = uint8((I1(:,:,1) - (1-t)*Max_dark_channel)./t); %使用公式②进行去雾
J(:,:,2) = uint8((I1(:,:,2) - (1-t)*Max_dark_channel)./t);
J(:,:,3) = uint8((I1(:,:,3) - (1-t)*Max_dark_channel)./t);
subplot(3,2,2); %在第二个位置绘制已经去雾的图像
%subplot(2,2,2);
imshow(J); %J是处理后的图像
%imwrite(J,'D:\Matlab\dehaze\去雾图像\去雾图像1.jpg');
imwrite(J,'D:\Matlab\dehaze\去雾图像\去雾图像2.jpg'); %使用绝对路径,不然会报错
title('去雾图像:');
subplot(3,2,5); %在第5个位置显示去雾后图像的灰度图
%subplot(2,2,4);
grayJ=rgb2gray(J);
imshow(grayJ,[]);
title('去雾后灰度图:')
subplot(3,2,6);
imhist(grayJ,256); %返回处理图像直方图每一级的像素个数
title('去雾图像灰度直方图:')