3. 色彩空间基础

做安防监控图像处理这几年,我越来越觉得色彩空间是绕不开的基础。说白了,摄像头拍下来的原始数据,和我们人眼感知到的颜色,中间差了好几个「翻译层」。你如果不懂这些空间怎么定义、怎么转换,那白平衡调优基本就是瞎调。

这一章,我就把 RGB、YUV、HSV 这三个最常用的色彩空间掰开揉碎讲清楚。嗯,咱们不搞纯数学推导,重点放在「为什么安防场景要用这个空间」以及「实际转换时有哪些坑」。

3.1 RGB 色彩空间:最原始,也最直接

RGB 就是红、绿、蓝三个通道。每个像素用三个数值表示,范围通常是 0-255(8bit)或 0-1023(10bit)。

为什么安防摄像头都用 RGB 作为原始输出? 因为 CMOS 传感器上的滤色片就是 Bayer 阵列,每个像素只采集一种颜色,然后通过插值算法补全成 RGB。所以 RGB 是「最接近硬件」的表达方式。

关键点: RGB 的三个通道是高度相关的。光照一变,三个值一起变。这就是为什么直接在 RGB 空间做白平衡很麻烦——你调一个通道,另外两个也得跟着调。

我在项目中遇到过一个问题:某款 IPC 在黄昏场景下,RGB 三个通道的数值分布完全乱掉,R 通道饱和、B 通道几乎为零。如果直接在 RGB 空间做白平衡,怎么调都偏色。后来我意识到,得换个空间处理。

3.2 YUV 色彩空间:亮度和颜色分开

YUV 的核心思想很简单:把亮度(Y)和色度(U、V)分开。Y 只代表明暗,U 和 V 代表颜色偏移。

为什么安防行业这么喜欢 YUV?两个原因:

  • 压缩友好: 人眼对亮度敏感、对色度不敏感。所以 Y 可以保留高分辨率,U 和 V 可以降采样(比如 4:2:0),带宽直接省一半。
  • 白平衡好做: 白平衡本质是调整色温,也就是调整 U、V 的偏移量。Y 通道基本不动,计算量小很多。

我记得第一次调 YUV 空间的 AWB 算法时,踩过一个坑:YUV 的转换矩阵是有标准版本的。BT.601 和 BT.709 的系数不一样。如果你用错矩阵,颜色会整体偏绿或偏紫。

标准 应用场景 Y 计算公式(简化)
BT.601 标清视频(SD) Y = 0.299R + 0.587G + 0.114B
BT.709 高清视频(HD) Y = 0.2126R + 0.7152G + 0.0722B
BT.2020 超高清(4K/8K) Y = 0.2627R + 0.6780G + 0.0593B

避坑指南: 我曾经在移植算法时,把 BT.601 的系数用到了 4K 摄像头上。结果画面整体偏黄,查了两天才发现是标准不匹配。所以,拿到摄像头的第一件事,确认它用的是哪个色彩标准。

3.3 HSV 色彩空间:更接近人眼的直觉

HSV 把颜色拆成三个维度:色相(Hue)、饱和度(Saturation)、明度(Value)。

  • H(色相): 0°-360°,决定是什么颜色(红、绿、蓝等)。
  • S(饱和度): 0%-100%,决定颜色有多浓。
  • V(明度): 0%-100%,决定颜色有多亮。

你想想看,人眼判断「这个红色偏不偏」时,其实是在看 H 值有没有偏移。而不是像 RGB 那样同时看 R、G、B 三个数。所以 HSV 在安防场景里特别适合做:

  • 颜色识别: 比如车牌颜色、指示灯状态。
  • 白平衡评估: 通过统计 H 通道的分布,判断是否有色偏。

我个人习惯在做 AWB 调优时,先用 HSV 空间做一次「色偏诊断」。如果 H 通道的直方图峰值不在预期范围内,那基本可以断定白平衡没调好。

3.4 三种空间的转换关系

实际项目中,我们经常需要在三个空间之间来回切换。下面这张图是我自己总结的转换流程,画出来方便你理解。

色彩空间转换关系图 色彩空间转换关系图 RGB 空间 YUV 空间 HSV 空间 线性变换 逆线性变换 非线性变换 逆非线性变换 通过 RGB 中转 实际项目中的转换策略 白平衡调优:RGB → YUV → 调整 UV → 转回 RGB 颜色诊断:RGB → HSV → 分析 H 直方图

3.5 转换代码实战

光讲理论不够,我直接给你一段实际项目中用过的转换代码。这是 C 语言版本,安防嵌入式设备上跑得很快。

// RGB 转 YUV (BT.601 标准)
void rgb_to_yuv(uint8_t r, uint8_t g, uint8_t b, 
                uint8_t *y, uint8_t *u, uint8_t *v) {
    *y = (uint8_t)(0.299f * r + 0.587f * g + 0.114f * b);
    *u = (uint8_t)(-0.147f * r - 0.289f * g + 0.436f * b + 128);
    *v = (uint8_t)(0.615f * r - 0.515f * g - 0.100f * b + 128);
}

// RGB 转 HSV
void rgb_to_hsv(uint8_t r, uint8_t g, uint8_t b,
                float *h, float *s, float *v) {
    float rf = r / 255.0f, gf = g / 255.0f, bf = b / 255.0f;
    float max = fmaxf(rf, fmaxf(gf, bf));
    float min = fminf(rf, fminf(gf, bf));
    float delta = max - min;
    
    *v = max;
    *s = (max == 0) ? 0 : delta / max;
    
    if (delta == 0) {
        *h = 0;
    } else if (max == rf) {
        *h = 60.0f * fmodf((gf - bf) / delta, 6.0f);
    } else if (max == gf) {
        *h = 60.0f * ((bf - rf) / delta + 2.0f);
    } else {
        *h = 60.0f * ((rf - gf) / delta + 4.0f);
    }
    if (*h < 0) *h += 360.0f;
}

小技巧: 在嵌入式平台上,浮点运算很慢。我建议你把转换系数提前算成定点数,用移位和整数乘法代替浮点。比如 0.299 可以近似为 77/256,用 (r * 77) >> 8 代替。

3.6 安防场景下的选择建议

最后,我根据实际项目经验,给你一个简单的选择指南:

场景 推荐空间 原因
白平衡调整 YUV 亮度色度分离,调整 UV 不影响亮度
颜色偏色诊断 HSV H 通道直接反映色偏方向
视频编码传输 YUV 兼容 H.264/H.265 压缩标准
目标颜色识别 HSV 对光照变化不敏感,鲁棒性好
原始传感器数据 RGB 最接近硬件输出,信息完整