4. 图像预处理:直方图均衡化、高斯滤波与中值滤波、边缘检测(Sobel/Canny)

图像预处理,说白了就是给原始图像“洗个澡、化个妆”。

在立体视觉系统里,这一步直接决定了后续匹配的成败。我见过太多项目,算法选得再好,预处理没做好,结果就是一团糟。

今天咱们就聊聊四个核心操作:直方图均衡化、高斯滤波、中值滤波,还有边缘检测。嗯,一个一个来。

4.1 直方图均衡化:让暗部亮起来

你想想看,如果一张图整体偏暗,或者对比度极低,立体匹配基本就废了。为什么?因为特征点太少,找不到对应关系。

直方图均衡化就是干这个的。它把像素值的分布拉得更均匀,让暗的地方变亮,亮的地方不至于过曝。

核心原理: 将原始图像的灰度直方图从集中在某个区间,变换为在整个灰度范围内均匀分布。

我在项目中遇到过这种情况:一个室内场景,光照不均匀,左边亮右边暗。直接做立体匹配,右边区域几乎全是误匹配。用了直方图均衡化之后,效果立竿见影。

// C++ 示例:直方图均衡化
cv::Mat src = cv::imread("left.png", cv::IMREAD_GRAYSCALE);
cv::Mat dst;
cv::equalizeHist(src, dst);
小技巧: 如果图像本身对比度已经很好,就别用均衡化了。它会过度拉伸噪声,反而坏事。

4.2 高斯滤波:平滑噪声,保留边缘

高斯滤波是我最常用的平滑手段。它不像均值滤波那样“一刀切”,而是根据像素距离中心的远近,赋予不同的权重。

说白了,离中心越近的像素,贡献越大;越远的,贡献越小。这个权重分布,就是高斯函数。

// C++ 示例:高斯滤波
cv::Mat blurred;
cv::GaussianBlur(src, blurred, cv::Size(5, 5), 1.5);

参数 cv::Size(5, 5) 是核大小,1.5 是标准差。核越大,平滑越强,但边缘也会越模糊。

注意: 核大小必须是奇数。我刚开始学的时候,用了个偶数,结果程序直接崩了。嗯,这个坑我踩过。

高斯滤波特别适合处理高斯噪声。什么是高斯噪声?就是那种在图像上随机分布、亮度变化平缓的噪点。比如传感器热噪声。

4.3 中值滤波:干掉椒盐噪声

中值滤波的思路很简单:把窗口内的像素排序,取中间值代替中心像素。

它对付椒盐噪声特别有效。什么是椒盐噪声?就是图像上随机出现的黑白点,像撒了盐和胡椒一样。

// C++ 示例:中值滤波
cv::Mat median;
cv::medianBlur(src, median, 5);

参数 5 是窗口大小,同样必须是奇数。

避坑指南: 我曾经在一个项目中,图像里既有高斯噪声又有椒盐噪声。我一开始只用了高斯滤波,结果椒盐噪声根本去不掉。后来改成先中值滤波、再高斯滤波,效果就好多了。

中值滤波的优点是能很好地保留边缘。因为它不取平均,而是取中间值,所以边缘不会像高斯滤波那样被模糊掉。

4.4 边缘检测:Sobel 与 Canny

边缘检测是立体视觉里最关键的一步。为什么?因为边缘是图像中信息最丰富的区域,也是立体匹配最可靠的依据。

4.4.1 Sobel 算子

Sobel 算子是一种基于一阶导数的边缘检测方法。它通过计算图像在 x 方向和 y 方向上的梯度,来找到边缘。

// C++ 示例:Sobel 边缘检测
cv::Mat grad_x, grad_y, grad;
cv::Sobel(src, grad_x, CV_16S, 1, 0, 3);
cv::Sobel(src, grad_y, CV_16S, 0, 1, 3);
cv::convertScaleAbs(grad_x, grad_x);
cv::convertScaleAbs(grad_y, grad_y);
cv::addWeighted(grad_x, 0.5, grad_y, 0.5, 0, grad);

参数 1, 0 表示计算 x 方向梯度,0, 1 表示 y 方向。最后用 addWeighted 把两个方向合并。

特点: Sobel 计算简单、速度快,但对噪声敏感。所以一般先做高斯滤波,再做 Sobel。

4.4.2 Canny 边缘检测

Canny 是目前最主流的边缘检测算法。它比 Sobel 复杂,但效果也更好。

它的流程大致是:

  1. 高斯滤波去噪
  2. 计算梯度幅值和方向
  3. 非极大值抑制(只保留梯度方向上的局部最大值)
  4. 双阈值检测(高阈值确定强边缘,低阈值连接弱边缘)
// C++ 示例:Canny 边缘检测
cv::Mat edges;
cv::Canny(src, edges, 50, 150);

参数 50 是低阈值,150 是高阈值。这两个值需要根据图像内容调整。

个人经验: 我一般把高阈值设为低阈值的 2-3 倍。如果边缘太多、太碎,就提高低阈值;如果边缘断断续续,就降低低阈值。

你想想看,Canny 为什么比 Sobel 好?因为它做了非极大值抑制,边缘更细、更干净。而且双阈值机制能有效抑制噪声产生的伪边缘。

4.5 知识体系总览

下面这张图,是我自己整理的预处理流程。你看一眼,心里就有数了。

图像预处理知识体系 原始图像 直方图均衡化 高斯滤波 中值滤波 边缘检测(Sobel / Canny) 预处理结果

这张图展示了预处理的标准流程:原始图像 → 直方图均衡化 → 滤波(高斯或中值) → 边缘检测 → 输出结果。

重要提醒: 流程不是死的。如果图像本身对比度很好,可以跳过均衡化。如果噪声很少,滤波也可以省掉。一切以实际效果为准。

好了,这一章的内容就到这里。预处理是立体视觉的基石,花时间把它做好,后面的匹配和重建会轻松很多。


公众号:蓝海资料掘金营,微信deep3321