1、什么是暗通道先验:在绝大多数非天空的局部区域里,某一些像素总会有至少一个颜色通道具有很低的值。
2、对于任意的输入图像J,其暗通道可以用下式表达:
Jc表示彩色图像的每个通道 ,Ω(x)表示以像素X为中心的一个窗口。(5)式的意义用代码表示:首先求出每个像素RGB分量中的最小值,存入一副和原始图像大小相同的灰度图中,然后再对这幅灰度图进行最小值滤波,滤波的半径由窗口大小决定,一般有WindowSize = 2 * Radius + 1; 若窗口大小为15*15,即最小值滤波的半径为7像素。
以像素点x为中心,分别取三个通道内窗口Ω内的最小值,然后再取三个通道的最小值作为像素点x的暗通道的值,如下图所示:(图来自:https://www.cnblogs.com/changkaizhao/p/3266798.html)
3、暗通道先验的理论指出:
4、采用暗通道先验去雾算法中模糊图像(有雾图像)模型被描述成:
I(x)是有雾图像,J(x)是去雾后图像,A是全局大气光强,t(x)为透射率。这个算法的目的就是从I、A、t中得到J。目前我们只知道I(x),需要求出A和t。
由此我们得到了t,因为这样在视觉上看起来是不自然的,我们修正了这个公式:
其中w=0.95,最终在把t,带入模型,可以得到
5、上述推论中都是假设全球达气光A值时已知的,在实际中,我们可以借助于暗通道图来从有雾图像中获取该值。具体步骤如下:
① 从暗通道图中按照亮度的大小取前0.1%的像素。
② 在这些位置中,在原始有雾图像I中寻找对应的具有最高亮度的点的值,作为A值。
到这一步,我们就可以进行无雾图像的恢复了。由式(1)可知: J = ( I - A)/t + A
现在I,A,t都已经求得了,因此,完全可以进行J的计算。
注:当投射图t 的值很小时,会导致J的值偏大,从而使得图像整体向白场过度,因此一般可设置一阈值T0,当t值小于T0时,令t=T0,本文中所有效果图均以T0=0.1为标准计算。
6、主程序: imageprocessing.m
clc
clear all;
%导入原始图片并显示
figure(1) %figure是建立图形的意思
subplot(1,2,1) %将多个图画到一个平面,图排成1行2列,从左到右从上到下的第一个位置
I1=imread('迷雾1.png'); %读入图片,返回一个数组(矩阵),往往a*b*c unit8 类型
imshow(I1) %显示图像I1
title('有雾图像1') %图像标题
impixelinfo; %显示像素坐标以及像素值(鼠标移动位置)
figure(1)
subplot(1,2,2) %第二个位置
I2=imread('迷雾2.png');
figure(1)
imshow(I2)
title('有雾图像2')
impixelinfo; %显示像素坐标以及像素RGB值
%A=antongdao(a,m,n); a为彩色图像矩阵;m,n为滤波窗口大小,滤波窗口自己设置一般是3*3,5*5,9*9,15*15,25*25
A1=antongdao(I1,25,25); %计算暗通道函数
figure(2) %创建第二个图窗
subplot(1,2,1)
imshow(A1)
title('暗通道图像1')
A2=antongdao(I2,5,5);
figure(2)
subplot(1,2,2) %在第二个窗口显示暗通道图像
imshow(A2) %显示暗通道图像
impixelinfo; %显示像素坐标以及像素值
title('暗通道图像2')
[Ac1]=qjdqgz(A1,I1); %调用qjdqgz()函数
[Ac2]=qjdqgz(A2,I2); %调用qjdqgz()函数
[t1,R1,G1,B1]=tsl(I1,Ac1); %调用函数ts1()
[t2,R2,G2,B2]=tsl(I2,Ac2);
I1=cat(3,R1,G1,B1);
I2=cat(3,R2,G2,B2);
figure(3)
subplot(1,2,1)
% I1=im2uint8(I1);
imshow(I1)
title('去雾图像1 ');
impixelinfo;
subplot(1,2,2)
% I2=im2uint8(I2);
imshow(I2)
title('去雾图像2 ');
impixelinfo;
7、求暗通道的部分:先求RGB三个通道的最小值,再进行最小值滤波
文件:antongdao.m---计算暗通道函数,c为彩色图像矩阵;m,n为滤波窗口大小,A为计算的暗通道
function A=antongdao(c,m,n)
c=im2double(c); %将图像数组转换为double型(c为主函数传过来的图像I1矩阵)
[a,b,~]=size(c); %行数(垂直辨率),列数(水平分辨率),层数
R1=c(:,:,1); %读取图像R值
G1=c(:,:,2); %读取图像G值
B1=c(:,:,3); %读取图像B值
A=zeros(a,b); %生成一个a*b的零矩阵
d=A;
for i=1:a %1~a的for循环
for j=1:b %1~b的for循环
d(i,j)=min(R1(i,j),G1(i,j)); %R1和G1中取较小值赋值给d
A(i,j)=min(d(i,j),B1(i,j)); %在d和B1中取较小值
end
end
A=ordfilt2(A,1,ones(m,n)); %m*n的最小值滤波
8、文件:qjdqgz.m---求解全局大气光照函数,A为暗通道,I1为原彩色图像,Ac为全局大气光照
求解全局大气光照过程如下:
1.首先对输入的有雾图像I求解其暗通道图像Jdark。
2.选择暗通道Jdark内图像总像素点个数(N_imagesize)千分之一(N=N_imagesize/1000)个最亮的像素点,并记录这些像素点(x,y)坐标。
3.根据点的坐标分别在原图像J的三个通道(r,g,b)内找到这些像素点并加和得到(sum_r,sum_g,sum_b)
4.Ac=[Ar,Ag,Ab]. 其中Ar=sum_r/N; Ag=sum_g/N; Ab=sum_b/N
function [Ac]=qjdqgz(A,I1)
I1=im2double(I1); %将图像数组转换为double型(c为主函数传过来的图像I1矩阵)
R1=I1(:,:,1);
G1=I1(:,:,2);
B1=I1(:,:,3);
[a,b]=size(A); %返回图片的尺寸信息, 并存储在a、b中,m中存储的是行数,n中存储的是列数。(要是数组就求出其m*n,要是照片的话就是求出其像素大小!)
c=ceil(a*b/1000); %朝正无穷大方向取整
r1=zeros(c,1); %返回一个c*1的零矩阵
g1=zeros(c,1);
b1=zeros(c,1);
m=0.9;
x=1;
d(1,1)=0;
q(1,1)=0;
while size(d,1)<=c
for i=1:a
for j=1:b
if A(i,j)>m && size(d,1)<=c
d(x,1)=i;
q(x,1)=j;
x=x+1;
end
if size(d,1)>c
break
end
end
end
if size(d,1)<=c
m=m-0.1;
end
end
for p=1:c
r1(p,1)=R1(d(p,1),q(p,1));
g1(p,1)=G1(d(p,1),q(p,1));
b1(p,1)=B1(d(p,1),q(p,1));
end
Ar=max(max(r1));
Ag=max(max(g1));
Ab=max(max(b1));
Ac=[Ar,Ag,Ab];
9、文件:tsl.m---求解透射率函数及去雾后RGB值。I1为原彩色图像,Ac为全局大气光照,t为透射率,R1,G1,B1为去雾后的值
function [t,R1,G1,B1]=tsl(I1,Ac)
[a,b,~]=size(I1);
I1=im2double(I1);
R1=I1(:,:,1);
G1=I1(:,:,2);
B1=I1(:,:,3);
t=zeros(a,b);
d=t;
for i=1:a
for j=1:b
d(i,j)=min(R1(i,j)/Ac(1,1),G1(i,j)/Ac(1,2));
t(i,j)=1-0.95*min(d(i,j),B1(i,j)/Ac(1,3));
end
end
t=imguidedfilter(t); %导向滤波
for i=1:a
for j=1:b
R1(i,j)=(R1(i,j)-Ac(1,1))./(max(t(i,j),0.1))+Ac(1,1);
G1(i,j)=(G1(i,j)-Ac(1,2))./(max(t(i,j),0.1))+Ac(1,2);
B1(i,j)=(B1(i,j)-Ac(1,3))./(max(t(i,j),0.1))+Ac(1,3);
end
end
10、 matlab
运行结果:
本文若有不足之处,望指正,共同进步 ❤