ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于神经网络的红外图像非均匀性校正:从标定到场景自适应

基于神经网络的红外图像非均匀性校正:从标定到场景自适应 简介这份PDF内容源自《红外技术》2018年第2期的学术论文面向红外图像处理、机器学习与深度学习应用领域的研究人员和工程技术人员聚焦红外焦平面材料、制造工艺及多路模拟信号输出电路差异导致的像元响应不一致问题提供基于神经网络与随机梯度下降的自适应非均匀性校正方案。全文围绕盲元检测与补偿、双边滤波获取像元期望输出、随机梯度下降法训练网络等关键环节展开并通过实验与传统标定方法对比验证该方法适应场景变化、校正效果良好可帮助读者理解红外图像非均匀性产生的机理、标定校正的局限以及神经网络在该任务中的建模思路。资源是包含1个PDF文件的压缩包大小仅1MB适用于专业指导与数据建模参考便于快速查阅论文中的摘要、关键词、引言、方法和实验分析。目前已有293人学习下载对从事红外探测、图像质量提升及深度学习落地的人员具有实用价值。1. 基于神经网络的红外图像非均匀性校正从标定到场景自适应的完整方案拿到这篇论文时我正被一个实际项目卡住——手里的非制冷红外机芯在野外场景下换挡后固定图案噪声反复冒出来两点标定参数跟不上焦平面温度漂移图像上的竖条纹怎么都压不下去。这篇发表在《红外技术》2018年第2期的工作恰好给出了一条不同于传统标定法的出路先用实验室两点标定获得增益和偏置作为初始值再用基于双边滤波的神经网络结构配合随机梯度下降SGD在场景中持续更新校正参数。它的核心价值不在于网络有多深实际就一个隐藏层而在于把红外非均匀性校正从“离线标定一次管到死”变成了“边成像边自校正”对384×288这类常见红外焦平面阵列尤其实用。适合的读者是做红外图像预处理、机芯嵌入式算法移植或目标检测前处理的工程师——你能从中拿到完整的算法流程、参数设置参考和改进方向。2. 非均匀性从哪来先搞懂像元响应的线性模型与标定法的边界红外焦平面的非均匀性不是简单加个噪声就能建模的它源于几个叠加的因素半导体材料掺杂浓度和表面态密度不一致导致阈值电压有差异模拟多路读出电路的增益和偏置不完全相同加上光学镜头本身引入的固定图案噪声。论文第1节给出的经典像元输出模型是 y(φ) ω·x(φ) b这里的ω和b分别指该像元的增益和偏置x是实际输出码值y是期望输出码值。这个线性模型是所有校正算法的地基区别只在于ω和b怎么求、多久更新一次。两点标定法就是在这个线性模型上做文章。它用T1、T2两个温度点的面源黑体辐射联立两个方程解出每个像元的ω和b。期望输出值y(T)通常取焦平面所有像元在该温度下的输出均值或者该像元邻域的均值。算法实现起来不算复杂计算量也小但它有一个根本问题像元输出随积分时间和辐射通量的变化并不是严格线性的。红外焦平面在低温段和高温段的响应曲线斜率有差异只用两点线性拟合去覆盖整个动态范围中间段的误差就会暴露出来。论文里给了一组很直观的数据。300 K面源黑体下未校正的焦平面输出码值分布在1.2×10⁴到1.3×10⁴之间按式(2)算出的非均匀性为0.6%。用两点校正后固定图案噪声消失直方图分布方差明显变小非均匀性降到0.54%。这个数值看起来改善有限但注意这是在均匀辐射源下的评测——实际场景里目标和背景温差可能只有几个码值0.06个百分点的非均匀性改善足以决定目标能否从背景中分离出来。不过两点标定的局限也很明显它是一次性标定标定过程需要遮挡光路、切换系统到标定模式后续焦平面温度和场景变化后参数就失效了。论文提到一个解决办法是多点标定即在多个温度点分段做线性拟合每段等效于一次两点校正。但分段线性校正的数据量和计算量都上去了而且仍然没有摆脱标定这个动作本身。对于需要连续工作、场景实时变化的系统这个方法并不合适。提示理解非均匀性校正要始终抓住那条线性模型。无论是标定法还是场景法本质上都在做同一件事——估计每个像元的ω和b只是估计的手段和更新频率不同。我自己的经验是做算法选型时先把应用场景摆清楚再谈算法。如果机芯长时间运行在固定温度环境、可以定期做快门校正两点标定够用如果像野外监控、机载吊舱那样温度和场景都在剧烈变化就必须上基于场景的自适应方法。3. 神经网络校正在做什么双边滤波期望值与SGD参数更新论文采用的是Scribner提出的神经网络结构核心思想是把非均匀性校正问题转化为一个回归问题对每个像元用其邻域像素的加权组合估计“真实”码值作为标签然后训练增益参数ω和偏置参数b使校正输出尽可能接近这个标签值。这个框架的关键有两个一是期望输出值怎么算二是参数怎么更新。3.1 为什么期望输出用双边滤波而不是邻域均值常见做法是拿邻域像元的平均值作为当前像元的理想期望值论文引用早期工作就用了图像整体码值均值来估计但这种方法要求场景单一且没有快速移动物体。一旦场景里有运动目标目标边缘被模糊成一片标签值本身就不准了后面怎么训练都是错的。双边滤波的改进在于同时考虑了空间距离和灰度距离两个维度。空间距离权重α针对邻域像元离中心像元的物理远近灰度距离权重β针对邻域像元跟中心像元在灰度值上的差异。把两个高斯权重结合得到每个像元的期望值y (1/N)·Σ(α·β·x)。这个设计的妙处在于当邻域像元跨越目标边缘时灰度距离差异大权重β会急剧衰减边缘信息就能保住而在平坦区域α和β都接近退化为一个保边的高斯平滑。import numpy as np from scipy.spatial.distance import cdist def bilateral_label(image, sigma_space3.0, sigma_range30.0, kernel_size5): 双边滤波获取期望输出标签值 image: 单帧红外图像16bit 灰度shape(H, W) sigma_space: 空间高斯核标准差单位像素 sigma_range: 灰度高斯核标准差单位码值 kernel_size: 邻域窗口边长必须为奇数 h, w image.shape pad kernel_size // 2 # 镜像填充边界避免边缘像素邻域缺失 padded np.pad(image, pad, modesymmetric) # 生成像素索引偏移网格 ys, xs np.mgrid[-pad:pad1, -pad:pad1] # 空间权重只算一次与图像内容无关 space_w np.exp(-(xs**2 ys**2) / (2 * sigma_space**2)) label np.zeros_like(image, dtypenp.float64) for i in range(h): for j in range(w): patch padded[i:ikernel_size, j:jkernel_size].astype(np.float64) center_val patch[pad, pad] range_w np.exp(-((patch - center_val)**2) / (2 * sigma_range**2)) weights space_w * range_w weights / weights.sum() label[i, j] np.sum(weights * patch) return label这段代码是期望输出标签生成的核心实现。空间权重sigma_space按像素距离设定5×5窗口下取2到3即可太大会把边缘也平滑掉。灰度权重sigma_range按16bit图像码值设定的论文中图像量化尺度是0到65535我一般取20到50。这里有一个容易被忽略的参数——窗口大小窗口太小期望值噪声大训练出来的参数跟着抖窗口太大边缘保持能力下降而且双边滤波本身就是O(H×W×K²)的计算复杂度嵌入式平台上要控制实时性通常用滑动窗口查表法做工程优化。注意循环里用的是镜像填充而不是补零这是因为补零会让图像边界的像元贡献一个假的最小码值这会污染标签。3.2 损失函数、正则项和梯度推导有了标签值之后训练目标就明确了设第i个像元的校正输出为h(ωxᵢ b)标签值为fᵢ损失函数取平方损失J (1/2n)·Σ[h(ωxᵢb) − fᵢ]²。论文对平方损失的选择作了推导假设误差服从零均值高斯分布最大化似然函数等价于最小化平方误差这是神经网络的常用取法对于非均匀性校正这种数值回归任务确实比交叉熵更合适。加正则项R是标准的防过拟合手段。红外图像每个像元都作为特征输入参数空间维度本身就高如果不对参数加以约束模型会对某些特征过分依赖对噪声特别敏感。论文采用L2正则最终损失函数为J (1/2n)·Σ[h(ωxᵢb) − fᵢ]² λ·ΣΘ²其中λ是正则项系数Θ代表网络中的所有参数即ω和b。注意这个正则项是针对参数本身惩罚而不是针对像元。它限制的是校正系数的幅度防止增益和偏置更新到不合理的极端值上。对ω求偏导时要用到链式法则。设激活函数h为线性激活红外非均匀性校正是线性模型不需要非线性激活则∂J/∂ω (1/n)·Σ(h(ωxᵢb) − fᵢ)·xᵢ 2λ·ω。梯度方向就是损失增长最快的方向所以参数更新要沿负梯度方向走θ ← θ − α·∂J/∂θ这里的α是学习率。标准梯度下降每次更新要遍历所有样本对于一幅384×288的图像意味着全部110592个像元都参与一次计算不仅慢而且每次参数更新都需要重新计算整个数据集的梯度内存开销大。论文用的是随机梯度下降法每次随机选取一个样本进行权值更新得到的梯度是真实梯度的一个近似估计。def sgd_update(image, label, omega, bias, lr1e-6, lambd1e-5): 随机梯度下降更新校正参数 image: 实际输出码值输入层 label: 双边滤波期望输出标签层 omega: 增益参数矩阵初始化来自两点标定 bias: 偏置参数矩阵初始化来自两点标定 lr: 学习率 lambd: L2正则项系数 h, w image.shape total_loss 0.0 idx_pixels list(zip(range(h), range(w))) rng np.random.default_rng(42) rng.shuffle(idx_pixels) for i, j in idx_pixels: x_val image[i, j].astype(np.float64) f_val label[i, j] pred omega[i, j] * x_val bias[i, j] error pred - f_val total_loss error**2 # 对 omega 和 bias 分别计算梯度并更新 grad_w error * x_val lambd * omega[i, j] grad_b error lambd * bias[i, j] omega[i, j] - lr * grad_w bias[i, j] - lr * grad_b return omega, bias, total_loss / (h * w)这段代码展示了单轮SGD更新的完整逻辑。几个地方值得注意一是设置随机种子保证可复现性实际工程中可以不设二是对每个像元独立更新像素之间没有共享参数这是线性校正模型跟卷积网络的区别——它没有感受野共享每个像元维护自己的ω和b三是学习率lr设置成1e-6这个量级论文强调过学习率太大损失会在极值附近振荡太小则收敛极慢红外图像码值动辄上万梯度也会被放大所以这个超参数对RGB图像的经验值完全不适用。另外SGD更新顺序要打乱。如果不打乱而按照行扫描顺序更新前面行的参数更新会影响后面行计算的梯度方向引入一种伪时序相关性。我用随机打乱后收敛曲线明显更平滑。4. 避坑指南场景自适应校正最常见的六个坑这一节全部来自我在实际调试中踩过的坑每条都是“现象→原因→解决”的结构建议先收藏调参的时候对照排查。4.1 图像出现白点或黑点闪烁现象校正后的图像在固定位置出现亮点或暗点且不随场景移动有时候是单个像素有时候是连续几个像素。原因盲元没有做检测和补偿或者补偿逻辑只在启动时跑了一次。盲元是响应率异常小的像元两点标定中它们的增益计算公式分母趋近于零甚至为零SGD更新时这些位置的标签值本身就有问题训练出来的参数自然异常。解决在进入神经网络校正之前强制走一遍盲元检测——多温度点黑体下采集像元响应曲线把响应异常码值不变或反向变化的像元定位然后用空间邻域均值替换。如果是连续坏元采用整幅图像均值填充。注意盲元位置要存成mask矩阵每次校正前检查一次因为焦平面盲元会随温度和时间漂移。4.2 静止场景下条纹纹波出现现象机芯对准静止场景时图像中的条纹状图案不消失甚至随着时间推移越来越明显。原因SGD更新是在时间-空间维度上进行的静止场景中每个像元的输出码值相对固定梯度方向没有有效的变化信号参数更新失去了约束。这正是论文中明确指出的局限单一不变场景中梯度下降得不到正确的校正参数。解决加入场景运动检测当帧间差异低于阈值时冻结参数更新只保留当前参数进行校正输出。工程上实现时用一个帧差平方均值统计量做判断低于设定阈值就跳过这一帧的参数更新。4.3 学习率设置后损失值剧烈振荡现象训练曲线在极值附近来回摆动loss降不下去在某个值附近上下跳动。原因学习率α设置过大。红外图像码值范围高达65535梯度量级也大学习率稍高就会冲过最优点。论文给出的方向是“随着循环迭代逐步减小学习率”我实践中的做法是先用1e-7跑一轮看loss下降趋势如果振荡就除以10如果下降太慢就乘以3五分钟就能找到合适的量级。解决采用学习率衰减策略每轮训练结束后lr * 0.95或者使用简单的步长自适应——连续N轮loss没有下降就减半学习率。4.4 校正结果出现块状伪影现象图像中出现方块状灰度痕迹块与块之间有明显的边界看起来像马赛克。原因初始化参数没有用好两点标定的结果而是随机初始化。神经网络的非均匀性校正本质是在标定参数的邻域内做精调随机初始化会让参数偏离合理范围很远SGD需要很多轮才能拉回来在未完全收敛时就输出就会出现块状伪影。解决严格按论文建议的流程——先用两点标定获得增益和偏置作为初始值再做SGD更新。论文原文说得很清楚“使用实验室两点标定获得的增益和偏置作为校正初始值加速网络收敛”。这一点在复现时最容易忽略。4.5 有运动目标时目标周围出现拖影现象场景中有行人或车辆移动时目标的边缘出现类似运动模糊的拖影目标内部纹理反而模糊。原因双边滤波的灰度距离权重参数σ_range设置过小导致边缘附近的有效邻域像素太少期望值估计不稳定同时SGD在目标运动过程中不断更新参数目标边缘的灰度跳变让梯度信号携带了目标轮廓信息。解决σ_range适当放大让平坦区域的标签更平滑运动目标场景下放慢SGD更新频率比如每10帧才更新一次参数而不是每帧都更新。4.6 红外机芯换挡后条纹立刻重现现象机芯切换积分时间或增益档位后校正失效条纹立刻出现必须重新训练几十帧才有改善。原因换挡改变的是整个焦平面的响应特性线性模型中的ω和b都变了而旧参数是基于上一档位的响应特性学出来的直接沿用自然失效。解决档位切换后用当前帧图像重新初始化标签值并调大学习率。知道档位切换触发的入口主动重置参数状态是这类系统设计时容易被忽略的一环。5. 训练策略与工程落地把SGD校正用起来的关键参数这一章从工程视角把训练流程的完整参数设置整理出来照着设置基本能复现论文的实验结果。5.1 校正流程整体框架算法流程分三阶段预处理、训练、输出。预处理阶段负责盲元检测与补偿以及对图像做均值归一化训练阶段用双边滤波生成标签、SGD迭代更新ω和b输出阶段直接用训练好的参数做逐像元线性变换。整个过程不需要帧间匹配不需要事先存储大量数据论文明确说这个方法“降低了存储空间和训练复杂度”这一点对嵌入式平台特别友好。图6给出的程序运行示意图就是以“initialize”为起点之后循环执行“双边滤波生成标签 → 比较输出与标签 → 更新参数 → 校正输出”。5.2 关键参数设置参考参数推荐值说明输入量化06553516bit直接使用图像码值会出现增益几十、偏置几百不易收敛的问题应做均值归一化空间距离权重 σ_space23像素5×5窗口下过大会让边缘被平滑灰度距离权重 σ_range3050码值过小会导致运动目标边缘拖影学习率 α1e-71e-6码值范围大时梯度幅值大学习率要相应调小正则项系数 λ1e-51e-4参数幅度约束防止过拟合邻域窗口5×5论文按邻域加权估计3×3噪声大7×7计算量大校正初始值两点标定结果否则收敛慢、易出现块状伪影学习率是这里最值得花时间调超参数。我习惯先固定σ_range30、λ1e-5然后把学习率从1e-7开始按1e-6、3e-6、1e-6梯度试几轮看训练损失曲线。如果每轮的MSE小于前一帧的MSE且下降平缓就是合适的学习率如果出现振荡就降一档。误差评估方面论文给出了均方差MSE指标作为量化评价加高斯随机噪声的场景均值滤波后的MSE为0.0011论文方法的MSE为0.00058。虽然这两个数值来自同一幅测试图直接对比是论文的结论但在自己的数据上复现时MSE下降一半左右是合理的指标预期。5.3 与两点标定结果对比测试论文的实验设计值得直接借鉴同一场景先做两点校正再做神经网络校正对比结果可见后者在头发、衣服褶皱等纹理细节上明显清晰。加随机噪声后均值滤波方法的图像还残留颗粒状噪声而神经网络校正方法几乎看不出噪声痕迹。这说明该方法的去噪能力来源于双边滤波器本身的保边平滑特性——它把噪声理解为灰度距离上的异常跳变权重β会抑制这类跳变的影响。# 训练收敛后以固定参数输出校正图像的示意命令行方式 # 假设 omega.bin 和 bias.bin 是训练好的参数文件image.raw 是 16bit 原始图像 # 校正输出 omega * image bias逐像元线性变换 # 可用如下 Python 脚本完成验证简化版 python3 -c import numpy as np img np.fromfile(image.raw, dtypenp.uint16).reshape(384,288) omega np.fromfile(omega.bin, dtypenp.float32).reshape(384,288) bias np.fromfile(bias.bin, dtypenp.float32).reshape(384,288) img img.astype(np.float32) corrected np.clip(omega * img bias, 0, 65535).astype(np.uint16) corrected.tofile(corrected.raw) 这一段是输出阶段的落地验证。校正公式的特性和参数选择有几个注意点一是乘法用float32避免16bit整数运算的截断误差二是输出要clip到065535范围因为增益放大后部分像素会超出原始动态范围三是验证用的原始图像必须跟训练图像来自同一工作温度环境否则参数没有意义。6. 算法验证技巧用坏元模拟、场景切换和参数复位检验校正鲁棒性把算法跑通是一回事验证它真的比两点标定靠谱是另一回事。这里分享三个我做完实现后一定会走的验证流程不用它们我没法确定这套算法在我的数据上到底是收敛了还是只是把噪声压低了。第一个验证是坏元模拟测试。人工在原始图像上把若干随机位置的像元置为极端码值比如65535或者0模拟响应率异常。跑完校正后检查这些位置的输出码值是否被压回正常范围。如果被压回说明盲元补偿链路是通的如果校正后这些位置依然明显偏亮或偏暗说明盲元被当成正常像元一起处理了得回头查补偿逻辑和mask更新的时序。这个测试要特别注意一点补偿完的盲元位置不应该参加SGD更新否则补偿值本身误差较大的信号会污染参数估计。第二个验证是场景切换测试。这是基于场景的自适应算法跟标定法拉开差距的核心场景——连续采集不同场景的图像序列室内人物、室外远景、运动物体让算法自己连续跑100帧以上观察两个指标一是校正参数是否震荡如果震荡说明学习率还是偏大二是切换场景瞬间的过冲情况有没有出现整幅图像变亮或变暗后慢慢恢复的现象。如果有过冲说明参数更新过急需要放缓学习率衰减。从工程角度看场景切换测试更接近真实使用条件论文中强调“当有数据输入时将数据直接输入到模型进行训练”这是SGD在线学习的优势不需要预先存储数据。但在线学习也意味着场景突变时参数会有一段时间的“混乱期”合理设计切换检测能显著提升体验。第三个验证是参数复位测试。用初始参数训练收敛后手动把ω和b重置为两点标定值重新开始训练观察是否能在相同帧数内收敛到同样的MSE水平。这一步验证的是算法的可重复性和初始化的合理性。论文里明确写了用两点标定结果作为初始值来加速收敛但如果复位后训练轨迹差异很大说明训练过程没有稳定收敛到同一套参数可能需要增加迭代轮数或者调整正则项系数。红外图像的非均匀性校正本质上是在一个高维度参数空间里搜索合适的ω和b这里的“合适”本身就不是唯一确定的——不同初始值收敛到不同但效果等效的参数组合是正常的。所以我一般对比的不是最终参数值而是最终MSE水平。还有一个小技巧值得养成习惯把所有训练过程的loss曲线和MSE曲线保存下来带时间戳和历史参数快照。我自己经历过一次“调了大半天感觉效果变好了第二天重跑又变差”的事故后来每次实验都强制走一遍“记录参数 → 跑测试序列 → 保存MSE曲线 → 对比上一次”从那以后任何一次参数变更都有据可查不会再出现凭感觉调参的翻车情况。希望这个习惯也能帮到你。本文还有配套的精品资源点击获取
返回列表