Process RAW Images in MATLAB
这是一篇由Rob Sumner写于2014年的文章,详细讲述了什么是RAW和在MATLAB中处理RAW文件。以下是对其的补充和若干翻译。
RAW Data及其意义
对于图像处理和计算机视觉来说,研究者往往对于图像本身的含义不感兴趣,他们将图像(往往是8bit的灰度或三通道彩色)视作多变量的函数、随机数构成的矩阵或是一些连接的像素,在此基础上设计算法。
RAW Data真正将场景中光照与图像连接起来,这对于HDR、天文摄影等与传感器行为有关的模型和方法是重要的。在这类问题下,知悉图像被捕获后的整个处理链是必要的。
The best image to deal with is the sensor data straight from the camera, the raw data.
现在(2023),很多设备都具备输出RAW文件的能力,比如中端和高端的单反相机与微单相机,甚至一些手机也可以输出RAW。但他们都将遵循以下几个原则。
RAW特指未经压缩的,包含了传感器像素值和一系列元数据(EXIF)的文件,可以有多种不同的专有的格式(尼康的NEF,佳能的CR2等),也可以是开放的格式,例如DNG(Digital Negative,数字负片)。RAW文件被故意设计成不可解读的数据格式(原文应该指厂商的专有格式),但一些逆向工程已经成功,比如CR2格式。具体请见CR2逆向工程
注:剩余文章中,RAW指代文件,例如CR2,raw指代未经处理的传感器原始数据
Raw Sensor Data的本质
从根本上来说,raw data不是能够被人眼所理解的,它既不包含一个确定的值来定义黑色,也没有确定的白色。raw是一个单通道的强度图像,像素值存储在10-16位数据中(根据不同型号的相机而定),对同一型号的传感器而言,不会有像素值高于某一个特定的值,表示了CCD或CMOS物理上的饱和点。实际输出的像素值可能大于我们期望的相机应有的范围(介于0到未曝光的像素值、或大于有意义的曝光像素值)。
注:最后一句稍微有些拗口,原文为:The output may also be larger than the expected pixel dimensions of the camera, including a border of unexposed pixels to the left and above the meaningfully exposed ones. 可能意指超出传感器预期的暗电流或饱和值(由于噪声或坏点)
Color Filter Array 颜色滤镜
光子传感器(也就是CMOS或CCD)实际上只能给出一个标量,不能给出实际颜色,通过在传感器表面安装一个与像素位置相对应的滤色片,可得知单个像素感知到的单个颜色的值,通过与邻近的其他颜色的像素比对,可以估计出这一点的颜色。这个估计的过程被称作解马赛克(Demosaicing),产生m乘n乘3的RGB值阵列,即我们需要的彩色数码图像。
最常见的CFA是拜尔阵列,其中绿色的像素数是红、蓝的两倍,通常的解释是人眼对于绿色细微的差别更为敏感,与场景中的光强度的感知也更为接近。注意的是,根据生产商的不同,拜尔阵列具备不同的“相位”,按传感器最左上角的第一个拜尔阵列,按左上、右上、左下、右下的顺序,可分为“RGGB”,“BGGR”,“GBRG”,“GRBG”。在反拜尔的过程中,知道正确的相位是重要的。
Color Channel Scaling 颜色通道缩放
An unfortunate reality of color imaging is that there is no truth in color.
想象一个正在发光的光源有它自己的颜色,而靠近这个光源的物体也有特定的颜色。任何相机或人眼接收到的光都离不开这两种颜色的组合。所以任何物体实际上可以看起来是任何颜色的,取决于他被什么样的光照射。我们需要的是一个参考点,一样我们已知是某特定颜色的物体(一个我们已知色度的物体),我们可以据此调整RGB颜色使之接近,这补偿了光源的颜色,展示出物体“真正”的颜色,在能够估计整个场景都由同一光源照射的情况下,我们能把这种补偿作用到画面的每一个像素上,这个过程即为白平衡(White balancing)。本质上,我们找到一个应该是白色或灰色的像素点,其RGB三值应当是相等的。
于是,问题简化为了找到两个标量,对三通道中的两个进行补偿,一般把绿色作为被对比的通道,拜尔阵列中的绿色滤光片比红色和蓝色有更高的透明度,因此绿色通道的标量常为1,而红色和蓝色大于1。
Camera Color Spaces 相机色彩空间
如何将无线多维度的一个空间转换为三维向量的空间是一件复杂的事情,对于可感知的颜色,可以将其抽象的转化为一个凸锥体,即色彩空间。这方面的内容请参阅关于色度学的有关内容。
在线性代数的语言中,我们使用三个坐标来表示一个像素的颜色,重要的是,这样的坐标需要一个特定的基,而传感器所使用的基与大多数显示屏使用的基是不相同的,我们假定显示屏输出色彩空间使用了通用的标准,sRGB。经过白平衡调整和解马赛克后,我们能够获得一个熟悉的彩色图像,但是这些颜色并非是显示器所期望的,为了矫正由相机的基和显示器的基导致的差异,需要进行一个线性变换来进行色彩空间的转换。
EXIF Metadata EXIF元数据
RAW文件除了有来自传感器的raw data,还包含了很多与像素值或曝光值有关的元数据,这些数据以EXIF标签的形式存储,格式为TagName: Value
,例如传感器数据,这些信息都存储在RAW文件中,需要特定的软件来获取。
之前提到的白平衡矫正系数、黑电平等都会记录在EXIF中,其他有用的信息有(注意具体命名会根据品牌不同而变化):相机型号,图像尺寸,测光模式,拍摄时间,闪光灯模式,地理信息,ISO,焦距,快门速度,光圈数,对焦距离,白平衡估计值。
RAW Image Editing Workflow RAW图像处理流程
这将是之后使用MATLAB处理的大纲,也可以作为其他编程语言的参考。
Raw sensor data -> Linearization -> White balance -> Demosaicing -> Color space correction -> Brightness control -> Viewable output
Raw传感器数据 -> 线性化 -> 白平衡处理 -> 解马赛克 -> 色彩空间转换 -> 亮度控制 -> 输出图像
RAW Utility Software 实用工具
由于专有格式RAW文件的存在,在使用MATLAB处理前,需要先使用其他软件“破解”,获得可读取的原始数据。以下介绍几个免费和实用的程序。
-
Dave Coffin’s dcraw 这是一个开源的跨平台软件,用于读取各种RAW文件并输出PPM或TIFF,内置了一些处理办法。 使用C语言编写,注释很少,一万行大概只有五十条注释。 dcraw可以做白平衡、解马赛克、色彩空间调整等,但为了在MATLAB中处理,只使用其转换专有格式的功能。 dcraw可以使用预编译的版本,也可以自己编译源代码。
-
Adobe DNG Converter 虽然是由Adobe主导的,但是DNG是一种开放、非专有的格式,基于TIFF格式,提供了充足的空间来存放来自原本RAW文件的元数据,但元数据的命名仍会随品牌而变化。缺点是不提供Linux版本,只有Windows和MacOS可用。在本案例中,需要启用未压缩,关闭线性、解马赛克。向前兼容可随意选择。
RAW to MATLAB Tutorial 在MATLAB中处理RAW
DNG Converter能够将RAW文件中的EXIF标签命名统一,并根据Adobe对各种相机的测试向其中添加一些原本不存在的信息,例如黑电平和饱和水平。
在MATLAB中使用imfinfo("filename.dng")
能够返回一个包含EXIF和RAW的结构。
在dcraw中,则可以通过dcraw -v
启用详细信息,获得我们需要的黑电平,饱和值和各颜色通道的增益系数。
在dcraw中使用dcraw -4 -D -T file_name
可以生成线性16bit,未经提亮、Gamma调整、解马赛克的TIFF格式图像,使用imread就能方便的导入MATLAB。
Linearizing 线性化
上一步获得的二维向量实际上并不是线性的图像,相机很有可能应用了一个非线性的传输方式来压缩和存储。DNG元数据中将会包含一个表,meta_info.SubIFDs{1}.LinearizationTable
,通过这个LUT可以将图像线性化处理,如果元数据中不包含这个表,则表示图像已经是线性的了。如果使用了dcraw的‘-4’选项,则已经应用过这个LUT了。
另外,需要根据黑电平和饱和值来将像素值归一化到[0,1]之间,由于噪声的存在,像素值可能高过饱和值或低于黑电平,需要进行裁切。注意有些传感器的不同拜尔滤镜通道可能具备不同的黑电平和饱和值,需要进行处理。
White Balancing 白平衡
首先,需要确定拜尔滤镜排列的方式,以及RGB对应的增益系数,增益系数可以是厂商定义的各场景下的标准值,或是相机在拍摄时计算得到的值。
原文通过一个wbmask函数根据拜尔滤镜排列方式定义出各种像素的遮罩,再以点乘矩阵的办法将增益应用到图像上。
Demosaicing 解马赛克
解马赛克有非常多的方法,也是研究的热点之一。MATLAB中内置了一种解马赛克的方法,只要输入图像和拜尔滤镜排列方式,调用demosaic(Img, 'rggb')
即可完成解马赛克。注意MATLAB内置的解马赛克函数只接受uint8或uint16输入,之前我们都以浮点存储数据,这一步需进行变换。
Color Space Conversion 色彩空间转换
如前所述,相机的颜色基与显示器是不用的,现在MATLAB的imshow函数能够显示图像,但是其颜色实际上是不准确的,因此,我们需要将图像中颜色的基进行变换,这一步将用到一个3x3的矩阵。
这个转换矩阵实际上是很难获得的,dcraw使用的矩阵由Adobe处获得,具体方法是先将相机的色彩空间转换到XYZ色彩空间,再从XYZ色彩空间转换到sRGB等需要的色彩空间。这两步矩阵可以合为一步。
我们希望确保变换前后图像中白色像素的像素值均为[1,1,1],因此需要对转换矩阵进行归一化,使其满足每一行的和为1。而sRGB和XYZ间的转换矩阵可以很方便的从各种地方获得。
DNG中,转换矩阵存储在meta_info.ColorMatrix2
中,dcraw则需要到源码中寻找。
Brightness and Gamma Correction 亮度与伽马矫正
现在,我们的图像仍然是线性的,并不适合用来显示。因此需要做一些亮度调整,可以是乘上一个系数,也可以是一个较复杂的非线性函数。注意,这一步可能是高度主观的。
- 平均亮度是最大值的四分之一
- Gamma校正,应用一个2.2的gamma曲线,即
Target = Current .^ (1/2.2)
,Gamma曲线是一种功率函数,在最低像素值区域包含一小段线性分段。
处理结束。