第1章:立体匹配——从像素到深度的桥梁
各位同学,今天咱们来聊聊立体匹配。说实话,这是整个双目视觉系统里最核心、也最让人头疼的一环。我做了这么多年机器人避障,踩过的坑有一半都跟立体匹配有关。
立体匹配到底在干什么?说白了,就是给左图和右图里的像素点「找对象」。左图里的某个像素,在右图里找到它的孪生兄弟,然后根据这对兄弟的位置差,算出深度信息。你想想看,这不就是模拟人眼的功能吗?
核心思想:立体匹配 = 寻找对应点 + 计算视差
1.1 立体匹配算法分类
立体匹配算法分几大类?我习惯把它们分成三类:全局匹配、局部匹配、半全局匹配。嗯,这里要注意,分类标准其实挺多的,但按计算方式分最实用。
| 算法类别 | 代表算法 | 精度 | 速度 | 适用场景 |
|---|---|---|---|---|
| 全局匹配 | Graph Cut、Belief Propagation | 高 | 慢 | 高精度离线处理 |
| 局部匹配 | BM、SAD、NCC | 低 | 快 | 实时避障、嵌入式 |
| 半全局匹配 | SGBM | 中高 | 中 | 平衡场景、主流选择 |
我在项目中遇到过最尴尬的事:用全局匹配算法跑一个720p的图像,结果一帧算了3秒钟。机器人早就撞墙了。所以啊,选算法一定要看你的硬件平台。
1.2 BM算法——简单粗暴但有效
BM算法,全称Block Matching,块匹配。它的思路特别直白:在左图取一个小窗口,然后在右图的水平方向上滑动,找最像的那个窗口。
怎么判断「像不像」?常用的有SAD(绝对差之和)和SSD(平方差之和)。我一般用SAD,因为计算量小,嵌入式上跑得动。
// BM算法核心伪代码
for each pixel (x, y) in left image:
min_cost = INF
best_disp = 0
for d in [0, max_disp]:
cost = SAD(window_left, window_right(x-d))
if cost < min_cost:
min_cost = cost
best_disp = d
disparity[y][x] = best_disp
我的经验:BM算法在纹理丰富的区域表现不错,但在弱纹理区域(比如白墙)会出很多噪声。我曾经在实验室的白墙前测试,结果视差图跟雪花一样。后来加了预处理,用Canny边缘增强,效果好了不少。
1.3 SGBM算法——BM的进阶版
SGBM,半全局块匹配。它比BM多了什么?多了「全局约束」。BM只考虑局部窗口的相似度,SGBM还考虑了相邻像素之间的视差连续性。
说白了,SGBM在BM的基础上加了一个平滑项。如果相邻像素的视差变化太大,就惩罚它。这样生成的视差图更平滑,噪声更少。
我记得第一次用OpenCV的SGBM时,参数调了一整天。后来发现几个关键参数:
- minDisparity:最小视差,一般设0
- numDisparities:视差范围,必须是16的倍数
- blockSize:匹配窗口大小,奇数,3~11之间
- P1、P2:平滑惩罚参数,P2一般比P1大
注意:P1和P2设得太大,视差图会过于平滑,丢失细节;设得太小,又跟BM一样全是噪声。我一般从P1=8*blockSize^2、P2=32*blockSize^2开始调。
1.4 视差图生成
视差图,就是一张灰度图。每个像素的值代表该点的视差大小。视差越大,说明物体离相机越近;视差越小,物体越远。
生成视差图其实就两步:
- 对每个像素计算最佳视差
- 把视差值映射到0~255的灰度范围
这里有个坑:视差图里会有一些「黑洞」——就是那些匹配失败的像素点。为什么会这样?因为遮挡、弱纹理、重复纹理都会导致匹配失败。
我曾经在户外测试,树影斑驳的地面让视差图出现了大量空洞。后来用了后处理:中值滤波+空洞填充,才勉强能用。
// 视差图后处理示例
cv::Mat disparity, filtered;
cv::medianBlur(disparity, filtered, 5); // 中值滤波去噪
// 空洞填充:用周围有效像素填充无效点
for each invalid pixel:
fill_with_nearest_valid_pixel()
关键点:视差图的质量直接决定深度估计的精度。我见过太多人把精力花在后面的障碍物检测上,结果视差图本身一塌糊涂。记住:垃圾进,垃圾出。
知识体系总览
下面这张图是我自己画的,把立体匹配的核心逻辑串起来了。你仔细看看,就能明白各个算法之间的关系。
从这张图你能看出来,立体匹配的核心就是「精度」和「速度」的博弈。全局匹配精度高但慢,局部匹配快但糙,半全局匹配取了个中间值。我在嵌入式平台上做避障,90%的情况都用SGBM,偶尔用BM做快速预览。
好了,这一章的内容就到这儿。立体匹配是双目视觉的基石,后面的深度估计、障碍物检测都依赖它。你先把这些基础概念吃透,后面咱们再深入细节。