第一章 图像预处理:让机器人的眼睛看清世界

各位同学,欢迎来到《双目视觉在机器人避障中的应用》课程。

我是你们的老朋友,一个在机器人视觉和SLAM领域摸爬滚打多年的工程师。今天咱们正式开始第一讲:图像预处理。

你想想看,机器人要避障,首先得“看见”障碍物吧?但摄像头直接拍回来的原始图像,就像没擦干净的眼镜——全是噪点、光线不均、颜色杂乱。机器要是直接拿这种图去算深度、做避障,那结果肯定惨不忍睹。我当年刚入行时,就吃过这个亏,以为算法牛逼就行,结果预处理没做好,后面全白搭。

核心观点:图像预处理不是可选项,而是必选项。它决定了后续所有算法的上限。

好,废话不多说。咱们直接进入正题,看看预处理到底要做哪几件事。

1.1 图像灰度化:扔掉颜色,保留结构

双目视觉里,我们最关心的是物体的轮廓和纹理,而不是它是什么颜色。彩色图像每个像素有RGB三个通道,数据量是灰度图的三倍。处理起来慢,而且颜色信息对避障来说基本没用。

为什么要灰度化?

  • 减少计算量:三通道变单通道,速度翻倍。
  • 消除光照干扰:不同颜色的物体在灰度下只反映亮度,更稳定。
  • 为后续算法做准备:边缘检测、特征匹配等算法大多基于灰度图。

灰度化的公式其实很简单,就是加权平均:

Gray = 0.299 * R + 0.587 * G + 0.114 * B

这个权重是模拟人眼对颜色的敏感度。绿色最敏感,权重最高;蓝色最不敏感,权重最低。嗯,这里要注意,有些偷懒的库直接用平均值,效果会差一些。我个人习惯用OpenCV的 cv2.cvtColor(),它默认就是这个加权公式。

我的经验:在嵌入式平台上,如果CPU资源紧张,可以用整数运算代替浮点:Gray = (77*R + 150*G + 29*B) >> 8。速度能快不少。

1.2 直方图均衡化:让暗处也能看清

灰度化之后,图像可能整体偏暗或偏亮。比如机器人在地下室或者强光下,细节全丢了。这时候就需要直方图均衡化。

说白了,就是把像素值的分布“拉平”。原来集中在暗区的像素,被拉伸到整个0-255范围。这样暗处的纹理就显现出来了。

效果对比:

处理前 处理后
直方图集中在低灰度区 直方图均匀分布
暗部细节丢失 暗部细节清晰可见
对比度低 对比度增强

代码实现也很简单:

import cv2
img = cv2.imread('image.jpg', 0)  # 以灰度图读取
equ = cv2.equalizeHist(img)       # 直方图均衡化

避坑指南:我曾经在户外场景直接对整图做均衡化,结果天空过曝,地面细节反而没了。后来改用CLAHE(对比度受限自适应直方图均衡化),效果就好多了。CLAHE只对局部区域做均衡化,不会放大噪声。

1.3 高斯滤波:温柔的降噪

图像里总有些随机噪点,比如传感器热噪声、光照闪烁。这些噪点如果不处理,后续边缘检测会检测出一堆假边缘。

高斯滤波是一种线性平滑滤波器。它用高斯核与图像做卷积,每个像素的值被周围像素的加权平均替代。权重由高斯分布决定——离中心越近,权重越大。

为什么用高斯?

  • 它模拟了自然界中噪声的分布(很多噪声是高斯分布的)。
  • 它比均值滤波更平滑,同时保留更多边缘信息。

核大小和标准差是关键参数。核越大,平滑效果越强,但细节丢失也越多。我一般用5x5的核,标准差取1.0,算是个折中。

blur = cv2.GaussianBlur(img, (5, 5), 1.0)

小技巧:在嵌入式设备上,如果实时性要求高,可以用分离的高斯滤波(先水平再垂直),速度能提升不少。OpenCV默认就是这么干的。

1.4 中值滤波:暴力去噪,专治椒盐

高斯滤波对付高斯噪声很有效,但遇到“椒盐噪声”(黑白点)就力不从心了。这时候需要中值滤波。

中值滤波的原理很简单:把像素邻域内的所有值排序,取中间值作为新像素值。椒盐噪声要么是极大值(白点),要么是极小值(黑点),排序后肯定被排到两端,中间值自然就是正常像素。

适用场景:

  • 摄像头传感器坏点
  • 传输过程中的丢包噪声
  • 激光雷达点云投影到图像后的离群点
median = cv2.medianBlur(img, 5)  # 5x5邻域

注意:中值滤波计算量比高斯滤波大,尤其是核尺寸大的时候。在实时系统中,我一般只用3x3或5x5的核。核太大,图像会变得像油画一样,边缘全糊了。

1.5 边缘检测:找到物体的轮廓

好了,图像干净了,接下来要找到障碍物的边界。边缘检测就是干这个的。

最经典的是Canny边缘检测。它分四步:

  1. 高斯滤波:先降噪(前面刚讲过)。
  2. 计算梯度:用Sobel算子算水平和垂直方向的梯度,得到边缘强度和方向。
  3. 非极大值抑制:只保留梯度方向上的局部最大值,让边缘变细。
  4. 双阈值检测:设定高低两个阈值。高于高阈值的肯定是边缘,低于低阈值的肯定不是,介于中间的如果与高阈值边缘相连,则保留。

为什么Canny这么流行?因为它能检测出连续、单像素宽的边缘,非常适合后续的直线检测、轮廓提取。

edges = cv2.Canny(img, 50, 150)  # 低阈值50,高阈值150

关键参数:高阈值和低阈值的比例一般在2:1到3:1之间。我习惯用50和150。如果边缘太多(噪声多),就提高低阈值;如果边缘太少(漏检),就降低高阈值。

为什么会这样?因为低阈值控制边缘的“灵敏度”,高阈值控制边缘的“确定性”。你想想看,如果低阈值设得太低,很多噪声也会被当成边缘;设得太高,真正的弱边缘就丢了。

知识体系总览

为了让你对整个预处理流程有个全局认识,我画了张图:

双目视觉图像预处理流程 原始彩色图像 灰度化 直方图均衡化 高斯滤波 中值滤波 Canny边缘检测

从这张图你可以看到,预处理是一个流水线:原始图像 → 灰度化 → 直方图均衡化 → 滤波(高斯或中值,根据噪声类型选择) → 边缘检测。每一步的输出都是下一步的输入,环环相扣。

总结一下:图像预处理不是花架子,它是机器人避障的基石。灰度化减负,直方图均衡化提亮,高斯滤波去噪,中值滤波除椒盐,Canny边缘检测找轮廓。每一步都有它的道理,缺一不可。

好了,第一章就到这里。记住,预处理做得好,后面的立体匹配和避障算法才能发挥出真正的实力。别嫌麻烦,多调调参数,多看看效果图。我当年就是靠着一遍遍调参,才摸清了每个算法的脾气。

专注资料整理