Matlab黑白图像彩色化实战:从优化着色到深度学习

发布时间:2026/9/26 4:06:44
Matlab黑白图像彩色化实战:从优化着色到深度学习 做图像处理的同行应该都遇到过这样的需求手头只有一张黑白老照片或一段监控灰度帧想给它补上颜色让画面活起来。黑白图像彩色化这个课题我在Matlab上折腾过很长时间从最传统的颜色扩散优化到基于深度学习的端到端训练都试过今天把整个实战过程整理成这篇博文包含完整可跑的代码、参数调优心得和踩坑记录。这篇文章适合刚接触图像处理、或者正在做Matlab图像处理大作业的朋友也适合想从零搭建一个彩色化原型的研究者我会把每一步的思路和实现细节都讲清楚让你能照着做而不是只看到一个模糊的流程图。彩色化本质上是一个病态问题灰度值丢失了色度信息同一个灰阶可以对应无数种颜色必须引入先验——人类的经验、参考图的色调分布或者大规模数据训练的统计规律。Matlab做这件事有天然优势它把图像当成矩阵所有算法都能用简洁的矩阵运算表达加上Image Processing Toolbox自带各种滤波、形态学、颜色空间转换函数Debug和可视化也特别方便。下面直接进入正题从方案选型开始讲。1. 彩色化问题的核心思路与方案选型1.1 灰度图到彩色图的数学本质一张黑白图像在Matlab里读进来本质是一个m x n的灰度矩阵每个像素的亮度值L在0到255之间。彩色图像则至少需要三个通道比如RGB三个矩阵。从数学角度看彩色化就是给每个像素的亮度值L补上另外两个通道的数值例如Lab颜色空间的a通道和b通道这个映射是完全不确定的。为什么不确定因为亮度相同的两个相邻像素在人眼的感知里可以是完全不同的颜色。比如一片灰蒙蒙的天空和一块灰色的石头灰度值几乎一样但颜色一个是蓝灰色一个是土黄色。这就是为什么简单的查找表或线性回归根本做不好彩色化——必须依赖上下文信息、用户交互或者大数据先验。目前主流的方案可以分成三类。第一类是用户交互式优化代表是Levin等人2004年提出的方法用户在灰度图上随意画几笔颜色线索算法把颜色平滑地传播到全图。第二类是颜色迁移找一张参考彩色图把它的颜色统计量映射到目标图不依赖用户涂色但要求参考图的内容与目标图比较接近。第三类是深度学习方法用大量彩色图训练一个神经网络输入灰度图直接预测a、b通道这是目前效果最好的方案也是工业界落地的主流。1.2 为什么用Matlab来做而不是Python很多读者会问现在深度学习都用Python为什么还要用Matlab做彩色化我个人的看法是Matlab在经典算法实现上有三个无法替代的优点。第一是矩阵思维直接落地。优化着色法需要解一个大型稀疏线性方程组Matlab的\运算符对稀疏矩阵做了高度优化写代码几乎不用考虑底层数据结构。同样的算法用Python需要先折腾scipy.sparse还要注意内存布局调试成本高不少。第二是工具箱完善。Image Processing Toolbox里灰度图转二值、连通域分析、颜色空间转换都是现成的rgb2lab、lab2rgb这类函数一行就能搞定颜色空间切换这在做颜色迁移时特别省心。第三是可视化方便。图像处理过程需要反复观察中间结果Matlab的imshow、subplot、montage可以快速拼图对比比OpenCV的cv2.imshow在交互性上更友好。此外Matlab的Deep Learning Toolbox同样支持训练CNN代码写起来和Python的Keras风格接近门槛并不高。所以我最终的推荐路线是先用经典优化方法跑通流程理解数学原理再用颜色迁移做一个无交互的快速版本最后有余力再上深度学习。这三个阶段难度递进正好覆盖初学者到研究者的需求。2. 环境准备与数据预处理2.1 Matlab版本与工具箱配置彩色化的代码对Matlab版本要求不高R2019b及以后的版本都可以正常运行核心依赖是Image Processing Toolbox。如果要做深度学习部分还需要Deep Learning Toolbox。我用的环境是Matlab 2023b操作系统为Windows 11配置了完整的工具箱。这里提醒一下安装时的两个细节。第一安装路径尽量不要有中文或空格否则后续加载预训练模型、保存数据集时容易出奇怪的路径错误。第二启动后先运行ver检查工具箱是否加载成功重点看Image Processing Toolbox版本号没有的话去Add-On Explorer手动安装。写代码时建议在脚本开头加一段环境检查代码避免半路才发现缺工具箱% 检查必备工具箱 if isempty(ver(images)) error(需要Image Processing Toolbox请先安装。); end if isempty(ver(deep)) warning(未检测到Deep Learning Toolbox深度学习部分无法运行。); end这个检查脚本虽简单但在换机器跑项目时能少很多烦恼特别是做图像大作业时老师机器上没装对应工具箱的情况太常见了。2.2 黑白图像的去噪与归一化实操彩色化算法的输入质量直接影响输出效果。老照片往往有扫描噪声、划痕、亮度不均匀如果不先做预处理颜色扩散时会把这些异常当成边界导致颜色渗透到错误区域。我的标准预处理流程是三步第一步灰度化统一格式。如果输入的是真彩色图但看起来是黑白的比如灰度图被存成了RGB三通道先用rgb2gray转换确保矩阵是二维的。注意一张灰度图三个通道数值完全相同直接用imread读进来是三个一模一样的矩阵很多算法会隐式处理但最好显式转换。第二步去噪。先试试中值滤波窗口大小建议3到5太大会抹掉边缘细节。对噪声比较重的老照片我会先用3x3的中值滤波再用5x5的高斯滤波平滑顺序不能反先中值后高斯能抑制椒盐噪声同时保留大结构。等效代码I imread(old_photo.png); if size(I,3) 3 Igray rgb2gray(I); else Igray I; end % 中值滤波去噪 Igray_med medfilt2(Igray, [3 3]); % 高斯平滑 Igray_smooth imgaussfilt(Igray_med, 0.8);第三步归一化到[0,1]浮点范围。Matlab图像处理中double类型与像素对应关系容易混乱建议所有算法内部统一用0到1的double值只在显示和保存时用0到255的uint8。转换代码I_norm double(Igray_smooth) / 255;这一步看似多此一举但能避免很多隐式数据类型转换的错误。比如imshow支持double显示时按0到1解释如果不归一化直接显示就是黑的。另外亮度值本身在Lab空间中是有意义的保留原始灰度分布对后续颜色迁移很重要归一化只是算法内部处理后续要还原尺度就乘回去。3. 基于优化着色法Levin算法的实现3.1 颜色扩散原理与能量最小化模型Levin算法的核心思想是用户在灰度图上指定少数像素的颜色算法假设颜色在亮度相近且空间相邻的区域里变化平滑。具体做法是先将图像转换到YUV颜色空间保持亮度通道Y不变只对U、V通道进行插值。为什么选择YUV而不是RGB因为RGB三个通道之间有很强的相关性直接对R、G、B分别插值容易产生伪彩色。YUV把亮度信息单独拎出来U和V只表征色度人类视觉对色度变化不怎么敏感所以我们可以大胆假设U、V通道是平滑变化的。数学上算法构建了一个拉普拉斯矩阵。对每个像素i定义它和四邻域像素j之间的权重权重取决于亮度相似度w_ij exp( - (Y_i - Y_j)^2 / (2 * sigma^2) )直观理解就是亮度越接近的邻域像素颜色越可能相同权重就大亮度差异大的边缘处权重小阻止颜色扩散过边界。为了避免除以零等问题通常还要给权重加上一个很小的正数。然后求解最优化问题已知部分像素的U、V值用户涂色的锚点要让所有未着色像素的U、V值尽量接近邻域值的加权平均同时强制性满足锚点处的约束。用矩阵形式表达就是求解稀疏线性方程组(L lambda * P) * U lambda * U_seeds其中L是拉普拉斯矩阵P是锚点指示矩阵只有用户涂色位置非零lambda是约束强度。lambda越大锚点颜色越是硬性约束lambda越小颜色扩散越自由。实际使用中lambda取100左右比较合适。3.2 稀疏线性方程组构建与求解在Matlab中算法的实现可以分成四个步骤。这里给出一个简洁且带注释的完整函数。第一步读入并预处理灰度图第二步定义邻域关系与权重第三步构建稀疏矩阵第四步用户标记锚点并求解。锚点标记可以用简单方法准备一张和原图一样大小的标记图直接在特定像素处赋一个颜色值。为了演示方便我用手工指定几个点的颜色来模拟用户涂色。function I_colorized colorize_levin(I, seeds_yx, seeds_uv) % I: 归一化灰度图double类型范围[0,1] % seeds_yx: kx2矩阵每一行是[y, x]锚点坐标 % seeds_uv: kx2矩阵每一行是对应锚点的[u, v]值范围[-0.5, 0.5] % 返回: 彩色化后的RGB图像范围[0,1] [h, w] size(I); N h * w; % 像素索引 idx reshape(1:N, h, w); % 构建四邻域权重 % 使用亮度差的高斯权重 sigma 0.1; % 亮度归一化后的sigma rows zeros(2*N, 1); cols zeros(2*N, 1); vals zeros(2*N, 1); cnt 0; for y 1:h for x 1:w p idx(y, x); % 右邻域 if x w q idx(y, x1); yd I(y, x) - I(y, x1); wgt exp(-(yd)^2 / (2*sigma^2)) 1e-6; cnt cnt 1; rows(cnt) p; cols(cnt) q; vals(cnt) wgt; cnt cnt 1; rows(cnt) q; cols(cnt) p; vals(cnt) wgt; end % 下邻域 if y h q idx(y1, x); yd I(y, x) - I(y1, x); wgt exp(-(yd)^2 / (2*sigma^2)) 1e-6; cnt cnt 1; rows(cnt) p; cols(cnt) q; vals(cnt) wgt; cnt cnt 1; rows(cnt) q; cols(cnt) p; vals(cnt) wgt; end end end W sparse(rows(1:cnt), cols(1:cnt), vals(1:cnt), N, N); % 拉普拉斯矩阵 L D - W其中D是对角度矩阵 D sum(W, 2); L spdiags(D, 0, N, N) - W; % 锚点约束项 k size(seeds_yx, 1); lambda 100; P sparse(seeds_yx(:,1) (seeds_yx(:,2)-1)*h, ... % 线性索引 1:N, 1:N); % 占位下面修正 % 正确构建锚点指示矩阵 seed_linear zeros(1, k); for i 1:k seed_linear(i) idx(seeds_yx(i,1), seeds_yx(i,2)); end P sparse(seed_linear, 1:k, ones(k,1), N, k); % 解U通道 A L lambda * (P * P); b lambda * P * seeds_uv(:,1); u A \ b; % 稀疏求解 u full(reshape(u, h, w)); % 解V通道 b lambda * P * seeds_uv(:,2); v A \ b; v full(reshape(v, h, w)); % 合成YUY - RGB Y I * 255; % Y亮度恢复到原始尺度 % YUV转RGB前转换范围这里假设u,v在[-0.5,0.5] YUV cat(3, Y, u*255, v*255); I_colorized ycbcr2rgb(uint8(YUV)); % 注意ycbcr和yuv有差异这里简化处理 % 实际应该用Lab或自写转换这里仅做示意 end这段代码有个问题我用ycbcr2rgb来近似YUV转RGB这是不严谨的实际项目里建议使用lab2double、applycform等标准转换。Levin原版在YUV空间但Matlab没有直接的YUV函数我建议改成Lab空间的L通道。不过思路是一致的你可以把上述代码里的YUV换Labu和v换成a和b。真正关键的代码逻辑在于稀疏矩阵的构建和方程求解。A \ b这一行是优化的核心Matlab会自己选择最适合稀疏矩阵的直接法或迭代法大多数情况下不需要你手动指定求解器。如果图像尺寸超过500x500直接法可能会内存不足这时建议改用pcg预处理共轭梯度法。我在实验中发现300x400的图用\求解大概需要1到3秒完全可接受。3.3 实操效果与参数调整技巧跑通这段代码后你会发现效果完全取决于两个地方锚点画得准不准以及sigma和lambda的参数匹配。先说sigma。sigma控制亮度差对权重的影响。sigma太小只有亮度几乎一样的邻域才会扩散颜色结果是颜色只局限在锚点附近的小区域无法充满整张图sigma太大颜色会无脑扩散到亮度差别很大的区域侵染边缘。我用过无数次的经验是归一化亮度图0到1的sigma取值0.05到0.15具体要看图像对比度。对比度大的图取小值避免颜色越过边缘对比度小的图取大值让颜色更容易传播开来。再说lambda。lambda是锚点约束与平滑约束的平衡。lambda0意味着没有锚点约束方程直接解出全图平滑颜色但锚点处颜色也被抹平了lambda无限大意味着锚点颜色完全不变但周围颜色扩散受限于数值条件。推荐100到500。如果发现锚点处颜色很突兀边缘处颜色像是涂抹上去的试着减小lambda如果发现锚点附近颜色扩散不开就增大lambda。还有一个经常被忽视的点锚点不要画在图像边缘也不要画在颜色剧烈变化的边界上。因为Laplacian方程在边界上的约束会不准确容易出现“颜色泄漏”。正确做法是在区域的中心位置取样。比如要给人脸着色锚点应点在脸颊中部而不是头发和脸的交界处。如果手动标记锚点太繁琐我们可以写一个交互式脚本让用户用鼠标在图上点击并输入颜色值。使用ginput和impoly工具就能实现这部分我在后面的扩展中提到初学者先把固定锚点的版本跑通即可。4. 基于颜色迁移统计匹配的快速实现4.1 Lab颜色空间与统计量线性映射Levin算法需要用户交互如果只有一张黑白图没有参考色也缺乏人力去涂色那就得用颜色迁移。颜色迁移的思路特别直白找一张颜色风格符合预期的彩色参考图把参考图的色度统计特性“移植”到目标灰度图上。常见的做法是Reinhard等人提出的颜色迁移算法步骤是将目标灰度图和参考彩色图都转换到Lab空间。Lab空间的L通道代表亮度a通道代表红绿b通道代表黄蓝。关键洞察在于灰度图的L通道本身就是原始亮度信息我们不需要动它需要做的是把参考图的a、b通道的全局统计量平均值和标准差映射到目标图的a、b通道上。具体映射公式是a_t (a_t - mean(a_t)) * (std(a_r) / std(a_t)) mean(a_r) b_t (b_t - mean(b_t)) * (std(b_r) / std(b_t)) mean(b_r)其中下标t表示目标图r表示参考图。这里有个前提假设目标图的色度分布应该和参考图的色度分布同属一个形态只是数值范围不同。换句话说参考图应该和被着色的场景类型接近比如要着色一幅山水画就找一幅风格类似的山水照片做参考。4.2 完整Matlab实现与代码逐行说明Matlab实现这个算法非常简洁核心只有十几行。我写好了一个完整的函数放在下面function I_colorized color_transfer(I_gray, I_ref) % I_gray: mxn double灰度图范围[0,1] % I_ref: mxn x 3 double 彩色参考图范围[0,1] % 返回: mxn x 3 double彩色图 % 转Lab空间 lab_gray rgb2lab(repmat(I_gray, [1 1 3])); % 亮度图扩展成三通道 lab_ref rgb2lab(I_ref); % 拆分L、a、b L_t lab_gray(:,:,1); a_t lab_gray(:,:,2); b_t lab_gray(:,:,3); L_r lab_ref(:,:,1); a_r lab_ref(:,:,2); b_r lab_ref(:,:,3); % 统计量匹配 m_a_t mean(a_t(:)); s_a_t std(a_t(:)); m_a_r mean(a_r(:)); s_a_r std(a_r(:)); m_b_t mean(b_t(:)); s_b_t std(b_t(:)); m_b_r mean(b_r(:)); s_b_r std(b_r(:)); a_t_new (a_t - m_a_t) * (s_a_r / s_a_t) m_a_r; b_t_new (b_t - m_b_t) * (s_b_r / s_b_t) m_b_r; % 重建Lab图像 lab_new cat(3, L_t, a_t_new, b_t_new); % 转回RGB I_colorized lab2rgb(lab_new); I_colorized max(0, min(1, I_colorized)); % 防止越界 end这段代码里有一个细节值得解释为什么先用repmat(I_gray, [1 1 3])再转Lab因为rgb2lab只接受RGB图我们用一个三通道完全相同的图作为占位让函数的输入格式合法。转换后取它的L通道作为目标亮度同时得到一个初始的a、b通道。但注意这个初始的a、b通道全图都是同一个值因为灰度图三通道相同所以后面直接用它们计算统计量是没问题的转换后再修正。另一个细节是s_a_r / s_a_t这个比值。如果目标图完全平坦比如纯色背景标准差接近0除法会不稳定。实践中要给标准差加一个极小值比如1e-6防止溢出。我在实际处理中遇到过一张纯白背景图导致a_t标准差为0结果全图颜色完全错误。4.3 如何挑选参考图像风格匹配的关键经验颜色迁移的效果好坏80%取决于参考图的选择而不是算法本身。这是我的血泪教训。同样是蓝天绿草如果参考图是一张阴天的灰色风景着色出来的图也是灰蒙蒙的如果参考图是一张暖色调沙漠照片那草地就会被染成黄褐色。挑选参考图的核心经验有三条第一场景类型要一致。人像、风景、建筑、植物分别找对应的参考图不要混用。人脸肤色和绿植色在Lab空间中的a、b分布完全不同用风景图给人脸着色会直接毁掉。第二色彩分布要有代表性。参考图应该包含目标图中可能出现的所有主要颜色。比如给一个包含天空、草地、人物的场景着色参考图最好同时有蓝天、绿草和肤色区域。如果参考图只有蓝天算法会把草地的a、b统计也强行拉到蓝色系导致草地变蓝。第三亮度对比度要接近。虽然算法只迁移色度统计量但参考图本身的亮度分布会影响lab2rgb转换后的视觉自然度。理想情况下参考图的L通道直方图应该和目标灰度图的直方图接近。一个快速检查办法是分别计算两幅图的L通道均值如果差异超过300到100范围就要找另一张参考图了。此外遇到多区域场景时全局统计量匹配会显得有点“平均化”比如天空被染成偏绿草被染成偏蓝。这时候可以使用分块颜色迁移——先对图像做超像素分割然后每个分割区域分别匹配参考图对应区域的统计量。Matlab里可以用superpixels函数但实现复杂度一下子提升不少初学者先用全局版本效果不好再考虑分块。5. 基于深度学习的彩色化进阶可选5.1 用Matlab加载预训练模型提取特征经典方法实现简单但对复杂场景的泛化能力有限。深度学习彩色化的代表工作是Zhang等人提出的“Colorful Image Colorization”和Larsson等人利用VGG多层特征的方案。Matlab的Deep Learning Toolbox同样完整支持CNN的训练与推理下面介绍如何在Matlab中实现一个简化版。核心思路是把灰度图的三个通道复制成三通道输入经过一系列卷积层输出两个通道a和b的预测。由于Lab空间中L通道保持原样网络只需要学习a、b通道。训练时用大量彩色图像作为标签计算预测a、b与真实a、b之间的损失。训练网络的第一步是准备好数据集。MATLAB有内置的imageDatastore可以方便地读入大量图片。每张彩色图先转成Lab空间输入网络的数据是调整大小后的RGB图灰度图复制三通道目标输出是原图的a、b通道。为了降低训练难度可以使用预训练模型如AlexNet或VGG16作为特征提取器。不过完整迁移学习需要较大的显存和较长的训练时间我建议从零训练一个小型UNet结构因为彩色化任务相对于高层次的图像分类来说对语义信息的要求不高一个小网络就能学会颜色分布。5.2 构建一个简易卷积网络并训练下面是一个极简的CNN网络定义输入224x224x3经过几层卷积和上采样输出224x224x2的ab通道。由于Matlab的layerGraph写起来比较长我用dlnetwork配合自定义训练循环的方式来说明这样更灵活。% 定义网络结构dlnetwork方式 layers [ imageInputLayer([224 224 3], Name, input, Normalization, none) convolution2dLayer(3, 16, Padding, same, Name, conv1) reluLayer(Name, relu1) convolution2dLayer(3, 32, Padding, same, Name, conv2) reluLayer(Name, relu2) % 下采样 maxPooling2dLayer(2, Stride, 2, Name, pool1) convolution2dLayer(3, 64, Padding, same, Name, conv3) reluLayer(Name, relu3) % 上采样 transposedConv2dLayer(4, 32, Stride, 2, Cropping, same, Name, up1) reluLayer(Name, relu4) convolution2dLayer(3, 32, Padding, same, Name, conv4) reluLayer(Name, relu5) convolution2dLayer(3, 2, Padding, same, Name, conv_out) ]; lgraph layerGraph(layers); dlnet dlnetwork(lgraph);训练循环的自定义部分比较长这里不贴出完整代码但提醒几个关键点第一输入数据要做dlarray转换并且指定维度标签SSCB空间、空间、通道、批量来让网络知道数据格式。第二损失函数用简单均方误差即可即预测的a、b通道与真实值之间的MSE不需要像分类任务那样用交叉熵。第三优化器用adamupdate学习率建议从1e-3开始每训练几轮手动衰减到5e-4。在视觉上这个精简网络训练几万步后已经能为简单场景天空、草地、人脸局部生成比较合理的颜色。如果想达到接近商业工具的效果就要用更深的结构如UNet和更大的数据集训练时间通常以天为单位这个超出了本文的篇幅但思路是一致的。5.3 训练数据的组织与数据增强训练数据很重要。不要拿零散的几张图片直接训练那样网络会过拟合给新图着色时颜色完全失真。我的做法是从网络中爬取下载到约1万张风景和人物图片然后做以下预处理每张图调整到256x256中心裁剪到224x224随机水平翻转、随机旋转正负15度、随机亮度扰动。这些操作我用augmentedImageDatastore封装。另外注意训练时颜色空间统一用Lab但输入层的Normalization要设置为none因为Lab空间a、b通道的范围不是0到1默认归一化反而会破坏数值分布。训练时每隔5000步保存一次模型参数同时把当前模型在测试集上的着色结果输出到文件夹看看直观判断效果进展。我发现训练初期模型会把所有东西都染成灰绿色中期开始出现暖色和冷色的区分后期才慢慢出现语义相关的颜色。如果你看到训练很久颜色仍然很平均先检查是不是Lab转换时取值范围搞错了——a、b通道取值范围大约是-128到127网络输出层的取值范围应该与之匹配需要添加一个tanhLayer或自行缩放。6. 常见问题与排查技巧实录6.1 问题速查表我把实战中碰到的高频问题整理成了一张表方便直接对号入座问题现象可能原因解决办法着色后颜色只集中在锚点附近sigma太小权重衰减过快增大sigma到0.2以上或减少亮度差阈值颜色大面积溢出到相邻物体sigma过大或锚点位于边缘减小sigma将锚点往区域内部移动整幅图颜色发灰、饱和度低参考图色彩本身较素换一张色彩饱和度更高的参考图颜色迁移后亮度变了图像过亮/过暗lab2rgb时L通道叠加错误确认L通道用的是目标灰度图的L而不是参考图的L求解稀疏方程报内存不足图像尺寸过大直接法消耗内存把图像缩小到300x300再算或用pcg迭代法深度学习训练损失不下降学习率太高或输入尺寸不匹配调低学习率到1e-4检查输入输出尺寸和通道数训练后颜色结果出现明显横条纹反卷积层上采样重叠改用resize2dLayer或调整kernel stride参数6.2 独家避坑心得这里有几个网上教程里很少提到的坑我逐个踩过值得专门记下来。第一Lab空间的L通道范围是0到100但imshow在显示float类型时默认按0到1解释所以如果你直接imshow(lab)会看到全黑或者整体偏移。显示Lab图像的正确姿势是单独显示a、b通道用imagesc并加上统一的颜色轴。这个bug困扰过我一下午排查时一度以为是算法写错了。第二颜色迁移中的lab2rgb结果会出现轻微越界也就是输出值小于0或大于1。虽然Matlab会自动截断但截断会带来颜色失真。更好的做法是做一个正常的拉伸比如把前1%和99%分位的像素值映射到[0,1]这样能保留更多色彩层次。第三Levin算法中权重计算用的亮度差要在Lab空间或者归一化灰度空间里计算不要在uint8的0到255范围内直接算否则sigma参数的经验值完全对不上。很多初学者在这一步卡住就是因为他们把I当成了uint8exp(-(yd)^2/(2*0.1^2))计算出来的权重几乎都是0因为yd通常取500以上的值。正确做法是先用double转成0到1范围再计算。第四交互式涂色时建议把画笔颜色选得稍微淡一点不要用纯蓝、纯红这些极端色。因为优化求解的过程会平滑颜色如果锚点颜色过于饱和扩散出去的颜色看起来会像荧光笔涂过。我习惯把锚点颜色的饱和度控制在0.5左右Lab中a、b约正负40效果自然很多。第五深度学习训练时记得关闭图的缩放显示否则imshow会把Lab转换后的图像自动拉伸看起来颜色诡异但模型实际上在正常训练。可以每隔几千步存一次用lab2rgb转换后的真实彩色图来检查而不是直接看训练样本。7. 实战扩展把脚本封装成一个小工具彩色化算法折腾成功后很多人都会想把它封装成一个小程序方便批量处理图片。Matlab的APP Designer或者直接写GUI都行但最省事的方案是用uigetfile和uiputfile做一个命令行交互工具。% 批量彩色化脚本 files uigetfile(*.jpg;*.png, 选择黑白图片, MultiSelect, on); if ~iscell(files) files {files}; end for i 1:numel(files) img imread(files{i}); % 这里调用你自己的彩色化函数 out my_colorize(img); % 示意 [~, name, ext] fileparts(files{i}); imwrite(out, sprintf(colorized_%s%s, name, ext)); end这个小脚本最大的价值在于批处理比如给一本扫描版黑白古籍的每一页着色算法跑的慢也没关系让它后台慢慢跑跑完直接在文件夹中看结果。另外提一个提升体验的细节保存结果时建议同时保存一幅对比图——左边原灰度图右边彩色化结果用imwrite把两幅图拼在一起。因为单看彩色化结果很难评估颜色是否合理并排对比能直观看到哪些区域的纹理被颜色淹没了、哪些区域染色染过了。我在做实验时还会把彩色化的结果转成视频展示颜色随时间逐渐扩散的过程这对理解Levin算法的原理非常有帮助。实现方法很简单在求解方程后用drawnow配合getframe持续记录每一轮迭代的中间结果最后用VideoWriter写入mp4。这个方法强烈推荐给学生党做演示。8. 写在最后的一点经验黑白图像彩色化是我接触过的最适合用来练手图像处理的课题之一因为它同时涉及优化理论、色彩空间、统计学习和深度学习算法之间可以形成清晰的对比。我的实验环境从R2019b到R2023b换过多次但从没用过任何付费工具箱以外的代码也没有依赖外部Python库全部功能都在Matlab内部完成。如果让我给后来者一个入门顺序我会建议你先跑通颜色迁移——这个脚本最短、最直观10分钟就能看到彩色化效果建立信心。接着实现Levin优化着色体会“先验约束”在图像修复中的巨大作用。最后再碰深度学习你就会明白为什么深度网络能自动学习到物体语义颜色而不是像一个简单的统计匹配那样盲目平均。最后分享一个我实际使用的小技巧彩色化完成后用imhist检查一下饱和度通道的直方图如果堆积在0附近说明颜色偏淡可以做一个饱和度增强比如在HSV空间把S通道整体乘以1.2。这个操作虽然简单但很多初学者不知道配合使用能让最终效果上一个台阶。希望这篇实战记录能帮你少踩几个坑如果你在跑代码时遇到新的问题欢迎在评论区交流我会尽量把排查思路补进来。