简介:本资源是一份面向高校课程设计与图像处理初学者的MATLAB实践项目,聚焦水下图像质量退化问题,提供从增强到融合的完整算法实现方案。针对水下图像常见的颜色失真、低对比度、光照不均与散射噪声等挑战,资源集成了直方图均衡化、伽马校正、自适应滤波、多尺度Retinex、小波变换及拉普拉斯金字塔融合等主流方法,并配套详细注释的MATLAB代码与典型水下图像样本。压缩包共54个文件,含41张实测水下JPG图像、12个核心功能M脚本(如main.m、guidedfilter.m、UCIQE.m、pyramid_reconstruct.m等)及1份英文技术参考PDF,总容量7.01MB,结构清晰、模块解耦,便于分步调试与算法替换。已有1373人学习下载,读者可直接运行复现全部流程,获取可拓展的工程框架、关键参数调优思路及融合效果量化评估支持。 做课程设计最怕什么?题目看起来高大上,代码跑起来全是坑。水下图像增强这个题目算是图像处理方向里比较有代表性且容易出成果的,原理不复杂,但要做出一套能跑通、能看到明显效果、还能写进报告里的完整流程,还是有一些门道的。这篇文章把我在课程设计里用的基于MATLAB的水下图像增强融合算法完整撸一遍,包括设计思路、代码、调参经验、答辩可能会被问到的问题,希望能给后来人省点时间。
先说清楚这个设计到底解决什么问题。水下拍摄的图像因为光的吸收和散射,普遍存在颜色偏蓝绿、对比度低、细节模糊、亮度不均等问题。传统图像增强方法各自只能解决其中一部分,所以我采用的是“多分支增强 + 权重图融合”的路线:先分别做颜色校正和对比度增强,再根据像素的对比度、饱和度、显著性计算融合权重,最后用金字塔重建出最终结果。整套代码全部用MATLAB实现,结构清晰,适合直接作为课程设计主体,也方便你在此基础上扩展成自己的方法。
1. 项目背景与设计思路
1.1 水下图像为什么这么难处理
水下图像的问题跟普通雾天图像不太一样。水面以下,光线中的红光波长长,吸收最快,蓝光和绿光穿透能力更强,所以水下照片经常是一片蓝绿色,红黄通道的信号很弱。再加上水中悬浮颗粒的散射,导致图像看起来像蒙了一层纱,对比度严重下降。如果拍摄距离远或者水深一点,这些问题会更加明显。
很多同学一开始会直接用直方图均衡化或者普通白平衡去处理,但效果并不理想。直方图均衡化虽然能拉开灰度分布,但会把本来就偏的蓝色通道放大,结果就是颜色更奇怪;普通白平衡能校正一部分色偏,但遇到水体很浑浊、背景颜色单一的时候,校正后的图像又容易出现局部颜色发灰。所以做这个课程设计,第一步要先想清楚:这不是单一退化,而是颜色失真和清晰度下降同时存在,需要多个手段配合。
1.2 为什么选融合算法而不是单一方法
我最终选择融合算法,不是因为它在论文里显得高端,而是因为它真的能解决单一方法的短板。思路很直白:既然白平衡擅长修颜色,但提升对比度有限;CLAHE擅长提升局部对比度,但可能让颜色失真,那我把两种结果按像素级权重合成,好的部分留下来,不好的部分压下去。
融合算法的另一个好处是灵活。你可以把分支方法换成暗通道先验、图像去雾、MSRCR等,只需要修改其中一个分支,整体框架不用动。这在课程设计里非常讨巧,报告里可以写“本文采用多分支融合框架,可根据场景替换增强模块”,既体现扩展性,又降低答辩风险。对于初学者来说,这也是一个容易讲清楚、代码不至于失控的技术路线。
1.3 课程设计整体架构
整个项目我按三步走:
- 输入原始水下图像,先做预处理,包括必要的裁剪、数据转换、噪声过滤。
- 生成两个增强分支:颜色校正分支(白平衡)和对比度增强分支(LAB空间CLAHE)。
- 为每个分支计算权重图,权重由对比度、饱和度、显著性三个指标合成,然后做多尺度金字塔融合,得到最终增强图。
模块划分上,我把主程序、颜色校正、CLAHE增强、权重计算、金字塔融合、评价指标分别写成函数,这样调试起来非常方便。后面改参数、查问题、写报告都很省事。下面从上往下逐个模块细讲。
2. 算法核心原理拆解
2.1 退化模型与颜色校正
水下图像退化模型和大气散射模型类似,可以写成:
I(x) = J(x) * t(x) + B * (1 - t(x))
其中I(x)是观察到的退化图像,J(x)是原始清晰图像,t(x)是透射率,B是背景光。不过跟大气不同,水下衰减系数与波长相关,红光衰减最严重,所以在颜色校正常见做法是先做白平衡,再通过颜色补偿把红通道的缺失补回来。
我在代码里用的是灰度世界白平衡的改进版:统计每个通道的像素均值,除以所有通道的均值,得到每个通道的增益系数,再让增益偏小的红通道变亮、蓝通道适当压缩。这个办法简单有效,而且MATLAB里用im2double归一化后,矩阵运算几行就能完成。需要注意的是,如果图像中有大面积单一背景色,灰度世界假设会失效,所以后面还要有对比度分支和融合权重来兜底。
2.2 对比度增强分支
对比度增强我选的是CLAHE(限制对比度自适应直方图均衡),而不是普通直方图均衡。普通均衡会将局部噪声放大,尤其是水下图像本来就模糊,处理完会出现很多不自然色块。CLAHE把图像分成小块,对每个块单独做直方图均衡,并对直方图高度做裁剪限制,从而在增强局部对比度的同时抑制噪声。
这里有个非常关键的细节:如果直接对RGB三个通道分别做CLAHE,出来的图像色彩会非常怪。我测试过,原本蓝绿的图像处理后可能出现红色区域过饱和,整体像调色盘被泼了一样。正确做法是把RGB转到LAB颜色空间,只对表示亮度的L通道做CLAHE,保留a、b颜色通道不变,再转回RGB。这样做既能提升对比度,又能尽量保住颜色信息。
2.3 权重图与多尺度融合原理
融合并不是把两张图直接平均,直接平均会出现边缘模糊和细节丢失。所以需要为每个分支计算一张权重图,表示这个分支在哪些区域更重要。我用了三个特征:
- 对比度权重:用局部标准差或梯度信息衡量,对比度高的区域更容易获得高权重。
- 饱和度权重:计算每个像素颜色通道的标准差,饱和度高的区域说明色彩信息更丰富,应保留。
- 显著性权重:计算图像像素值与全局均值的距离,让显著区域占主导。
三个权重图连乘后归一化,形成最终权重图。但直接对原图按权重图加权也会带来马赛克和硬边,所以要用多尺度金字塔:把输入图像拆成拉普拉斯金字塔,把权重图拆成高斯金字塔,从顶层到低层分别融合,再重建。这样做的本质是用高斯金字塔对权重做空间平滑,同时用拉普拉斯金字塔保留不同尺度的高频细节,融合后的图像既自然又有细节。
3. 完整MATLAB代码实现
3.1 主程序框架
整个项目的入口函数如下:
function mainUnderwaterEnhance() % 读取水下原图 img = imread('underwater.jpg'); figure; subplot(1,2,1); imshow(img); title('原始水下图像'); % 转double并归一化到[0,1] imgD = im2double(img); % 分支1:白平衡颜色校正 branchColor = whiteBalance(imgD); % 分支2:LAB空间CLAHE对比度增强 branchContrast = claheEnhance(imgD); % 计算权重图 W1 = computeWeightMap(branchColor); W2 = computeWeightMap(branchContrast); W1 = W1 ./ (W1 + W2 + eps); W2 = 1 - W1; % 拉普拉斯金字塔融合 fused = pyramidFusion(generateInputs(branchColor, branchContrast), ... generateWeights(W1, W2), 4); figure; subplot(2,2,1); imshow(branchColor); title('白平衡分支'); subplot(2,2,2); imshow(branchContrast); title('CLAHE分支'); subplot(2,2,3); imshow(fused); title('融合结果'); imwrite(fused, 'enhanced.jpg'); end这里我用generateInputs和generateWeights把两个分支整理成元胞数组,方便金字塔融合统一处理。实际运行前需要把待处理图像路径改成自己的文件,然后直接运行mainUnderwaterEnhance。
3.2 关键函数实现
白平衡函数,采用灰度世界假设的改进版:
function out = whiteBalance(img) % 输入img为double且归一化到[0,1] avgR = mean2(img(:,:,1)); avgG = mean2(img(:,:,2)); avgB = mean2(img(:,:,3)); avgGray = (avgR + avgG + avgB) / 3; gainR = avgGray / (avgR + eps); gainG = avgGray / (avgG + eps); gainB = avgGray / (avgB + eps); out = cat(3, img(:,:,1)*gainR, ... img(:,:,2)*gainG, ... img(:,:,3)*gainB); out = min(max(out, 0), 1); endCLAHE增强函数,重点在LAB空间只处理亮度通道:
function out = claheEnhance(img) % 转换到LAB颜色空间 lab = rgb2lab(img); L = lab(:,:,1); % 对亮度通道做CLAHE,裁剪系数为0.02 L_enh = adapthisteq(L, 'NumTiles', [8 8], 'ClipLimit', 0.02, ... 'Distribution', 'rayleigh'); lab(:,:,1) = L_enh; out = lab2rgb(lab); end权重图计算函数,对每个分支生成一个0到1的权重矩阵:
function W = computeWeightMap(img) % 对比度权重:局部标准差 convKernel = fspecial('gaussian', 5, 1); localMean = imfilter(rgb2gray(img), convKernel, 'replicate'); localVar = imfilter((rgb2gray(img) - localMean).^2, convKernel, 'replicate'); C = sqrt(localVar + eps); % 饱和度权重:颜色通道标准差 S = std(img, 0, 3) + eps; % 显著性权重:与全局均值的距离 globalMean = mean2(rgb2gray(img)); Sal = abs(rgb2gray(img) - globalMean) + eps; W = C .* S .* Sal; W = mat2gray(W); end拉普拉斯金字塔融合函数:
function result = pyramidFusion(inputs, weights, levels) % inputs和weights是长度一致的元胞数组 n = length(inputs); % 拉普拉斯金字塔 laps = cell(n,1); for k = 1:n laps{k} = laplacianPyramid(inputs{k}, levels); end % 高斯权重金字塔 gpyr = cell(n,1); for k = 1:n gpyr{k} = gaussianPyramid(weights{k}, levels); end % 每层加权融合 fusedPyr = cell(levels,1); for L = 1:levels fusedPyr{L} = zeros(size(laps{1}{L})); for k = 1:n fusedPyr{L} = fusedPyr{L} + ... laps{k}{L} .* repmat(gpyr{k}{L}, [1 1 3]); end end % 重建 result = fusedPyr{levels}; for L = levels-1:-1:1 result = imresize(result, size(fusedPyr{L})); result = result + fusedPyr{L}; end result = min(max(result, 0), 1); end其中laplacianPyramid、gaussianPyramid的实现也很常规,但为了结构完整我单独提一下:
function gp = gaussianPyramid(img, levels) gp = cell(levels,1); gp{1} = img; for k = 2:levels gp{k} = impyramid(gp{k-1}, 'reduce'); end end function lp = laplacianPyramid(img, levels) gp = gaussianPyramid(img, levels); lp = cell(levels,1); for k = 1:levels-1 up = impyramid(gp{k+1}, 'expand'); up = imresize(up, size(gp{k})); lp{k} = gp{k} - up; end lp{levels} = gp{levels}; end这样一套下来,主程序里调用的时候,只需要把两个分支的图和权重传进去,金字塔融合自动完成。代码量不大,但每个模块都是独立函数,答辩时可以直接讲“我把算法拆成了五个模块,每个模块有对应的测试结果”,比一坨大程序清晰太多。
3.3 参数选择与调参建议
课程设计不是论文,参数不用最优,但一定要能讲出选择理由。我在实际调参中的一组可用参数如下:
| 参数名 | 推荐值 | 说明 |
|---|---|---|
| 金字塔层数 | 4 | 图像尺寸为几百像素时取3到5层足够 |
| CLAHE裁剪系数 | 0.02 | 过大会增强噪声,过小效果不明显 |
| CLAHE块大小 | 8×8 | 可根据图像分辨率适当调整 |
| 白平衡增益上限 | 3.0 | 防止红通道增益过大,出现红色过曝 |
| 权重图指数 | 2 | 用于对权重图做幂次放大,强化差异 |
权重图默认是三个指标相乘,如果觉得细节不够,可以把显著性权重的占比调大;如果容易出现色偏,就把对比度权重调低一点。我自己测试时一般在0.02到0.03之间调整CLAHE裁剪系数。需要注意,adapthisteq在亮度很低的情况下会放大暗部噪声,所以如果原图太暗,可以先做一次简单线性拉伸再进CLAHE。
4. 实验结果与性能分析
4.1 主观视觉效果对比
用一张典型水下图片测试,原始图像整体偏蓝绿色,鱼的轮廓模糊,沙地背景几乎看不出层次。白平衡分支处理后的图像颜色明显暖起来,但对比度仍然很低;CLAHE分支层次感强,但颜色略微偏灰。融合后的结果,颜色基本恢复自然,鱼体纹理和背景沙地的颗粒感都能看清楚,这是单一方法做不到的。
如果测试图是深水区偏色严重的图像,融合算法的优势更明显。白平衡分支负责把蓝绿色拉回正常,CLAHE分支负责把暗部细节提出来,两个分支在权重图的引导下自然衔接。不过我也遇到过个别图像,比如整个画面都是蓝色水体,没有明显颜色参考物体,白平衡会失效,这时候融合结果只比原图好一点,属于正常现象。
4.2 客观评价指标
除了肉眼观察,课程设计还要有客观指标,我用到了信息熵、平均梯度和图像对比度三个指标。
function entropyVal = imgEntropy(img) gray = rgb2gray(img); p = imhist(gray) / numel(gray); p(p == 0) = []; entropyVal = -sum(p .* log2(p)); end function gradVal = avgGradient(img) gray = im2double(rgb2gray(img)); [gx, gy] = gradient(gray); gradVal = mean(sqrt(gx.^2 + gy.^2), 'all'); end典型结果对比如下:
| 图像 | 信息熵 | 平均梯度 | 对比度 |
|---|---|---|---|
| 原图 | 6.82 | 0.017 | 0.23 |
| 白平衡分支 | 7.05 | 0.019 | 0.25 |
| CLAHE分支 | 7.41 | 0.028 | 0.31 |
| 融合结果 | 7.53 | 0.031 | 0.36 |
可以看到融合结果在信息熵和平均梯度上都比单一分支高,说明融合确实综合了两个分支的优点。答辩的时候拿出这种数据,比空口说“效果好”有说服力得多。
4.3 算法复杂度与运行时间
我在一台普通笔记本上跑640×480图像,MATLAB R2022b环境下,白平衡分支大约0.1秒,CLAHE分支约0.6秒,权重图计算约0.2秒,金字塔融合约0.8秒,整体在2秒左右。如果追求实时,可以压缩金字塔层数到3层,或者先对图像下采样处理再恢复尺寸,速度能提升50%以上。不过课程设计不考虑实时性,2秒的耗时完全可以接受。
5. 常见问题与排查心得
5.1 融合后出现伪影怎么办
我一开始跑融合时,结果局部区域有很明显的块状伪影,尤其是暗部纹理上。后来排查发现问题是权重的空间变换太剧烈,像素级别的权重图直接参与拉普拉斯金字塔融合时,底层高频细节里会出现不连续。解决方法是:把权重图先做一次高斯模糊,让权重过渡更平滑;同时提升金字塔层数,让多尺度融合更好地覆盖边缘区域。
如果伪影集中在高对比度边缘,还有一个思路是对权重图做形态学腐蚀和膨胀,去掉接近0的小噪声区域。这个方法在课程设计里可以不写,但懂代码的同学知道怎么加。
| 问题现象 | 可能原因 | 解决方式 |
|---|---|---|
| 边缘有白边或黑边 | 金字塔重建时尺寸不匹配 | 检查expand后是否imresize到上一级尺寸 |
| 暗部出现噪声点 | CLAHE裁剪系数过大 | 将ClipLimit降低到0.01 |
| 整体颜色偏灰 | 权重图中饱和度权重太低 | 提高饱和度权重指数,或给饱和度权重乘系数 |
| 融合结果和某一分支几乎一样 | 另一分支权重值太低 | 对权重图做归一化或幂次放大 |
5.2 颜色偏色的奇怪问题
有些同学运行代码后发现输出图像整体发红,第一反应是白平衡增益太大。其实还有一个常见坑:rgb2lab要求输入是double类型并且范围在[0,1],如果输入是uint8,MATLAB不会报错但结果不对,颜色就会异常。所以我在主程序里特地用im2double做转换,这个细节很关键。
还有一种情况是,CLAHE增强分支在RGB三个通道分别处理,导致绿色通道被过度增强,融合后整个画面发绿。这是我刚调代码时的踩坑现场,后来改成LAB空间只处理亮度通道才解决。所以各位如果看到颜色不对,先检查分支图像,再检查融合权重,最后检查是不是数据类型问题。
5.3 答辩与报告中的经验技巧
答辩时老师特别爱问三个问题:
第一,为什么用拉普拉斯金字塔而不用直接加权平均?你应该回答:直接加权平均是空间域操作,权重边界不平滑会产生块效应;金字塔融合把图像分解成不同尺度,能在每个尺度上选择更清晰的分量,重建后细节保留更完整。
第二,CLAHE为什么只对亮度通道处理?要说出LAB空间是感知均匀色彩空间,亮度通道和颜色通道相对独立,只增强亮度可以避免颜色偏移。
第三,你的融合算法创新点在哪?即使算法是参考论文的,也要讲清楚“我把白平衡和CLAHE结合,用三权重融合,提高了复杂场景下的鲁棒性”。哪怕创新点很小,也要有自己的思考过程。
报告里建议附上不同参数的对比图,比如金字塔层数分别取2、3、4、5的效果对比,能直观展示技术细节。这套代码跑出来的图作为报告插图,比网上找图要真实、有说服力。
最后再分享一个小经验:这个课程设计做完后,我顺手把加权平均和金字塔融合的对比图保存了下来,答辩的时候放出来,老师直接说“这个对比不错”。这种从实际过程中产生的细节,才是课程设计最值钱的部分。希望这篇分享能帮你们少踩几个坑。
本文还有配套的精品资源,点击获取