资讯动态

水下图像增强融合算法MATLAB复现与调优实践

发布时间:2026/9/16 13:10:15 来源:尧图企业网站定制
简介面向水下图像增强与融合的Matlab算法包适合计算机视觉方向的毕业设计或课程设计。算法基于图像融合框架涵盖颜色平衡、对比度增强、显著性检测、引导滤波、双边滤波、拉普拉斯/高斯金字塔重建等核心步骤并集成了RGB/CIELab色彩空间转换及UCIQE水下图像质量评价模块整套源码经过严格测试解压后可直接运行。资源共55个文件含12个.m源码文件、41张测试与效果对比图片、1篇相关论文PDF及1个说明文档压缩包大小仅7.01MB目录按代码、输入图、结果图分组便于对照学习与二次开发。测试图片覆盖多种水下场景结果图可直观展示颜色校正与细节恢复效果适合需要快速复现水下图像增强方法并在此基础上做改进的同学目前已有74人学习该资源。1. 从一篇经典论文说起为什么水下增强要用融合而非单路增强水下拍出来的照片问题往往不是“欠曝”而是“偏色”——红光在水下衰减最快剩下蓝绿光主导画面所以原图始终带一层青蓝色罩子远处细节被压在低对比度里。常规修法里直方图均衡容易把色偏放大成色斑单独做白平衡救不回远处对比度Retinex 又对水下这种低纹理场景容易溢出光晕。Ancuti 在 Enhancing Underwater Images and Videos by Fusion 这篇论文里换了个思路同时生成一张颜色校正图和一张对比度增强图让像素自己决定该信谁再做多尺度融合。这份 matlab 源码就是这套水下图像增强融合算法的完整复现自带显著性检测、双边/引导滤波、高斯/拉普拉斯金字塔和 UCIQE 客观评价适合做毕设、课设的对比实验也适合想彻底拆开这套融合管线的人逐文件阅读。2. 输入分支构建Lab 空间白平衡与 simple_color_balance 参数调优2.1 为什么先转 LabRGB 白平衡在水下的通病水下图像增强的第一步是生成融合输入不是直接进滤波器。很多初版实现直接对 RGB 三个通道做白平衡效果往往很糟蓝色通道在直方图裁剪后获得最大的拉伸幅度结果越拉越蓝。这里的关键在于RGB 三通道高度耦合单独拉伸会把色偏从“偏蓝”变成“蓝紫分层”。项目里同时放了rgb_to_lab.m和lab_to_rgb.m说明主体流程是在 Lab 空间完成的。Lab 把亮度 L 和颜色 a、b 分开对水下场景非常合适——亮度做对比度拉伸不会牵连色调a、b 通道做色偏校正也不会把画面拉灰。这也是为什么 5 年经验以上的工程师看到这个文件列表基本能猜到 main.m 的前半段长什么样。2.2 simple_color_balance直方图裁剪不是无脑拉伸simple_color_balance.m是整个白平衡分支的核心。常见实现是逐通道取百分位裁剪再做线性映射代码骨架是这样function out simple_color_balance(img, clip_percent) % clip_percent: 裁剪比例, 0.01 表示高低端各砍掉 1% 像素 out img; for c 1:size(img, 3) ch img(:, :, c); lo prctile(ch(:), clip_percent * 100); hi prctile(ch(:), 100 - clip_percent * 100); ch (ch - lo) / (hi - lo 1e-6); % 加 eps 防止除零 out(:, :, c) max(0, min(1, ch)); end end逻辑拆开看prctile找低分位和高分位中间像素被线性铺满 0~1。clip_percent是比例而不是像素个数0.01 表示两端各砍 1% 极值防止个别过曝白点把整个灰度范围拖垮。这段代码直接在 RGB 上跑会有一个隐患——蓝通道极值分布宽、红通道极值分布窄独立拉伸后红通道增益远大于蓝通道色偏被结构性放大。更稳的用法是只对 L 通道做裁剪拉伸a、b 通道做温和的均值偏移。用项目自带的 Lab 转换函数组织在一起lab rgb_to_lab(img); L lab(:, :, 1); lo prctile(L(:), 0.5); hi prctile(L(:), 99.5); L (L - lo) / (hi - lo 1e-6) * 100; % L 通道范围 0~100 lab(:, :, 1) min(max(L, 0), 100); out lab_to_rgb(lab);这样亮度拉伸不碰色度配合 a、b 通道的灰度世界校正把 a、b 均值挪到中心就能得到第一路输入。参数上clip_percent在 0.005~0.02 之间调色偏重的图取大值近景本来就清晰的就取小值。项目里 4.jpg、6.jpg 这类偏蓝明显的测试图用 0.01 起步是合理的。2.3 第二路输入用 gamma 做出对比度分支融合算法要的是两个“性格不同”的输入。第一路已经偏中性色第二路应该偏对比度。原论文用对比度增强操作实际复现时最常见的手段是对 Lab 的 L 通道做 gamma 映射不需要额外文件lab2 lab; L2 (lab2(:, :, 1) / 100) .^ 0.8 * 100; % gamma 1 提亮暗部 lab2(:, :, 1) L2; input2 lab_to_rgb(lab2);gamma 取 0.7~0.9 时暗部细节被提起来水下远景的轮廓从迷雾里露出来低于 0.5 会把蓝色通道里的噪点一起放大观感反而变脏。如果嫌 gamma 不够激进可以自己接 MATLAB 自带的adapthisteq对 L 通道做对比度受限自适应直方图均衡无需改动项目文件。两路输入准备好之后剩下的问题就变成融合时每个像素该信谁多一点。这就轮到显著性检测和权重图出场了。3. 权重图生成saliency_detection 与边缘保持滤波的配合3.1 权重由什么决定融合不是把两张图居中平均那是 blur。权重图回答的是空间上“哪个区域的哪个输入更可信”。Ancuti 的框架里权重由三个分量乘积构成饱和度高说明颜色信息丰富拉普拉斯响应强说明纹理细节足显著度突出说明这个区域是视觉焦点。项目里saliency_detection.m负责显著度这一路而bilateralFilter.m和guidedfilter.m负责把粗糙权重图磨光滑。给其中一张输入图构建原始权重的常规写法function W compute_weight(img) lab rgb_to_lab(img); sal saliency_detection(img); % 显著度 - 注意重点 sat std(lab(:, :, 2:3), 0, 3); % a/b 通道标准差 - 饱和度 lap abs(imfilter(rgb2gray(img), fspecial(laplacian))); % 拉普拉斯对比度 W mat2gray(sal .* sat .* (lap eps)); end注意三个分量的单位都不一致直接用乘积会被拉普拉斯项主导所以最后要mat2gray归一化到 0~1。实际项目里如果发现权重图几乎全是黑的、只有几条亮边就是拉普拉斯项绝对值量纲太大对lap先做一次mat2gray再乘进去。3.2 saliency_detection 的频率调谐实现saliency_detection.m对应经典频率调谐显著图原理很简单一个区域跟整幅图的平均色偏离越大显著性越高。核心代码等价于function S saliency_detection(img) lab rgb2lab(img); % 老版本可用 makecform 转换 blur imgaussfilt(lab, 5); % 高斯模糊, sigma5 avg mean(mean(lab, 1), 2); % 整图平均 Lab diff (double(lab) - avg) .^ 2 - (double(blur) - avg) .^ 2; S mat2gray(sqrt(sum(diff, 3))); end这里的关键参数是高斯核的 sigma。sigma 越大也能检测到的“焦点区域”越粗水下图像里鱼群、珊瑚这类小目标跟 sigma5 搭配起来差不多但如果测试图是大面积均匀沙地sigma 拉到 8 更合适。注意imgaussfilt需要 R2015a 以上老环境里用imfilter(lab, fspecial(gaussian, 31, 5), replicate)等效替换。3.3 bilateralFilter 与 guidedfilter细化权重的两条路线初始权重图往往带噪声和块状边缘直接拿去融合会在物体边缘产生锯齿状光晕。项目里准备了两种边缘保持滤波器对应result目录下的*_bilateral.jpg和*_guide.jpg两组输出。双边滤波做的是保边平滑W_bil bilateralFilter(W, W, 5, [0.1 0.1]);有一个版本差异要警惕bilateralFilter的参数顺序在不同开源实现里不一样有的是(src, r, sigma_s, sigma_i)有的把引导图和原图分开传。项目内 README 没有写明时先打印尺寸检查有没有把参数传反——最常见的运行报错就是这里把r5传成了 sigma。引导滤波走的是另一条路用原图灰度做引导结构细化权重的同时把边缘从原图“借用”过来W_guide guidedfilter(double(rgb2gray(img)), W, 8, 0.01);guidedfilter的四参数形态固定为(guide, src, r, eps)guide是引导图eps是正则化系数。eps取 0.001~0.1值越小越贴近引导图的边缘细节水下噪声多时取 0.1 压一压。boxfilter.m是引导滤波的加速内核没有它guidedfilter会慢一个量级。两条路线直接对比双边滤波耗时随图像尺寸和空间 sigma 非线性上涨1200px 大图能走到十几秒引导滤波因为基于积分图几乎与内容无关地稳定在亚秒级。毕设里追求视觉效果展示用双边批量跑数据集用引导。权重图备好后最后一步是金字塔融合。4. 金字塔融合与 UCIQE从像素加权到多尺度重建4.1 为什么不能在原分辨率上直接加权权重图和输入图都已经准备好最容易想到的做法是result W1 .* I1 W2 .* I2。这么写出来的结果在平坦区域还行一到边缘就露馅单像素级权重不连续会把一个物体的边缘切出半透明残影专业点叫光晕伪影。多尺度金字塔的思路是把图像的“大意”和“细节”分层处理——每层只负责一个频段权重也对应分层这样融合边界在每一层都被摊薄了。4.2 gaussian_pyramid 与 laplacian_pyramid 各管什么项目里的gaussian_pyramid.m做降采样模糊laplacian_pyramid.m负责抽出层间差结构上互补。高斯金字塔的核心只有几行function pyr gaussian_pyramid(img, levels) pyr cell(levels, 1); pyr{1} img; for l 2:levels pyr{l} impyramid(pyr{l-1}, reduce); % 高斯降采样, 每层缩半 end end拉普拉斯金字塔则用高层高斯上采样后与原层相减得到这一层的带通细节function lpyr laplacian_pyramid(gpyr, levels) lpyr cell(levels, 1); for l 1:levels-1 up impyramid(gpyr{l1}, expand); % 防止 expand 后尺寸奇偶不一致 if size(up, 1) ~ size(gpyr{l}, 1) || size(up, 2) ~ size(gpyr{l}, 2) up imresize(up, [size(gpyr{l}, 1), size(gpyr{l}, 2)]); end lpyr{l} gpyr{l} - up; end lpyr{levels} gpyr{levels}; % 顶层留低频残差 end这里的levels不是越大越好。层数过多顶层只剩一两颗像素重建后会出现色块一般按min(5, floor(log2(min(h, w))))定层数800px 的图取 5 层足够。README 没提这层细节但 result 目录里近景图1.jpg、2.jpg和远景图8.jpg如果出现整体偏灰先检查的就是层数是不是一刀切用了同一个值。4.3 融合主循环与 pyramid_reconstruct 重建融合的核心循环是把两张输入的拉普拉斯金字塔按对应层的高斯权重金字塔做加权levels length(lap1); fused cell(levels, 1); for l 1:levels % 权重金字塔各自归一化, 避免两层权重合不为一 wsum w1_gauss{l} w2_gauss{l} 1e-6; nw1 w1_gauss{l} ./ wsum; nw2 w2_gauss{l} ./ wsum; fused{l} nw1 .* lap1{l} nw2 .* lap2{l}; end result pyramid_reconstruct(fused);pyramid_reconstruct.m是逐层上采样累加的过程方向与构建相反function img pyramid_reconstruct(lpyr) img lpyr{end}; for l length(lpyr)-1:-1:1 img impyramid(img, expand); if size(img, 1) ~ size(lpyr{l}, 1) || size(img, 2) ~ size(lpyr{l}, 2) img imresize(img, [size(lpyr{l}, 1), size(lpyr{l}, 2)]); end img img lpyr{l}; end end同一套流程跑两遍只是权重细化方式不同就得到项目result目录下的2_bilateral.jpg和2_guide.jpg成对结果这是做横向对比的标准姿势。到这里增强主链路已经完整难点转变成“怎么证明增强有效”。4.4 UCIQE.m水下图像客观评价的量化口径UCIQE 是水下图像质量评价常见指标计算核心放在 Lab 空间综合色度标准差、亮度对比度和饱和度均值。UCIQE.m的标准实现等价于function q UCIQE(img) lab rgb2lab(img); l lab(:, :, 1); a lab(:, :, 2); b lab(:, :, 3); chroma sqrt(a.^2 b.^2); sigma_c std2(chroma); % 色度标准差 con_l prctile(l(:), 95) - prctile(l(:), 5); % 亮度对比度 hsv rgb2hsv(img); mu_s mean(hsv(:, :, 2)); % 饱和度均值 q 0.4680 * sigma_c 0.2573 * con_l 0.2573 * mu_s; end三个系数的来源是论文里针对主观评分回归出来的权重改系数会影响分数排序但不会颠覆相对优劣。经验上一组测试图跑下来UCIQE 提升 0.05~0.15 属于典型正常范围超过 0.2 要警惕是不是颜色过饱和了单看分数不保险要配合原图检查。同样的图片用rgb2labMATLAB 自带和项目自带rgb_to_lab算出的 UCIQE 会有桌面级别的数值差做对比实验时前后必须用同一个转换函数。5. main.m 调参与水下标定实战5.1 main.m 的调用顺序拆开 main.m 看调用顺序基本是固定的读图 -simple_color_balance生成颜色校正路 - gamma 生成对比度路 -saliency_detection做显著度权重 -bilateralFilter和guidedfilter各出一版细化权重 - 高斯/拉普拉斯金字塔分频 - 融合重建 -UCIQE输出分数。测试images目录下 1.jpg 到 10.jpg 全部跑通后替换成自己拍摄的水下图唯一要改的就是clip_percent和 gamma 两个参数。5.2 三个高频坑与排查顺序第一是金字塔层数。层数写死成 6 而图片只有 480px 高时顶层会塌成 7×7 的色斑重建后整张图发灰。先按floor(log2(min(h,w)))动态算层数再向下裁剪不超过 5。第二是bilateralFilter太慢。RGB 大图直接上双边滤波会卡到怀疑人生优先换引导滤波真要用双边先把图像缩到 800px 以内做实验参数稳定后再放原尺寸跑最终版。result 目录里同样编号的两版成图就是为此准备的对照组。第三是增强结果偏灰。权重图归一化正常时融合结果的标准差应该在 0.15~0.35 之间低于 0.15 说明权重分配太平均、细节层贡献不足fprintf(contrast std: %.3f\n, std2(result(:)));低于 0.15 时不是去调金字塔而是检查权重图的直方图——如果显著度一项几乎全平说明测试图没有明显焦点这时候把sal的权重整体放大两倍再融合。5.3 用中性灰块做白平衡验证UCIQE 给出的是整体分数验证白平衡是否过头更直接的方法是找画面里的中性灰区域增强后看 Lab 的 a、b 通道偏离 0 的程度lab rgb_to_lab(result); mask roipoly(lab); % 手动圈出灰色卡或中性色墙面 a_mean mean(lab(:, :, 2), mask); b_mean mean(lab(:, :, 3), mask);增强后灰块的 a、b 均值落在 ±5 以内算正常超过 ±8 说明颜色校正分支用力过猛。这时候回到第 2 章把clip_percent从 0.01 调小到 0.005而不是去动金字塔层数——白平衡的错不该让融合来背。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价