下雪天拍出来的照片往往布满密密麻麻的雪点,尤其在使用闪光灯或逆光拍摄时,近处的雪花会被照亮成醒目的白色颗粒,严重破坏画面的通透感。除了影响美观,雪颗粒还会干扰目标检测、自动驾驶感知等计算机视觉任务的准确性。图像去雪(Image Desnowing)就是要解决这一问题:它不仅要检测并去除图像中的雪颗粒,还要在被遮挡的位置恢复出合理的背景内容,属于图像复原领域里一个兼具检测与修复双重性质的子问题。

雪颗粒的成像特性与去雪难点
要理解去雪算法的设计思路,首先要弄清雪颗粒在图像中呈现什么样的特征。雪花是三维空间中随机分布、随机运动的粒子,离镜头越近的雪花在画面上形成的模糊斑越大、越亮,离镜头远的雪花则表现为细小锐利的亮点。这种距离相关的成像特性意味着雪颗粒并不是简单的噪声,不能用普通的高斯噪声或椒盐噪声模型来描述。
另一个难点在于雪与背景的混淆。图像中本身就存在的白色区域,比如雪地、白色建筑、天空中的云,在颜色分布上与雪花高度相似,仅凭亮度或颜色特征很难区分。此外,雪颗粒之间存在半透明叠加:多片雪花重叠成像时会与背景发生混合,遮挡区域既包含雪花的信息也包含背景的信息,这给完整的背景恢复带来了不小的挑战。
从数学建模的角度看,含雪图像通常被分解为透射模型:观测图像等于背景图像与雪层的加权融合,权重由雪颗粒的不透明度决定。这个模型与图像去雾、去雨有相似之处,但雪颗粒的形状不规则、尺度跨度大、密度分布不均匀,使得去雪任务比去雨更复杂,简单套用去雨算法往往效果不佳。
传统去雪方法:基于滤波与稀疏编码的思路
深度学习兴起之前,研究者主要依靠信号的物理特性来分离雪颗粒。代表性的方法是2016年提出的DesnowNet前身的稀疏编码方案:先把彩色图像转换到HSV颜色空间,利用雪花在饱和度通道上数值低(接近白色)、在亮度通道上数值高的特点提取候选雪颗粒区域,再通过字典学习判断哪些图像块确实属于雪花并予以去除。
另一类思路是频域滤波。雪花的运动模糊特性使其在特定方向和频率上有能量聚集,通过方向滤波器或小波分解可以把高频细节中的雪颗粒分量与背景纹理分离开来。这类方法计算量小、不需要训练数据,在轻度降雪场景下有一定效果,但当雪密度较高或背景纹理复杂时,容易把背景中的高频细节一并抹掉,导致图像过度平滑、细节丢失。
下面的代码演示了一个基于HSV颜色空间的简单雪颗粒候选区域提取过程,可以帮助理解传统方法的判断逻辑:
import cv2
import numpy as np
def extract_snow_candidates(image_path, threshold=0.85):
# 读取图像并转换到HSV颜色空间
img = cv2.imread(image_path)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
# 雪颗粒特征:低饱和度(接近白色)且高亮度
snow_mask = ((s < 50) & (v > int(255 * threshold))).astype(np.uint8) * 255
# 形态学操作去除孤立噪点,保留成片雪颗粒
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
snow_mask = cv2.morphologyEx(snow_mask, cv2.MORPH_OPEN, kernel)
return img, snow_mask
img, mask = extract_snow_candidates('snowy_photo.jpg')
cv2.imwrite('snow_mask.jpg', mask)可以看到,这种基于阈值的方法实现简单、可解释性强,但它无法区分真正的雪花与画面中的白色背景,这正是后续深度学习方法要解决的核心问题。
基于深度学习的去雪网络
卷积神经网络凭借强大的特征提取能力成为去雪任务的主流方案。早期代表性工作DesnowNet将去雪显式建模为雪颗粒检测和背景恢复两个阶段:网络先用检测分支输出雪颗粒置信图,再用恢复分支依据置信图对污染区域进行修复,这种两阶段的设计把「找到雪」和「补背景」解耦,逻辑清晰且各分支可以针对性优化。
随后的JSTASR网络提出了更精细的思路,它引入雪颗粒尺度的概念,通过尺度感知的分支网络分别处理大小不同的雪花,并使用时间一致性约束提升视频去雪的稳定性。而最新的方法如HDC-Net采用混合融合结构,把下采样分支、原尺度分支和上采样分支并行组合,兼顾大范围上下文信息与细节纹理的保留,在真实雪景数据集上取得了更好的视觉效果。
在实现层面,训练数据通常通过对干净图像人工合成雪颗粒来构造,也可以借助真实降雪场景的成对数据集。损失函数一般组合逐像素的重建误差和感知损失,代码框架可以基于PyTorch快速搭建:
import torch
import torch.nn as nn
class DesnowNet(nn.Module):
def __init__(self):
super().__init__()
# 检测分支:输出雪颗粒置信图
self.detect = nn.Sequential(
nn.Conv2d(3, 32, 3, padding=1), nn.ReLU(),
nn.Conv2d(32, 32, 3, padding=1), nn.ReLU(),
nn.Conv2d(32, 1, 3, padding=1), nn.Sigmoid()
)
# 恢复分支:根据置信图修复背景
self.restore = nn.Sequential(
nn.Conv2d(4, 64, 3, padding=1), nn.ReLU(),
nn.Conv2d(64, 64, 3, padding=1), nn.ReLU(),
nn.Conv2d(64, 3, 3, padding=1), nn.Sigmoid()
)
def forward(self, x):
snow_map = self.detect(x) # 雪颗粒掩码
inp = torch.cat([x, snow_map], dim=1) # 拼接原图与掩码
clean = self.restore(inp) # 恢复的干净图像
return clean, snow_map
model = DesnowNet()
x = torch.randn(1, 3, 256, 256)
clean, snow_map = model(x)
print(clean.shape, snow_map.shape)深度学习方法的优势在于能够学习到雪颗粒与白色背景在结构、纹理、上下文层面的细微差异,对复杂场景的适应能力远超传统方法。不过它也有代价:需要大量标注数据,模型在训练分布之外的极端天气(暴雪、大雾混合)下可能出现泛化问题,且推理开销在边缘设备上不可忽视。
背景恢复的核心技术与效果评估
去雪的第二步是背景恢复,即在被去除的雪颗粒位置填补合理的图像内容。这一步本质上与图像修复(Inpainting)相通:小面积遮挡可以用扩散式的纹理合成方法,从周边像素延展纹理;大面积、高密度遮挡则需要借助学习式修复网络,利用全局语义信息生成合理的填补内容。目前主流去雪网络把检测与恢复融合在端到端框架里,通过跳跃连接保留原始细节,避免恢复区域与周边区域出现色差和纹理断裂。
评估去雪效果通常使用PSNR和SSIM两项指标,前者衡量像素级保真度,后者衡量结构相似性。在真实场景(没有干净参考图)下,则会借助人工打分或无参考质量评价模型。实际应用中还需关注处理速度,视频监控和自动驾驶等实时场景要求算法达到每秒数十帧的处理能力,因此模型轻量化与加速也是工程落地的关键环节。
总体来看,图像去雪已经从手工特征走向了端到端深度学习,并在合成数据与真实数据的联合训练下不断逼近实用水平。对于普通用户,一些图像处理软件已经集成了类似的天气去除功能;对于开发者,基于开源模型微调自己场景的数据,往往是取得理想效果的捷径。理解雪颗粒的成像特性与检测恢复相分离的设计思想,也能为处理去雨、去雾等其他天气复原任务提供有益的借鉴。