2024年图像去雾去雨去噪算法权威高分排行榜与实战对比评测
先交代一下背景。不少研究者在图像去雨、去雾任务中经常遇到算法过度平滑或残留痕迹明显的痛点。我在这个方向上做了一些实验,把思路和代码整理出来,希望能帮到正在攻关的同学。
去雨核心原理
从单张静态图像中移除雨滴,听起来简单,实际操作却相当棘手。雨点覆盖的区域通常面积很小,这就带来一个关键问题——到底哪些像素需要处理,哪些应该保留?市面上不乏基于FFT的去雨方案,但效果参差不齐。本文尝试了一条差异化路径:利用L0梯度最小化方法,专门抑制雨像素,同时避免破坏图像中重要的边缘信息。
具体来看,这套策略具备三大优势:
- L0最小化能从全局视角控制非零梯度的数量,不纠结局部细节,只锁定真正显著的边缘。
- 显著边缘得以完整保留,而低幅度的琐碎纹理(比如雨痕)则被平滑掉,这正是去雨的关键所在。
- 最后通过直方图调整技术,将去雨后图像的亮度拉回合理范围,提升对比度。实验证实,这套流程在消除雨痕方面确实有效。
算法流程
去雨代码实现
clear;
close all;
I=imread('youwutu.jpg'); %读入图像
R=I(:,:,1);% 取输入图像的R分量
[N1,M1]=size(R);
R0=double(R);% 对R分量进行数据转换,并对其取对数
Rlog=log(R0+1);
Rfft2=fft2(R0);% 对R分量进行二维傅里叶变换
sigma=250;% 形成高斯滤波函数
F = zeros(N1,M1);
for i=1:N1
for j=1:M1
F(i,j)=exp(-((i-N1/2)^2+(j-M1/2)^2)/(2*sigma*sigma));
end
end
F=F./(sum(F(:)));
Ffft=fft2(double(F)); %对高斯滤波函数进行二维傅里叶变换
DR0=Rfft2.*Ffft;%对R分量与高斯滤波函数进行卷积运算
DR=ifft2(DR0);
DRdouble=double(DR); %在对数域中,用原图像减去低通滤波后的图像,得到高频增强图像
DRlog=log(DRdouble+1);
Rr=Rlog-DRlog;
G=I(:,:,2); % 取输入图像的G分量
[N1,M1]=size(G);
G0=double(G);%对G分量进行数据转换,并对其取对数
Glog = log(G0+1);
Gfft2=fft2(G0);%对G分量进行二维傅里叶变换
sigma=250;
for i=1:N1
for j=1:M1
F(i,j)=exp(-((i-N1/2)^2+(j-M1/2)^2)/(2*sigma*sigma));
end
end
F = F./(sum(F(:)));
Ffft=fft2(double(F));%对高斯滤波函数进行二维傅里叶变换
DG0=Gfft2.*Ffft;%对高斯滤波函数进行二维傅里叶变换
DG=ifft2(DG0);
DGdouble=double(DG); %在对数域中,用原图像减去低通滤波后的图像,得到高频增强图像
DGlog=log(DGdouble+1);
Gg=Glog-DGlog;
EXPGg=exp(Gg); %取反对数,得到增强后的图像分量
MIN = min(min(EXPGg)); %对增强后的图像进行对比度拉伸增强
MAX = max(max(EXPGg));
去雨结果 MATLAB 展示
图像去雾
去雾理论基础
去雾的底层原理基于暗通道先验。通俗讲,在大多数非天空的局部区域中,总存在某些像素在至少一个颜色通道上的亮度极低——即该区域的光强趋近于零。基于此,我们可以给“暗通道”一个严谨的数学定义:对于任意输入图像J,其暗通道可用公式表达为:
其中c表示彩色图像的每个通道,Ω(x)代表以像素x为中心的局部窗口。
计算暗通道图并不复杂:首先求出每个像素在三个通道的最小值,得到一张二维灰度矩阵,然后对该矩阵进行最小值滤波。滤波半径由窗口大小决定,窗口大小与半径的关系可表述为:……其中r表示滤波半径。
至于暗通道先验为什么成立?文献中给出了几个合理解释:
- 汽车、建筑物、城市玻璃窗的阴影,或是树叶、树冠、岩石等自然场景的投影;
- 色彩鲜艳的物体或表面——例如绿色草地、树木、植被,红色或黄色的花朵、叶子,或者蓝色水面——它们在RGB三个通道中总有至少一个通道的值很低。
去雾代码实现
计算雾化图像的暗通道
def DarkChannel(img, size=15):
"""
暗通道的计算主要分成两个步骤:
1.获取BGR三个通道的最小值
2.以一个窗口做MinFilter
ps.这里窗口大小一般为15(radius为7)
获取BGR三个通道的最小值就是遍历整个图像,取最小值即可
"""
r, g, b = cv2.split(img)
min_img = cv2.min(r, cv2.min(g, b))
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (size, size))
dc_img = cv2.erode(min_img, kernel)
return dc_img
估算全局大气光值
def GetAtmo(img, percent=0.001):
"""
1.计算有雾图像的暗通道
2.用一个Node的结构记录暗通道图像每个像素的位置和大小,放入list中
3.对list进行降序排序
4.按暗通道亮度前0.1%(用percent参数指定百分比)的位置,在原始有雾图像中查找最大光强值
"""
mean_perpix = np.mean(img, axis=2).reshape(-1)
mean_topper = mean_perpix[:int(img.shape[0] * img.shape[1] * percent)]
return np.mean(mean_topper)
估算透射率图
def GetTrans(img, atom, w):
"""
w为去雾程度,一般取0.95
w的值越小,去雾效果越不明显
"""
x = img / atom
t = 1 - w * DarkChannel(x, 15)
return t
def GuidedFilter(p, i, r, e):
"""
:param p: input image
:param i: guidance image
:param r: radius
:param e: regularization
:return: filtering output q
"""
# 1
mean_I = cv2.boxFilter(i, cv2.CV_64F, (r, r))
mean_p = cv2.boxFilter(p, cv2.CV_64F, (r, r))
corr_I = cv2.boxFilter(i * i, cv2.CV_64F, (r, r))
corr_Ip = cv2.boxFilter(i * p, cv2.CV_64F, (r, r))
# 2
var_I = corr_I - mean_I * mean_I
cov_Ip = corr_Ip - mean_I * mean_p
# 3
a = cov_Ip / (var_I + e)
b = mean_p - a * mean_I
# 4
mean_a = cv2.boxFilter(a, cv2.CV_64F, (r, r))
mean_b = cv2.boxFilter(b, cv2.CV_64F, (r, r))
# 5
q = mean_a * i + mean_b
return q
上述代码同样提供了Python版本。
去雾结果 MATLAB GUI 交互展示
总结与应用
本文所述流程只是整个链路中的一环,核心目标是为目标检测及其他视觉应用奠定坚实基础。通过将提出的算法与经典方法进行对比验证,结果表明:在极端环境条件下,这套目标检测与测距方案具备良好的有效性与可行性。经处理的图像输入目标检测和测距模型后,精度显著提升,进而为自动驾驶的主动安全决策提供了可靠的技术支撑,也让自动驾驶车辆在极端环境下稳定运行成为可能。







