OpenCV 从零学习 · 第 3 讲:色彩空间转换 cvtColor
上节课我们用 BGR 三通道做处理。但如果你试过"把照片里红色的杯子抠出来",会发现用 BGR 直接判断颜色非常麻烦——同一只红杯子,在阳光下和阴影里,BGR 三个值全变了。这一讲教你用
cv2.cvtColor 换一套"描述颜色的方式",让按颜色抠图变得简单可靠。
1. 函数签名
dst = cv2.cvtColor(src, code)
# src : 输入图 (uint8)
# code: 转换方式, 如 cv2.COLOR_BGR2GRAY
# dst : 转换后的图
| 常用 code | 含义 |
|---|---|
| cv2.COLOR_BGR2GRAY | BGR → 灰度 |
| cv2.COLOR_BGR2HSV | BGR → HSV(色相/饱和度/明度) |
| cv2.COLOR_BGR2RGB | BGR → RGB(给 matplotlib/PIL 用) |
| cv2.COLOR_GRAY2BGR | 灰度 → BGR(升回三通道) |
| cv2.COLOR_HSV2BGR | HSV → BGR(处理结果转回显示) |
新手必踩坑:OpenCV 里 H(色相) 范围是 0~179,不是 0~360!
8 位图放不下 360,OpenCV 把色相压缩到 0~179。写颜色阈值时别照着网上的 0~360 来。
8 位图放不下 360,OpenCV 把色相压缩到 0~179。写颜色阈值时别照着网上的 0~360 来。
2. BGR → GRAY 灰度化:降维、去干扰
场景案例 A:OCR / 人脸检测前的标准动作
很多算法(如人脸检测、文字识别)只需要"亮度信息"不需要颜色。先灰度化能少算 2/3 的数据量,还能去掉颜色噪声:
很多算法(如人脸检测、文字识别)只需要"亮度信息"不需要颜色。先灰度化能少算 2/3 的数据量,还能去掉颜色噪声:
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
print(gray.shape) # (高, 宽) —— 注意通道维没了!
灰度图是单通道
(h,w),不能直接和彩色图做运算。要再转回三通道才兼容显示/合成:gray3 = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)。
3. 为什么抠"红色物体"要用 HSV,而不是 BGR?
HSV 把颜色拆成三部分:
- H(Hue 色相):到底是什么颜色(红/绿/蓝),0~179;
- S(Saturation 饱和度):颜色浓不浓,0~255;
- V(Value 明度):亮不亮,0~255。
关键差异:同一只红杯子,光照一变,BGR 三个通道值全跟着变;但 H(色相)基本不动。所以"按颜色找东西"用 HSV 的 H 通道来卡范围,比在 BGR 里卡三个通道稳得多。
场景案例 B:从照片里只保留"红色"的杯子
步骤:转 HSV → 用
步骤:转 HSV → 用
cv2.inRange 圈出红色范围得到掩膜 → 用掩膜把红色部分抠出来:
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 红色在 HSV 里"跨过 0 度": 一段在 0~10, 一段在 170~179, 所以要取两个区间的并集
lower1 = np.array([0, 100, 100]); upper1 = np.array([10, 255, 255])
lower2 = np.array([170, 100, 100]); upper2 = np.array([179, 255, 255])
mask = cv2.bitwise_or(cv2.inRange(hsv, lower1, upper1),
cv2.inRange(hsv, lower2, upper2))
red_only = cv2.bitwise_and(img, img, mask=mask) # 只保留红色区域, 其余变黑
对比一下:如果直接用 BGR 写
cv2.inRange(img, (0,0,200), (80,80,255)) 去卡红色,阴影里的红杯子(偏暗、B/G 略高)会大量漏掉;HSV 方案几乎不会。这就是"换色彩空间"带来的实质性差别。
场景案例 C:绿幕抠像(chroma key)
视频/直播里的绿幕,本质是"把某一片颜色换成透明"。用 HSV 卡住绿色范围做掩膜即可:
视频/直播里的绿幕,本质是"把某一片颜色换成透明"。用 HSV 卡住绿色范围做掩膜即可:
lower_green = np.array([35, 43, 46]); upper_green = np.array([77, 255, 255])
mask = cv2.inRange(hsv, lower_green, upper_green) # 绿幕区域为 255
fg = cv2.bitwise_and(img, img, mask=mask) # 只留前景(非绿幕)
4. 常见色彩空间该用在哪(对照表)
| 色彩空间 | 典型用途 |
|---|---|
| GRAY(灰度) | OCR、人脸检测、边缘检测等前处理;减少计算量 |
| HSV | 按颜色追踪/抠图、绿幕、皮肤检测、交通灯识别 |
| LAB | 颜色校正、白平衡、肉眼感知更均匀的颜色比较 |
| RGB | 给 matplotlib / PIL 显示(OpenCV 读进来是 BGR,要先转) |
新手必踩坑:用 matplotlib 显示前必须转 RGB!
OpenCV 读的是 BGR,matplotlib 按 RGB 画,直接
OpenCV 读的是 BGR,matplotlib 按 RGB 画,直接
plt.imshow(img) 颜色会发蓝。正确做法:plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))。
5. 本讲要点清单
cv2.cvtColor(src, code)负责色彩空间转换,code 决定转成什么。- 灰度化
BGR2GRAY:检测/OCR 前处理首选,省算力。 - 按颜色抠图用 HSV:H 通道对光照稳定,远强于 BGR 三通道硬卡。
- HSV 的 H 范围是 0~179,红色跨 0 度要取两段并集。
- 配
cv2.inRange出掩膜,再用cv2.bitwise_and抠图。 - 给 matplotlib 显示前记得
BGR2RGB。
✅ 下一讲预告:图片尺寸不对、拍歪了、需要镜像怎么办?第 4 讲:几何变换 resize / flip / 旋转。
