双目立体视觉技术一直是机器视觉领域中既备受关注又充满挑战的研究方向。之所以“热”,是因为从机器人导航到医学成像、从工业检测到虚拟现实,其应用前景极为广阔,而且随着光学与计算机科学的不断进步,这项技术将逐步渗透到人类生产生活的方方面面。之所以“难”,则在于摄像机、镜头等硬件设备以及匹配算法本身的局限性,要真正将双目立体视觉应用到实际生产中,仍需投入大量精力攻克技术难关。
一. 简介
双目立体视觉是机器视觉的关键分支之一,自20世纪60年代中期起步,至今已有数十年发展历史。目前,该技术在机器人视觉、航空测绘、军事应用、医学成像、工业检测等领域均有广泛应用。其核心原理并不复杂:利用成像设备从不同角度拍摄被测物体的左右两幅图像,然后基于视差原理,通过三角测量法计算空间点在二维图像上的位置偏差,进而利用该偏差进行三维重建,获取物体的三维几何信息。具体的数学推导在此不再赘述,有兴趣的读者可自行查阅相关资料。
二. 双目立体视觉的三大基本算法原理及代码实现(基于OpenCV)
在双目立体视觉中,基于区域的局部匹配准则主要有三种:SAD(绝对差之和)、SSD(平方差之和)以及SGM(半全局匹配)。下面逐一介绍。
2.1 SAD(绝对差之和)的原理
SAD的基本思想非常直观:对于已经行对准的左右视图,将对应像素块内每个像素灰度差的绝对值累加求和。数学公式如下:

SAD匹配算法的流程可概括为以下几个步骤:
① 输入两幅已完成校正并实现行对准的左视图和右视图。
② 在左视图上选定一个锚点,构建一个类似卷积核的小窗口。
③ 用该小窗口覆盖左视图,提取窗口内的所有像素值。
④ 同样用小窗口覆盖右视图,提取相应位置的像素值。
⑤ 计算左窗口与右窗口像素差的绝对值之和。
⑥ 在右视图上移动小窗口(设定搜索范围),重复步骤④和⑤,直至搜索范围结束。
⑦ 找出SAD值最小的那个小窗口,此时即得到左视图锚点的最佳匹配像素块。
2.1.1 SAD的基于OpenCV的C++代码实现
首先定义SAD算法的头文件(SAD_Algorithm.h):
#include"iostream"
#include"opencv2/opencv.hpp"
#include"iomanip"
using namespace std;
using namespace cv;
class SAD{
public:
SAD() :winSize(7), DSR(30) {}
SAD(int _winSize, int _DSR) :winSize(_winSize), DSR(_DSR) {}
Mat computerSAD(Mat &L, Mat &R); //计算SAD
private:
int winSize; //卷积核尺寸
int DSR; //视差搜索范围
};
Mat SAD::computerSAD(Mat &L, Mat &R){
int Height = L.rows;
int Width = L.cols;
Mat Kernel_L(Size(winSize, winSize), CV_8U, Scalar::all(0));
Mat Kernel_R(Size(winSize, winSize), CV_8U, Scalar::all(0));
Mat Disparity(Height, Width, CV_8U, Scalar(0));
for (int i = 0; i < Width; i++){
for (int j = 0; j < Height; j++){
Kernel_L = L(Rect(i, j, winSize, winSize));
Mat MM(1, DSR, CV_32F, Scalar(0));
for (int k = 0; k < DSR; k++){
int x = i - k;
if (x >= 0){
Kernel_R = R(Rect(x, j, winSize, winSize));
Mat Dif;
absdiff(Kernel_L, Kernel_R, Dif);
Scalar ADD = sum(Dif);
float a = ADD[0];
MM.at(k) = a;
}
}
Point minLoc;
minMaxLoc(MM, NULL, NULL, &minLoc, NULL);
int loc = minLoc.x;
Disparity.at(j, i) = loc * 16;
}
double rate = double(i) / (Width);
cout << "已完成" << setprecision(2) << rate * 100 << "%" << endl;
}
return Disparity;
}
调用示例:
#include"SAD_Algorithm.h"
int main(int argc, char* argv[]){
Mat Img_L = imread("Teddy_L.png", 0);
Mat Img_R = imread("Teddy_R.png", 0);
Mat Disparity;
SAD mySAD(7, 30);
Disparity = mySAD.computerSAD(Img_L, Img_R);
imshow("Teddy_L", Img_L);
imshow("Teddy_R", Img_R);
imshow("Disparity", Disparity);
waitKey();
system("pause");
return 0;
}
2.1.2 SAD算法的运行效果

从运行结果可以明显看出,SAD算法虽然计算速度较快,但生成的视差图质量较差,噪声较多,细节丢失严重。
2.2 SSD(平方差之和)的原理
SSD算法与SAD算法非常相似,区别仅在于将绝对值差替换为平方差。数学公式如下:

由于SSD的算法流程和代码实现与SAD基本一致,此处不再重复贴出代码。感兴趣的读者可以自行实现,只需将absdiff操作改为平方运算即可。
2.3 SGBM(半全局块匹配)的原理
SGM(半全局匹配)是一种经典的视差图计算算法,在OpenCV中的实现称为SGBM。其核心思路是构建一个与视差图相关的全局能量函数,并通过优化使该能量函数最小化。
原始文献:Heiko Hirschmuller. Stereo processing by semiglobal matching and mutual information. Pattern Analysis and Machine Intelligence, IEEE Transactions on, 30(2):328–341, 2008.
能量函数如下:

其中D是视差图,p和q是图像中的像素,Np是p的相邻像素(通常按8连通考虑),C(p,Dp)是当前像素视差为Dp时的代价,P1和P2是惩罚系数(分别用于相邻像素视差差值为1和大于1的情况),I[]是示性函数。
SGBM算法的基本流程:
① 预处理:使用Sobel算子对源图像进行处理,将结果映射为新图像,以获得梯度信息用于后续代价计算。
② 代价计算:采用采样方法计算梯度代价,同时计算源图像的SAD代价。
③ 动态规划:默认四条路径,设置惩罚系数P1、P2,以及图像通道数cn和SAD窗口大小。
④ 后处理:唯一性检测、亚像素插值、左右一致性检测、连通区域检测。
2.3.1 SGBM的基于OpenCV的C++代码实现
首先定义SGBM算法的头文件(SGBM_Algorithm.h),具体参数含义见代码注释:
enum { STEREO_BM = 0, STEREO_SGBM = 1, STEREO_HH = 2, STEREO_VAR = 3, STEREO_3WAY = 4 };
#include"iostream"
#include"opencv2/opencv.hpp"
using namespace std;
using namespace cv;
void calDispWithSGBM(Mat Img_L, Mat Img_R, Mat &imgDisparity8U){
Size imgSize = Img_L.size();
int numberOfDisparities = ((imgSize.width / 8) + 15) & -16;
Ptr sgbm = StereoSGBM::create(0, 16, 3);
int cn = Img_L.channels();
int SADWindowSize = 9;
int sgbmWinSize = SADWindowSize > 0 ? SADWindowSize : 3;
sgbm->setMinDisparity(0);
sgbm->setNumDisparities(numberOfDisparities);
sgbm->setP1(8 * cn * sgbmWinSize * sgbmWinSize);
sgbm->setP2(32 * cn * sgbmWinSize * sgbmWinSize);
sgbm->setDisp12MaxDiff(1);
sgbm->setPreFilterCap(31);
sgbm->setUniquenessRatio(10);
sgbm->setSpeckleWindowSize(100);
sgbm->setSpeckleRange(32);
sgbm->setMode(0);
sgbm->setBlockSize(sgbmWinSize);
int algorithm = STEREO_SGBM;
if (algorithm == STEREO_HH)
sgbm->setMode(StereoSGBM::MODE_HH);
else if (algorithm == STEREO_SGBM)
sgbm->setMode(StereoSGBM::MODE_SGBM);
else if (algorithm == STEREO_3WAY)
sgbm->setMode(StereoSGBM::MODE_SGBM_3WAY);
Mat imgDisparity16S = Mat(Img_L.rows, Img_L.cols, CV_16S);
sgbm->compute(Img_L, Img_R, imgDisparity16S);
imgDisparity16S.convertTo(imgDisparity8U, CV_8U, 255 / (numberOfDisparities * 16.));
}
调用示例:
#include"SGBM_Algorithm.h"
int main(){
Mat Img_L = imread("Teddy_L.png", 0);
Mat Img_R = imread("Teddy_R.png", 0);
Mat Disparity8U = Mat(Img_L.rows, Img_R.cols, CV_8UC1);
calDispWithSGBM(Img_L, Img_R, Disparity8U);
imshow("Teddy_L", Img_L);
imshow("Teddy_R", Img_R);
imshow("Disparity", Disparity8U);
waitKey();
system("pause");
return 0;
}
2.3.2 SGBM算法的运行效果

为了展示SADWindowsize对效果的影响,这里调整了几组参数(其他参数保持不变),结果如下(皆为MODE_SGBM模式):



从对比中可以总结出规律:当SADWindowsize较小时,视差图噪声较多;随着窗口增大,视差图趋于平滑;但窗口过大时,空洞现象会加重。因此,选择合适的窗口大小至关重要,一般建议取9左右。
三. 双目立体视觉的发展现状
在国外,双目立体视觉技术已较为广泛地应用于生产与生活。但在国内,该技术仍处于起步阶段,需要投入更多研发力量,力争实现创新与突破。
3.1 双目立体视觉的发展方向
要实现类似人眼的通用双目立体视觉系统,还有很长的路要走。未来的发展方向可从以下几个方面着力:
① 探索新的更具通用性的计算理论与匹配算法结构,以应对灰度失真、噪声干扰及几何畸变等问题。
② 提升算法性能,持续优化,向实时处理的目标迈进。
③ 建立更有效的双目体视模型,更充分地反映立体视觉的不确定性本质,为匹配提供更多约束信息,降低匹配难度。
④ 强调场景与任务的约束,建立适用于不同场景和任务的双目立体视觉系统标准及方法。
3.2 双目立体视觉的国内外发展动态
双目体视目前主要应用于四大领域:机器人导航、微操作系统的参数检测、三维测量和虚拟现实。
海外方面,日本大阪大学自适应机械系统研究院研制了一种自适应双目视觉伺服系统,利用双目体视原理,以每幅图像中三个相对静止的标志为参考,实时计算目标图像的雅可比矩阵,从而预测目标的下一步运动方向,实现了对运动方式未知的目标的自适应跟踪。该系统仅需两幅图像中均有静止参考标志,无需摄像机参数。
日本奈良科技大学信息科学学院提出了一种基于双目立体视觉的增强现实系统注册方法,通过动态修正特征点位置来提高注册精度。
日本东京大学将实时双目立体视觉与机器人整体姿态信息集成,开发了仿真机器人动态行长导航系统,使机器人能够根据实时情况建立地图并检测障碍物。
日本冈山大学利用立体显微镜、两个CCD摄像头、微操作器等研制了视觉反馈系统,用于细胞操作、基因注射和微装配等场景。
麻省理工学院计算机系统提出了一种新的智能交通工具传感器融合方式:由雷达系统提供目标深度的大致范围,双目立体视觉提供粗略的深度信息,结合改进的图像分割算法,实现了高速环境下对视频图像中目标位置的分割。
华盛顿大学与微软公司合作,为火星卫星“探测者”号研制了宽基线立体视觉系统,使探测器能够在火星上对即将跨越的数千米内地形进行精确定位与导航。
国内方面,浙江大学机械系统完全利用透视成像原理,采用双目体视方法实现了对多自由度机械装置的动态、精确位姿检测。只需从两幅对应图像中提取必要的特征点三维坐标,信息量少,处理速度快,尤其适合动态场景。
维视图像公司采用双目CCD相机,从工业相机内参标定、镜头畸变标定、立体匹配、特征点分割处理等方面给出了详细的数学模型和算法接口。其双目标定软件CCAS采用张正友平面标定法,可支持机器人导航、微操作系统的参数检测、三维测量和虚拟现实等应用。
东南大学电子工程系基于双目立体视觉,提出了一种灰度相关多峰值视差绝对值极小化立体匹配新方法,可对三维不规则物体(如偏转线圈)进行非接触精密测量。
哈工大采用异构双目活动视觉系统实现了全自主足球机器人导航。一个固定摄像机和一个可水平旋转的摄像机分别安装在机器人的顶部和中下部,能够同时监视不同方位视点,体现出比人类视觉更优越的性能。即使其他传感器失效,仅靠双目协调仍能实现全自主导航。
火星863计划课题“人体三维尺寸的非接触测量”采用双视点投影光栅三维测量原理,由双摄像机获取图像对,通过计算机处理,不仅可以获得服装设计所需的特征尺寸,还能得到人体图像上任意一点的三维坐标。
四. 总结
本文从双目立体视觉的三种基本匹配算法入手,介绍了它们的基本原理、操作步骤以及基于OpenCV的代码实现,并对该技术的发展趋势与现状进行了梳理。力求为读者提供一份可供参考和借鉴的入门指南,若有疏漏之处,敬请谅解。
