4. 图像预处理:图像灰度化、高斯滤波、直方图均衡化、Canny边缘检测
各位同学,咱们今天聊聊图像预处理。说实话,这部分内容在自动驾驶感知里,就像盖房子打地基一样。地基没打好,后面什么车道线检测、可行驶区域计算,全得翻车。
我在项目里见过不少团队,一上来就急着跑模型,结果边缘检测出来全是噪声。为什么?预处理没做到位。今天我就把这四个核心步骤掰开揉碎了讲给你听。
4.1 图像灰度化
摄像头采集到的原始图像,通常是RGB三通道的彩色图。但咱们做边缘检测时,其实不需要颜色信息。为什么?因为边缘是亮度突变的地方,跟颜色关系不大。
灰度化说白了,就是把每个像素的RGB值,按照一个权重公式,算出一个灰度值。常用的公式是:
Gray = 0.299 * R + 0.587 * G + 0.114 * B
这个权重不是随便定的。人眼对绿色最敏感,对蓝色最不敏感。所以绿色权重最高,蓝色最低。嗯,这里要注意,有些库直接用平均值法(R+G+B)/3,效果其实差不少。
cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)。它内部用的就是上面那个加权公式。别自己手写,容易出错。
4.2 高斯滤波
灰度化之后,图像里还有噪声。比如摄像头传感器的高斯噪声、路面反光造成的椒盐噪声。这些噪声如果不处理,Canny边缘检测会把它当成边缘,结果就是一堆假边缘。
高斯滤波的原理,我简单说一下。它用一个高斯核(一个权重矩阵)去扫过整张图像。每个像素的新值,是它周围像素的加权平均。离中心越近,权重越大。
举个例子,一个5x5的高斯核,中心点的权重最高,边缘的权重低。这样平滑效果自然,不会像均值滤波那样产生块状效应。
import cv2
import numpy as np
# 读取图像
img = cv2.imread('road.jpg', cv2.IMREAD_GRAYSCALE)
# 高斯滤波,核大小5x5,sigma=1.0
blurred = cv2.GaussianBlur(img, (5, 5), 1.0)
4.3 直方图均衡化
你想想看,自动驾驶的车子,一天要经历各种光照条件。大晴天、阴天、黄昏、隧道入口。光照不均匀,图像对比度就会很差。直方图均衡化就是来解决这个问题的。
它的原理很简单:把图像的灰度直方图,从集中在某个小范围,拉伸到整个0-255范围。这样暗的地方变亮,亮的地方变暗,细节就出来了。
我举个例子。你在隧道里拍到的路面,整体偏暗,灰度值集中在30-80之间。均衡化之后,灰度值分布到0-255,路面的纹理、裂缝全都能看清了。
# 直方图均衡化
equalized = cv2.equalizeHist(blurred)
但这里有个坑。直方图均衡化会放大噪声。所以一定要先做高斯滤波,再做均衡化。顺序不能乱。
重要: 在夜间场景下,我建议用CLAHE(对比度受限自适应直方图均衡化)。它把图像分成小块,每块单独做均衡化,效果比全局均衡化好很多。代码是 cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))。
4.4 Canny边缘检测
终于到了核心环节。Canny边缘检测,说白了就是找图像中亮度变化剧烈的地方。这些地方,就是道路边界、车道线、路沿。
Canny算法分四步走:
- 高斯滤波:去噪声,我们已经做过了。
- 计算梯度:用Sobel算子算水平和垂直方向的梯度,得到梯度幅值和方向。
- 非极大值抑制:只保留梯度方向上的局部最大值,把其他像素置零。这一步让边缘变细。
- 双阈值检测:设定高低两个阈值。高于高阈值的,是强边缘;介于中间的,是弱边缘;低于低阈值的,直接丢弃。弱边缘只有跟强边缘相连,才保留。
为什么Canny这么流行?因为它能检测出单像素宽度的边缘,而且对噪声鲁棒。我在项目中用过很多边缘检测算法,Sobel太粗,Laplacian对噪声太敏感,最后还是Canny最稳。
# Canny边缘检测
# 参数:低阈值50,高阈值150
edges = cv2.Canny(equalized, 50, 150)
# 显示结果
cv2.imshow('Edges', edges)
cv2.waitKey(0)
4.5 完整流程串联
好了,四个步骤都讲完了。咱们把它们串起来,形成一个完整的预处理流水线:
import cv2
def preprocess(image_path):
# 1. 读取图像
img = cv2.imread(image_path)
# 2. 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 3. 高斯滤波
blurred = cv2.GaussianBlur(gray, (5, 5), 1.0)
# 4. 直方图均衡化
equalized = cv2.equalizeHist(blurred)
# 5. Canny边缘检测
edges = cv2.Canny(equalized, 50, 150)
return edges
这个流程,我在多个量产项目里都用过。效果稳定,计算量也不大。在嵌入式平台上,一帧640x480的图像,预处理时间能控制在10ms以内。
4.6 常见问题与调试
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 边缘太多,全是噪声 | 高斯滤波核太小,或Canny阈值太低 | 增大核大小,提高低阈值 |
| 边缘断断续续 | Canny阈值太高,或图像对比度不足 | 降低阈值,或加强直方图均衡化 |
| 边缘位置偏移 | 高斯滤波核太大,导致边缘模糊 | 减小核大小,或改用双边滤波 |
| 处理速度慢 | 图像分辨率太高,或核太大 | 先降采样,再预处理 |
好了,图像预处理这部分就讲到这里。记住,预处理做得好,后面的道路边界检测就成功了一半。下一章咱们聊聊如何从这些边缘中提取出真正的道路边界线。
公众号:蓝海资料掘金营,微信deep3321