如何科学而正确地去除色罩?
2026.6.21
更新了专栏文章,尝试用纯计算的方法模拟理想完美的印相光源,获得理论上电影负片印相到2383上的色彩重现结果。欢迎讨论!
色罩、密度和光源 - 刘磊的文章 - 知乎
以下为原回答
这其实不是一个关于去色罩的文章,算得的上是彩色负片数字化“邪修”吧。

在我把一个负片翻拍得到的raw文件转换成TIFF格式图像并尝试用Photoshop打开时,软件询问我,该为这个图像指定什么色彩空间。对啊,彩色负片的扫描档或是翻拍档中记录下来的像素,究竟代表什么呢?不似反转片,底片就是供人眼观看的最终产物。如果用相机翻拍反转片,作为图像观看还算说的过去。但是彩色负片数字档里的RGB值该如何理解呢?显然它不是一张传统意义上的“照片”。也就是说,该如何给传感器响应值进行“上色”呢?
也许,答案应该从“光学印相”中寻找。

彩色负片并不是直接给人眼观看的,是要在暗房里印相到银盐相纸上的。放大机用卤素光源照射底片,宽谱光透过底片,投影到感光相纸上。通过调整曝光时间调节照片的明暗,通过调节混光桶里滤色片的遮光量调节照片的色彩平衡,再辅以高级的蒙版(mask)技巧调节局部曝光,输出最终的结果--照片。
所以,负片没有色彩,相纸才有色彩。那些冰冷的传感器值的最佳翻译方法,就是模拟印相过程,模拟人眼看到相纸上图像的过程。

这个想法早在我了解了一些色彩科学知识后就涌现出来了。同时期网上已经有非常多爱好者的硬核科普文章,甚至也有很多人也在做或是已经做完了我打算做的事情。但我还是打算先不看这些资料,将这些作为自己业余的爱好研究打发时间。
这里介绍一个简化的光学印相模型。透过底片某处的光谱函数分别和相纸生成CMY三种染料的感光层光谱敏感函数相乘,乘积函数的积分结果等比例于相纸该处的三层染料曝光值,
其中为 CMY 各层的曝光量,
为透过底片后的光谱函数,
为相纸各感光层的光谱敏感函数。曝光值会根据相纸的感光特性映射得到每层染料的密度,
其中为最终得到的染料密度,
为该层乳剂的特征映射函数,通常呈“S”型曲线。再结合密度数据和相纸染料的漫射光谱特性,计算出相纸该处的光谱反射率函数,
其中为相纸处的最终光谱反射率,
为相纸白基底的反射率,
为各染料在单位密度下的归一化光谱吸收特性。此时用一个标准光源谱函数和反射率函数乘积,再分别与标准观察者色匹配函数积分,就可以得到三刺激值,
其中 ,
为观看环境下的标准光源光谱函数,
,
,
为 CIE 标准观察者色匹配函数。有了三刺激值,就可以转换到任意的色彩空间,底片的“上色”步骤就完成了。

模拟印相理论上实现起来非常简单,但是从理论模型到工程实际间存在着巨大的鸿沟。这期间走了很多弯路,写了海量的代码,花了非常多的时间精力去试验。
首先,计算相纸曝光值这一过程几乎是不可实现的,因为根本没办法测量透过底片每一处的光谱。虽然我们可以寻找三种分别完全匹配相纸三条光谱敏感函数的光源,如下图,

然后采集它们透射底片后的光强,作为曝光值进行后续计算。也就是现在连我奶奶都知道的用窄带光源翻拍底片的流程。但是,仅就波峰来讲,红光波峰700nm,都快到CMOS红外滤镜截止频率了,更不要说找到光谱形状完全匹配的光源,简直就是天方夜谭。光源问题先挖个坑后面讨论,这里最终使用了波峰660nm红光的窄带RGB LED光源作为近似替代。(这目前是我能找到的最接近700nm的光源,https://tinker.koraks.nl/photography/why-rgb-leds-suck-for-a-color-ra4-enlarger/中提到了LED光源对印相的影响,读者有兴趣可以查看)

然后是如何测量透过底片的这三种窄带光的曝光值。这里使用数码相机翻拍。最“正确”的方法,应该是类似三色摄影的方法,分别用三种波长的光独立照射底片进行拍摄,每张图像作为每个通道的灰阶合成RGB图像。黑白传感器是最适合的,连解拜耳都省了。我只有普通拜耳阵列传感器,不过也完全可以。翻拍的图像的像素值,就代表了底片在一种“虚拟”相纸上的曝光值,这种相纸的光谱敏感曲线形状完全匹配窄带光源的光谱。后面提到的所有“相纸曝光值”本质上说的都是这里测量并三色合成出的像素值。
接着是影调和反差,即曝光值如何对应到染料密度。相纸等印相材料文档一般会提供H&D曝光特性曲线,如下图,

理论上对像素值取对数,就得到了H&D曲线的横轴,查询曲线就可以知道染料密度。但直接从曲线上无法得到纯净的CMY染料密度。无论是柯达的RA4相纸还是电影正片2383,H&D曲线都注明了Status A密度。这意味着上面的密度数据是一个符合Status A标准滤镜下的“积分密度”(Integral Density)。而精确模拟印相需要的是真实的染料层密度,也就是“分析密度”(Analytical Denstiy)。自然有方法可以从Status A积分密度转换到染料层的分析密度,后面可以和光源问题一块讨论。总之,对于模拟印相的重点是,我们需要得到一个密度的范围和斜率作为输出图像的动态范围和反差基准。
然后是色彩和调整。相纸文档一般都提供了三层染料的漫射光谱特性曲线,如下图,

结合染料密度按照公式进行积分得到CIE XYZ三刺激值,再转换到可供显示的色彩空间,比如sRGB、Adobe RGB等,就完成了对Photoshop询问的问题的解答。色匹配积分和色彩空间转换算法都有成熟的代码库。
色彩平衡的调整就是调整相纸每个感光层的曝光量,从数学模型上看即对整体的对数曝光值做加减操作。这有点像现在连我太奶都知道的对数域去色罩流程。区别在于,这是一个从相纸曝光值到最终照片的映射,而非底片密度到照片像素值的映射,没有对密度值的直接“反相”,相纸等印相材料的减色特性完美隐藏了对数域去色罩的“反相”操作。实际操作中,由于从相纸对数曝光值到显示色彩空间的映射和积分计算非常耗时,我预计算了一个3D-LUT,用于将线性的虚拟相纸对数曝光值转换到显示色彩空间。同时,由于我个人简陋的冲洗条件和随缘的温度控制,我需要一个可以完全控制的数字化调整流程,Photoshop无疑是最好的选择。把相纸的三个感光层对数曝光值,分别作为RGB通道像素值写进tiff文件,用PS打开这个tiff文件后,选择这个3D-LUT作为最上层的上色图层,所有对相纸曝光的调整都是对其下曲线图层的调整,最后经过最上层的印相LUT实时显示。理论上曲线平移就可以完全模拟暗房里放大机滤光片的调整,对于糟糕的冲洗结果,也许需要额外的分别调整每个通道的曲线斜率等。至于个性化色彩调整,也可以在PS中一并打包处理了。

最后说一下整个流程中的色彩管理。
采集阶段,不需要、也不能有任何色彩管理。在对CMOS线性响应的假设下,必须拿到纯粹的传感器本征色彩空间下的像素值,没有白平衡补偿系数,只做黑场补偿。目前成熟的商业软件,都会最终给传感器raw像素值“上色”,也就是转换到一个目标色彩空间,这个转换是我极力避免的。对于开源软件Rawtherapee,虽然可以选择input profile为none避免传感器值到工作色彩空间的转换,但是工作色彩空间到output profile的转换无法避免。save reference image功能可以做到全避免,但一来没有命令行支持该功能,二来rawtherapee也不好集成在脚本甚至自定义代码库中。Dcraw的-o选项的0参数也可以做到,但是dcraw质量最高的解拜耳算法还是古老的AHD算法,我个人觉得效果不好,远不如Rawtherapee默认的amaze算法,更不要提商业软件的闭源算法了。不过还好Rawtherapee是开源的,我最后干脆自己移植了amaze算法结合libraw库到我的处理流程中。总之采集到的值需要绝对的线性,绝对的“raw”,绝对的“无色”。
处理阶段需要色彩管理,分为三部分要对齐。第一个是图像部分,对三色照片进行合成,然后转换到对数域,准备写出到供PS处理的tiff文件时,仍然要保持线性,即嵌入一个线性gamma的icc配置文件,比如自定义一个gamma为1.0的Prophoto RGB色彩空间;第二个是生成3D-LUT时的目标色彩空间,需要和嵌入tiff的色彩空间一致,即也需要转换到gamma为1.0的Prophoto RGB色彩空间;第三个是PS工作空间,也要和上面两者保持一致,这是为了确保曲线调整是在做没有gamma影响的线性变换。三者任何一者改变,都要同步改变。

总结一下,这个数字化流程主要分为两大部分:后端是对于相纸曝光情况的模拟,主要是一些代码体力活;前端是对曝光后染料密度到色彩的模拟,涉及到色彩科学处理和图像调整。后端我取巧的使用了一个“不太”近似相纸感光特性的窄带RGB光源,直接得到虚拟的相纸曝光值,暂时避免了底片密度域的处理。前端使用成熟的Photoshop软件结合预计算的3D-LUT在色彩管理流程中进行色彩调整和实时显示。这里没有任何高深的理论和公式,但这其中还有大量的问题没有解决,可能也有大量的争议需要澄清。

限于时间和篇幅,我在前端部分色彩科学里遇到的一些“玄学”,以及后端“分析密度”的讨论会在我的专栏中继续。