【转载请注明来源和作者】

虽然你可能拥有不止一个相机,而且现在用手机也能拍出精彩的照片,但你肯定也曾困惑过,为什么数码相机(单反),包括手机,可以拍出精彩的照片,它们跟传统的照相机到底区别在哪里?其实我自己也曾很困惑。我依稀记得我大学期间使用的相机都还是胶卷式的,怎么突然满大街都是数码相机和手机,人们甚至已经习惯了用手机来拍照,连数码相机都要被淘汰掉了似的。科技实在是进步得太快了。

现在让我们停下脚步,仔细的来探究一下,包括手机在内的数码摄影设备是如何将入射光转换为最终的JPEG格式的图片的。我会回答两个问题:

  1. RAW文件是如何生成的?
  2. 相机如何将RAW数据转换为最终我们看到的RGB图像(并存储为常见的JPG格式文件)

下图正是照相机将入射光转换为「常规」图像的完整操作序列。

我们今天会谈到的内容有感测器(Sensor),模拟前端(Analog front-end),颜色滤镜(Color Filter),相机内图像处理(红框内黄色部分)这几个主题。

一. RAW图像是如何得到的?

让我们先看看现代数码相机的工作流程示意图。可以看到,从物体上传来的入射光通过相机的光学器件(蓝框部分)后会穿透颜色滤镜到达感测器,并通过模拟前端转化为数字信号(绿框部分),最后通过相机内的图像处理系统转换为最终的RGB格式图像,并存储为常见的JPG文件。

这一节我们先忽略光学部分,直接学习绿框部分的感测器、模拟前端、颜色滤镜,看看它们是如何将接收到的光线转换为RAW图像数据的。

1. 感测器

1.1 感测器的基本组成

正如下图所示,当相机的快门打开时入射光会穿过快门(通过镜头)到达感测器。此时到底会发生什么事?

快门关闭时

快门打开时

正如让爱因斯坦在1921年获得诺贝尔奖的发现「光电效应」所揭示的,入射光子进入感测器后会转换为电子。因此,基本的感测器的设计如下图所示,其目的还是使得微透镜所汇聚的光子能被光电二极体转换为电子并存储在势阱中。

光电效应

基本感测器设计

1.2 感测器的性能衡量

衡量一个感测器的性能的基本指标有:

  • Photodiode quantum efficiency(QE): 光电二极体量子效率
  • Photodiode response function:光电二极体响应函数
  • Photodiode full well capacity:光电二极体满阱容量

量子效率 是指转换的电子数量与入射的光子数量的比值

量子效率(QE)

当不断改变入射光的强度时,转换的电子数量也会发生改变,这构成了上述所说的光电二极体的响应函数。通常来讲这是一个线性函数,如下图所示。 但当势阱饱和(过曝)或者光线过暗(杂讯淹没了信号)时,它将不再是线性的。这个特性与后面之后会讲到的HDR图像的演算法高度相关。

光电二极体的响应函数

势阱的最大容量称为满阱容量,下图显示了常见相机的感测器的满阱容量,由于硅中光子的有限和固定的吸收长度,满阱基本上是像素面积(而不是体积)的函数。

满井容量

1.3 两种不同的感测器:CCD和CMOS

根据读取电路的设计的不同,有两种不不同的感测器类型:CCD和CMOS。它们的区别可以用下表简要的概括。以前高端设备会采用CCD,而中低端、消费级产品才会采用CMOS。而现在的CMOS感测器已经和CCD感测器有相当的性能了,大多数消费级和工业摄像机已经采用了CMOS感测器。

CCD和CMOS的比较

仔细看看CCD和CMOS的结构图如下:

CCD

CMOS

2. 模拟前端

模拟前端

当相机镜头关闭时,模拟前端会从感测器的势阱中读出电子,并转换为模拟信号。这些信号首先被Analog Amplifier(也称为Gain)所放大。大家在相机设置中的ISO通常是会映射为对Gain的放大倍率的设置,而这个模块也跟后续会提到的相机的Vignetting(渐晕)高度相关。

放大后的模拟信号接下来由Analog-to-Digital Converter(ADC)转换为通常是10bits-16bits的数字信号,常见的为12bits。

Look-Up Table (LUT)用于在一定的范围内修正感测器响应的非线性,这个模块同时还能够修复一些损坏的像素的输出。

我们上面提到了一种现象叫做Vignetting,它实际上是指生成的图像四周比中间暗,如下图所示:

Vignetting

Vignetting的产生有多种原因,例如:

  • 机械原因:边缘的光线被滤镜遮挡
  • 镜头原因:边缘光线被镜头内组件所遮挡
  • 物理原因:光衰减与光入射到感测器阵列的角度的余弦的四次方成比例(cos4定律)
  • 像素原因:在正常入射下入射到感测器上的光产生的信号比以斜角入射光的信号强。

有了LUT,可以产生非线性的Gain从而纠正Vignetting现象

纠正Vignetting

通过模拟前端生成的就是我们所说的RAW格式图像,后续的一系列处理都是基于RAW格式图像进行的。当然,不同的相机生产商会以不同的格式来存储RAW格式图像,大家可以查询到很多资料,推荐维基百科上的这一篇,此处不再赘述。

3. 颜色基础

有没有记得前面曾经提到的颜色滤镜?这是起什么作用呢?

基本感测器示意图

在进一步讲解之前,让我们先来了解一下颜色的基础知识。

3.1 颜色到底是什么?

我们知道光是一种电磁波,而颜色并不是光的客观属性——光的客观属性是它的波长。下图展示了几乎完整的电磁波谱,而我们人眼所能看到的只是其中400nm到700nm的一小段,而颜色则是我们对这一小段电磁波的一种主观的感觉而已。

电磁波谱

这种主观的感觉既跟入射光的功率谱分布(SPD)相关,也跟人眼对不同光源的光谱敏感度相关,我们分别来探讨下这两个概念。

3.2 光源的功率谱分布(Spectral Power Distribution - SPD)

通常的光源都由多个波长的光组成,而每一种波长的光的功率一般都不一样。如果画出每种波长的功率和它的波长之间的关系,我们可以得到光源的功率谱分布(SPD)。例如下图展示了几种光源的SPD

功率谱分布(SPD)

3.3 感测器的光谱敏感度函数(Spectral Sensitivity Function - SSF)

不管是数字的还是非数字的感测器,它们对不同波长的入射光线会有不同的敏感度,可以用感测器的谱敏感度函数(SSF)来衡量。感测器对入射光的响应是一个累加了所有光波响应的单一的值,我们可以用一个积分表达式来描述:

感测器响应是入射光SPD与感测器本身的光谱敏感度函数乘积的积分

那么人眼呢?实际上人眼是由包含对不同光波敏感的三种视锥细胞,最终的感觉是由这三种细胞的响应共同构成的,如下公式所示。

三种细胞的响应函数

3.4 颜色滤光阵列(Color Filter Array)

现在我们回到相机的感测器就明白了,为了能在最终的相片中加入颜色信息,人们用颜色滤镜来模拟了不同的视锥细胞。当这些颜色滤镜以预先设定好的形式排列时,就构成了颜色滤光阵列(Color Filter Array)

这里面牵涉两个问题,第一是如何设计滤光镜对不同光线的敏感度,第二是如何设计不同的颜色滤光镜的最佳空间排列(也成为Mosaic)。

下图是Canon 40D和50D的谱敏感函数图比较。每个相机厂商,甚至是同一厂商的不同型号的相机的感测器的SSF都可能不同

Canon 40D 和 Canon 50D 的SSF不同

下图是一些Mosaic设计,其中我们最常用最基础的是Bayer Mosaic。

常见的一些Mosaic设计

因此,当光线通过颜色滤光镜到达感测器,由模拟前端最终转换为数字RAW图像时,图像会变成什么样呢?可以看到RAW图像并未显示出颜色,反而显示出马赛克一样的方块,并且还有大量的杂讯。所以,接下来很重要的就是通过相机内的图像处理系统对图像进行一系列处理,来使之变成最终美观的RGB图像。

RAW图像上的杂讯和马赛克效应

二. 相机如何将RAW数据转换为最终我们看到的RGB图像?

相机内基本处理流程

1. 白平衡(White Balance)

前面讲过,颜色是我们对光的一种主观感受,它直接与我们人眼的SSF以及入射光的SPD相关,那么除此之外,是否跟别的因素相关呢?的确如此,从下图可以看到我们人眼对不同环境光线下拍摄的物体的颜色具有自纠正的作用。

但相机不具备这样的功能,因此如果不经过颜色的校正,拍出来的图片的颜色就会很失真。这就是白平衡的作用:它使得我们人眼感知为白色的物体在最终的成像中也为白色。

白平衡

现在大家用普通的相机一般都会内置一些白平衡选项,可以根据自己的喜好和环境的光线选择合适的白平衡选项进行颜色的矫正:

相机上预设的白平衡设置

实际上,自动白平衡是一个很热门的研究领域,这里我们介绍两种基本的白平衡演算法。正如前面所讲,白平衡是要使得我们人眼感知到的白色最后成像也是白色,那么首先就要确定图像中哪些是白色。这里有两种假设

  • 灰色世界假设(Gray World Assumption)

它假设图像的平均颜色是白色,其基本的演算法可以用如下公式表示

  • 白世界假设(While World Assumption)

它假设图像中最亮的区域是白色,公式如下:

我们会在之后用实际代码来验证这两者的不同。但如果大家观察上述公式会发现,白平衡演算法的前提是要能够获取不同通道的数据,但我们前面已经讲过,RAW格式图像实际上是不带颜色的数据。那么从RAW格式图像中分离三个通道的数据,就是所谓的Demosaicing的过程。

2. 去马赛克(Demosaicing)

在去马赛克之前,每个像素只有一个单一的颜色,而我们是想恢复完整的颜色,如何做到呢?

基本上这是通过「插值」来完成的。 常见的插值方法有:

  • Bilinear插值
  • Bicubic插值
  • Edge-Aware插值

这里我们介绍只需要像素的四个领域即可完成的Bilinear插值,简单讲只需将同一颜色的四个领域取平均值即可:

而对于不同的颜色通道则独立的重复这一过程

3. 去噪(Denoising)

如下图所示,未经去噪处理前的图像通常会包含很多杂讯,尤其是在低光环境下。

杂讯的来源是多样的,例如:

  • 散粒杂讯:由光子到达感测器的数量分布的

图像上的杂讯

随机性导致,场景越量,这种随机分布的方差越小,越不容易产生杂讯。对于比较明亮的场景以及较大像素尺寸的感测器,散粒杂讯是最主要的杂讯来源。

  • 暗粒杂讯:感测器发热导致逸出电子从而产生的杂讯,温度越高,杂讯越大
  • 读取杂讯:由于读取电路引起的杂讯

那么如何去噪呢?我们这里谈论的是相机内的去噪演算法,由于大部分相机本身的运算能力不高,这也意味著无法选择很复杂的不利于硬体化的演算法。这里简单用下面这页图来展示均值滤波和中值滤波,以后还会给大家介绍更多的去噪演算法。

4. 色调重建(Tone reproduction)

现在我们来谈一个很重要的问题:色调重建,也叫做Gamma校正。

我们已经知道,感测器对输入图像的响应大部分是线性的,而且我们人眼对输入光的响应也是线性的。然而,人的感觉却是非线性的,即人对暗光会更加敏感,而这种感觉上的敏感度很接近Gamma函数。与此同时,我们的显示设备相对输入图像通常也是非线性的,在亮光图像更敏感, 如下图。显示器和人眼的特性是相反的,这就加倍使得我们感知中的图像显得很暗。

人眼的响应特性

相机的原始响应是线性的,但是人眼和显示器却是非线性的

我们解决此问题的办法,是对图像做一次Gamma校正,使得真正显示的图片呈现出相反的特性。如果原图为L,那么新的图像会是Lγ, γ一般取2.2.

Gamma校正

gamma校正一般在哪个阶段进行呢?可不可以在拍摄的过程中不进行gamma校正,只是保存图像为jpeg形式,在下一次显示之前才做呢? 通常来说不宜这样,因为当我们把图像保存为jpeg形式是会进行位空间压缩,这会导致信息损失。所以最好是在压缩前就做好gamma校正。大家注意回顾gamma校正的位置:

三、raw图像的获取和处理

到此为止,我相信你已经对我阐述过的模块有了基本的理解。我特意忽略掉了色彩转换这一部分,因为关于颜色我会用专门的文章来做深入的探讨。

此时让我们来尝试模拟从入射光到最终的jpg图像的全过程, 我会把实例模拟分为两个部分:

  1. 获取RAW图像
  2. 用dcraw转换raw图像

1. 获取RAW图像

当我们谈到获取RAW图像时,先回答一个问题:为什么我们需要RAW图像?我们平时用相机拍摄并存储的JPEG图像文件不够好吗?

事实上,JPEG是图像压缩后的存储格式,解压后是RGB图像,它本身正如上面所讲是非线性的,这使得很多计算摄影相关的演算法直接作用到RGB图像上都会产生错误的结果,例如photometric stereo, shape from shading, image-based relighting, illumination estimation, 包括与光传输和反向渲染有关的任何演算法。这时候,最佳的解决方案就是采用线性的RAW图像来替代。

那么如何获取到RAW图像呢?很简单,大部分单反在拍摄时都可以选择保存RAW图像文件。当然每个相机厂商都有自己不同的存储RAW图像的格式,例如Canon的RAW文件格式是CR2,是一种遵循TIFF规范的14bit的RAW文件。这里可以查到更多的信息。

假如你使用手机拍摄呢?你还可以使用lightroom这一款应用,不过注意并不是每一款手机都支持。你可以在这里查到更多的信息。

2 用dcraw转换raw图像

RAW格式文件是否可以直接用Matlab、Python或别的开发工具打开?事实上并不能直接打开。虽然有很多方法可以解决此问题,但这里推荐的一种方法是利用dcraw这个小软体来将RAW格式文件转换为TIFF文件,而后者时可以直接被很多图像处理软体打开的。dcraw的官网在这里:cybercom.net/~dcoffin/d,它由很多可选的参数。

为了3.3节模拟相机内的处理流程,我用下面的命令将一个CR2格式的RAW文件转换为对应的TIFF文件,并确保后者未经过相机内的任何处理,只包含原始信息。

dcraw -4 -D -T <RAW_filename>

dcraw非常强大,可以模拟相机内的的大部分标准流程。例如-a选项就可以模拟用全图信息做灰度世界的白平衡,-q可以用于控制demosaicing的插值质量等等。看官可以自行探索。

例如,我可以用dcraw -4 -D -T banana_slug.cr2轻松的将附件RAW文件转换为了banana_slug.tiff文件,后续就可以用任意一种开发语言来处理它。

四、总结

从入射光到最终的相片,相机拍照的过程是非常复杂的,我们今天的内容对这个过程的大部分基本模块进行了介绍。但是需要注意的是,每个相机厂商都会设计自己私有的、非常复杂的In Camera Image Process Pipeline,很多时候通过最终的成像是完全无法知道其内部到底有哪些私有操作、以及这些操作的顺序的。

如下是这个帖子的核心内容总结,希望本文对你所有帮助,谢谢。

我在如下的Jupyter Notebook中展示了本帖中的相关操作,你可以对著它获取更深入的理解,也能够进一步掌握用Python来进行图像处理的一些技巧。

nbviewer.jupyter.org/gi

跟这一系列专题文章相关的Notebook可以从下面的仓库获取

https://github.com/yourwanghao/CMUComputationalPhotography.git

参考资料:

这一篇文章的绝大部分素材来自于

[1] CMU 2017 Fall Computational Photography Course 15-463, Lecture 2

如果不做特别说明,素材均来自于[1]

我也会参考下面的重要资料中的内容

[2] Richard Szeliski, Computer Vision : Algorithms and Applications,

[3] Michael Brown, 「Understanding the In-Camera Image Processing Pipeline for Computer Vision,」 CVPR 2016


推荐阅读:
相关文章