立体匹配——在两个不同摄像机视图中匹配一个三维点——只能在两个摄像机视图重叠的可视区域进行计算,OpenCV实现了两种立体匹配算法,并且它们共享通用的对象接口。首先是快匹配算法(block matching,BM),它使用小的 “绝对值之差的和” (SAD)窗口来寻找左右立体校正图像之间的匹配点,更适合与强纹理图像;第二个是半全局块匹配算法(semi-global block matching,SGBM),为SGM的变形形式。
SGBM算法与BM算法的不同之处:
1.SGBM使用Birchfield-Tomasi度量[Birchfield99]在子像素水平上进行匹配。
2.SGBM视图基于所计算的深度信息来强制实现全局平滑约束。
这两种算法是互补的,BM计算稍快一些,但SGBM的可靠性和精确性更高一些。
使用BM算法和SGBM算法
这两个算法都需要调用create()
函数获取一个智能指针指向cv::StereoBM
对象 或者 cv::StereoSGBM
对象,但在参数设置上是不相同的。
对于BM算法:静态create()
函数有两个参数,numDisparities 和 blockSize;numDisparities 视差搜索范围。对于每个像素算法将找到从0(默认最小视差)到numdifferences的最佳视差。然后可以通过改变最小视差来移动搜索范围。;blockSize 设置每个像素周围的区域大小,也会计算 “绝对差分符号” 度量。这个值越大找到的错误匹配越少。但是请注意,算法的计算成本不仅与窗口面积(即窗口大小的平方)相关,靠近不连续处(对象的边缘)将可能找不到匹配,结果是空白区域,因为在接近对象边缘处不存在视差。且窗口越大,空白区域的厚度越大;窗口越大,获得的深度图越模糊,意味着视差图中对象的剪影将越平滑,以一种近似的方式捕捉实际剪影。
create()
函数的使用方法
Ptr<StereoBM> bm =StereoBM::create (
int numDisparities = 0,
int blockSize = 21
)
在调用create()
函数创建BM算法的智能指针后,还可以通过一系列set*()
函数进一步配置。可进一步配置的参数有:
参数名称 | 参数含义 |
---|---|
numDisparities | 最大视差与最小视差的差值,该值总是大于零,且必须能被16整除。 |
PreFilterCap | 预滤波图像像素的截断值。该算法首先在每个像素处计算x导数,并按[-preFilterCap, preFilterCap]间隔剪辑其值。结果值被传递给Birchfield-Tomasi像素代价函数。 |
PreFilterSize | 用于设置滤波器的窗口大小 |
PreFilterType | 用于设置滤波器的类型 |
ROI1 | 与setROI2设置对矫正后的图像的裁剪区域 |
ROI2 | 与setROI1设置对矫正后的图像的裁剪区域 |
TextureThreshold | 用于设置低纹理区域的判断阈值 |
UniquenessRatio | 计算出的最佳(最小)成本函数值应该“赢得”第二个最佳值的百分比余量,从而认为找到的匹配是正确的。通常情况下,5-15范围内的值就足够了。 |
set*
函数指的是“set”+“参数名称”+“()”,且*()*中写入该参数的取值,例如:setMinDisparity(0)
像如下这样进行进一步配置
bm->setROI1(validROIL);
bm->setROI2(validROIR);
bm->setPreFilterCap(31);
bm->setMinDisparity(0);
bm->setNumDisparities(numDisparities * 16 + 16);
bm->setTextureThreshold(10);
bm->setUniquenessRatio(uniquenessRatio);
bm->setSpeckleWindowSize(100);
bm->setSpeckleRange(32);
bm->setDisp12MaxDiff(-1);
对于SGBM算法:
SGBM算法在利用create()
函数创建cv::StereoSGBM
对象的智能指针时,就设置了其用到的所有参数。在OpenCV StereoSGBM类中给出的create()
函数声明是这样的:
static Ptr<StereoSGBM> cv::StereoSGBM::create(
int minDisparity = 0,
int numDisparities = 16,
int blockSize = 3,
int P1 = 0,
int P2 = 0,
int disp12MaxDiff = 0,
int preFilterCap = 0,
int uniquenessRatio = 0,
int speckleWindowSize = 0,
int speckleRange = 0,
int mode = StereoSGBM::MODE_SGBM
)
其中最后一个参数mode的取值是枚举的,可以直接输入对应的整型值,缺省值为0,即MODE_SGBM
enum
{
MODE_SGBM = 0,
MODE_HH = 1,
MODE_SGBM_3WAY = 2
};
各参数的含义如下表
参数名称 | 参数含义 |
---|---|
minDisparity | 最小可能的视差值。通常为零,但有时校正算法会使图像移位,因此需要对该参数进行相应调整 |
numDisparities | 最大视差减去最小视差。该值总是大于零。在当前实现中,该参数必须能被16整除 |
blockSize | 匹配的块大小。必须是奇数>=1。通常情况下,它应该在3…11范围 |
P1 | 控制视差平滑的第一个参数,P1是对相邻像素之间视差变化的加减1的惩罚,8*number_of_image_channels*SADWindowSize*SADWindowSize |
P2 | 第二个控制视差平滑的参数。值越大,视差越平滑。P2是相邻像素之间视差变化大于1的惩罚。该算法要求P2 > P1,32*number_of_image_channels*SADWindowSize*SADWindowSize |
disp12MaxDiff | 左右的最大允许差异(以整数像素单位)差异检查,将其设置为非正数以禁用检查 |
preFilterCap | 预滤波图像像素的截断值。首先是算法在每个像素处计算x导数,并按[-preFilterCap, preFilterCap]间隔剪辑其值 |
uniquenessRatio | 最佳(最小)计算成本函数的百分比边际Value应该“赢得”第二个最佳值,从而认为找到的匹配是正确的。通常在5-15个范围内 |
speckleWindowSize | 平滑视差区域的最大大小,以考虑它们的噪点和无效。将其设置为0以禁用散斑过滤。否则,将其设置在50 - 200的范围内 |
speckleRange | 每个连接组件内的最大视差变化,如果进行散斑过滤,将参数设置为正值,将隐式地乘以16。通常1或2就足够了 |
mode | 选择MODE_SGBM,MODE_HH = 1,MODE_SGBM_3WAY 三种计算模式 |
在自行搭建双目设备过程中,软件部分的立体匹配我使用的就是SGBM算法,下面是在我的实际工程项目中定义的SGBM算法的指针,参数取值为这个工程的实际取值
cv::Ptr<cv::StereoSGBM> sgbm = cv::StereoSGBM::create(
0, 144, 5, 8 * 8 * 5 * 5, 8 * 32 * 5 * 5, 1, 63, 10, 100, 16, 0);
SGBM算法也可以像BM算法那样使用一些列set*
函数设置其参数。
如果我的文章有幸被您看到,希望您能不吝赐教,向您学习,感觉写得不错的话请点个赞哦。