在 Apple Silicon 上初次接触 KAIR:一次图像恢复实践
此前我接触过摄影和数字图像后期处理,对曝光、ISO、白平衡等数字图像相关概念有一些基础了解。这些经历让我对图像质量的变化有过比较直观的认识。为了进一步了解图像恢复方向,我近期尝试配置并运行了 KAIR 这一图像恢复工具箱。
KAIR 基于 PyTorch,包含图像去噪、超分辨率、去模糊等任务,也提供了 DnCNN、USRNet、SwinIR 等模型的训练和测试代码。由于目前对图像恢复方向的理论和模型设计还缺少系统了解,这次实践的目的比较朴素:先把代码配置起来,完成一次测试,再结合输出图像记录自己的初步观察。
环境与安装
这次使用的是一台 Apple M4 MacBook Air,系统为 macOS,Python 版本为 3.11。我在仓库目录中创建了独立的 Python 虚拟环境,并按照项目说明安装依赖。
依赖安装完成后,第一次运行测试脚本时还需要补充安装 matplotlib:
ModuleNotFoundError: No module named 'matplotlib'
当前仓库运行测试脚本时仍需要额外安装这一依赖。这个过程也提醒我,配置研究代码时,除了按照 README 执行主流程,还需要结合实际入口检查运行环境。
下载模型并运行测试
随后运行了仓库提供的预训练模型下载脚本:
python main_download_pretrained_models.py
这一步下载了 model_zoo/dncnn3.pth。为了测试 Set12 上的固定噪声去除效果,我使用了仓库中已有的 dncnn_25.pth,命令如下:
python main_test_dncnn.py \
--model_name dncnn_25 \
--testset_name set12 \
--noise_level_img 25
这里的 noise_level_img 25 表示测试时添加的噪声等级。需要特别说明的是:这次最终测试使用的是 dncnn_25.pth,而不是前一步刚下载的 dncnn3.pth。两者在这次记录中扮演的是不同角色。
测试集一共包含 12 张图像,模型参数量为 555,137。最终得到的平均结果是:
Average PSNR/SSIM(RGB) - set12_dncnn_25
PSNR: 30.43 dB
SSIM: 0.8617
这说明测试流程已经完成,但单独看这两个数字,我还不能理解模型在不同图像上的具体表现,也不能判断它如何处理纹理。因此,我继续逐张对照了原图和输出图,并把下面的内容作为这次运行中的初步观察,而不是严格的实验结论。
逐图观察:去掉噪声,也可能去掉纹理
下面的对比图来自这次实际运行生成的结果。每组图片按照上图为测试图、下图为 DnCNN 输出图的顺序排列。为了让对比更容易复核,我保留了几组具有代表性的样本。
01:条纹噪声去除得最明显
![]()
![]()
在 01 中,背景中的条纹噪声被明显压制,人物、相机和三脚架的主要轮廓仍然保留得比较完整。就主观观感而言,这是这一组中最成功的结果之一:噪声减少带来的收益很明显,而主体结构没有出现同样程度的破坏。
02:墙面砖纹理出现明显损失
![]()
![]()
02 暴露出了另一面。墙壁上的砖块纹理属于密集、重复的高频结构。输出图中,墙面的整体明暗和屋顶轮廓还在,但细密的砖纹明显被平滑掉了。
这让我开始意识到,去噪效果不能只用“噪声有没有变少”来判断。对于模型来说,规则的细纹和噪声在局部统计上可能存在相似之处;模型在抑制噪声的同时,是否也会损失一部分纹理,应该与噪声类型、图像内容和模型设计等因素有关。仅凭这一次观察,我还不能进一步判断具体原因。
03:蔬菜表面细节被部分抹平
![]()
![]()
03 中,蔬菜的整体形状和亮暗关系仍然清楚,但表面细小的起伏、纹理和局部变化变得不那么丰富。这种变化不像 02 的砖墙那样集中,却更容易出现在自然物体上:它们的纹理没有明确的规则,模型更难判断哪些细节应该保留。
05:蝴蝶翅膀边缘变得更平滑
![]()
![]()
05 中,蝴蝶翅膀上的主要黑白图案仍然存在,但深色条纹边缘的细小毛刺和局部锐度有所下降。大尺度结构被保留下来,小尺度边缘被削弱,这种差异在放大观察时尤其明显。
07:羽毛细节明显变软
![]()
![]()
07 中,鹦鹉的轮廓和面部区域基本保持,但羽毛的细碎层次明显减少。对于人眼来说,羽毛、头发、织物和皮肤纹理往往是图像真实感的重要来源;它们被平滑后,图像虽然更干净,却也更像经过了轻微的涂抹。
这次运行让我想到的事情
完成 DnCNN 的测试后,我观察到模型能够较好地去除背景中的随机噪声,但与此同时,墙面瓷砖的纹理、缝隙以及人物面部的部分细节也出现了一定程度的平滑。这让我第一次较为直观地感受到,图像去噪算法需要在噪声抑制与细节保留之间进行权衡。
虽然目前我还不了解模型背后的具体设计原理,但这也让我产生了进一步阅读论文、理解模型设计的兴趣。
PSNR 和 SSIM 不能替代逐图观察
30.43 dB 的平均 PSNR 和 0.8617 的平均 SSIM 能够概括整体效果,但它们无法说明 01 和 02 之间的差异,也无法直接表达“砖纹被抹平了多少”。如果只看最终指标,很容易错过模型在不同类型纹理上的行为差异。
去噪本质上包含了保真度取舍
DnCNN 的目标是从带噪图像中恢复更干净的图像,但“干净”和“细节完整”并不总是同时达到。噪声越像真实纹理,去除它时误伤纹理的风险就越高。这次 Set12 的结果让我第一次比较直观地看到,图像复原并不是简单地把错误像素擦掉,而是需要在噪声抑制和细节保留之间进行取舍。至于模型具体依据什么进行这种取舍,我目前还没有足够的理论基础去解释。
跑通代码只是开始
这次实践让我初步建立了从依赖、模型、测试参数到输出图像之间的联系:
环境配置
→ 模型与测试集
→ 噪声等级
→ 推理输出
→ PSNR / SSIM
→ 逐图分析
回看输出图像之后,我才开始意识到指标背后还对应着具体的视觉变化。
后续计划
接下来,我希望继续尝试不同噪声等级和其他 DnCNN 模型,并进一步运行一个超分辨率模型。同时,我也想阅读测试脚本和模型实现,弄清楚数据预处理、噪声添加、推理和指标计算分别发生在哪里。
这只是一次简单的环境配置和测试,但它让我第一次真正接触到了图像恢复项目的代码组织方式,也让我意识到,相比于看到最终效果,我更想理解模型为什么能够产生这样的效果。
对我来说,比较有意思的并不是项目最终能够运行,而是第一次有机会观察图像恢复模型在图像上的实际作用:噪声消失的同时,一些细小纹理也变得更加平滑。图像恢复并不只是让图像变得“更干净”,其中始终存在去除噪声与保留细节之间的权衡。虽然我目前对背后的原理还了解得很少,但这次小实验让我更想继续看看模型是怎样做出这种取舍的。