密集匹配之动态规划DP

       动态规划通常应用于最优化问题的求解中,Baker、Ohta 等将动态规划引入立体匹配中来获取视差图。动态规划匹配的过程可以分为两个阶段,建立视差空间和动态规划优化,将立体匹配问题转化为视差空间内寻找最优路径的问题。

       密集匹配通常会充分利用影像间的核线约束条件,对立体像对进行核线纠正,这样同名像点肯定位于对应的同名核线上,降低了匹配的难度。视差空间影像DSI(Disparity Space Image)是一种反映核线立体像对间同一扫描线视差关系的数据结构,将视差分析转化为一种类似的谱分析。其数学表达为:


其中w 为图像的宽度, NaN 表示在该视差值为d 时不可能有对应的同名点,L((* ))  是对应点之间的相似性测度函数。在匹配核线影像时,逐行计算像素的DSI,将每一行的DSI 依次叠加起来构成一个三维空间,称之为视差空间,视差空间包含了每个像素所有可能的视差取值。如下图所示,图中的x、y 代表图像的横纵坐标,d 表示视差搜索范围。


在建立好视差空间后,立体匹配问题就会转化为在视差空间内寻找最佳路径的问题,该路径上的视差累积的能量最小,相似性最大。一般采用从图像左边到右边的顺序,逐行进行。

实现过程如下:

//////minDeta、maxDeta为最小、大视差,P1、P2为平滑惩罚项
void Dynamic(Mat lImg,Mat rImg,int minDeta,int maxDeta,int P1,int P2)
{
	if (lImg.empty() || rImg.empty() || (lImg.type() != CV_8UC3&&lImg.type() != CV_8UC1) || (rImg.type() != CV_8UC3&&rImg.type() != CV_8UC1)) return;
	Mat lGrayImg = lImg.type == CV_8UC3 ? cvtColor(lImg, lGrayImg, COLOR_BGR2GRAY) : lImg;
	Mat rGrayImg = rImg.type == CV_8UC3 ? cvtColor(rImg, rGrayImg, COLOR_BGR2GRAY) : rImg;
	
	int detaRang=maxDeta-minDeta+1;///视差范围
	Mat dispMap(lGrayImg.size(),CV_8UC1,Scalar::all(0));//////左视差图
	for(int r=0;r<lGrayImg.rows;r++)
	{
		printf("动态规划...%d%%\r",(int)(r*100.0/(lGrayImg.rows)));/////方便查看进度
		Mat dif(Size(detaRang, lGrayImg.cols),CV_32FC1,Scalar::all(0));////视差空间
		Mat Emat(Size(detaRang, lGrayImg.cols),CV_32FC1,Scalar::all(0));/////能量空间
		Mat Dmat(Size(detaRang, lGrayImg.cols),CV_8UC1,Scalar::all(0));/////路径走向
		for(int c=0;c<lGrayImg.cols;c++)
		{
			for(int d=0;d<detaRang;d++)
			{
				int rc=c-d-minDeta;///当前视差下左像素对应对的右像素坐标
				if(rc>=0)
				{
					dif.ptr<float>(c)[d] = SAD(lGrayImg, rGrayImg,Point2i(c, r),Point2i(c - d, r), 0);//////AD匹配代价
				}
				else
				{
					dif.ptr<float>(c)[d]=c<minDeta?0:dif.ptr<float>(c)[d-1];/////防止边界超限处代价对整体路径的影响
				}
			}
		}
		for(int c=1;c<lGrayImg.cols;c++)
		{
			for(int match=0;match<detaRang;match++)
			{
				float tmpmin=FLT_MAX;//////当前状态下路径代价
				int pmin=NULL;////路径走向
				for(int pre=0;pre<=detaRang;pre++)
				{
					int Edata=dif.ptr<float>(c)[match];////数据项
					int dd=abs(match-pre);
					float Esmooth=dd>1?P2:(dd==0?0:P1);////视差等于1与大于1时候的平滑惩罚不同
					float E=Edata+Esmooth+Emat.ptr<float>(c-1)[pre];/////路径能量值
					if (E<tmpmin)
					{
						tmpmin=E;
						pmin=pre;
					}
				}
				Emat.ptr<float>(c)[match]=tmpmin;
				Dmat.ptr<uchar>(c)[match]=pmin;
			}
		}
		int minID=0;
		float min=Emat.ptr<float>(lGrayImg.cols-1)[0];
		for(int i=0;i<detaRang;++i)
		{
			if(Emat.ptr<float>(lGrayImg.cols-1)[i]<min)
			{
				minID =i;
				min=Emat.ptr<float>(lGrayImg.cols-1)[i];
			}
		}
		//取得视差
		for(int c= lGrayImg.cols-1;c>=0;--c)
		{
			int d=Dmat.ptr<uchar>(c)[minID];
			minID =d;
			dispMap.ptr<uchar>(r)[c]=d+minDeta;/////
		}
	}	
}

本人水平有限,如有错误,还望不吝指正,代码有一定删减,没有重新编译,如有错误,请自行调试,有问题请邮箱联系。

猜你喜欢

转载自blog.csdn.net/u014493244/article/details/72780696