一。算法原理。
SAD(Sum of absolute differences)是图像立体匹配中常用的初级块匹配算法,其基本运算思想是求取相对应的左右两个像素块内像素值之差的绝对值之和。
二。计算流程。
前期准备:某物体在同一时刻左右相机拍摄得到的左右图像。left_image,right_image.
!!!强调一点:在进行立体匹配之前,两幅图像处于经过立体校正之后的行对准状态。
(1)设定SAD窗口的大小,left_image中开始匹配的位置,(p,q)以及在right_image中SAD窗口移动的范围D。
(2)在left_image图像中,确定待匹配的像素点的位置(x,y),并以此位置作为SAD窗口的锚点,用SAD窗口覆盖left_image中以(x,y)为锚点的区域regionl。
(3)在right_image图像中,选取匹配的开始点,位置为(m,n),并以该点作为SAD窗口的锚点,用SAD窗口去覆盖,在right_iamge中形成以(m,n)为锚点的图像区域regionr.
(4)定义differernce=regionr-regionl。计算difference中的和。
(5)在right_image图像中沿行方向移动SAD(移动次数为匹配的范围大小),重复步骤(3),(4),并将每次得到的difference记录在mat矩阵中。
(6)找到mat矩阵中difference最小的值,则其所在位置就是right_image和left_image的视差。
三。代码实现
SAD.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-winSize;i++) //左图从DSR开始遍历
{
for(int j=0;j<Height-winSize;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];
//以视差作为Dif的位置标记,下一步通过查找最小Dif的位置即可得到视差。
MM.at<float>(k)=a;
}
}
Point minLoc;
minMaxLoc(MM, NULL, NULL,&minLoc,NULL);
int loc=minLoc.x;//视差值。
//int loc=DSR-loc;
Disparity.at<char>(j,i)=loc*16;
}
double rate=double(i)/(Width);
cout<<"已完成"<<setprecision(2)<<rate*100<<"%"<<endl; //处理进度
}
return Disparity;
}
// MySAD.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include"SAD.h"
int _tmain(int argc, _TCHAR* argv[])
{
Mat Img_L=imread("imL.png",0);
Mat Img_R=imread("imR.png",0);
Mat Disparity; //视差图
//SAD mySAD;
SAD mySAD(7,30);
Disparity=mySAD.computerSAD(Img_L,Img_R);
imshow("Img_L",Img_L);
imshow("Img_R",Img_R);
imshow("Disparity",Disparity);
waitKey();
return 0;
}
实际处理效果如下:
参考链接:https://blog.csdn.net/liulina603/article/details/53302168