旋转图像
以下内容中,都假设图像以横向拍摄。如果需要匹配竖拍的图像,需要进行旋转,可以从 EXIF 中读取 Orientation 标签来决定旋转的角度。比如说使用 Python 的 exifread 库:
with open(image_path, 'rb') as f:
tags = exifread.process_file(f)
orientation = tags.get('Image Orientation', 'Unknown')
print(f"Image Orientation: {orientation}") # e.g. Rotated 90 CCW
读取 RAW 数据的工具
Dcraw
最著名的读取 raw 数据的工具莫过于 dcraw。Dcraw 能够将各种编码方式的 raw 文件转换成 TIFF 或 PPM 格式。
使用命令行 dcraw -4 -T -D file_name 就能够获得一个 16 bit 的 TIFF 文件,记录了 raw 的直接数值,没有经过包括解拜尔、白平衡、扣除黑电平在内的操作。
遗憾的是,dcraw 的最后一次更新是 2018 年 6 月 1 日。因此之后相机的附加参数(白平衡,颜色矩阵等)不再包含,仅用于提取 raw 数据的功能也不一定能够正常使用。
比如说:对于索尼在四代机(ILCE-7M4)中加入的无损压缩 RAW 格式,虽然后缀名都是 arw,但 dcraw 会报 cannot decode file 的错误,而和之前一样的无压缩 RAW 是可以解的。
dcraw.c 是 dcraw 的核心文件,由一万多行纯 c 语言完成。
Rawpy/Libraw
Rawpy 是 libraw 的 python warpper。Libraw 提供了访问 raw 数据的统一接口,用于提取像素值,它基于 dcraw,将 dcraw.c 重构为更现代和模块化的库,并在 dcraw 停止维护后继续支持。
各方法和品牌的差别
Sony
无压缩 RAW
在更新的机器上(应该是 ZVE-10 II 之后的机型),索尼不再提供无压缩 RAW 选项。
测试机型是 ILCE-7 CM2:
以下方式读取的无压缩 RAW 结果是一样的:
- Dcraw 转 tiff 后用 openimageio 读取
- 直接用 rawpy 读取
- 用 adobe DNG converter 转换后用 rawpy 读取
- 用 adobe camera raw 转换后用 rawpy 读取(同上,虽然在 acr 中查看尺寸时不同)
- 用 adobe DNG converter 转换后,用 dcraw 转 tiff 再用 oiio 读取
以上方法读出的尺寸都是 (4688, 7040),总之就是怎么读都一样,毕竟它无压缩嘛。
实际上,用 adobe dng converter 和 adobe camera raw 转换的 dng 是完全一样的,以下不再赘述。用 Rawpy 和 dcraw 读取 dng 也是等效的。
无损压缩 RAW
索尼的无损压缩 RAW 原理是先补 0 到长宽为 512 的倍数,然后分块,再按照 Bayer 分四个子图进行差分编码和霍夫曼编码。
对于无损压缩 RAW 来说,情况比较复杂,因为目前没有办法在无压缩的 ARW 和无损压缩的 ARW 间转换。以下是经过测试的情况:
- Dcraw 不支持无损压缩 RAW(因为索尼引入无损压缩 RAW 时 dcraw 已不再更新)。
- Rawpy 读取 ARW,得到的是 (5120, 7168) 尺寸,这是由于分块压缩导致的(512 的倍数),只有左上角 (4688, 7040) 区域有内容,剩下的是 0(而不是黑电平),数值是 0-16383。
- 用 adobe DNG converter 转换成 dng 后用 rawpy 读取,得到的尺寸是 (4686, 7038),比无压缩 RAW 等少两个像素。上一种情况中再去掉底部和右边各 2 像素,可以完全匹配,也是 0-16383。
压缩 RAW:Compressed HQ
曾经,索尼的有损压缩 RAW 格式因为太过垃圾而臭名昭著。到了 a7M5 上,终于推出了改进的有损压缩模式:Compressed HQ,应当具有更平衡的画质和体积。目前是只有索尼自己的 IEDT 能解码该格式,等第三方软件更新后,再来仔细品鉴。
关于 Capture One 等其它软件的 DNG
理论上,一个解码 RAW 并编码到 DNG 的编解码器不会带来太复杂的误差。但 Capture One 导出的 DNG 不仅尺寸有区别,还会将原本 14 bit 的数据拉伸到 16 bit,且不能与其它方法读的 raw 完全匹配。
在 Gemini 和 DeepSeek 的帮助下,进行了一些更细致的分析。关于如何从 14 bit 到 16 bit,Capture One 进行的应该是左移两位,即直接 *4。将 rawpy 读取的 arw 左移后与 C1 导出的 dng 相除与相减,得到的商为 1.000004,差也是 e-7 的数量级。其中,R 和 B 通道是完全匹配的,误差全部来自两个 G 通道,而且和图像内容有关,个别图像中,G 的最大误差甚至能达到 10%,多数情况下,最大误差不超过 5%。
DNG 作为一个有规范要求的文件格式,不应该对 RAW 数据本身做处理,因此不推荐用 Adobe 以外的软件来转换 RAW 图像格式到 DNG。
Sony RAW 的最佳实践
综上,最推荐的 Sony RAW 使用方法是拍摄无压缩的 RAW 之后直接用 Rawpy 读取,用 dng converter 可以方便的把无压缩 RAW 转换成无损压缩的 DNG 来减少体积,同时不会有任何损失,或是无损压缩 RAW 用 Rawpy 读取并做裁切,但注意无损压缩 RAW 转换成 DNG 时会损失两行两列像素。
Canon
测试机型是从一个数据集里拿的 600D,输出的是 CR2。
用 rawpy 和转成 dng 之后读取是一致的,图像尺寸是 (3516, 5344),左边 142 像素和上方 51 像素应该是光学黑场(被物理遮盖用于黑电平校正的部分),能读出近似黑电平的数值,剩余部分是图像。
Dcraw 是可以处理 600D 的,读出的是没有光学黑场的部分,这一部分和裁切后的 rawpy 或 dng 匹配。
R6 Mark II 输出的 CR3 (用 rawpy 或转成 dng 读取)也类似,左侧 154 个像素、顶部 96 个像素是光学黑场,另外右侧还有 8 个像素的白色区域。
到了 R6 Mark III,似乎就没有光学黑场了,读出的全部是图像内容。不得不说 CR3 格式确实非常先进,无损压缩的同时,压缩率也非常高。
Hasselblad
测试机型为哈苏 X2D-100C,相机直接输出 3FR 格式的 RAW 文件。其传感器型号可从 3FR 文件中直接确认,为索尼 IMX461-BQR。
哈苏的 RAW 工作流历史上涉及 3FR 和 FFF 两种文件格式。
随着新版 Phocus 的发布,FFF 文件已被移出 RAW 工作流,现在无需先转换到 FFF 再处理 RAW 图像。
在旧版流程中,用户可以通过 Phocus 软件将 3FR 转换为 FFF。转换时有一些可选的调整选项,但这不影响 FFF 文件本身的原始数据(例如,使用 rawpy 读取的结果都相同)。从文件头可以发现,3FR (49 49 2A 00) 遵循小端序 TIFF 规范,而 FFF (4D 4D 00 2A) 则是大端序 TIFF。
IMX461-BQR 的公开规格显示,其总像素为 11760×8896,有效像素为 11664×8750。然而,使用 dcraw 或 rawpy 等工具直接解析 3FR 文件,会得到一个 11904×8842 的超大图像。这个图像包含了以下几个区域:
- 图像内容区: 尺寸为 11664×8750,与 461 的有效像素一致。
- 光学黑场 (Optical Black): 包围在图像内容区外,左右各 48px,上方 90px。
- 额外内容: 在最外围,包含左侧 76px、右侧 68px 和上方 2px 的非图像数据。
分析可知,包含光学黑场在内的图像宽度为 11760px(与传感器总像素宽度吻合),但高度为 8840px,略有出入。
无论是 3FR 还是 FFF,都可以转换为 DNG 格式,转换后的 DNG 文件尺寸会裁切到与有效像素区一致,内容上,虽然画面内容能够对齐,但数值上有一些小区别。
所以目前来看,处理哈苏 3FR 文件的最佳实践是直接使用 libraw 读取,提取出有效的图像区域,并利用图像中的光学黑场数据进行精确的黑电平校正。
Fujifilm
测试机型是 X-T5。
富士的 raw 比较特殊,因为其表面的滤色片不是普通的拜尔排列,而是 X-Trans,最小重复单元是 6 行 6 列。好在不影响我们分析 raw 图像本身。
把 RAF 直接输入 rawpy,得到的图像长 7872,高 5196,转换成 DNG 后,长 7728,高 5152。多出来的长 44 个像素,高 144 个像素具体分布是:
- 左侧 12 个有画面的像素,右侧 12 个有画面的像素和 120 个黑。
- 顶部 16 个有画面的像素和 5 个黑,底部 16 画面 7 黑。
重叠部分的像素值是完全一样的。
另外,rawpy 读取 raf 的 raw pattern 有错误,dng 中的 raw pattern 是正确的。
需要提醒的是,libraw 提供了一个名为 halfsize 的选项,在 Bayer 传感器上,可以讲 RGGB 合并成一个像素,输出一个半分辨率的三通道图像,理论上来说,该选项不应对 X-Trans 传感器使用,但在 libraw 中仍然可以开启,似乎会走和 Bayer 一样的管线,产生错误的结果。
Nikon
尼康的情况最为简单,测试机型是 Z6,输出的是 NEF 文件。直接用 libraw 读取或者转成 dng 读取,得到的图像尺寸都是 (6064, 4040),除了图像没有多余的区域,内容也完全一样。
总结
通常来说,最方便的做法总是转换成 DNG,这样既缩小了文件体积,又统一了格式,还裁切掉了各种图像以外的区域,便于后续处理。如果希望保留原始格式,元数据和被裁切的区域,则可以用 libraw 或 rawpy 直接读取原始 RAW 文件。经过各种测试,在绝大多数情况下,重合的图像区域里,像素值是完全一致的。
不推荐使用 Adobe 以外的软件来转换 RAW 到 DNG。Dcraw 由于停止维护,推荐迁移至 libraw/rawpy。