4. 色彩空间
色彩空间转换,说白了就是让计算机用不同的方式去理解颜色。我刚开始接触工业视觉时,总觉得这玩意儿不就是换个颜色看看嘛,后来才发现——选错色彩空间,算法直接报废。
举个例子。你在流水线上检测一个红色标签的位置。用BGR直接做阈值分割?光照一变,红色就飘了。换成HSV,只取H通道,光照再变,红色还是那个红色。这就是色彩空间的价值。
4.1 BGR与RGB:OpenCV的默认姿势
OpenCV读图默认是BGR顺序,不是RGB。这个坑我踩过不止一次。
import cv2
import matplotlib.pyplot as plt
# 读图默认BGR
img_bgr = cv2.imread('sample.jpg')
# 转RGB用于显示
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)
plt.show()
工业场景里,BGR和RGB的转换主要发生在两个地方:
- 与深度学习模型对接:很多预训练模型(比如ResNet、YOLO)训练时用的是RGB,推理前必须转。
- 与上位机/显示器交互:HMI界面通常用RGB,传给OpenCV处理前要转回BGR。
我个人习惯在代码开头就统一色彩空间,避免后面到处转来转去。
4.2 灰度图:工业视觉的基石
灰度图只有亮度信息,没有颜色。你可能会问:颜色信息丢了,还能用吗?
能。而且很多场景下,灰度图比彩色图更稳定。
我记得有一次做手机中框划痕检测。彩色图下,划痕和背景的色差很小,阈值分割死活分不开。转成灰度图后,划痕的亮度突变反而更明显,一个简单的Canny边缘检测就搞定了。
# BGR转灰度
gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
# 或者直接读灰度图
gray = cv2.imread('sample.jpg', cv2.IMREAD_GRAYSCALE)
灰度图在工业视觉中的典型应用:
- 边缘检测、轮廓提取
- 模板匹配(基于灰度值的相关性)
- 二值化前的预处理
- OCR文字识别(大部分OCR引擎用灰度图)
4.3 HSV:光照变化的克星
HSV把颜色拆成色调(H)、饱和度(S)、明度(V)。
为什么它在工业视觉里这么重要?因为H通道对光照变化不敏感。
你想想看,一个红色零件,在强光下是亮红,在弱光下是暗红。BGR空间里,这两个红色的RGB值差很远。但在HSV空间里,它们的H值几乎一样。
# BGR转HSV
hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
# 提取红色区域(H在0-10和160-180之间)
lower_red1 = np.array([0, 50, 50])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([160, 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)
我曾经做过一个项目,检测PCB板上不同颜色的电阻。车间灯光从上午到下午变化很大。用BGR做颜色分类,准确率只有70%。换成HSV后,准确率直接跳到95%以上。
HSV的工业应用场景:
- 颜色分类与分拣
- 彩色标签定位
- 光照变化环境下的目标检测
- 肤色检测(人机协作场景)
4.4 Lab:人眼感知的模拟器
Lab色彩空间的设计目标是模拟人眼对颜色的感知。L是亮度,a和b是颜色对立通道。
为什么工业视觉要用Lab?因为Lab空间里的欧氏距离,近似于人眼感知的颜色差异。
举个例子。你要检测两个蓝色瓶盖的颜色是否一致。在BGR空间里,两个蓝色可能距离很远,但人眼看差不多。在Lab空间里,它们的距离就和人眼判断一致。
# BGR转Lab
lab = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2Lab)
# 提取L通道(亮度)
L = lab[:,:,0]
# 计算两个颜色的Lab距离
color1 = np.array([50, 20, -30]) # Lab值
color2 = np.array([52, 18, -28])
distance = np.sqrt(np.sum((color1 - color2) ** 2))
Lab的典型工业应用:
- 颜色一致性检测(化妆品、汽车漆面)
- 色差测量(Delta E计算)
- 印刷品质量检测
- 食品成熟度判断
4.5 色彩空间选择决策框架
说了这么多,到底该用哪个?我整理了一个决策流程,你直接套用就行。
4.6 各色彩空间对比总结
| 色彩空间 | 通道含义 | 光照鲁棒性 | 颜色区分度 | 计算速度 | 典型工业场景 |
|---|---|---|---|---|---|
| BGR/RGB | 红、绿、蓝三通道 | 低 | 中等 | 最快(无转换) | 深度学习推理、显示 |
| 灰度 | 单通道亮度 | 中等 | 无(只有亮度) | 最快 | 边缘检测、模板匹配 |
| HSV | 色调、饱和度、明度 | 高(H通道) | 高 | 快 | 颜色分割、光照变化场景 |
| Lab | 亮度、绿-红、蓝-黄 | 中等 | 最高(感知均匀) | 中等 | 色差检测、颜色一致性 |
4.7 实战避坑指南
最后分享几个我踩过的坑,你遇到了直接绕开。
cv2.imshow()显示H、S、V三个单通道图像,观察目标在哪个通道最明显。我一般先调H通道,再微调S和V。
cv2.cvtColor()把BGR转成灰度,然后做二值化。结果发现有些区域死活分不开。后来检查发现,原图是8位深度,但某些像素值超出了0-255范围。转灰度前先检查数据类型和范围。
a_std = a_opencv - 128。我当年没注意这个,算出来的色差全是错的。
嗯,色彩空间这块就讲到这里。记住一句话:没有最好的色彩空间,只有最合适的。根据你的光照条件、检测目标和精度要求,选对了,算法就成功了一半。