相机流水线基础:从光子到像素的旅程
做端侧推理引擎适配相机,第一件事不是写代码,而是搞懂相机是怎么把光变成数字信号的。我刚开始接触这个领域时,以为相机就是个传感器加个驱动,后来被 ISP 流水线狠狠教育了一顿。今天咱们就把这条流水线拆开看看。
相机成像原理:光子的奇幻漂流
说白了,相机成像就是光子从镜头进入,最终变成数字像素的过程。整个过程可以分成三步:
- 镜头组聚焦:光线通过多片透镜,被折射到传感器表面。这里有个坑——镜头畸变,广角镜头尤其明显,后面 ISP 会做校正。
- 传感器光电转换:CMOS 传感器上的每个像素点(photosite)吸收光子,产生电子。电子数量与光强成正比。嗯,这里要注意,传感器只能感知光的强度,不能感知颜色。
- Bayer 阵列采样:为了获取颜色信息,传感器表面覆盖了一层彩色滤光片阵列(CFA),最常见的是 Bayer 模式——RGGB。每个像素只记录一种颜色,另外两种颜色要靠插值算出来。
关键理解:传感器输出的原始数据叫 RAW 数据,每个像素只有 10bit 或 12bit 的灰度值,没有颜色、没有白平衡、没有伽马校正。这就是 ISP 流水线的起点。
ISP 流水线:三大域的处理逻辑
ISP(Image Signal Processor)把 RAW 数据变成人眼看起来舒服的图像。我习惯把 ISP 流水线分成三个处理域:RAW 域、RGB 域、YUV 域。每个域干的事完全不同。
RAW 域:原始数据的预处理
这个阶段处理的是传感器直接输出的 RAW 数据。我在项目中遇到过一个问题:暗光下图像全是噪点,后来发现是 RAW 域的降噪参数没调好。
- 黑电平校正:传感器在无光时也有微弱输出,需要减去这个基准值。
- 镜头阴影校正:镜头边缘进光量比中心少,需要补偿。
- 坏点校正:传感器上总有那么几个像素是坏的,需要用邻居像素插值替换。
- 去马赛克:把 Bayer 阵列插值成完整的 RGB 图像。这一步很关键,算法好坏直接影响画质。
个人经验:RAW 域处理是 ISP 性能瓶颈之一。如果你要在相机流水线里插入 AI 推理,最好在 RAW 域或 YUV 域做,别在 RGB 域折腾——RGB 域数据量大,带宽吃不消。
RGB 域:色彩的重塑
去马赛克之后,图像变成了 RGB 格式。这个阶段主要做色彩相关的处理:
| 处理模块 | 作用 | 我踩过的坑 |
|---|---|---|
| 白平衡 | 校正色温,让白色物体在不同光源下都呈现白色 | 荧光灯下白平衡经常偏绿,需要手动干预 |
| 颜色校正矩阵 | 把传感器色彩空间映射到标准色彩空间 | 不同传感器矩阵参数完全不同,不能复用 |
| 伽马校正 | 调整亮度曲线,适配显示设备 | 伽马值设错了,图像要么发白要么发暗 |
YUV 域:压缩与传输的妥协
RGB 转 YUV 是为了压缩和传输。Y 是亮度分量,UV 是色度分量。人眼对亮度敏感、对色度不敏感,所以 UV 可以降采样,数据量直接减半。
为什么会这样?说白了,视频编码和显示接口都基于 YUV 设计。你在手机上看到的每一帧画面,最终都是以 YUV 格式在流水线里跑的。
注意:YUV 有多种格式,NV12、NV21、YV12 等等。Android 相机默认输出 NV21,iOS 默认输出 NV12。做推理引擎适配时,输入格式不匹配是常见问题。我曾经因为格式搞错,浪费了两天调试时间。
Android Camera2 API 与 iOS AVFoundation 框架
这两个是移动端相机开发的入口。我简单对比一下:
| 维度 | Android Camera2 | iOS AVFoundation |
|---|---|---|
| 架构 | 基于管道(Pipeline)模型,异步回调 | 基于会话(Session)模型,代理回调 |
| 数据流控制 | 通过 CaptureRequest 和 CaptureResult 控制 | 通过 AVCaptureOutput 子类控制 |
| YUV 获取 | ImageReader 获取 YUV_420_888 格式 | AVCaptureVideoDataOutput 获取 CMSampleBuffer |
| 性能 | 碎片化严重,不同厂商实现差异大 | 统一性好,但定制化能力弱 |
我个人习惯在 Android 上用 Camera2 的 ImageReader 获取 YUV 数据,然后传给推理引擎。iOS 上则用 AVCaptureVideoDataOutput 的代理方法,在 captureOutput:didOutputSampleBuffer:fromConnection: 里拿到数据。
相机数据流:Preview、Video、Photo
相机有三种数据流,它们的处理逻辑完全不同:
- Preview 流:实时性要求最高,延迟要控制在 30ms 以内。分辨率通常较低(1080p 或更低),帧率 30fps。推理引擎做实时检测时,一般挂在这个流上。
- Video 流:需要编码存储,对画质要求高。分辨率可达 4K,帧率 60fps。推理引擎可以在这里做视频分析,但要注意功耗。
- Photo 流:单帧最高质量,分辨率最大。适合做高精度推理,但延迟不是问题。
实战建议:做端侧推理时,优先挂载 Preview 流。原因很简单——Preview 流分辨率低、帧率稳定、延迟可控。Video 流和 Photo 流数据量大,推理耗时高,容易导致手机发热降频。
本章知识结构图
下面这张图展示了相机流水线的完整链路,以及推理引擎可以插入的位置: