OpenCV BM对于处理非畸变的立体图像, 主要有以下 3 个步骤:
1. 预处理滤波: 使图像亮度归一化并加强图像纹理
2. 立体匹配: 沿着水平极线用 SAD 窗口进行匹配搜索
3. 再滤波: 去除坏的匹配点.
匹配之后, 如果左右视差检查使能了 disp12MaxDiff >= 0, 还有使用
cv::validateDisparity进行左右视差检查.
最后, 由于匹配窗口捕捉的是物体一侧的前景和另一侧的背景, 基于块匹配在物体边界附近会有一些问题.
这会导致同时产生大小视差的局部区域(散斑). 可以通过 filterSpeckles 滤除散斑.
1 预处理滤波
预处理滤波(Pre-filter), 左右两个矫正过的图像并行计算, 使图像亮度归一化并加强图像纹理.
在预处理滤波中 输入图像被归一化处理, 从而减少了亮度差异, 也增强了图像纹理. 算法:
X-方向 Sobel运算, 可以加强 X 方向图像纹理, 同时归一化图像亮度
(计算图像亮度梯度的近似值, 然后归一化到 [0, 2ftzero], ftzero: 预处理滤波截断值).
“Normalized Response” TODO
这个过程通过在整幅图像上移动窗口实现, 窗口大小 [5×5, 7×7 … 21×21].
最后得到两张滤波后图像, 然后用于下一步匹配
2 立体匹配
即 Stereo correspondence.
立体匹配: 沿着水平极线用 SAD 窗口进行匹配搜索 多路并行计算
结果: 生成视差图.
对左图像的每个特征而言, 搜索右图像中对应行以找到最佳匹配.
校正之后, 每一行就是一条极线, 因此右图像上的匹配位置就一定会在左图像的相同行上
(即具有同样的 y 坐标).
如果特征有足够多的可检测纹理, 并且位于右相机视图内, 就可以找出该匹配位置 如图:
如果左特征像素位于 (x0,y0) 那么对于水平前向平行的相机排列,
它的匹配点(若有)就一定与 x0 在同一行,
3 再滤波
或后滤波即 Post-filters, knock out bad matches.
在立体匹配后开始后滤波成处理, 仅在视差唯一性百分比(uniqueness_ratio)大于 0 时才执行,
去除坏的匹配点, 预防虚匹配.
由于匹配值经常有一个特点 — 强烈的中央峰被副瓣包围
因此视差窗口范围内最低代价是次低代价的 (1 + uniquenessRatio / 100) 倍时,
最低代价对应的视差值才是该像素点的视差, 否则该像素点的视差为 0. 即 SAD 的阈值为:
int const thresh = minsad + (minsad * uniquenessRatio / 100);.
因此检查 idx in [0, nDisp) 共 nDisp 个 SADs,
如果idx 不在 [minDispIdx – 1, minDispIdx + 1] 范围内,
并且SAD 值小于或等于 thresh 则视差无效:
for (d = 0; d < nDisp; ++d) {
if (((d < minDispIdx - 1) || (d > minDispIdx + 1)) && (sad[d] <= thresh)) {
break;
}
}
if (d < nDisp) {
dptr[y * dstep] = FILTERED;
continue;
}
立体匹配主要是通过找出每对图像间的对应关系,根据三角测量原理,得到视差图;在获得了视差信息后,根据投影模型很容易地可以得到原始图像的深度信息和三维信息。立体匹配技术被普遍认为是立体视觉中最困难也是最关键的问题,主要是以下因素的影响:
(1) 光学失真和噪声(亮度、色调、饱和度等失衡)
(2) 平滑表面的镜面反射
(3) 投影缩减(Foreshortening)
(4) 透视失真(Perspective distortions)
(5) 低纹理(Low texture)
(6) 重复纹理(Repetitive/ambiguous patterns)
(7) 透明物体
(8) 重叠和非连续
目前立体匹配算法是计算机视觉中的一个难点和热点,算法很多,但是一般的步骤是:
A、匹配代价计算
匹配代价计算是整个立体匹配算法的基础,实际是对不同视差下进行灰度相似性测量。常见的方法有灰度差的平方SD(squared intensity differences),灰度差的绝对值AD(absolute intensity differences)等。另外,在求原始匹配代价时可以设定一个上限值,来减弱叠加过程中的误匹配的影响。以AD法求匹配代价为例,可用下式进行计算,其中T为设定的阈值。
图18
B、 匹配代价叠加
一般来说,全局算法基于原始匹配代价进行后续算法计算。而区域算法则需要通过窗口叠加来增强匹配代价的可靠性,根据原始匹配代价不同,可分为:
图19
C、 视差获取
对于区域算法来说,在完成匹配代价的叠加以后,视差的获取就很容易了,只需在一定范围内选取叠加匹配代价最优的点(SAD和SSD取最小值,NCC取最大值)作为对应匹配点,如胜者为王算法WTA(Winner-take-all)。而全局算法则直接对原始匹配代价进行处理,一般会先给出一个能量评价函数,然后通过不同的优化算法来求得能量的最小值,同时每个点的视差值也就计算出来了。
D、视差细化(亚像素级)
大多数立体匹配算法计算出来的视差都是一些离散的特定整数值,可满足一般应用的精度要求。但在一些精度要求比较高的场合,如精确的三维重构中,就需要在初始视差获取后采用一些措施对视差进行细化,如匹配代价的曲线拟合、图像滤波、图像分割等。
有关立体匹配的介绍和常见匹配算法的比较,推荐大家看看Stefano Mattoccia 的讲义 Stereo Vision: algorithms and applications,190页的ppt,讲解得非常形象详尽。