Opencv——立体匹配

Opencv——立体匹配

立体匹配

立体匹配,就是匹配两个不同的摄像头视图的3D点,只有在两个摄像头的重叠视图内的可视区域才能被计算,这就是为什么要使摄像头靠近前向平行了。

立体匹配的目的是通过匹配得到视差。

立体匹配的方法

BM算法:

该算法代码:

CvStereoBMState *BMState = cvCreateStereoBMState();  
int SADWindowSize=15;   
BMState->SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 9;  
BMState->minDisparity = 0;  
BMState->numberOfDisparities = 32;  
BMState->textureThreshold = 10;  
BMState->uniquenessRatio = 15;  
BMState->speckleWindowSize = 100;  
BMState->speckleRange = 32;  
BMState->disp12MaxDiff = 1;  
cvFindStereoCorrespondenceBM( left, right, left_disp_,BMState);  
   cvNormalize( left_disp_, left_vdisp, 0, 256, CV_MINMAX ); 

其中minDisparity是控制匹配搜索的第一个参数,代表了匹配搜苏从哪里开始,numberOfDisparities表示最大搜索视差数uniquenessRatio表示匹配功能函数,这三个参数比较重要,可以根据实验给予参数值。

该方法速度最快,一副320*240的灰度图匹配时间为31ms,视差图如下。
Opencv——立体匹配_第1张图片
这图是解释BM(bidirectional matching)算法的很好的例子。进行双向匹配,首先通过匹配代价在右图中计算得出匹配点。然后相同的原理及计算在左图中的匹配点。比较找到的左匹配点和源匹配点是否一致,如果你是,则匹配成功。

SGBM方法

cv::StereoSGBM sgbm;  
        sgbm.preFilterCap = 63;  
        int SADWindowSize=11;   
        int cn = 1;  
        sgbm.SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 3;  
        sgbm.P1 = 4*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;  
        sgbm.P2 = 32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;  
        sgbm.minDisparity = 0;  
        sgbm.numberOfDisparities = 32;  
        sgbm.uniquenessRatio = 10;  
        sgbm.speckleWindowSize = 100;  
        sgbm.speckleRange = 32;  
        sgbm.disp12MaxDiff = 1;  
        sgbm(left , right , left_disp_);  
        sgbm(right, left  , right_disp_); 

各参数设置如BM方法,速度比较快,320*240的灰度图匹配时间为78ms,视差效果如下图。
Opencv——立体匹配_第2张图片

GC方法:

vStereoGCState* state = cvCreateStereoGCState( 16, 2 );  
left_disp_  =cvCreateMat( left->height,left->width, CV_32F );  
right_disp_ =cvCreateMat( right->height,right->width,CV_32F );  
cvFindStereoCorrespondenceGC( left, right, left_disp_, right_disp_, state, 0 );  
cvReleaseStereoGCState( &state ); 

该方法速度超慢,但效果超好。
Opencv——立体匹配_第3张图片

函数解释

(1)StereoBMState

1.// 预处理滤波参数

preFilterType:预处理滤波器的类型,主要是用于降低亮度失真(photometric distortions)、消除噪声和增强纹理等, 有两种可选类型:CV_STEREO_BM_NORMALIZED_RESPONSE(归一化响应) 或者 CV_STEREO_BM_XSOBEL(水平方向Sobel算子,默认类型), 该参数为 int 型;
preFilterSize:预处理滤波器窗口大小,容许范围是[5,255],一般应该在 5x5…21x21 之间,参数必须为奇数值, int 型
preFilterCap:预处理滤波器的截断值,预处理的输出值仅保留[-preFilterCap, preFilterCap]范围内的值,参数范围:1 - 31(文档中是31,但代码中是 63), int
2.// SAD 参数

SADWindowSize:SAD窗口大小,容许范围是[5,255],一般应该在 5x5 至 21x21 之间,参数必须是奇数,int 型
minDisparity:最小视差,默认值为 0, 可以是负值,int 型
numberOfDisparities:视差窗口,即最大视差值与最小视差值之差, 窗口大小必须是 16 的整数倍,int 型
3.// 后处理参数

textureThreshold:低纹理区域的判断阈值。如果当前SAD窗口内所有邻居像素点的x导数绝对值之和小于指定阈值,则该窗口对应的像素点的视差值为 0(That is, if the sum of absolute values of x-derivatives computed over SADWindowSize by SADWindowSize pixel neighborhood is smaller than the parameter, no disparity is computed at the pixel),该参数不能为负值,int 型
uniquenessRatio:视差唯一性百分比, 视差窗口范围内最低代价是次低代价的(1 + uniquenessRatio/100)倍时,最低代价对应的视差值才是该像素点的视差,否则该像素点的视差为 0 (the minimum margin in percents between the best (minimum) cost function value and the second best value to accept the computed disparity, that is, accept the computed disparity d^ only if SAD(d) >= SAD(d^) x (1 + uniquenessRatio/100.) for any d != d*+/-1 within the search range ),该参数不能为负值,一般5-15左右的值比较合适,int 型
speckleWindowSize:检查视差连通区域变化度的窗口大小, 值为 0 时取消 speckle 检查,int 型
speckleRange:视差变化阈值,当窗口内视差变化大于阈值时,该窗口内的视差清零,int 型
4.// OpenCV2.1 新增的状态参数

roi1, roi2:左右视图的有效像素区域,一般由双目校正阶段的 cvStereoRectify 函数传递,也可以自行设定。一旦在状态参数中设定了 roi1 和 roi2,OpenCV 会通过cvGetValidDisparityROI 函数计算出视差图的有效区域,在有效区域外的视差值将被清零。
disp12MaxDiff:左视差图(直接计算得出)和右视差图(通过cvValidateDisparity计算得出)之间的最大容许差异。超过该阈值的视差值将被清零。该参数默认为 -1,即不执行左右视差检查。int 型。注意在程序调试阶段最好保持该值为 -1,以便查看不同视差窗口生成的视差效果。具体请参见《使用OpenGL动态显示双目视觉三维重构效果示例》一文中的讨论。
在上述参数中,对视差生成效果影响较大的主要参数是 SADWindowSize、numberOfDisparities 和 uniquenessRatio 三个,一般只需对这三个参数进行调整,其余参数按默认设置即可。

在OpenCV2.1中,BM算法有C和C++ 两种实现模块。

(2)StereoSGBMState

SGBM算法的状态参数大部分与BM算法的一致,下面只解释不同的部分:

1.SADWindowSize: SAD窗口大小,容许范围是[1,11],一般应该在 3x3 至 11x11 之间,参数必须是奇数,int 型
P1, P2:控制视差变化平滑性的参数。P1、P2的值越大,视差越平滑。P1是相邻像素点视差增/减 1 时的惩罚系数;P2是相邻像素点视差变化值大于1时的惩罚系数。P2必须大于P1。OpenCV2.1提供的例程 stereo_match.cpp 给出了 P1 和 P2 比较合适的数值。
fullDP:布尔值,当设置为 TRUE 时,运行双通道动态编程算法(full-scale 2-pass dynamic programming algorithm),会占用O(WHnumDisparities)个字节,对于高分辨率图像将占用较大的内存空间。一般设置为 FALSE。

注意OpenCV2.1的SGBM算法是用C++ 语言编写的,没有C实现模块。与H. Hirschmuller提出的原算法相比,主要有如下变化:

算法默认运行单通道DP算法,只用了5个方向,而fullDP使能时则使用8个方向(可能需要占用大量内存)。
算法在计算匹配代价函数时,采用块匹配方法而非像素匹配(不过SADWindowSize=1时就等于像素匹配了)。
匹配代价的计算采用BT算法(“Depth Discontinuities by Pixel-to-Pixel Stereo” by S. Birchfield and C. Tomasi),并没有实现基于互熵信息的匹配代价计算。
增加了一些BM算法中的预处理和后处理程序。

(3)StereoGCState

GC算法的状态参数只有两个:numberOfDisparities 和 maxIters ,并且只能通过 cvCreateStereoGCState 在创建算法状态结构体时一次性确定,不能在循环中更新状态信息。GC算法并不是一种实时算法,但可以得到物体轮廓清晰准确的视差图,适用于静态环境物体的深度重构。

注意GC算法只能在C语言模式下运行,并且不能对视差图进行预先的边界延拓,左右视图和左右视差矩阵的大小必须一致。

原理解释

目前立体匹配算法是计算机视觉中的一个难点和热点,算法很多,但是一般的步骤是:
A、匹配代价计算

匹配代价计算是整个立体匹配算法的基础,实际是对不同视差下进行灰度相似性测量。常见的方法有灰度差的平方SD(squared intensity differences),灰度差的绝对值AD(absolute intensity differences)等。另外,在求原始匹配代价时可以设定一个上限值,来减弱叠加过程中的误匹配的影响。以AD法求匹配代价为例,可用下式进行计算,其中T为设定的阈值。

这就是在参数设置中阈值的作用,在视差图中经常有黑色区域,就是和阈值的设置关。

B、 匹配代价叠加

一般来说,全局算法基于原始匹配代价进行后续算法计算。而区域算法则需要通过窗口叠加来增强匹配代价的可靠性,根据原始匹配代价不同,可分为:

此图是核心算法的解释,就是计算区域内像素差值,可以为单个像素也可以为一定区域内,主要看SAD的窗口大小的设置,同时SAD设置决定误匹配的多少和运算效率问题,所以大小设置一定要很慎重。

C、 视差获取

对于区域算法来说,在完成匹配代价的叠加以后,视差的获取就很容易了,只需在一定范围内选取叠加匹配代价最优的点(SAD和SSD取最小值,NCC取最大值)作为对应匹配点,如胜者为王算法WTA(Winner-take-all)。而全局算法则直接对原始匹配代价进行处理,一般会先给出一个能量评价函数,然后通过不同的优化算法来求得能量的最小值,同时每个点的视差值也就计算出来了。

D、视差细化(亚像素级)

大多数立体匹配算法计算出来的视差都是一些离散的特定整数值,可满足一般应用的精度要求。但在一些精度要求比较高的场合,如精确的三维重构中,就需要在初始视差获取后采用一些措施对视差进行细化,如匹配代价的曲线拟合、图像滤波、图像分割等。

亚像素级的处理就是涉及到BMState参数设置后后续参数的设置了。

在调试参数时,用此函数在线调,而方便

int createTrackbar(const String& trackbarname, const String& winname,
                              int* value, int count,
                              TrackbarCallback onChange = 0,
                              void* userdata = 0);

你可能感兴趣的:(机器视觉)