图片去雾GUI

代码

主程序代码

m1.m

% MATLAB 图形用户界面 (GUI) 用于实现去雾
function varargout = m1(varargin)
% 设置 GUI 为单例模式,确保只能打开一个实例。
gui_Singleton = 1;
% 定义了 GUI 的状态,包括界面名字、是否单例模式等。
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @m1_OpeningFcn, ...
                   'gui_OutputFcn',  @m1_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
% 判断输入参数是否是一个字符串,用于判断 GUI 的回调函数。
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

% 判断是否需要返回输出参数。
if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end

% 在 GUI 可见之前执行的函数。将默认命令行输出作为 GUI 的输出。
function m1_OpeningFcn(hObject, eventdata, handles, varargin)
handles.output = hObject;
guidata(hObject, handles);

% 设置 GUI 的输出函数。
function varargout = m1_OutputFcn(hObject, eventdata, handles) 
varargout{1} = handles.output;

% 选择图片导入
function pushbutton1_Callback(hObject, eventdata, handles)
[imgfilename,imgpathname] = uigetfile({'*.jpg;*.png'},'输入图像');
if imgfilename
    img = imread([imgpathname imgfilename]);
    % 导入原图到第一个坐标系上
    axes(handles.axes1);
    imshow(img);
    title('原图','FontWeight','Bold');
    handles.imgfilename=imgfilename;
    handles.imgpathname = imgpathname;
    handles.img = img;
end
guidata(hObject,handles)

% 当按钮 pushbutton2 被点击时执行的回调函数。该函数使用全局直方图均衡化算法对图像进行去雾处理,
% 并在第二个坐标轴上显示去雾后的图像
function pushbutton2_Callback(hObject, eventdata, handles)
pnum=get(handles.popupmenu1,'value');
switch pnum
    case 1
        handles.img1=GlobalHistogram(handles.img);%执行全局直方图均衡化去雾
        axes(handles.axes3);
        cla reset;
        axes(handles.axes4);
        cla reset;
        axes(handles.axes2);imshow(handles.img1,[]);%结果图显示在axes2
        guidata(hObject,handles);
        set(handles.edit1,'String','全局直方图算法');%将方法名显示在edit1中
    case 2
        handles.img1=Localhistogram1(handles.img);%执行局部直方图均衡化去雾
        axes(handles.axes3);
        cla reset;
        axes(handles.axes4);
        cla reset;
        axes(handles.axes2);imshow(handles.img1,[]);%结果图显示在axes2
        guidata(hObject,handles);
        set(handles.edit1,'String','局部直方图算法');%将方法名显示在edit1中
    case 3
        handles.img1=Retinexsuanfa(handles.img);%执行Retinex单尺度算法去雾
        axes(handles.axes3);
        cla reset;
        axes(handles.axes4);
        cla reset;
        axes(handles.axes2);imshow(handles.img1,[]);%结果图显示在axes2
        guidata(hObject,handles);
        set(handles.edit1,'String','Retinex单尺度算法');%将方法名显示在edit1中
    case 4
        handles.img1=Retinexsuanfa1(handles.img);%执行Retinex多尺度算法去雾
        axes(handles.axes3);
        cla reset;
        axes(handles.axes4);
        cla reset;
        axes(handles.axes2);imshow(handles.img1,[]);%结果图显示在axes2
        guidata(hObject,handles);
        set(handles.edit1,'String','Retinex多尺度算法');%将方法名显示在edit1中
    case 5
        method = 'manual'; 
        % Window Size设置为15
        wsz = 15;
        A = Airlight(handles.img, method, wsz); 
        % 计算边界约束
        wsz = 3;
        ts = Boundcon(handles.img, A, 30, 300, wsz);
        % 改进传输评估
        % 正则化参数,该参数越多,就越接近原始逐片传输
        lambda = 2;
        % 使用上下文信息
        t = CalTransmission(handles.img, ts, lambda, 0.5);
        % 去雾
        handles.img1 = Dehazefun(handles.img, t, A, 0.85); 
        axes(handles.axes3);
        cla reset;
        axes(handles.axes4);
        cla reset;
        axes(handles.axes2);imshow(handles.img1,[]);%结果图显示在axes2
        guidata(hObject,handles);
        set(handles.edit1,'String','Dark_channel算法');%将方法名显示在edit1中
    case 6
        % estimate_airlight用于估计图像的大气光照(airlight)。它基于一种3*2D霍夫变换方法,其中每个点使用一组固定角度为给定位置进行投票。
        A = reshape(estimate_airlight(im2double(handles.img).^(1)),1,1,3);
        % 图像去雾	
        [handles.img1,trans_refined] = non_local_dehazing(handles.img, A, 1 ); % imgdata是输入图片handles是指针,A和gamma=1是它的参数
        axes(handles.axes3);
        cla reset;
        axes(handles.axes4);
        cla reset;
        axes(handles.axes2);imshow(handles.img1,[]);%结果图显示在axes2
        guidata(hObject,handles);
        set(handles.edit1,'String','non_local算法');%将方法名显示在edit1中
    otherwise
end
title('去雾后','FontWeight','Bold');

% 显示直方图
function pushbutton3_Callback(hObject, eventdata, handles)
img=rgb2gray(handles.img);
img1=rgb2gray(handles.img1);
axes(handles.axes3);imhist(img);title('原图灰度直方图','fontweight','bold');
axes(handles.axes4);imhist(img1);title('去雾后灰度直方图','fontweight','bold');

% 退出系统
function pushbutton4_Callback(hObject, eventdata, handles)
choice = questdlg('确定要退出系统?', ...
    '退出', ...
    '确定','取消','取消');
switch choice
    case '确定'
        close;
    case '取消'
        return;
end

% --- Executes on selection change in popupmenu1.
% 当用户改变下拉菜单的选择时触发,用来重置相关显示区域,清除之前的结果。
function popupmenu1_Callback(hObject, eventdata, handles)
pnum=get(handles.popupmenu1,'value');
if isequal(pnum==1, ~1)
    axes(handles.axes2);
    cla reset;
    axes(handles.axes3);
    cla reset;
    axes(handles.axes4);
    cla reset;
    set(handles.edit1,'string','')
end
if isequal(pnum==2, ~2)
    axes(handles.axes2);
    cla reset;
    axes(handles.axes3);
    cla reset;
    axes(handles.axes4);
    cla reset;
    set(handles.edit1,'string','')
end
if isequal(pnum==3, ~3)
    axes(handles.axes2);
    cla reset;
    axes(handles.axes3);
    cla reset;
    axes(handles.axes4);
    cla reset;
    set(handles.edit1,'string','')
    
end
if isequal(pnum==4, ~4)
    axes(handles.axes2);
    cla reset;
    axes(handles.axes3);
    cla reset;
    axes(handles.axes4);
    cla reset;
    set(handles.edit1,'string','')
    
end
    
% 仅当控件创建时调用,可以用来设置默认属性
function popupmenu1_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% ispc 函数检查当前操作系统是否为 Windows(PC)。如果是在 Windows 上运行,则继续执行后续代码。
% isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) 检查编辑框的背景颜色是否为MATLAB默认的用户界面控件背景颜色。
% set 函数将编辑框的背景颜色设置为白色 ('white')。这主要是为了确保在不同系统上的视觉一致性,因为MATLAB的默认背景颜色可能会随系统主题而变化。
function edit1_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% 保存图片
% function pushbutton5_Callback(hObject, eventdata, handles)
% imwrite(handles.img1,'D:\课程作业\1.jpg')
function pushbutton5_Callback(hObject, eventdata, handles)
% 构造新的文件名,添加 'dehazing_' 前缀到原始文件名。
[~, name, ext] = fileparts(handles.imgfilename);
newFileName = ['dehazing_' name ext];

% 指定保存路径。这里假设你想要保存到与导入图片相同的目录。
savePath = fullfile(fileparts(handles.imgpathname), newFileName);

% 保存去雾后的图像。
imwrite(handles.img1, savePath);

% 可选:显示保存成功的消息框。
msg = sprintf('图片已保存为: %s', savePath);
uiwait(msgbox(msg, '保存成功', 'help'));

全局直方图均衡化

GlobalHistogram.m

function img1 = GlobalHistogram( img )
% 从输入图像img中分别各通道的像素值。
r=img(:,:,1);
g=img(:,:,2);
b=img(:,:,3);
% 对通道的像素值进行直方图均衡化处理
R=histeq(r);
G=histeq(g);
B=histeq(b);
% 将经过均衡化处理的通道重新组合成一个新的彩色图像
img1=cat(3,R,G,B);
end

局部直方图均衡化

Localhistogram1.m

function img1 = Localhistogram1( img )
% 分离通道
R =img(:, :, 1);
G =img(:, :, 2);
B =img(:, :, 3);
%对RGB分量进行局部直方图均衡化
IR=adapthisteq(R,'numtiles',[2 2],'clipLimit',0.02,'Distribution','rayleigh');
IG=adapthisteq(G,'numtiles',[2 2],'clipLimit',0.02,'Distribution','rayleigh');
IB=adapthisteq(B,'numtiles',[2 2],'clipLimit',0.02,'Distribution','rayleigh');
% 恢复到RGB
img1= cat(3, IR, IG, IB);
end

Retinex单尺度算法

Retinexsuanfa.m

function img = Retinexsuanfa( img )
R = img(:, :, 1);
%取对数将照射光分量和反射光分量分离
R0 = double(R);
Rlog = log(R0+1);
Rfft2 = fft2(R0);
%定义模板大小
[N1, M1] = size(R); 
sigma1 =250;
F1= fspecial('gaussian', [N1,M1], sigma1);
Ffft1 = fft2(double(F1));
 %高斯模板和原图像作卷积,低通滤波
DR0 = Rfft2.* Ffft1;
DR = ifft2(DR0);
 %在对数域中,原始图像减去低通滤波后的图像,得到高频增强的图像
DRlog = log(DR +1);
Rr = Rlog - DRlog;
%取反对数
EXPRr = exp(Rr);
%对增强后的图像对比度拉伸增强
MIN = min(min(EXPRr));
MAX = max(max(EXPRr));
EXPRr1 = (EXPRr - MIN)/(MAX - MIN);
EXPRr2 = adapthisteq(EXPRr1);
 
G = img(:, :, 2);
G0 = double(G);
Glog = log(G0+1);
Gfft2 = fft2(G0);
%定义模板大小
[N2, M2] = size(G); 
sigma2= 250;
F2= fspecial('gaussian', [N2,M2], sigma2);
Ffft2 = fft2(double(F2));
 %高斯模板和原图像作卷积,低通滤波
DG0 = Gfft2.* Ffft2;
DG = ifft2(DG0);
DGlog = log(DG +1);
Gg = Glog - DGlog;
EXPGg = exp(Gg);
MIN = min(min(EXPGg));
MAX = max(max(EXPGg));
EXPGg1 = (EXPGg - MIN)/(MAX - MIN);
EXPGg2 = adapthisteq(EXPGg1);
 
B = img(:, :, 3);
B0 = double(B);
Blog = log(B0+1);
Bfft2 = fft2(B0);
%定义模板大小
[N3, M3] = size(B); 
sigma3= 250;
F3 = fspecial('gaussian', [N3,M3], sigma3);
Ffft3 = fft2(double(F3));
 %高斯模板和原图像作卷积,低通滤波
DB0 = Bfft2.* Ffft3;
DB = ifft2(DB0);
DBlog = log(DB+1);
Bb = Blog - DBlog;
EXPBb = exp(Bb);
MIN = min(min(EXPBb));
MAX = max(max(EXPBb));
EXPBb1 = (EXPBb - MIN)/(MAX - MIN);
EXPBb2 = adapthisteq(EXPBb1);
%RGB三通道合成一副图像
img= cat(3, EXPRr2, EXPGg2, EXPBb2);
end

Retinex多尺度算法

Retinexsuanfa1

function img = Retinexsuanfa1( img )
R = img(:, :, 1);
%取对数将照射光分量和反射光分量分离
R0 = double(R);
Rlog = log(R0+1);
Rfft2 = fft2(R0);

G = img(:, :, 2);
G0 = double(G);
Glog = log(G0+1);
Gfft2 = fft2(G0);

B = img(:, :, 3);
B0 = double(B);
Blog = log(B0+1);
Bfft2 = fft2(B0);
%色彩恢复因子C
a=2.5;
I1=imadd(R0,G0);
I2=imadd(I1,B0);
Ir=immultiply(R0,a);
C1=imdivide(Ir,I2);
C=log(C1+1);

%定义模板大小
[N1, M1] = size(R); 
sigma1= 128;
F1= fspecial('gaussian', [N1,M1], sigma1);
Ffft1 = fft2(double(F1));
 %高斯模板和原图像作卷积,低通滤波
DR01 = Rfft2.* Ffft1;
DR1 = ifft2(DR01);
 %在对数域中,原始图像减去低通滤波后的图像,得到高频增强的图像
DRlog1 = log(DR1 +1);
Rr1 = Rlog - DRlog1;

sigma2= 256;
F2= fspecial('gaussian', [N1,M1], sigma2);
Ffft2 = fft2(double(F2));
 %高斯模板和原图像作卷积,低通滤波
DR02 = Rfft2.* Ffft2;
DR2 = ifft2(DR02);
 %在对数域中,原始图像减去低通滤波后的图像,得到高频增强的图像
DRlog2 = log(DR2 +1);
Rr2 = Rlog - DRlog2;

sigma3= 512;
F3 = fspecial('gaussian', [N1,M1], sigma3);
Ffft3 = fft2(double(F3));
 %高斯模板和原图像作卷积,低通滤波
DR03 = Rfft2.* Ffft3;
DR3 = ifft2(DR03);
 %在对数域中,原始图像减去低通滤波后的图像,得到高频增强的图像
DRlog3 = log(DR3 +1);
Rr3 = Rlog - DRlog3;

Rr=(1/3)*(Rr1+Rr2+Rr3);
Rr4=immultiply(C,Rr);
%取反对数
EXPRr = exp(Rr4);
%对增强后的图像对比度拉伸增强
MIN = min(min(EXPRr));
MAX = max(max(EXPRr));
EXPRr1 = (EXPRr - MIN)/(MAX - MIN);
EXPRr2 = adapthisteq(EXPRr1);

%定义模板大小
[N2, M2] = size(G); 
sigma4= 128;
F4= fspecial('gaussian', [N2,M2], sigma4);
Ffft4 = fft2(double(F4));
 %高斯模板和原图像作卷积,低通滤波
DG01= Gfft2.* Ffft4;
DG1 = ifft2(DG01);
DGlog1 = log(DG1 +1);
Gg1 = Glog - DGlog1;

sigma5= 256;
F5= fspecial('gaussian', [N2,M2], sigma5);
Ffft5 = fft2(double(F5));
 %高斯模板和原图像作卷积,低通滤波
DG02 = Gfft2.* Ffft5;
DG2 = ifft2(DG02);
DGlog2 = log(DG2 +1);
Gg2 = Glog - DGlog2;

sigma6= 512;
F6 = fspecial('gaussian', [N2,M2], sigma6);
Ffft6 = fft2(double(F6));
 %高斯模板和原图像作卷积,低通滤波
DG03 = Gfft2.* Ffft6;
DG3 = ifft2(DG03);
DGlog3 = log(DG3 +1);
Gg3 = Glog - DGlog3;

Gg=(1/3)*(Gg1+Gg2+Gg3);
Gg4=immultiply(C,Gg);
EXPGg = exp(Gg4);
MIN = min(min(EXPGg));
MAX = max(max(EXPGg));
EXPGg1 = (EXPGg - MIN)/(MAX - MIN);
EXPGg2 = adapthisteq(EXPGg1);

%定义模板大小
[N3, M3] = size(B); 
sigma7= 128;
F7= fspecial('gaussian', [N3,M3], sigma7);
Ffft7 = fft2(double(F7));
 %高斯模板和原图像作卷积,低通滤波
DB01 = Bfft2.* Ffft7;
DB1 = ifft2(DB01);
DBlog1 = log(DB1+1);
Bb1 = Blog - DBlog1;

sigma8= 256;
F8= fspecial('gaussian', [N3,M3], sigma8);
Ffft8 = fft2(double(F8));
 %高斯模板和原图像作卷积,低通滤波
DB02 = Bfft2.* Ffft8;
DB2 = ifft2(DB02);
DBlog2 = log(DB2+1);
Bb2 = Blog - DBlog2;

sigma9= 512;
F9 = fspecial('gaussian', [N3,M3], sigma9);
Ffft9 = fft2(double(F9));
 %高斯模板和原图像作卷积,低通滤波
DB03 = Bfft2.* Ffft9;
DB3 = ifft2(DB03);
DBlog3 = log(DB3+1);
Bb3 = Blog - DBlog3;

Bb=(1/3)*(Bb1+Bb2+Bb3);
Bb4=immultiply(C,Bb);
EXPBb = exp(Bb4);
MIN = min(min(EXPBb));
MAX = max(max(EXPBb));
EXPBb1 = (EXPBb - MIN)/(MAX - MIN);
EXPBb2 = adapthisteq(EXPBb1);
img= cat(3, EXPRr2, EXPGg2, EXPBb2);
end

Dark_channel算法

Airlight.m 估计图像的大气光

function A = Airlight(HazeImg, method, wsz)
% estimating the global airlight
%
if strcmp(method, 'manual')
    h = figure, imshow(HazeImg, []); 
    title('manual airlight estimation: left click to pick a most hazy pixel. ')
    [x, y] = ginput(1);
    A = HazeImg(round(y), round(x), :);
    A = double(A) -1;
    A = min(A, 255);
    close(h);
elseif strcmp(method, 'he')
    A = airlight_he(HazeImg, wsz);    
elseif strcmp(method, 'our')
    A = airlight_our(HazeImg, wsz);
else
    error('parameter error.');
end

%% 
function A = airlight_our(HazeImg, wsz)
% estimating A channel by channel separately
for k = 1 : 3
    minImg = ordfilt2(double(HazeImg(:, :, k)), 1, ones(wsz), 'symmetric');
    A(k) = max(minImg(:));
end

%%
function A = airlight_he(HazeImg, wsz)
% estimating A using He's method
hsv = rgb2hsv(HazeImg);
GrayImg = hsv(:, :, 3);
[nRows, nCols, bt] = size(HazeImg);

% computing dark channel
DarkImg = min(double(HazeImg), [], 3);
DarkImg = ordfilt2(DarkImg, 1, ones(wsz), 'symmetric');
% 
topDark = sort(DarkImg(:), 'descend');
idx = round(0.001 * length(topDark));
val = topDark(idx); 
id_set = find(DarkImg >= val);  % the top 0.1% brightest pixels in the dark channel
BrightPxls = GrayImg(id_set);
iBright = find(BrightPxls >= max(BrightPxls));
id = id_set(iBright); id = id(1);
row = mod(id, nRows);
col = floor(id / nRows) + 1;

% A is a vector
A = HazeImg(row, col, :);
A = double(A(:));

Boundcon.m计算边界约束

function [t_bdcon, t_b] = Boundcon(HazeImg, A, C0, C1, sz)
% patch-wise transmission from boundary constraint
if length(A) == 1
    A = A * ones(3, 1);
end
if length(C0) == 1
    C0 = C0 * ones(3, 1);
end
if length(C1) == 1
    C1 = C1 * ones(3, 1);
end
HazeImg = double(HazeImg);

% pixel-wise boundary
t_r = max((A(1) - HazeImg(:, :, 1)) ./ (A(1)  -  C0(1)), (HazeImg(:, :, 1) - A(1)) ./ (C1(1) - A(1) ));
t_g = max((A(2) - HazeImg(:, :, 2)) ./ (A(2)  - C0(2)), (HazeImg(:, :, 2) - A(2)) ./ (C1(2) - A(2) ));
t_b = max((A(3) - HazeImg(:, :, 3)) ./ (A(3)  - C0(3)), (HazeImg(:, :, 3) - A(3)) ./ (C1(3) - A(3) ));
t_b = max(cat(3, t_r, t_g, t_b), [], 3);
t_b = min(t_b, 1);

% minimum filtering
se = strel('square', sz);
t_bdcon = imclose(t_b, se);

CalTransmission使用上下文信息

function t = CalTransmission(HazeImg, t, lambda, param)
% estimating the transmission function
[nRows, nCols] = size(t);

% differential filters bank
% Note: filter must have odd size to ensure the correct boundary
nsz = 3; NUM = nsz * nsz;
d{1} = [5, 5, 5; -3, 0, -3; -3, -3, -3];
d{2} = [-3, 5, 5; -3, 0, 5; -3, -3, -3];
d{3} = [-3, -3, 5; -3, 0, 5; -3, -3, 5];
d{4} = [-3, -3, -3; -3, 0, 5; -3, 5, 5];
d{5} = [5, 5, 5; -3, 0, -3; -3, -3, -3];
d{6} = [-3, -3, -3; 5, 0, -3; 5, 5, -3];
d{7} = [5, -3, -3; 5, 0, -3; 5, -3, -3];
d{8} = [5, 5, -3; 5, 0, -3; -3, -3, -3];

% normalizing filters
num_filters = length(d); 
for k = 1 : num_filters
    d{k} = d{k} / norm(d{k}(:));
end

% calculating weighting function
for k = 1 : num_filters
    WFun{k} = CalWeightFun(HazeImg, d{k}, param);
end

% precomputing constant terms
Tf = fft2(t);
DS = 0; 
for k = 1 : num_filters
    D{k} = psf2otf(d{k}, [nRows, nCols]);
    DS = DS + abs(D{k}).^2;
end

% cyclic looping for refining t
beta = 1; beta_rate = 2 * sqrt(2);
beta_max = 2^8;
Outiter = 0;

while beta < beta_max
    % updating parameters    
    gamma = lambda / beta;
    % show the results
    Outiter = Outiter + 1; 
    fprintf('Outer iteration %d; beta %.3g\n', Outiter, beta);    
    figure(1000), imshow(t, []); title(num2str(Outiter)); pause(0.05);     

    % fixing t, solving u
    DU = 0;
    for k = 1 : num_filters
        dt{k} = imfilter(t, d{k}, 'circular');
        u{k} = max(abs(dt{k}) - WFun{k} / beta / num_filters, 0) .* sign(dt{k}); 
        DU = DU + fft2(imfilter(u{k}, flipud(fliplr(d{k})), 'circular')); 
    end
    % fixing u, solving t;    
    t = abs(ifft2((gamma * Tf + DU) ./ ( gamma + DS)));  
    % increasing beta
    beta = beta * beta_rate;
end

close(1000);

%%
function WFun = CalWeightFun(HazeImg, D, param)
% parameters setting
sigma = param; 

% calculating the weighting function
HazeImg = double(HazeImg) / 255;

% weighting function
method = 'circular';
d_r = imfilter(HazeImg(:, :, 1), D, method);
d_g = imfilter(HazeImg(:, :, 2), D, method);
d_b = imfilter(HazeImg(:, :, 3), D, method);
WFun = exp(-(d_r.^2 + d_g.^2 + d_b.^2) / sigma / 2);

Dehazefun.m去雾

function rImg = Dehazefun(HazeImg, t, A, delta)
% dehaze an image given t and A
t = max(abs(t), 0.0001).^delta;

% extropolation to dehaze
HazeImg = double(HazeImg);
if length(A) == 1
    A = A * ones(3, 1);
end
R = (HazeImg(:, :, 1) - A(1)) ./ t + A(1);  %R = max(R, 0); R = min(R, 255);
G = (HazeImg(:, :, 2) - A(2)) ./ t + A(2);  %G = max(G, 0); G = min(G, 255);
B = (HazeImg(:, :, 3) - A(3)) ./ t + A(3);   %B = max(B, 0); B = min(B, 255);
rImg = cat(3, R, G, B) ./ 255;

non_local算法

estimate_airlight.m估计图像的大气光照

function [ Aout ] = estimate_airlight( img, Amin, Amax, N, spacing, K, thres )

%% Verify input params, set defaults when necessary (same as published results)
if ~exist('thres','var') || isempty(thres), thres = 0.01 ; end;
if ~exist('spacing','var') || isempty(spacing), spacing = 0.02 ; end; %1/M in the paper
if ~exist('n_colors','var') || isempty(N), N = 1000 ; end; %number of colors clusters
if ~exist('K','var') || isempty(K), K = 40 ; end; %number of angles

% Define search range for the air-light. The search range is different for each 
% color channel. These values were used in all of our experiments.
if ~exist('Amin','var') || isempty(Amin), Amin = [0,0.05,0.1]; end;
if ~exist('Amax','var') || isempty(Amax), Amax = 1; end;

% Air-light search range, accept a scalar if identical for all color channels
if isscalar(Amin), Amin = repmat(Amin,1,3); end 
if isscalar(Amax), Amax = repmat(Amax,1,3); end

%% Convert input image to an indexed image
[img_ind, points] = rgb2ind(img, N);
[h,w,~] = size(img);
% Remove empty clusters
idx_in_use = unique(img_ind(:));
idx_to_remove = setdiff(0:(size(points,1)-1),idx_in_use);
points(idx_to_remove+1,:) = [];
img_ind_sequential = zeros(h,w);
for kk = 1:length(idx_in_use)
    img_ind_sequential(img_ind==idx_in_use(kk)) = kk;
end
% Now the min value of img_ind_sequential is 1 rather then 0, and the indices
% correspond to points

% Count the occurences if each index - this is the clusters' weight
[points_weight,~] = histcounts(img_ind_sequential(:),size(points,1));
points_weight = points_weight./(h*w);
if ~ismatrix(points), points = reshape(points,[],3); end % verify dim

%% Define arrays of candidate air-light values and angles
angle_list = reshape(linspace(0, pi, K),[],1);
% Use angle_list(1:end-1) since angle_list(end)==pi, which is the same line
% in 2D as since angle_list(1)==0
directions_all = [sin(angle_list(1:end-1)) , cos(angle_list(1:end-1)) ];

% Air-light candidates in each color channel
ArangeR = Amin(1):spacing:Amax(1);
ArangeG = Amin(2):spacing:Amax(2);
ArangeB = Amin(3):spacing:Amax(3);

%% Estimate air-light in each pair of color channels
% Estimate RG
Aall = generate_Avals(ArangeR, ArangeG);
[~, AvoteRG] = vote_2D(points(:,1:2), points_weight, directions_all, Aall, thres );
% Estimate GB
Aall = generate_Avals(ArangeG, ArangeB);
[~, AvoteGB] = vote_2D(points(:,2:3), points_weight, directions_all, Aall, thres );
% Estimate RB
Aall = generate_Avals(ArangeR, ArangeB);
[~, AvoteRB] = vote_2D(points(:,[1,3]), points_weight, directions_all, Aall, thres);

%% Find most probable airlight from marginal probabilities (2D arrays)
% Normalize (otherwise the numbers are quite large)
max_val = max( [max(AvoteRB(:)) , max(AvoteRG(:)) , max(AvoteGB(:)) ]);
AvoteRG2 = AvoteRG./max_val;
AvoteGB2 = AvoteGB./max_val;
AvoteRB2 = AvoteRB./max_val;
% Generate 3D volumes from 3 different 2D arrays
A11 = repmat( reshape(AvoteRG2, length(ArangeG),length(ArangeR))', 1,1,length(ArangeB));
tmp = reshape(AvoteRB2, length(ArangeB),length(ArangeR))';
A22 = repmat(reshape(tmp, length(ArangeR),1,length(ArangeB)) , 1,length(ArangeG),1);
tmp2 = reshape(AvoteGB2, length(ArangeB),length(ArangeG))';
A33 = repmat(reshape(tmp2, 1, length(ArangeG),length(ArangeB)) , length(ArangeR),1,1);
AvoteAll = A11.*A22.*A33;
[~, idx] = max(AvoteAll(:));
[idx_r,idx_g,idx_b] = ind2sub([length(ArangeR),length(ArangeG),length(ArangeB)],idx);
Aout = [ArangeR(idx_r), ArangeG(idx_g), ArangeB(idx_b)];


end % function estimate_airlight_2D

%% Sub functions

function Aall = generate_Avals(Avals1, Avals2)
%Generate a list of air-light candidates of 2-channels, using two lists of
%values in a single channel each
%Aall's length is length(Avals1)*length(Avals2)
Avals1 = reshape(Avals1,[],1);
Avals2 = reshape(Avals2,[],1);
A1 = kron(Avals1, ones(length(Avals2),1));
A2 = kron(ones(length(Avals1),1), Avals2);
Aall = [A1, A2];
end % function generate_Avals

function [Aout, Avote2] = vote_2D(points, points_weight, directions_all, Aall, thres)
n_directions = size(directions_all,1);
accumulator_votes_idx = false(size(Aall,1), size(points,1), n_directions);
for i_point = 1:size(points,1)
    for i_direction = 1:n_directions
		 % save time and ignore irelevant points from the get-go
        idx_to_use = find( (Aall(:, 1) > points(i_point, 1)) & (Aall(:, 2) > points(i_point, 2)));
        if isempty(idx_to_use), continue; end
		
        % calculate distance between all A options and the line defined by
        % i_point and i_direction. If the distance is smaller than a thres,
        % increase the cell in accumulator
        dist1 = sqrt(sum([Aall(idx_to_use, 1)-points(i_point, 1), Aall(idx_to_use, 2)-points(i_point, 2)].^2,2));
        %dist1 = dist1 - min(dist1);
        dist1 = dist1./sqrt(2) + 1;
        
        dist =  -points(i_point, 1)*directions_all(i_direction,2) + ...
            points(i_point, 2)*directions_all(i_direction,1) + ...
            Aall(idx_to_use, 1)*directions_all(i_direction,2) - ...
            Aall(idx_to_use, 2)*directions_all(i_direction,1);
        idx = abs(dist)<2*thres.*dist1;
        if ~any(idx), continue; end

        idx_full = idx_to_use(idx);
        accumulator_votes_idx(idx_full, i_point,i_direction) = true;
    end
end
% use only haze-lined that are supported by 2 points or more
accumulator_votes_idx2 = (sum(uint8(accumulator_votes_idx),2))>=2; 
accumulator_votes_idx = bsxfun(@and, accumulator_votes_idx ,accumulator_votes_idx2);
accumulator_unique = zeros(size(Aall,1),1);
for iA = 1:size(Aall,1)
    idx_to_use = find(Aall(iA, 1) > points(:, 1) & (Aall(iA, 2) > points(:, 2)));
    points_dist = sqrt((Aall(iA,1) - points(idx_to_use,1)).^2+(Aall(iA,2) - points(idx_to_use,2)).^2);
    points_weight_dist = points_weight(idx_to_use).*(5.*exp(-reshape(points_dist,1,[]))+1); 
    accumulator_unique(iA) = sum(points_weight_dist(any(accumulator_votes_idx(iA,idx_to_use,:),3)));
end
[~, Aestimate_idx] = max(accumulator_unique);
Aout = Aall(Aestimate_idx,:);
Avote2 = accumulator_unique; 

end 

wls_optimization优化传输图

function out = wls_optimization(in, data_weight, guidance, lambda)

small_num = 0.00001;

if ~exist('lambda','var') || isempty(lambda), lambda = 0.05; end

[h,w,~] = size(guidance);
k = h*w;
guidance = rgb2gray(guidance);

% Compute affinities between adjacent pixels based on gradients of guidance
dy = diff(guidance, 1, 1);
dy = -lambda./(sum(abs(dy).^2,3) + small_num);
dy = padarray(dy, [1 0], 'post');
dy = dy(:);

dx = diff(guidance, 1, 2); 
dx = -lambda./(sum(abs(dx).^2,3) + small_num);
dx = padarray(dx, [0 1], 'post');
dx = dx(:);


% Construct a five-point spatially inhomogeneous Laplacian matrix
B = [dx, dy];
d = [-h,-1];
tmp = spdiags(B,d,k,k);

ea = dx;
we = padarray(dx, h, 'pre'); we = we(1:end-h);
so = dy;
no = padarray(dy, 1, 'pre'); no = no(1:end-1);

D = -(ea+we+so+no);
Asmoothness = tmp + tmp' + spdiags(D, 0, k, k);

% Normalize data weight
data_weight = data_weight - min(data_weight(:)) ;
data_weight = 1.*data_weight./(max(data_weight(:))+small_num);

% Make sure we have a boundary condition for the top line:
% It will be the minimum of the transmission in each column
% With reliability 0.8
reliability_mask = data_weight(1,:) < 0.6; % find missing boundary condition
in_row1 = min( in,[], 1);
data_weight(1,reliability_mask) = 0.8;
in(1,reliability_mask) = in_row1(reliability_mask);

Adata = spdiags(data_weight(:), 0, k, k);

A = Adata + Asmoothness;
b = Adata*in(:);

% Solve
% out = lsqnonneg(A,b);
out = A\b;
out = reshape(out, h, w);

adjust全局线性对比度拉伸

function adj = adjust(img,percen)
if ~exist('percen','var') || isempty(percen), percen=[0.01 0.99]; end;

% linear contrast stretch to [0,1], identical on all colors
minn=min(img(:));
img=img-minn;
img=img./max(img(:));

% limit the change magnitude so the WB would not be drastically changed
contrast_limit = stretchlim(img,percen);
val = 0.2;
contrast_limit(2,:) = max(contrast_limit(2,:), 0.2);
contrast_limit(2,:) = val*contrast_limit(2,:) + (1-val)*max(contrast_limit(2,:), mean(contrast_limit(2,:)));
contrast_limit(1,:) = val*contrast_limit(1,:) + (1-val)*min(contrast_limit(1,:), mean(contrast_limit(1,:)));
adj=imadjust(img,contrast_limit,[],1);

non_local_dehazing去雾

function [img_dehazed, transmission] = non_local_dehazing(img_hazy, air_light, gamma)
%% Validate input
[h,w,n_colors] = size(img_hazy);
if (n_colors ~= 3) % input verification
    error(['Non-Local Dehazing reuires an RGB image, while input ',...
        'has only ',num2str(n_colors),' dimensions']);
end

if ~exist('air_light','var') || isempty(air_light) || (numel(air_light)~=3)
    error('Dehazing on sphere requires an RGB airlight');
end

if ~exist('gamma','var') || isempty(gamma), gamma = 1; end

img_hazy = im2double(img_hazy);
img_hazy_corrected = img_hazy.^gamma; % radiometric correction

%% Find Haze-lines
% Translate the coordinate system to be air_light-centric (Eq. (3))
dist_from_airlight = double(zeros(h,w,n_colors));
for color_idx=1:n_colors
    dist_from_airlight(:,:,color_idx) = img_hazy_corrected(:,:,color_idx) - air_light(:,:,color_idx);
end

% Calculate radius (Eq. (5))
radius = sqrt( dist_from_airlight(:,:,1).^2 + dist_from_airlight(:,:,2).^2 +dist_from_airlight(:,:,3).^2 );

% Cluster the pixels to haze-lines
% Use a KD-tree impementation for fast clustering according to their angles
dist_unit_radius = reshape(dist_from_airlight,[h*w,n_colors]);
dist_norm = sqrt(sum(dist_unit_radius.^2,2));
dist_unit_radius = bsxfun(@rdivide, dist_unit_radius, dist_norm);
n_points = 1000;
% load pre-calculated uniform tesselation of the unit-sphere
fid = fopen(['TR',num2str(n_points),'.txt']);
points = cell2mat(textscan(fid,'%f %f %f')) ;
fclose(fid);
mdl = KDTreeSearcher(points);
ind = knnsearch(mdl, dist_unit_radius);

%% Estimating Initial Transmission

% Estimate radius as the maximal radius in each haze-line (Eq. (11))
K = accumarray(ind,radius(:),[n_points,1],@max);
radius_new = reshape( K(ind), h, w);
    
% Estimate transmission as radii ratio (Eq. (12))
transmission_estimation = radius./radius_new;

% Limit the transmission to the range [trans_min, 1] for numerical stability
trans_min = 0.1;
transmission_estimation = min(max(transmission_estimation, trans_min),1);

%% Regularization
% Apply lower bound from the image (Eqs. (13-14))
trans_lower_bound = 1 - min(bsxfun(@rdivide,img_hazy_corrected,reshape(air_light,1,1,3)) ,[],3);
transmission_estimation = max(transmission_estimation, trans_lower_bound);
 
% Solve optimization problem (Eq. (15))
% find bin counts for reliability - small bins (#pixels<50) do not comply with 
% the model assumptions and should be disregarded
bin_count       = accumarray(ind,1,[n_points,1]);
bin_count_map   = reshape(bin_count(ind),h,w);
bin_eval_fun    = @(x) min(1, x/50);

% Calculate std - this is the data-term weight of Eq. (15)
K_std = accumarray(ind,radius(:),[n_points,1],@std);
radius_std = reshape( K_std(ind), h, w);
radius_eval_fun = @(r) min(1, 3*max(0.001, r-0.1));
radius_reliability = radius_eval_fun(radius_std./max(radius_std(:)));
data_term_weight   = bin_eval_fun(bin_count_map).*radius_reliability;
lambda = 0.1;
transmission = wls_optimization(transmission_estimation, data_term_weight, img_hazy, lambda);

%% Dehazing
% (Eq. (16))
img_dehazed = zeros(h,w,n_colors);
leave_haze = 1.06; % leave a bit of haze for a natural look (set to 1 to reduce all haze)
for color_idx = 1:3
    img_dehazed(:,:,color_idx) = ( img_hazy_corrected(:,:,color_idx) - ...
        (1-leave_haze.*transmission).*air_light(color_idx) )./ max(transmission,trans_min);
end

% Limit each pixel value to the range [0, 1] (avoid numerical problems)
img_dehazed(img_dehazed>1) = 1;
img_dehazed(img_dehazed<0) = 0;
img_dehazed = img_dehazed.^(1/gamma); % radiometric correction

% For display, we perform a global linear contrast stretch on the output, 
% clipping 0.5% of the pixel values both in the shadows and in the highlights 
adj_percent = [0.005, 0.995];
img_dehazed = adjust(img_dehazed,adj_percent);
img_dehazed = im2uint8(img_dehazed);
end % function non_local_dehazing

non_local算法还需要标识文件TR1000.txt,所有代码文件的链接如下:

通过网盘分享的文件:去雾
链接: https://pan.baidu.com/s/1YjNoFjbQ-TSEelS94d0uTA?pwd=3cbc 提取码: 3cbc
–来自百度网盘超级会员v4的分享

效果展示

主程序的运行效果

在这里插入图片描述

全局直方图算法去雾

在这里插入图片描述

局部直方图算法去雾

在这里插入图片描述

单尺度算法去雾

在这里插入图片描述

多尺度算法去雾

在这里插入图片描述

Dark_channel算法去雾

在这里插入图片描述

non_local算法去雾

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值