news 2026/9/19 17:39:11

火场灰度图像去烟算法:从物理退化建模到半监督微调实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
火场灰度图像去烟算法:从物理退化建模到半监督微调实战

简介:这份PDF文献面向图像处理、计算机视觉方向的研究者与消防信息化技术人员,聚焦火场灰度图像中烟雾干扰导致监控画面模糊、对比度下降的问题,提出一套基于深度学习的去烟算法方案。资源为单篇学术论文,压缩包内仅含1个PDF文件,约1.26MB,便于快速查阅与引用。论文核心由检测子网络与去除子网络串联构成:前者借助残差学习网络定位烟雾区域,缓解深层网络梯度消失;后者采用密集连接的U型网络,通过Dense Block将低层特征复用到高层,在保留原始背景的同时去除烟雾。文中还系统比较了直方图均衡化、Retinex等传统增强方法在火场场景下的局限,并给出主观视觉与PSNR、SSIM等客观指标的实验对比。目前已有376人学习,适合作为深度学习图像复原方向的参考文献与算法设计思路来源。

1. 火场灰度图去烟:为什么单通道反而比 RGB 更难做

消防机器人和无人机回传的画面里,烟是最讨厌的东西。可见光摄像头在火场里拍到的图像,往往被浓烟压成一片灰白,对比度掉到个位数,边缘几乎消失。更麻烦的是,很多嵌入式前端为了省带宽和算力,直接把图像转成灰度再传——单通道,8 位,没有色彩信息可用。这时候再想"去烟",就变成了一个纯灰度域的病态逆问题:烟是加性散射叠加,目标纹理被淹没,没有颜色先验可以借力。

基于深度学习的火场灰度图像去烟算法,要解决的就是这件事:输入一张被烟污染的灰度图,输出一张烟雾散射被抑制、目标轮廓和纹理恢复的灰度图。它适合两类人:一类是做消防视觉、应急感知的工程同学,需要在低算力前端上跑通;另一类是研究图像复原、想拿火场这种极端场景做实验的算法同学。核心难点不在网络多深,而在于灰度域没有色彩冗余,模型必须学会从局部对比度和结构先验里"猜"回被烟吃掉的信息。

2. 灰度去烟的数据构造与物理退化建模

2.1 为什么不能直接拿清晰图加高斯噪声

很多人第一反应是:找一批清晰灰度图,加噪声,训练去噪网络。这条路在火场去烟上基本走不通。烟雾的退化不是独立同分布噪声,而是散射介质成像,物理上更接近大气散射模型:

I(x) = J(x) * t(x) + A * (1 - t(x))

其中I是观测到的含烟图,J是无烟清晰图,t(x)是透射率,A是大气光(在灰度域就是一个标量亮度)。烟越浓,t越小,图像越接近A这个常数,细节全丢。用高斯噪声去模拟,网络学到的只是平滑,遇到真实浓烟会直接糊掉。

常见做法是:收集一批无烟火场/建筑灰度图作为J,然后按上式合成含烟图。t(x)用随机生成的平滑场(比如对低分辨率随机噪声做双三次上采样),A取图像亮度的 85% 到 98% 分位数附近。这样合成的样本才带有"空间变化的透射率",网络才有机会学到去烟而不是去噪。

2.2 用 Python 合成灰度含烟样本的最小脚本

下面这段代码给出一个可复现的合成流程,输入一张清晰灰度图,输出含烟图和无烟图配对:

import cv2 import numpy as np def make_smoke_pair(gray, A_ratio=0.92, t_min=0.25, t_max=0.85, seed=0): """ gray: 单通道 uint8 清晰图 A_ratio: 大气光占最大亮度的比例 t_min/t_max: 透射率范围,越小烟越浓 返回: (hazy, clear) 两张 uint8 灰度图 """ rng = np.random.default_rng(seed) h, w = gray.shape # 低分辨率随机场 -> 上采样,得到空间平滑的透射率 low = rng.random((h // 32 + 1, w // 32 + 1)).astype(np.float32) t = cv2.resize(low, (w, h), interpolation=cv2.INTER_CUBIC) t = (t - t.min()) / (t.max() - t.min() + 1e-6) t = t_min + t * (t_max - t_min) # 映射到 [t_min, t_max] A = A_ratio * 255.0 clear = gray.astype(np.float32) hazy = clear * t + A * (1.0 - t) # 大气散射模型 return np.clip(hazy, 0, 255).astype(np.uint8), gray img = cv2.imread("clear.png", cv2.IMREAD_GRAYSCALE) hazy, clear = make_smoke_pair(img, A_ratio=0.92, t_min=0.3, t_max=0.8, seed=42) cv2.imwrite("hazy.png", hazy)

逻辑说明:t用低分辨率随机场上采样,保证透射率在空间上连续变化,符合真实烟雾的分布;A取 255 的固定比例,模拟灰度域的大气光。参数上,t_min控制最浓处的烟浓度,做训练集时建议在 0.2 到 0.4 之间随机;A_ratio建议 0.85 到 0.98 随机,避免网络只适应单一亮度。seed固定后样本可复现,方便对比不同模型。

2.3 训练集、验证集怎么切才不泄漏

合成数据最大的坑是泄漏:同一张清晰图合成出多张含烟图,如果随机划分,验证集里会出现训练集用过的清晰图,指标虚高。正确做法是按"清晰源图"划分,一张源图的所有含烟变体只能进同一个集合。常见比例是 8:1:1,验证集和测试集各留 10% 的源图。另外,测试集里最好混入少量真实含烟图(哪怕没有对应清晰图,只做主观评估),用来判断模型是否过拟合到合成分布。

数据集划分源图比例每源图变体数用途
训练集80%8~12梯度更新
验证集10%4~6早停、调参
测试集10%4~6最终指标
真实烟图独立无配对主观评估

提示:合成时给每张源图随机不同的t_minA_ratio和随机种子,变体多样性比单纯增加数量更重要。

3. 去烟网络结构选型与训练参数配置

3.1 灰度去烟为什么常用 U-Net 加残差学习

灰度去烟本质是图像到图像的稠密预测,输入输出同尺寸,U-Net 的编码器-解码器加跳跃连接天然合适。但直接让网络回归清晰图,训练初期梯度不稳定,收敛慢。更稳的做法是残差学习:网络只预测"烟层",最终输出clear = hazy - smoke。因为烟层整体平滑、能量集中,网络学起来比直接重建纹理容易得多。

编码器可以用轻量卷积堆叠,比如 4 个下采样阶段,通道从 32 递增到 256;解码器对称上采样,跳跃连接把浅层的高频细节直接送到对应层,弥补下采样丢失的边缘。对于嵌入式部署,可以把基础通道压到 16 或 24,深度可分离卷积替换标准卷积,参数量能降一个数量级。

3.2 用 PyTorch 搭一个最小可训练去烟网络

import torch import torch.nn as nn class ConvBlock(nn.Module): def __init__(self, cin, cout): super().__init__() self.net = nn.Sequential( nn.Conv2d(cin, cout, 3, padding=1), nn.ReLU(inplace=True), nn.Conv2d(cout, cout, 3, padding=1), nn.ReLU(inplace=True), ) def forward(self, x): return self.net(x) class SmokeNet(nn.Module): def __init__(self, base=32): super().__init__() self.enc1 = ConvBlock(1, base) self.enc2 = ConvBlock(base, base * 2) self.enc3 = ConvBlock(base * 2, base * 4) self.pool = nn.MaxPool2d(2) self.up2 = nn.ConvTranspose2d(base * 4, base * 2, 2, stride=2) self.dec2 = ConvBlock(base * 4, base * 2) self.up1 = nn.ConvTranspose2d(base * 2, base, 2, stride=2) self.dec1 = ConvBlock(base * 2, base) self.out = nn.Conv2d(base, 1, 1) # 预测烟层 def forward(self, x): e1 = self.enc1(x) e2 = self.enc2(self.pool(e1)) e3 = self.enc3(self.pool(e2)) d2 = self.dec2(torch.cat([self.up2(e3), e2], dim=1)) d1 = self.dec1(torch.cat([self.up1(d2), e1], dim=1)) smoke = self.out(d1) return x - smoke # 残差:输入减烟层

逻辑说明:enc1enc3逐级下采样扩大感受野,up2up1上采样恢复分辨率,torch.cat把编码器浅层特征和解码器特征拼接,保留边缘。最后一层out输出单通道烟层,return x - smoke实现残差去烟。参数base控制模型宽度,桌面训练用 32,嵌入式部署可降到 16。

3.3 损失函数与关键训练参数

只用 L1 或 L2 损失,结果会偏平滑,纹理发糊。常见组合是 L1 加结构相似性损失(SSIM),再 optionally 加一个梯度损失约束边缘:

def total_loss(pred, target, alpha=0.8, beta=0.2): l1 = nn.functional.l1_loss(pred, target) # 简化 SSIM:用局部均值方差近似 mu_p = pred.mean(dim=(1,2,3), keepdim=True) mu_t = target.mean(dim=(1,2,3), keepdim=True) var_p = pred.var(dim=(1,2,3), keepdim=True) var_t = target.var(dim=(1,2,3), keepdim=True) cov = ((pred - mu_p) * (target - mu_t)).mean(dim=(1,2,3), keepdim=True) c1, c2 = 0.01**2, 0.03**2 ssim = ((2*mu_p*mu_t + c1)*(2*cov + c2)) / ((mu_p**2 + mu_t**2 + c1)*(var_p + var_t + c2)) return alpha * l1 + beta * (1 - ssim.mean())

参数说明:alphabeta控制 L1 与 SSIM 的权重,经验值 0.8/0.2 起步,纹理恢复不够就加大beta。训练用 Adam,学习率 1e-3,配合余弦退火到 1e-5;batch size 8 到 16,取决于显存。epoch不用盲目堆,合成数据上通常 60 到 100 轮就收敛,看验证集 PSNR 连续 10 轮不升就早停。

参数推荐值作用
学习率1e-3 → 1e-5余弦退火
batch size8~16显存与稳定性平衡
base 通道16~32控制模型容量
L1/SSIM 权重0.8 / 0.2保真与结构平衡
早停耐心10 轮防过拟合

注意:灰度域没有颜色约束,SSIM 权重过高会让结果过度平滑,边缘反而变软,调参时以主观边缘锐度为先。

4. 推理部署与火场场景下的排错

4.1 从训练权重到单张图推理的命令行脚本

训练完要能落地,下面是一个最小推理脚本,读入含烟灰度图,输出去烟结果:

import cv2 import numpy as np import torch from model import SmokeNet device = torch.device("cuda" if torch.cuda.is_available() else "cpu") net = SmokeNet(base=32).to(device) net.load_state_dict(torch.load("smokenet.pth", map_location=device)) net.eval() img = cv2.imread("hazy.png", cv2.IMREAD_GRAYSCALE).astype(np.float32) / 255.0 tensor = torch.from_numpy(img)[None, None].to(device) # (1,1,H,W) with torch.no_grad(): out = net(tensor).clamp(0, 1) out = (out[0, 0].cpu().numpy() * 255).astype(np.uint8) cv2.imwrite("dehazed.png", out)

逻辑说明:输入归一化到 [0,1],加 batch 和通道维度变成(1,1,H,W)torch.no_grad()关闭梯度,省显存;输出 clamp 到 [0,1] 再还原到 0-255。参数上,base必须和训练时一致,否则load_state_dict会报维度不匹配。如果部署到嵌入式,可以把模型导出为 ONNX 再用推理引擎跑,输入尺寸固定后速度更稳。

4.2 火场实测常见的四类失败与排查

第一类,浓烟区域出现块状伪影。多半是透射率合成时t_min设得太低,训练分布和真实浓烟不匹配,解决方法是把t_min下限提到 0.15 到 0.2,并加入真实浓烟图做微调。第二类,去烟后整体偏暗。这是残差学习把烟层减多了,检查A_ratio是否偏高,或者损失里加一个亮度一致性项。第三类,边缘出现光晕。跳跃连接把含烟浅层特征直接送进解码器,可以在跳跃连接上加一个 1x1 卷积做门控。第四类,视频上帧间闪烁。逐帧推理没有时序约束,常见做法是加一个轻量时序模块,或者对输出做时域平滑。

现象可能原因处理
块状伪影t_min 过低提高下限,混真实图微调
整体偏暗烟层减多降 A_ratio,加亮度损失
边缘光晕跳跃连接直通加门控卷积
帧间闪烁无时序约束时域平滑或时序模块

4.3 评价指标怎么选才不被合成数据骗

PSNR 和 SSIM 在合成测试集上很好看,但真实火场里没有配对清晰图,这两个指标用不了。工程上更实用的是无参考指标,比如对比度增益、暗通道先验的透射率估计变化,以及最直接的主观打分。建议在测试时同时报告合成集 PSNR/SSIM 和真实烟图的主观对比,避免只报一个漂亮数字。如果要做消融,固定随机种子,同一批源图跑不同配置,差异才可信。

5. 用半监督微调把合成模型拉到真实火场

合成数据训出来的模型,直接上真实火场往往差一口气,因为真实烟雾的颗粒感、光照和运动模糊跟合成分布有差距。但真实火场很难拿到配对清晰图,全监督微调不现实。一个可落地的技巧是半监督微调:用少量真实含烟图,配合模型自身输出的伪清晰图做自训练,再加一个一致性约束。

具体做法是,先用合成模型对真实含烟图推理得到伪清晰图,然后对同一张图做两种不同增强(比如随机裁剪和亮度扰动),要求网络对两种增强的输出保持一致。损失由三部分组成:合成数据上的监督损失、真实数据上的伪标签损失、以及增强一致性损失。伪标签损失权重从 0.1 起步,一致性损失权重 0.05 左右,太高会让模型塌缩到平凡解。

# 半监督微调核心片段 for hazy_real in real_loader: with torch.no_grad(): pseudo = net(hazy_real).detach() # 伪清晰图 aug1, aug2 = random_aug(hazy_real), random_aug(hazy_real) out1, out2 = net(aug1), net(aug2) loss_pseudo = nn.functional.l1_loss(net(hazy_real), pseudo) loss_cons = nn.functional.l1_loss(out1, out2) loss = loss_sup + 0.1 * loss_pseudo + 0.05 * loss_cons loss.backward() optimizer.step()

参数上,伪标签损失权重建议 0.05 到 0.2 之间网格搜索,一致性权重不超过 0.1。微调学习率要比预训练低一个数量级,用 1e-4 起步,避免把合成阶段学到的先验冲掉。验证时重点看真实烟图的主观效果,合成集指标只作参考。如果发现伪标签越来越糊,说明自训练在放大误差,这时候降低伪标签权重,或者只对高置信度区域(比如透射率估计较高的区域)计算伪标签损失。这套流程不需要额外标注,适合真实数据稀缺的火场场景,也是把实验室模型推到现场的关键一步。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 17:34:46

学术英语视听说PPT课件模板:模块化设计与工程化规范

简介:本资源为《新世纪学术英语视听说》课程配套的Lesson级PPT教学课件,面向高校英语专业教师、公共英语授课教师及学术英语学习者,旨在支撑视听说融合教学场景下的课堂讲授、学生预习与自主训练。课件采用标准PowerPoint格式(.pp…

作者头像 李华
网站建设 2026/9/19 17:33:21

YooAsset资源管理设计哲学:从AssetBundle构建到热更新落地实践

1. 为什么资源管理是Unity项目的隐形地基做Unity项目超过三年的朋友,大概率都经历过这样的场景:游戏在编辑器里跑得飞快,打包出来一进战斗场景就卡成幻灯片;或者热更之后玩家反馈资源错乱,模型贴图张冠李戴&#xff1b…

作者头像 李华
网站建设 2026/9/19 17:33:18

Greasy Fork 用户脚本实战指南:从安装到编写发布

我第一次打开 Greasy Fork 的脚本列表,说实话没什么特别的感觉。满屏的英文、奇怪的注释、参数列表,第一眼看上去离普通人太远了。但真正把一个用户脚本装进浏览器,跑起来之后,我才意识到过去自己花在网页重复操作上的时间有多冤枉…

作者头像 李华
网站建设 2026/9/19 17:32:31

FigmaCN使用指南:6个实用技巧,让设计师彻底告别英文界面

FigmaCN使用指南:6个实用技巧,让设计师彻底告别英文界面 【免费下载链接】figmaCN 中文 Figma 插件,设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN FigmaCN 是一款免费的中文 Figma 插件,能把 …

作者头像 李华