4. 图像基础与色彩空间:像素、分辨率与色彩转换
各位同学,今天我们来聊聊图像预处理里最基础、也最容易被忽视的一块——像素与色彩空间。我刚开始做工业视觉那会儿,总觉得这些概念太简单,结果在项目里栽过不少跟头。说白了,你连图像里每个像素存的是什么数据都不清楚,后面做再好的模型也是白搭。
4.1 像素与分辨率:图像的最小单元
一张数字图像,本质上就是一个二维数组。数组里的每个元素,就是一个像素。像素是图像的最小信息单元,它记录的是该位置的颜色或亮度值。
分辨率则决定了图像的精细程度。工业相机选型时,分辨率是第一个要敲定的参数。
| 分辨率类型 | 定义 | 工业场景举例 |
|---|---|---|
| 空间分辨率 | 单位长度内的像素数(如 dpi、ppi) | PCB 检测要求 0.05mm/pixel |
| 图像分辨率 | 图像的总像素数(如 1920×1080) | 500 万像素相机用于精密零件测量 |
| 位深 | 每个像素用多少 bit 表示 | 8bit(0-255)vs 10bit(0-1023) |
4.2 BGR 与 RGB:OpenCV 的“坑”
如果你用过 OpenCV,一定被它坑过——它默认的通道顺序是 BGR,而不是我们熟悉的 RGB。为什么?因为早期相机硬件厂商习惯用 BGR 顺序存储数据,OpenCV 沿用了这个传统。
但深度学习框架(比如 PyTorch、TensorFlow)的预训练模型,几乎都是用 RGB 训练的。这就导致了一个经典问题:你直接拿 OpenCV 读图,然后送进模型,结果完全不对。
import cv2
import matplotlib.pyplot as plt
# OpenCV 默认 BGR
img_bgr = cv2.imread('example.jpg')
# 显示时如果不转换,颜色会偏蓝
plt.subplot(1, 2, 1)
plt.imshow(img_bgr) # 错误显示
# 转换为 RGB
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
plt.subplot(1, 2, 2)
plt.imshow(img_rgb) # 正确显示
4.3 灰度图与二值图:简化信息,突出结构
灰度图去掉了颜色信息,只保留亮度。每个像素值范围 0(黑)到 255(白)。工业视觉里,很多场景根本不需要颜色——比如测量尺寸、检测划痕、定位边缘。
二值图更进一步,像素只有 0 和 1(或 0 和 255)。它是图像分割的最终结果,也是很多形态学操作的基础。
# 灰度化
gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY)
# 二值化(固定阈值)
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 二值化(自适应阈值——光照不均时更鲁棒)
adaptive_binary = cv2.adaptiveThreshold(
gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2
)
- 形状检测、尺寸测量、边缘提取
- 纹理分析、表面缺陷检测(如划痕、凹坑)
- OCR 文字识别前的预处理
- 颜色分选(如水果成熟度、药品胶囊颜色)
- 多通道融合(如红外+可见光)
- 需要利用颜色特征的深度学习模型
4.4 HSV 色彩空间:更符合人眼直觉
RGB 虽然直观,但它不适合做颜色分割。为什么?因为 RGB 的三个通道高度相关,光照一变,三个值一起变,你很难设定一个固定的阈值。
HSV 把颜色分解为:
- H(Hue,色调):颜色的种类,用角度表示(0°-180° 在 OpenCV 中)
- S(Saturation,饱和度):颜色的纯度
- V(Value,明度):亮度
你想想看,在 HSV 空间里做颜色检测,你只需要设定 H 的范围,S 和 V 可以适当放宽——光照变化主要影响 V,不影响 H。这就稳定多了。
# RGB 转 HSV
hsv = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HSV)
# 设定红色范围(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)
4.5 Lab 色彩空间:感知均匀,适合度量颜色差异
Lab 色彩空间的设计目标是感知均匀——也就是说,两个颜色在 Lab 空间里的欧氏距离,与人眼感知到的颜色差异成正比。这在工业视觉里非常有用,比如检测产品颜色是否合格。
- L:亮度(0-100)
- a:红绿色度(负值偏绿,正值偏红)
- b:黄蓝色度(负值偏蓝,正值偏黄)
# RGB 转 Lab(注意 OpenCV 需要先转 float32)
lab = cv2.cvtColor(img_rgb.astype(np.float32) / 255.0,
cv2.COLOR_RGB2Lab)
# 计算两个颜色的色差(Delta E)
color1 = lab[100, 200] # 参考颜色
color2 = lab[150, 250] # 待测颜色
delta_e = np.sqrt(np.sum((color1 - color2) ** 2))
print(f'色差 Delta E = {delta_e:.2f}')
4.6 知识体系总览
下面这张图总结了本章的核心知识点和它们之间的关系。你可以把它当作一个快速索引。
4.7 本章小结
图像预处理不是花架子,它直接决定了后续模型能不能学到有效特征。我见过太多项目,模型调了半天没效果,最后发现是色彩空间用错了。嗯,这里要注意:
- 像素和分辨率决定了你能看到多细的细节
- BGR vs RGB 是个容易忽略的坑,训练和推理必须对齐
- 灰度图和二值图是形状分析的基础,简单但高效
- HSV 适合做颜色分割,对光照变化鲁棒
- Lab 适合做颜色差异度量,感知均匀
把这些基础打牢,后面讲图像增强、几何变换、滤波去噪的时候,你才能理解每一步操作到底在改变什么。