3、图像处理基础:灰度图、二值化、色彩空间转换、感兴趣区域(ROI)设置与图像滤波
在机器视觉测量任务中,OpenMV 摄像头采集到的原始图像通常是 RGB565 彩色图像,但直接对彩色图像进行边缘检测或几何测量往往计算量大、噪声干扰多且精度不稳定。因此,图像预处理是视觉测量流程中至关重要的一环。本章将系统讲解灰度图转换、二值化分割、色彩空间转换、ROI 区域设定以及图像滤波五大基础操作,帮助你在 OpenMV 环境中建立一套高效、稳定的图像预处理流水线。
3.1 灰度图转换:降低维度,保留关键亮度信息
3.1.1 核心原理
灰度图(Grayscale)是将 RGB 三通道彩色图像转换为单通道亮度图像的过程。OpenMV 的传感器在 GRAYSCALE 模式下直接输出 8 位灰度值(0~255),每个像素仅占用 1 字节存储空间,相比 RGB565 的 2 字节减少了一半内存占用,同时帧率可提升约 30%~50%。灰度图保留了图像中物体与背景的亮度对比关系,而边缘检测、几何测量等算法本质上依赖的是亮度梯度变化,因此灰度图是视觉测量的理想输入。
Gray = 0.299R + 0.587G + 0.114B,OpenMV 硬件自动完成该转换,无需软件计算。
3.1.2 操作流程
- 初始化传感器:
sensor.reset()复位摄像头。 - 设置像素格式:
sensor.set_pixformat(sensor.GRAYSCALE)。 - 设置分辨率:
sensor.set_framesize(sensor.QVGA)(320×240)。 - 设置帧率:
sensor.set_vflip(True)(根据安装方向调整)。 - 启动传感器:
sensor.run(1)。
import sensor, image, time
sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE) # 灰度模式
sensor.set_framesize(sensor.QVGA) # 320×240
sensor.set_vflip(True) # 垂直翻转
sensor.run(1)
clock = time.clock()
while True:
clock.tick()
img = sensor.snapshot() # 获取灰度图
print("帧率:", clock.fps())
3.1.3 实战场景与误区
在测量金属零件边缘时,灰度图能清晰呈现轮廓的亮度跳变。但需注意:灰度图会丢失颜色信息,如果被测物体与背景颜色不同但亮度相近,灰度图将无法区分。此时应改用 RGB 或 LAB 色彩空间。另一个常见误区是忽略光照均匀性——灰度图对光照变化极其敏感,建议在镜头前加装漫射板或使用环形光源。
3.2 二值化:阈值分割与目标提取
3.2.1 核心原理
二值化(Binary Thresholding)是将灰度图或彩色图转换为仅含 0(黑)和 255(白)两种像素值的图像。OpenMV 的 image.binary() 函数支持两种模式:固定阈值和自动阈值(Otsu 法)。固定阈值适用于光照稳定的场景,自动阈值则能根据图像直方图自适应计算最佳分割点。二值化的核心目的是将目标物体从背景中分离出来,为后续的 blob 检测、边缘提取提供干净的输入。
| 阈值类型 | 适用场景 | OpenMV 实现 | 优缺点 |
|---|---|---|---|
| 固定阈值 | 光照恒定、目标与背景对比度高 | img.binary([(threshold_min, threshold_max)]) | 速度快,但适应性差 |
| 自动阈值(Otsu) | 光照变化、直方图双峰明显 | img.binary([(0, 180)], auto=True) | 自适应强,但计算量稍大 |
| LAB 色彩阈值 | 彩色目标分割(如红色零件) | img.binary([(L_min,L_max,A_min,A_max,B_min,B_max)]) | 颜色区分度高,需先转换色彩空间 |
3.2.2 操作流程与代码
# 灰度图二值化示例
img = sensor.snapshot()
# 方法1:固定阈值,假设目标亮度在 100~200 之间
img.binary([(100, 200)])
# 方法2:自动阈值(Otsu)
img.binary([(0, 180)], auto=True)
# 方法3:LAB 色彩阈值(红色目标示例)
img.to_lab() # 转换为 LAB 色彩空间
img.binary([(0, 80, 30, 80, 30, 80)]) # L, A, B 范围
3.2.3 案例拆解:PCB 焊盘定位
假设需要定位 PCB 板上的圆形焊盘,焊盘为金色(高亮度),背景为绿色(低亮度)。初始图像中焊盘亮度约 180~220,背景约 60~100。使用固定阈值 img.binary([(150, 255)]) 即可将焊盘提取为白色区域。但若环境光波动导致焊盘亮度降至 140,固定阈值会失效。此时改用自动阈值 img.binary([(0, 255)], auto=True),Otsu 算法会自动计算最佳分割点(约 130),确保焊盘始终被正确提取。实测数据:固定阈值在光照变化 ±10% 时误检率约 15%,自动阈值误检率降至 2% 以下。
img.erode(1)(腐蚀)或 img.dilate(1)(膨胀)操作来消除噪点。
3.3 色彩空间转换:RGB、LAB 与 YUV 的选择
3.3.1 核心原理
OpenMV 支持 RGB565、GRAYSCALE、LAB、YUV 四种像素格式。其中 LAB 色彩空间将亮度(L)与颜色(A、B)分离,A 通道表示红绿轴(负值偏绿,正值偏红),B 通道表示黄蓝轴(负值偏蓝,正值偏黄)。这种分离特性使得颜色识别不受光照强度影响,非常适合彩色目标检测。YUV 格式则常用于视频传输,Y 为亮度,U/V 为色度,在 OpenMV 中较少直接使用。
3.3.2 转换方法与对比
# RGB 转 LAB
img.to_lab()
# RGB 转 YUV
img.to_yuv()
# 从 LAB 转回 RGB
img.to_rgb()
| 色彩空间 | 通道含义 | 优势 | 劣势 | 典型应用 |
|---|---|---|---|---|
| RGB | 红/绿/蓝 | 直观,硬件原生 | 通道相关性强,受光照影响大 | 彩色显示、简单颜色识别 |
| LAB | 亮度/红绿/黄蓝 | 颜色分离好,光照鲁棒 | 转换计算量稍大 | 颜色追踪、多色分割 |
| YUV | 亮度/色度 | 兼容视频标准 | 色度分辨率较低 | 视频流处理 |
3.3.3 实战场景:红色 LED 指示灯检测
在检测设备面板上的红色 LED 指示灯时,若使用 RGB 阈值,红色在 R 通道值高(200+),但 G、B 通道值也受环境光影响。转换为 LAB 后,红色目标的 A 通道值通常在 40~80 之间,B 通道接近 0,L 通道随亮度变化。通过 img.binary([(0, 80, 30, 80, -20, 20)]) 即可稳定提取红色区域,即使环境光从 200 lux 变化到 800 lux,检测成功率仍保持在 98% 以上。
3.4 感兴趣区域(ROI)设置:聚焦关键区域
3.4.1 核心原理
ROI(Region of Interest)是在图像中指定一个矩形区域,后续所有图像处理操作仅在该区域内执行。ROI 的数学表示为 (x, y, w, h),其中 (x, y) 为左上角坐标,w 为宽度,h 为高度。合理设置 ROI 能带来三大好处:减少计算量(处理像素数减少)、排除干扰(忽略 ROI 外的无关物体)、提高稳定性(固定区域内的光照和背景更一致)。
3.4.2 设置方法与代码
# 定义 ROI:中心区域 160×120
roi = (80, 60, 160, 120)
# 在 ROI 内查找直线
lines = img.find_lines(roi=roi, threshold=1000)
# 在 ROI 内查找色块
blobs = img.find_blobs([(0, 80, 30, 80, 30, 80)], roi=roi)
# 在 ROI 内统计像素均值
stats = img.get_statistics(roi=roi)
3.4.3 案例拆解:轴承外径测量
测量传送带上的轴承外径时,整个图像包含传送带边缘、背景杂物等干扰。通过设置 ROI 为轴承可能出现的区域(例如图像中央 200×150 像素),可以:
- 将 ROI 设定为
(60, 45, 200, 150),覆盖轴承的移动范围。 - 在 ROI 内执行二值化,提取轴承轮廓。
- 使用
find_blobs找到最大色块,计算其外接圆直径。
实测效果:未设置 ROI 时,单帧处理时间约 45ms,且偶尔将传送带边缘误判为轴承;设置 ROI 后处理时间降至 28ms,误判率降为 0。ROI 的代价是如果目标移出 ROI 区域将无法检测,因此需要根据目标运动范围预留足够余量。
3.5 图像滤波:去噪与边缘保留
3.5.1 核心原理
图像滤波是抑制噪声、平滑图像的操作。OpenMV 提供三种常用滤波器:中值滤波(median_blur)、均值滤波(mean_filter)和高斯滤波(gaussian_filter)。中值滤波对椒盐噪声(随机黑白点)效果最佳,且能较好保留边缘;均值滤波平滑效果好但会使边缘模糊;高斯滤波在去噪和边缘保留之间取得平衡,但计算量最大。
| 滤波器 | 核大小 | 适用噪声类型 | 边缘保留 | 计算耗时(320×240) |
|---|---|---|---|---|
| 中值滤波 | 3×3 或 5×5 | 椒盐噪声 | 优秀 | 约 8ms |
| 均值滤波 | 3×3 | 高斯噪声 | 较差 | 约 3ms |
| 高斯滤波 | 3×3 | 高斯噪声 | 良好 | 约 12ms |
3.5.2 操作流程与代码
img = sensor.snapshot()
# 中值滤波,核大小 3
img.median_blur(3)
# 均值滤波,核大小 3
img.mean_filter(3)
# 高斯滤波,核大小 3
img.gaussian_filter(3)
3.5.3 实战案例:金属表面划痕检测
检测金属表面的细微划痕时,原始图像中往往混有传感器噪声和光照反射噪声。直接进行边缘检测会产生大量伪边缘。处理流程:
- 采集灰度图,执行
img.median_blur(3)去除椒盐噪声。 - 使用
img.laplacian(1)提取边缘(拉普拉斯算子对噪声敏感,必须先滤波)。 - 对边缘图二值化,统计边缘像素数量判断是否存在划痕。
对比实验:未滤波时,误检率约 20%(将噪声误判为划痕);中值滤波后误检率降至 3%。但滤波过度(核大小 5×5)会导致细小划痕被平滑掉,漏检率上升至 10%。因此滤波核大小的选择需要根据划痕宽度调整——划痕宽度为 2~3 像素时,3×3 核最合适。
3.6 综合应用:预处理流水线搭建与调优
3.6.1 标准流水线流程
一个完整的 OpenMV 图像预处理流水线应遵循以下顺序:
- 采集设置:选择 GRAYSCALE 或 RGB565 格式,设置合适分辨率。
- ROI 裁剪:先设定 ROI,减少后续处理区域。
- 滤波去噪:根据噪声类型选择中值或高斯滤波。
- 色彩空间转换:如需颜色分割,转换为 LAB。
- 二值化:使用固定或自动阈值提取目标。
- 形态学处理:腐蚀/膨胀消除残留噪点。
- 特征提取:find_blobs、find_lines 等。
3.6.2 调优策略与性能平衡
在实际项目中,预处理流水线的调优需要平衡三个指标:精度、速度、鲁棒性。例如,在高速产线(要求 30 FPS)上,应优先使用灰度图 + 固定阈值 + 均值滤波的组合,单帧处理时间可控制在 15ms 以内;而在精密测量(要求 0.01mm 精度)场景,则需使用 LAB 色彩空间 + 自动阈值 + 中值滤波,处理时间约 30ms,但精度显著提升。
3.6.3 案例复盘:透明玻璃瓶液位检测
背景与约束:某灌装线需检测透明玻璃瓶内的液位高度,瓶子在传送带上以 0.5m/s 速度移动,相机固定拍摄。初始方案直接使用灰度图 + 固定阈值,但玻璃瓶反光导致液位线模糊,误检率高达 25%。
分析过程:通过直方图分析发现,液位区域的灰度值在 120~160 之间,但瓶壁反光区域灰度值也在 140~180 之间,两者重叠。进一步检查发现,液位线具有水平方向的长条特征,而反光区域形状不规则。
优化方案:
- 将 ROI 设置为瓶子中部窄条区域
(80, 100, 160, 80),排除瓶口和瓶底干扰。 - 使用
img.median_blur(3)消除反光产生的椒盐噪声。 - 改用 LAB 色彩空间,利用液位与空气的色差(A 通道差异)进行分割。
- 二值化后使用
find_blobs查找水平长条色块,计算其垂直中心作为液位高度。
结果对比:优化前误检率 25%,优化后降至 1.5%;处理时间从 35ms 降至 28ms;在光照波动 ±15% 时仍保持稳定。
复盘经验:单一预处理手段往往无法解决复杂场景问题,需要组合使用 ROI、滤波、色彩空间转换等多种手段。同时,ROI 的合理设置能显著降低算法难度——将问题从全局搜索简化为局部检测。