1. 色彩空间基础:RGB、BGR、HSV、Lab、YUV 的概念与区别
做图像处理这些年,我见过不少新手一上来就对着像素值猛调,结果效果一塌糊涂。说白了,就是没搞懂色彩空间这回事。你想想看,RGB 适合显示器,但不适合做颜色分析。选错色彩空间,就像用锤子拧螺丝——费劲还容易坏。
今天我们就来聊聊 OpenCV 里最常见的几种色彩空间。我会结合自己的踩坑经历,帮你理清它们的区别和适用场景。
1.1 RGB 与 BGR:OpenCV 的“反直觉”设计
RGB 大家最熟悉了。红绿蓝三通道,每个通道 0-255。但 OpenCV 默认用的是 BGR,不是 RGB。我第一次用 OpenCV 显示图片时,发现人脸是蓝色的,吓我一跳。
cv2.cvtColor(img, cv2.COLOR_BGR2RGB) 转换一下。
为什么 OpenCV 要这么设计?历史原因。早期摄像头硬件厂商偏爱 BGR 排列,OpenCV 为了兼容就沿用了下来。你记住一点:读图用 BGR,显示用 RGB,就不会出问题。
import cv2
import matplotlib.pyplot as plt
# 读取图片(BGR 格式)
img = cv2.imread('photo.jpg')
# 转成 RGB 再显示
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)
plt.show()
1.2 HSV:更适合做颜色分割
HSV 把颜色拆成三个维度:色调(H)、饱和度(S)、明度(V)。我个人习惯用 HSV 做颜色检测,因为它对光照变化不敏感。
举个例子。你想从图片里找出红色的物体。在 RGB 空间里,红色可能是 (200, 30, 30),也可能是 (180, 20, 20),阈值很难定。但在 HSV 空间里,红色的 H 值基本在 0-10 和 170-180 之间,S 和 V 只要不太低就行。这样阈值就好设多了。
# BGR 转 HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 红色范围(OpenCV 中 H 范围是 0-180)
lower_red1 = np.array([0, 50, 50])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([170, 50, 50])
upper_red2 = np.array([180, 255, 255])
# 生成掩码
mask1 = cv2.inRange(hsv, lower_red1, upper_red1)
mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
mask = cv2.bitwise_or(mask1, mask2)
1.3 Lab:人眼感知最均匀的色彩空间
Lab 色彩空间的设计初衷是模拟人眼对颜色的感知。L 代表亮度,a 代表红绿色,b 代表黄蓝色。它的特点是:两个颜色之间的欧氏距离,大致等于人眼感知到的颜色差异。
这有什么用?做颜色相似度比较时特别准。我记得有一次做产品色差检测,用 RGB 算距离,结果深红和浅红被判成完全不同的颜色。换成 Lab 空间后,准确率直接提升到 95% 以上。
# BGR 转 Lab
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
# 提取亮度通道
l_channel = lab[:, :, 0]
# 直方图均衡化(只对亮度做,避免颜色失真)
l_eq = cv2.equalizeHist(l_channel)
lab[:, :, 0] = l_eq
# 转回 BGR
img_enhanced = cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)
1.4 YUV:视频压缩的老朋友
YUV 最早是为电视广播设计的。Y 是亮度,U 和 V 是色度。人眼对亮度敏感,对颜色不敏感。所以视频压缩时,可以保留完整的 Y,但把 UV 的分辨率降低一半,人眼几乎察觉不到。
你在看视频时,其实大部分数据都是 Y 通道。UV 通道被压缩得很厉害。这就是为什么同样码率下,视频比图片小很多的原因。
| 色彩空间 | 通道含义 | 主要用途 | 我的评价 |
|---|---|---|---|
| RGB/BGR | 红、绿、蓝 | 显示、存储 | 最直观,但不适合分析 |
| HSV | 色调、饱和度、明度 | 颜色分割、物体跟踪 | 颜色检测首选 |
| Lab | 亮度、红绿、黄蓝 | 颜色匹配、图像增强 | 感知均匀,精度高 |
| YUV | 亮度、蓝色差、红色差 | 视频编码、传输 | 压缩效率高 |
1.5 如何选择?我的经验总结
说了这么多,到底该用哪个?我根据项目经验给你几个建议:
- 只是显示图片:用 RGB,记得从 BGR 转过来。
- 做颜色检测或分割:用 HSV,阈值好设,抗光照干扰。
- 做颜色相似度比较:用 Lab,感知均匀,结果更符合人眼。
- 处理视频或压缩:用 YUV,效率高。
- 做图像增强:用 Lab 或 YUV,只处理亮度通道,避免颜色失真。
cv2.cvtColor() 函数,转换起来很方便。
嗯,色彩空间的基础就讲到这里。下一章我们会深入每个空间的转换原理,以及如何用它们做出各种滤镜效果。到时候我会分享一些我在项目中用过的“骚操作”,保证让你大开眼界。