1. 色彩校正概述:为什么需要色彩校正?
各位同学,咱们直接进入正题。色彩校正,说白了就是让摄像头拍出来的颜色,跟人眼看到的真实颜色尽量一致。你想想看,手机拍出来的蓝天发紫、人脸发黄,这种体验谁受得了?
我刚开始做图像处理时,总觉得色彩校正不就是调几个参数嘛。直到有一次,一个安防客户反馈说他们的监控摄像头在黄昏时分把绿色车牌拍成了蓝色——嗯,差点导致误判。从那以后,我再也不敢小看这个模块了。
1.1 为什么需要色彩校正?
图像传感器(CMOS/CCD)天生就有色彩偏差。原因主要有三个:
- 传感器光谱响应不完美:每个像素的R/G/B滤光片对光的敏感度曲线,跟人眼视锥细胞的光谱响应不一样。说白了,传感器是个“色盲”。
- 光源色温变化:日光灯下偏绿,白炽灯下偏橙,阴天偏蓝。传感器可不会自动适应。
- 镜头光学特性:镜头本身会引入色差,尤其是边缘区域。
核心目标:色彩校正模块要做的,就是把传感器输出的原始Bayer数据,经过一系列矩阵运算和查表映射,最终输出符合人眼视觉感知的RGB数据。
1.2 色彩校正的基本原理
原理其实不复杂。我习惯把它拆成两步:
- 白平衡(White Balance):先让白色物体在任何光源下都呈现白色。说白了就是调整R/G/B三个通道的增益。
- 颜色矩阵校正(Color Correction Matrix, CCM):用一个3x3矩阵把传感器RGB空间映射到标准RGB空间(比如sRGB)。
数学表达很简单:
R_out = C00 * R_in + C01 * G_in + C02 * B_in
G_out = C10 * R_in + C11 * G_in + C12 * B_in
B_out = C20 * R_in + C21 * G_in + C22 * B_in
这个矩阵系数怎么来的?靠标定。拿一张标准色卡(比如X-Rite ColorChecker),拍下来,然后最小二乘法拟合出最优矩阵。我在项目中遇到过,标定环境的光源均匀性直接影响校正效果,差一点就全偏了。
个人经验:CCM矩阵的系数通常不是满秩的,对角线占主导。调试时先调对角线,再调非对角线,效率高很多。
1.3 色彩空间介绍
做色彩校正,你得先搞清楚你在哪个色彩空间里干活。常用的有三个:
| 色彩空间 | 特点 | 硬件实现难度 | 典型用途 |
|---|---|---|---|
| RGB | 最直观,R/G/B三通道线性相关 | 低(直接矩阵运算) | 传感器原始输出、显示驱动 |
| YCbCr | 亮度与色度分离,Y通道独立 | 中(需要矩阵变换) | 视频压缩、传输(JPEG/H.264) |
| HSV | 色调/饱和度/明度,符合人眼感知 | 高(非线性变换) | 图像编辑、特效处理 |
RGB 空间
传感器直接输出的就是RGB。但要注意,这个RGB是设备相关的——每个厂家的传感器RGB都不一样。所以校正的第一步,就是把它转到设备无关的标准RGB空间。
YCbCr 空间
这个空间在视频领域用得最多。Y是亮度,Cb和Cr是蓝色差和红色差。为什么用它?因为人眼对亮度变化敏感,对色度变化不敏感。压缩时可以多砍色度的精度,省带宽。
RGB到YCbCr的转换公式(BT.601标准):
Y = 0.299 * R + 0.587 * G + 0.114 * B
Cb = -0.169 * R - 0.331 * G + 0.500 * B + 128
Cr = 0.500 * R - 0.419 * G - 0.081 * B + 128
注意那个+128,这是8位数据的偏移量。我刚开始写RTL时忘了加,结果出来的图像全是负的色度,调试了整整一天才找到原因。
HSV 空间
HSV更接近人眼感知颜色的方式:H是色调(红绿蓝),S是饱和度(鲜艳程度),V是明度(亮度)。这个空间在色彩校正里用得不多,但在图像增强和特效处理里很常见。
HSV的转换是非线性的,硬件实现比较费资源。我一般只在后处理阶段用,不会放在ISP流水线的前端。
避坑指南:我曾经在YCbCr和RGB之间来回转换时,因为定点化精度不够,导致颜色漂移。建议中间计算至少保留12位精度,最后再截断到8位。
1.4 色彩校正的完整流程
下面这张图展示了色彩校正模块在ISP流水线中的位置和内部结构:
1.5 硬件实现要点
做RTL设计时,有几个地方我特别留意:
- 流水线结构:白平衡、CCM、Gamma校正都是逐像素处理的,可以做成三级流水线,每级一个时钟周期。
- 定点化精度:矩阵系数用S1.8格式(1位符号,8位小数),中间结果保留16位,最后截断到8位。
- 查表优化:Gamma校正用查找表实现,256个entry,每个entry 8位,总共256字节,用ROM存。
- 边界处理:图像边缘的像素不做特殊处理,直接走流水线。但要注意数据有效信号的同步。
调试技巧:我习惯在仿真时把中间结果dump出来,用Python画成图像看看颜色对不对。比盯着波形看效率高多了。