3、图像处理基础:灰度图、二值化、色彩空间转换、感兴趣区域(ROI)设置与图像滤波

在机器视觉测量任务中,OpenMV 摄像头采集到的原始图像通常是 RGB565 彩色图像,但直接对彩色图像进行边缘检测或几何测量往往计算量大、噪声干扰多且精度不稳定。因此,图像预处理是视觉测量流程中至关重要的一环。本章将系统讲解灰度图转换、二值化分割、色彩空间转换、ROI 区域设定以及图像滤波五大基础操作,帮助你在 OpenMV 环境中建立一套高效、稳定的图像预处理流水线。

OpenMV 图像预处理流水线 原始图像 RGB565 彩色 320×240 / 640×480 灰度转换 sensor.set_pixformat (GRAYSCALE) 图像滤波 中值/高斯/均值 去除椒盐噪声 二值化 threshold 阈值分割 0/255 黑白图像 ROI 感兴趣区域 (x, y, w, h) 矩形裁剪 减少计算量,排除干扰 色彩空间转换 RGB ↔ LAB / YUV 颜色识别与追踪 预处理完成 → 视觉测量 find_lines / find_blobs / 几何测量 边缘检测、尺寸测量、缺陷检测 图3-1 OpenMV图像预处理标准流程:从采集到可测量的二值化/ROI图像

3.1 灰度图转换:降低维度,保留关键亮度信息

3.1.1 核心原理

灰度图(Grayscale)是将 RGB 三通道彩色图像转换为单通道亮度图像的过程。OpenMV 的传感器在 GRAYSCALE 模式下直接输出 8 位灰度值(0~255),每个像素仅占用 1 字节存储空间,相比 RGB565 的 2 字节减少了一半内存占用,同时帧率可提升约 30%~50%。灰度图保留了图像中物体与背景的亮度对比关系,而边缘检测、几何测量等算法本质上依赖的是亮度梯度变化,因此灰度图是视觉测量的理想输入。

关键参数:OpenMV 的灰度模式分辨率最高支持 640×480,但实际测量中建议使用 320×240 或 240×160,以平衡精度与帧率。灰度转换的数学本质是加权平均:Gray = 0.299R + 0.587G + 0.114B,OpenMV 硬件自动完成该转换,无需软件计算。

3.1.2 操作流程

  1. 初始化传感器:sensor.reset() 复位摄像头。
  2. 设置像素格式:sensor.set_pixformat(sensor.GRAYSCALE)。
  3. 设置分辨率:sensor.set_framesize(sensor.QVGA)(320×240)。
  4. 设置帧率:sensor.set_vflip(True)(根据安装方向调整)。
  5. 启动传感器: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% 以下。

风险提示:二值化后图像中可能残留孤立噪点(白色小点),这些噪点会干扰后续的 blob 检测。建议在二值化后执行一次 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 像素),可以:

  1. 将 ROI 设定为 (60, 45, 200, 150),覆盖轴承的移动范围。
  2. 在 ROI 内执行二值化,提取轴承轮廓。
  3. 使用 find_blobs 找到最大色块,计算其外接圆直径。

实测效果:未设置 ROI 时,单帧处理时间约 45ms,且偶尔将传送带边缘误判为轴承;设置 ROI 后处理时间降至 28ms,误判率降为 0。ROI 的代价是如果目标移出 ROI 区域将无法检测,因此需要根据目标运动范围预留足够余量。

经验建议:ROI 并非越小越好。过小的 ROI 会导致目标频繁出界,建议 ROI 尺寸为目标尺寸的 1.5~2 倍,并确保目标在 ROI 内至少有 70% 的像素占比。

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 实战案例:金属表面划痕检测

检测金属表面的细微划痕时,原始图像中往往混有传感器噪声和光照反射噪声。直接进行边缘检测会产生大量伪边缘。处理流程:

  1. 采集灰度图,执行 img.median_blur(3) 去除椒盐噪声。
  2. 使用 img.laplacian(1) 提取边缘(拉普拉斯算子对噪声敏感,必须先滤波)。
  3. 对边缘图二值化,统计边缘像素数量判断是否存在划痕。

对比实验:未滤波时,误检率约 20%(将噪声误判为划痕);中值滤波后误检率降至 3%。但滤波过度(核大小 5×5)会导致细小划痕被平滑掉,漏检率上升至 10%。因此滤波核大小的选择需要根据划痕宽度调整——划痕宽度为 2~3 像素时,3×3 核最合适。

注意事项:滤波会改变图像的频率特性,过度滤波会丢失高频细节(如锐利边缘)。在测量精度要求高的场景(如亚像素边缘检测),建议先滤波再测量,但滤波核不宜超过 5×5。

3.6 综合应用:预处理流水线搭建与调优

3.6.1 标准流水线流程

一个完整的 OpenMV 图像预处理流水线应遵循以下顺序:

  1. 采集设置:选择 GRAYSCALE 或 RGB565 格式,设置合适分辨率。
  2. ROI 裁剪:先设定 ROI,减少后续处理区域。
  3. 滤波去噪:根据噪声类型选择中值或高斯滤波。
  4. 色彩空间转换:如需颜色分割,转换为 LAB。
  5. 二值化:使用固定或自动阈值提取目标。
  6. 形态学处理:腐蚀/膨胀消除残留噪点。
  7. 特征提取:find_blobs、find_lines 等。

3.6.2 调优策略与性能平衡

在实际项目中,预处理流水线的调优需要平衡三个指标:精度、速度、鲁棒性。例如,在高速产线(要求 30 FPS)上,应优先使用灰度图 + 固定阈值 + 均值滤波的组合,单帧处理时间可控制在 15ms 以内;而在精密测量(要求 0.01mm 精度)场景,则需使用 LAB 色彩空间 + 自动阈值 + 中值滤波,处理时间约 30ms,但精度显著提升。

性能参考:OpenMV Cam H7 Plus 在 320×240 分辨率下,灰度图采集约 5ms,中值滤波(3×3)约 8ms,二值化约 2ms,find_blobs 约 5ms,总耗时约 20ms,可稳定运行在 40 FPS 以上。

3.6.3 案例复盘:透明玻璃瓶液位检测

背景与约束:某灌装线需检测透明玻璃瓶内的液位高度,瓶子在传送带上以 0.5m/s 速度移动,相机固定拍摄。初始方案直接使用灰度图 + 固定阈值,但玻璃瓶反光导致液位线模糊,误检率高达 25%。

分析过程:通过直方图分析发现,液位区域的灰度值在 120~160 之间,但瓶壁反光区域灰度值也在 140~180 之间,两者重叠。进一步检查发现,液位线具有水平方向的长条特征,而反光区域形状不规则。

优化方案:

  1. 将 ROI 设置为瓶子中部窄条区域 (80, 100, 160, 80),排除瓶口和瓶底干扰。
  2. 使用 img.median_blur(3) 消除反光产生的椒盐噪声。
  3. 改用 LAB 色彩空间,利用液位与空气的色差(A 通道差异)进行分割。
  4. 二值化后使用 find_blobs 查找水平长条色块,计算其垂直中心作为液位高度。

结果对比:优化前误检率 25%,优化后降至 1.5%;处理时间从 35ms 降至 28ms;在光照波动 ±15% 时仍保持稳定。

复盘经验:单一预处理手段往往无法解决复杂场景问题,需要组合使用 ROI、滤波、色彩空间转换等多种手段。同时,ROI 的合理设置能显著降低算法难度——将问题从全局搜索简化为局部检测。