第二章:图像预处理基础——色彩空间转换、高斯滤波与Canny边缘检测

各位同学好,我是你们的自动驾驶感知工程师。今天咱们聊聊图像预处理里最基础、也最关键的几个操作。说实话,很多刚入行的同学觉得预处理就是“调参”,随便搞搞就行。但我在实际项目中吃过不少亏——有一次车道线检测在晴天表现完美,一到阴雨天就崩了,最后发现是色彩空间没选对。嗯,从那以后我再也不敢小看预处理了。

2.1 色彩空间转换:为什么RGB不够用?

咱们摄像头拍出来的图像,默认是RGB格式。R、G、B三个通道,每个0-255。这玩意儿对人眼很友好,但对机器来说,有个致命问题——它对光照变化太敏感了。

你想想看,同样是黄色车道线,晴天和阴天的RGB值能差出一大截。我当年做第一个车道线项目时,用RGB阈值分割,调了一周参数,结果换个场景就废了。后来换成HSV,半小时搞定。

2.1.1 RGB vs HSV

色彩空间 通道含义 光照鲁棒性 典型应用
RGB 红、绿、蓝 差 显示、存储
HSV 色调、饱和度、明度 好 颜色分割、目标检测
灰度 亮度 中等 边缘检测、特征提取

HSV里,H(色调)代表颜色本质,S(饱和度)代表颜色纯度,V(明度)代表亮度。你看,亮度和颜色分开了。所以提取黄色车道线时,我只需要固定H的范围,V随便变都不影响。这就是为什么自动驾驶里HSV用得比RGB多。

核心结论:做车道线检测,优先用HSV做颜色分割。RGB更适合做显示,不适合做分析。

2.1.2 代码实现:RGB转HSV

import cv2
import numpy as np

# 读取图像
img = cv2.imread('road.jpg')  # OpenCV默认是BGR,不是RGB!

# 转HSV
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

# 定义黄色范围(我常用的值)
lower_yellow = np.array([20, 100, 100])
upper_yellow = np.array([30, 255, 255])

# 提取黄色区域
mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
result = cv2.bitwise_and(img, img, mask=mask)

个人经验:H的范围别设太死。我一般给±10的余量。比如黄色H是25,我就设15-35。不同摄像头色彩偏差不一样,建议先拍几张图看看直方图。

2.2 高斯滤波:去噪但不模糊边缘

图像里总有噪声。椒盐噪声、高斯噪声,乱七八糟的。直接做边缘检测,噪声会被当成边缘,结果惨不忍睹。所以要先滤波。

滤波方法很多,均值滤波、中值滤波、高斯滤波。我个人习惯用高斯滤波。为什么?因为它模拟了人眼的视觉特性——中心权重高,边缘权重低。说白了,就是“近朱者赤,近墨者黑”。

2.2.1 高斯核原理

高斯滤波的核心是高斯核。一个5x5的高斯核长这样:

1/273 × [
  [1,  4,  7,  4, 1],
  [4, 16, 26, 16, 4],
  [7, 26, 41, 26, 7],
  [4, 16, 26, 16, 4],
  [1,  4,  7,  4, 1]
]

你看,中心41最大,角落1最小。这样平滑时,中心像素贡献最大,边缘像素贡献小。既去除了噪声,又保留了边缘的锐度。

避坑指南:我曾经把高斯核设得太大(比如15x15),结果车道线边缘全糊了,检测精度直接掉20%。核大小一般取3x3或5x5就够了,别贪心。

2.2.2 代码实现

# 高斯滤波
blurred = cv2.GaussianBlur(img, (5, 5), 1.5)

# 参数说明:
# (5,5) 是核大小,必须奇数
# 1.5 是标准差σ,控制平滑程度

σ越大,图像越模糊。我一般设1.0-2.0之间。太小了去噪效果差,太大了边缘丢失。

2.3 Canny边缘检测:从图像到轮廓

好了,现在图像干净了。下一步是找边缘。Canny算法是业界标准,没有之一。为什么?因为它做了三件事:去噪、找梯度、双阈值筛选。

2.3.1 Canny四步走

  1. 高斯滤波——去噪,上面刚讲过
  2. 计算梯度幅值和方向——用Sobel算子,得到每个像素的梯度大小和方向
  3. 非极大值抑制——只保留梯度方向上的局部最大值,让边缘变细
  4. 双阈值检测——高阈值确定强边缘,低阈值连接弱边缘

第四步是关键。高阈值设高了,边缘断断续续;设低了,噪声全进来了。我一般设高阈值100-150,低阈值50-75。比例大概2:1到3:1。

我的调参口诀:高阈值定主边缘,低阈值补断点。先调高阈值,再调低阈值。

2.3.2 代码实现

# 先转灰度
gray = cv2.cvtColor(blurred, cv2.COLOR_BGR2GRAY)

# Canny边缘检测
edges = cv2.Canny(gray, 50, 150)

# 50是低阈值,150是高阈值
# 返回二值图像,边缘为白色(255),背景为黑色(0)

你看,代码就一行。但这一行背后,是几十年的计算机视觉研究积累。

2.4 本章知识体系

下面这张图,是我自己画的预处理流程。建议你保存下来,每次做项目前看一眼。

图像预处理流程 原始图像 (BGR) 色彩空间转换 (BGR → HSV / Gray) 高斯滤波 (去噪) Canny边缘检测 输入:摄像头原始帧 分离颜色与亮度信息 消除噪声,保留边缘 输出:二值边缘图

2.5 实战建议

最后,给你几个我在项目中踩过的坑:

  • 别在RGB里做阈值分割——光照一变就废,血的教训
  • 高斯核大小和σ要匹配——核越大,σ也要越大,否则效果奇怪
  • Canny阈值不是固定的——不同场景要调,我一般先试(50,150),再微调
  • 预处理顺序不能乱——先转色彩空间,再滤波,最后边缘检测。顺序错了,效果天差地别

一个小技巧:调试时,把每一步的中间结果都显示出来。看一眼灰度图、看一眼滤波后的图、看一眼边缘图。哪里出问题一目了然。我调试时至少开4个窗口。

好了,这一章就到这里。预处理是基本功,但基本功往往决定上限。你把这些搞透了,后面做车道线拟合、地图匹配才会顺手。

可可精品资料库