简介这份资源面向计算机相关专业的在校学生、教师及企业员工提供一套基于深度学习CNN网络实现图像着色的完整Python源码可用于课程设计、毕业设计、大作业或初期项目立项演示。压缩包共40个文件约17.52MB包含14个py源码文件、12张png效果图、10个pyc编译文件以及txt说明和pdf参考文献源码涵盖eccv16、siggraph17等经典着色模型及工具模块结构清晰便于按模块学习。目前已有50人学习下载。读者可借此掌握CNN图像着色从数据到推理的完整流程理解模型组织与调用方式并参考效果图与文献进行二次开发或功能扩展适合入门进阶与项目借鉴。1. 从一张泛黄老照片说起CNN图像着色到底在做什么手里有一张上世纪的黑白照片人脸模糊、天空灰白、衣服看不出颜色。你想把它变成彩色但手工上色一张要几个小时还未必自然。基于深度学习CNN网络实现图像着色解决的就是这件事输入一张灰度图或L通道输出对应的a、b两个色度通道再和原L通道拼回RGB彩色图。它适合三类人想入门深度学习但不想只跑MNIST的Python开发者、需要批量处理老照片的影像从业者、以及想拿一个完整源码项目练手CNN回归任务的学生。这个方向不算新但它是极好的练手项目——输入输出都是图像损失函数直观训练过程肉眼可见地在变好。更关键的是它把CNN从“分类”拉到了“回归生成”的领域你会第一次认真思考为什么预测颜色这么难因为同一张灰度图天空可以是蓝色也可以是橙色模型必须学会“合理”而不是“唯一”。2. 图像着色的CNN架构选型从编码器-解码器到U-Net2.1 为什么着色任务不适合直接套用分类网络图像着色本质上是一个逐像素回归问题。输入是H×W×1的灰度图输出是H×W×2的ab色度图。分类网络如ResNet、VGG最后接全连接层输出类别概率这个结构对着色毫无用处——你需要的是和输入同分辨率的空间输出而不是一个类别标签。常见做法是采用编码器-解码器结构编码器用卷积池化逐步降采样提取语义特征解码器用转置卷积或上采样逐步恢复分辨率。但朴素编码器-解码器有个致命问题降采样过程中空间细节丢失上色结果边缘模糊、颜色溢出。我一般会直接上U-Net因为它的跳跃连接skip connection把编码器的高分辨率特征直接拼到解码器对应层边缘和纹理信息得以保留。对于着色任务这个改进不是锦上添花是刚需。另一个选型点是输入输出空间。不要在RGB空间直接回归因为RGB三个通道高度相关模型容易学成“灰色平均”。标准做法是转到Lab色彩空间L是亮度a和b是色度。输入只给L让模型预测a和b任务解耦更干净。这也是学术界和工业界最通用的方案。2.2 用PyTorch搭一个最小可用的着色U-Net下面这段代码是一个可以直接跑通的U-Net着色网络定义。我刻意把通道数压小方便你在单卡甚至CPU上先验证流程。import torch import torch.nn as nn import torch.nn.functional as F class ColorizationUNet(nn.Module): def __init__(self): super().__init__() # 编码器输入1通道(L)逐层升到256通道 self.enc1 self._block(1, 64) self.enc2 self._block(64, 128) self.enc3 self._block(128, 256) self.enc4 self._block(256, 256) self.pool nn.MaxPool2d(2) # 瓶颈层 self.bottleneck self._block(256, 512) # 解码器转置卷积 跳跃连接拼接 self.up4 nn.ConvTranspose2d(512, 256, 2, stride2) self.dec4 self._block(512, 256) # 256(上采样)256(skip)512 self.up3 nn.ConvTranspose2d(256, 128, 2, stride2) self.dec3 self._block(256, 128) self.up2 nn.ConvTranspose2d(128, 64, 2, stride2) self.dec2 self._block(128, 64) self.up1 nn.ConvTranspose2d(64, 32, 2, stride2) self.dec1 self._block(64, 32) # 输出层2通道对应a、b用tanh限制到[-1,1] self.out_conv nn.Conv2d(32, 2, 1) self.tanh nn.Tanh() def _block(self, in_ch, out_ch): return nn.Sequential( nn.Conv2d(in_ch, out_ch, 3, padding1), nn.BatchNorm2d(out_ch), nn.ReLU(inplaceTrue), nn.Conv2d(out_ch, out_ch, 3, padding1), nn.BatchNorm2d(out_ch), nn.ReLU(inplaceTrue), ) def forward(self, x): # 编码路径 e1 self.enc1(x) # [B,64,H,W] e2 self.enc2(self.pool(e1)) # [B,128,H/2,W/2] e3 self.enc3(self.pool(e2)) # [B,256,H/4,W/4] e4 self.enc4(self.pool(e3)) # [B,256,H/8,W/8] # 瓶颈 b self.bottleneck(self.pool(e4)) # [B,512,H/16,W/16] # 解码路径 跳跃连接 d4 self.up4(b) d4 self.dec4(torch.cat([d4, e4], dim1)) d3 self.up3(d4) d3 self.dec3(torch.cat([d3, e3], dim1)) d2 self.up2(d3) d2 self.dec2(torch.cat([d2, e2], dim1)) d1 self.up1(d2) d1 self.dec1(torch.cat([d1, e1], dim1)) return self.tanh(self.out_conv(d1)) # [B,2,H,W]逻辑说明编码器每经过一个_block后做一次2倍下采样特征图尺寸减半、通道翻倍。瓶颈层在H/16分辨率上提取全局语义。解码器每一步先转置卷积放大2倍再和编码器同分辨率的特征在通道维拼接最后过卷积块融合。输出层用1×1卷积压到2通道tanh把值域限制在[-1,1]和Lab空间中a、b的归一化范围对齐。参数说明_block里的两个3×3卷积是标准配置padding1保证尺寸不变。BatchNorm加速收敛如果显存吃紧可以换成InstanceNorm。转置卷积的kernel_size2、stride2是精确2倍上采样的常用组合。输出通道数必须是2这是Lab空间决定的不要改成3。2.3 损失函数怎么选L1、L2还是分类式着色任务最常用的损失是L1损失平均绝对误差直接对预测的a、b和真实的a、b做逐像素比较。L2MSE也可以但L2对异常值更敏感容易让模型偏向“安全”的灰色。实践中L1收敛更稳颜色更饱和。但纯L1有个问题它假设每个像素的颜色是确定的而实际上同一灰度值可能对应多种合理颜色。进阶做法是把a、b空间量化成313个色块bin把回归问题转成分类问题用交叉熵训练推理时取概率最高的bin或做软编码。这个方案来自2016年的一篇经典工作效果比纯回归好但实现复杂度高不少。我的建议是先用L1跑通全流程确认数据管道和网络结构没问题再考虑升级到分类式。# L1损失直接比较预测ab和真实ab criterion nn.L1Loss() # 训练循环中的关键一行 pred_ab model(L) # [B,2,H,W] loss criterion(pred_ab, true_ab)参数说明L1Loss没有超参数直接调用即可。如果发现颜色偏灰可以尝试对损失加权比如对a、b通道分别给不同权重或者加入梯度惩罚项让边缘更锐利。3. 数据管道与训练流程从ImageNet到自定义照片3.1 数据从哪来、怎么转Lab、怎么归一化着色模型的训练数据就是彩色图像本身。你不需要标注任何彩色图都可以ImageNet、COCO、你自己的相册。流程是读入RGB图 → 转Lab → 取L作为输入、ab作为标签 → 归一化。import numpy as np from PIL import Image import torch from torch.utils.data import Dataset, DataLoader import torchvision.transforms as T class ColorizationDataset(Dataset): def __init__(self, image_paths, size256): self.paths image_paths self.size size self.resize T.Resize((size, size), interpolationT.InterpolationMode.BICUBIC) def __len__(self): return len(self.paths) def __getitem__(self, idx): img Image.open(self.paths[idx]).convert(RGB) img self.resize(img) img np.array(img).astype(np.float32) / 255.0 # RGB - Lab注意skimage的Lab范围 from skimage.color import rgb2lab lab rgb2lab(img) # L:[0,100], a:[-128,127], b:[-128,127] L lab[:, :, 0] / 50.0 - 1.0 # 归一化到[-1,1] ab lab[:, :, 1:] / 128.0 # 归一化到约[-1,1] L torch.from_numpy(L).unsqueeze(0).float() # [1,H,W] ab torch.from_numpy(ab).permute(2,0,1).float() # [2,H,W] return L, ab # 使用示例 dataset ColorizationDataset([photo1.jpg, photo2.jpg]) loader DataLoader(dataset, batch_size16, shuffleTrue, num_workers4)逻辑说明rgb2lab把RGB转到Lab空间。L通道除以50再减1映射到[-1,1]ab通道除以128也大致落在[-1,1]。这样输入输出都在同一量级训练更稳定。参数说明size256是常用训练分辨率太小丢失细节太大显存吃不消。batch_size16是8GB显存下的保守值可以按需调整。num_workers4加速数据加载Windows下如果报错就改成0。3.2 训练循环与关键超参数import torch.optim as optim device torch.device(cuda if torch.cuda.is_available() else cpu) model ColorizationUNet().to(device) optimizer optim.Adam(model.parameters(), lr1e-4, betas(0.5, 0.999)) criterion nn.L1Loss() for epoch in range(50): model.train() total_loss 0 for L, ab in loader: L, ab L.to(device), ab.to(device) pred model(L) loss criterion(pred, ab) optimizer.zero_grad() loss.backward() optimizer.step() total_loss loss.item() print(fEpoch {epoch1}, Loss: {total_loss/len(loader):.4f})参数说明Adam的lr1e-4是着色任务的常用起点太大颜色会震荡太小收敛慢。betas(0.5, 0.999)是GAN训练中的经典设置纯回归任务用默认(0.9, 0.999)也行。训练50轮是起步实际到100轮以上颜色才比较自然。每轮打印平均损失如果损失卡在0.05左右不降说明模型容量或数据量到瓶颈了。3.3 推理把预测的ab拼回彩色图def colorize(model, img_path, device): model.eval() img Image.open(img_path).convert(RGB) img img.resize((256, 256)) arr np.array(img).astype(np.float32) / 255.0 from skimage.color import rgb2lab, lab2rgb lab rgb2lab(arr) L lab[:, :, 0] / 50.0 - 1.0 L_tensor torch.from_numpy(L).unsqueeze(0).unsqueeze(0).float().to(device) with torch.no_grad(): pred_ab model(L_tensor).cpu().numpy()[0] # [2,H,W] # 反归一化 pred_ab pred_ab.transpose(1, 2, 0) * 128.0 lab_out np.zeros((256, 256, 3)) lab_out[:, :, 0] (L 1.0) * 50.0 lab_out[:, :, 1:] pred_ab rgb_out lab2rgb(lab_out) return (rgb_out * 255).astype(np.uint8)逻辑说明推理时只取L通道送入模型得到预测的ab后反归一化和原始L拼成完整Lab再转回RGB。注意lab2rgb输出是[0,1]浮点乘255转成uint8才能保存。参数说明推理分辨率必须和训练一致否则跳跃连接的尺寸对不上。如果要用不同尺寸需要把网络改成全卷积结构并处理padding。4. 避坑与排查着色模型翻车的五个血泪现场4.1 输出全是灰色颜色去哪了现象训练几十轮后推理结果几乎还是灰度图只有极淡的色偏。原因最常见的是损失函数用错。如果用MSE且学习率偏大模型很快学会“预测ab接近0”这个安全策略因为灰色在所有样本上平均损失最低。另一个原因是ab归一化范围不对导致梯度消失。解决换L1损失检查ab是否真的落在[-1,1]。如果还不行在损失里给ab通道加权比如loss 1.0*L1(pred, target) 0.5*L1(pred[:,0], target[:,0])强制模型关注色度。4.2 颜色溢出到不该有的区域现象天空的蓝色渗到建筑上人脸的颜色糊到背景。原因编码器降采样太狠空间信息丢失严重。或者跳跃连接没加解码器只能靠低分辨率特征猜颜色。解决确认U-Net的skip connection正确拼接。如果还溢出减少下采样次数比如从4次降到3次。另一个技巧是在损失里加入感知损失用预训练VGG提取特征做比较能显著改善边缘。4.3 训练损失降了但视觉效果没变好现象Loss从0.1降到0.03但生成的彩色图看起来还是脏脏的。原因L1/L2损失优化的是像素平均误差和人类视觉感知不一致。模型可能学会了“平均颜色”但缺乏饱和度和对比度。解决引入对抗损失加一个判别器判断生成图是真是假。这就是着色GAN的思路。判别器用PatchGAN输出N×N的patch真假概率。对抗损失让颜色更鲜艳、更真实。代价是训练不稳定需要调GAN的权重。4.4 显存爆炸batch size只能设1现象训练时OOM只能把batch size降到1训练极慢。原因U-Net在256×256分辨率下第一层64通道的特征图占大量显存。加上跳跃连接保留所有中间特征显存占用是普通CNN的好几倍。解决用混合精度训练AMP显存直接减半。代码里加torch.cuda.amp即可。另一个办法是把训练分辨率降到128或者用梯度累积模拟大batch。from torch.cuda.amp import autocast, GradScaler scaler GradScaler() with autocast(): pred model(L) loss criterion(pred, ab) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()4.5 推理速度慢一张图要好几秒现象模型在GPU上推理一张256×256的图要2-3秒批量处理老照片时等不起。原因U-Net的转置卷积和跳跃连接拼接在推理时也有大量计算。如果没开torch.no_grad()还会额外占用显存和计算。解决推理时务必加with torch.no_grad():。导出ONNX或TorchScript做图优化。如果还慢把模型通道数减半或者用MobileNet作为编码器骨干。5. 进阶技巧让着色结果从“能看”到“好看”跑通基础版本后你大概会发现颜色是有了但总差一口气。天空不够蓝草地不够绿人脸偏黄。这不是模型不够大而是损失函数和训练策略的问题。我自己的经验是从L1升级到L1对抗损失感知损失视觉质量会有质的飞跃。具体做法保留U-Net作为生成器加一个PatchGAN判别器。判别器输入是ab通道或Lab三通道输出是N×N的真假概率图。生成器损失 L1损失 0.1×对抗损失 0.01×感知损失。感知损失用预训练VGG16的relu3_3层特征做比较。这个组合在多个公开数据集上都被验证有效。另一个技巧是训练数据增强。着色模型对数据量很敏感ImageNet的128万张图是底线。如果只有几千张照片必须做增强随机裁剪、水平翻转、颜色抖动对输入L做轻微亮度扰动。注意不要对ab做颜色抖动那会破坏标签。还有一个容易被忽略的点推理时的后处理。模型输出的ab可能有噪声可以用双边滤波或导向滤波平滑一下边缘保持的同时去掉色斑。如果做视频着色还要在时间维度上做一致性约束否则相邻帧颜色会跳。最后说一个我踩过的坑不要用太小的数据集硬训。我曾经用500张风景照训了200轮结果模型把所有天空都涂成紫色。后来换成ImageNet子集5万张同样的网络结构颜色立刻正常了。着色任务对数据多样性的要求比分类任务还高因为模型要学的不是“这是什么”而是“这应该是什么颜色”——后者需要见过足够多的场景组合。希望帮到你。本文还有配套的精品资源点击获取
企业数字化 ERP 产品动态
相关推荐
DBC导入ISOLAR-A的五个典型坑:编码、属性、字节序、扩展帧、节点映射 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/28 1:51:51
5脚188数码管驱动全解析:查理复用原理、贴片直插差异与代码实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/28 1:51:51
STM32 PWM转DAC实战:二阶RC滤波器设计与OrCAD仿真 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/28 1:51:51
Python搭建QQ聊天机器人极简教程 随着QQ粉丝群管理需求的不断增长,简单的群管工具难以满足复杂的信息响应和自动化需求。现有的自动回复机器人虽然功能强大,但其高昂的年费成为不少用户的顾虑。因此,通过搭建一个自定义机器人来实现自动回复,成为解决这一问题的有效途径。
基于此需求,本文介绍了使用go-c… · 2026/9/28 2:14:08
Python整理百度云盘文件大量重复无用文件 百度云盘容量有限,当文件数量逐渐增多,空间很容易被填满。删除重复文件可以帮助释放大量空间。通过获取云盘缓存目录并使用Python脚本来整理数据,可以高效识别重复文件并避免手动操作的繁琐。
此方法基于 sqlite3 和 pandas 进行数据处理,简单快捷。 文章目录 云盘数据整理… · 2026/9/28 2:14:07
Python实现将图片转化为具有视觉震撼效果的字符图 字符画是一种将图片转化为字符的艺术表现形式,它通过字符的密度和排列来模拟图片的色彩和形状效果。这种技术不仅在视觉上充满了创造力,还在文字处理领域展示了字符的丰富表现力。通过Python,可以将图片转换为字符画,生成具有视觉冲击力的字符艺术。
本文将通过具体步骤和… · 2026/9/28 2:13:48
Python实现将目录下的图片合并成PDF文件 在图像处理和文档管理中,经常需要将一系列图片文件合并为PDF格式,以便于传输、存档和阅读。Python凭借其丰富的第三方库,为图像处理和PDF操作提供了便捷的解决方案。
本文将详细介绍如何通过Python脚本,将目录中的所有图片合并为一个PDF文件,内容包括从基础环境配置到代码… · 2026/9/28 2:13:48
Python实现文件移动到指定文件夹 在编程过程中,经常需要对文件进行整理和管理,将不同类型的文件分类存放在指定文件夹中。Python提供了强大的文件操作模块,使得文件的移动操作变得简单高效。这篇教程将详细讲解如何使用Python实现将文件移动到指定文件夹的功能,帮助理解并掌握文件操作的基本方法和常见应用… · 2026/9/28 2:13:47
【PyQt】PyQT6制作一个Django项目启动器 在现代的桌面和Web应用开发中,Python以其简单高效的特点获得了广泛的应用。通过集成PyQt和Django框架,将桌面应用的便捷操作与Django项目的后端处理相结合,不仅能够提升用户体验,更能显著提高开发的便利性和效率。
本文将聚焦于如何构建一个基于PyQt的Django项目启动器,实… · 2026/9/28 2:13:40
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
制作网页比较方便的软件怎么选?一文搞懂避坑指南 制作网页比较方便的软件怎么选?一文搞懂避坑指南 很多老板一上来就问:做个网站多少钱?但我反问他:你的域名买了吗?服务器租了吗?他一脸懵。这就是典型的“域名服务器搞不懂”。别急,今天咱们不聊虚的,直接 一文搞懂 那些让你头秃的技术名词。… · 2026/9/28 0:00:06
婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量 婚恋网站实战案例:避开3个高价坑,省钱50%还能跑赢流量 找婚恋网站建站公司,最怕的就是被坑高价。很多同行跟我吐槽,报价单上写得模棱两可,功能栏里全是“高级定制”、“专属UI”,结果落地全是套壳。今天不聊虚的,直接甩几个我经手的 实战案例… · 2026/9/28 0:00:19
济南做网站多少钱:3个案例拆解,防黑源码下载全攻略 济南做网站多少钱:3个案例拆解,防黑源码下载全攻略 上周济南一个做建材的老板找我,脸都绿了。他的官网首页弹出了赌博广告,后台被植入了挖矿脚本。他慌得问我:“网站被黑挂马不知道怎么办?能不能直接找之前的外包公司要源码下载,看看哪里被动了手脚?… · 2026/9/28 0:00:25