密集匹配之半全局匹配SGBM

       动态规划算法本身存在拖尾效应,视差突变处易产生错误的匹配,利用态规划进行一维能量累积累,会将错误的视差信息传播给后面的路径上。半全局算法利用多个方向上的信息,试图消除错误信息的干扰,能明显减弱动态规划算法产生的拖尾效应。

       半全局算法试图通过影像上多个方向上一维路径 的约束,来建立一个全局的马尔科夫能量方程,每个像素最终的匹配代价是所有路径信息的叠加,每个像素的视差选择都只是简单通过 WTA(Winner Takes All)决定的。多方向能量聚集如下图所示:


在每个方向上按照动态规划的思想进行能量累积,然后将各个方向上的匹配代价相加得到总的匹配代价,如下式所示:

式中L为当前路径累积的代价函数,P1、P2为像素点与相邻点视差存在较小和较大差异情况下的平滑惩罚,P1<P2,第三项无意义,仅仅是为了消除各个方向路径长度不同造成的影响。将所有r方向的匹配代价相加得到总的匹配代价,如下:


理论概述完毕,详细的可下载论文研究,此处不再详述。下面请看代码:

////FullPath判断是否全路径匹配
void SGM::Matcher(Mat lImg, Mat rImg, int minDeta, int maxDeta,int wSize, bool FullPath)
{
	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;
	P1 = 8 * (2 * wSize + 1)*(2 * wSize + 1);
	P2 = 32 * (2 * wSize + 1)*(2 * wSize + 1);
    printf("半全局SGM匹配:    \n");
	////*********************************构建视差空间***************************************/////
	float ***dif;//////像素的视差空间
	float ***Emat;////能量空间
	float ***TmpE;////临时能量空间
	dif=new float**[lImg.rows];///////初始化视差空间和能量空间
	Emat = new float**[lImg.rows];
	TmpE = new float**[lImg.rows];
	int Deta=maxDeta-minDeta+1;////视差大小
	for (int i = 0; i<lImg.rows; i++)
	{
		printf("构建视差空间和能量空间...%d%%\r", (int)(i*100.0 / (lImg.rows)));
		dif[i]=new float*[lImg.cols ];
		Emat[i] = new float*[lImg.cols];
		TmpE[i] = new float*[lImg.cols];
		for (int j = 0; j<lImg.cols; j++)
		{
			dif[i][j]=new float[Deta];
			Emat[i][j]=new float[Deta];
			TmpE[i][j]=new float[Deta];
			for(int d=0;d<Deta;d++)
			{
				Emat[i][j][d]=0;
				TmpE[i][j][d]=0;
				int rc=j-d-minDeta;///当前视差下左像素对应对的右像素坐标
				if(rc>=0)
				{
					dif[i][j][d]=SAD(lGrayImg, rGrayImg,j,i,rc,i,wSize);//////计算匹配代价
				}
				else
				{
					dif[i][j][d]=d>0?dif[i][j][d-1]:0;
				}
			}
		}
	}
	printf("构建视差空间和能量空间...ok    \n");
	///////////*********************************多方向动态规划***************************************/////

	/////////////////////////////******************左向动态规划**************************////////////////
	for(int r=0;r<lImg.rows;r++)
	{
		float minEmin = FLT_MAX;///截断值防止累积的能量值过大
		for(int d=0;d<Deta;d++)
		{
			TmpE[r][0][d] = dif[r][0][d];
			minEmin = minEmin < dif[r][0][d] ? minEmin : dif[r][0][d];
		}
		for(int c=1;c<lImg.cols;c++)
		{
			float tmpminEmin = FLT_MAX;
			for(int match=0;match<Deta;match++)
			{
				float Emin=FLT_MAX;//////当前状态下路径代价
				for(int pred=0;pred<Deta;pred++)
				{
					float Esmooth=abs(match-pred)>1?P2:(abs(match-pred)==0?0:P1);//////平滑项
					float E = dif[r][c][match] + Esmooth + TmpE[r][c - 1][pred];
					if(E<Emin)
					{
						Emin=E;
					}
				}
				TmpE[r][c][match] = Emin - minEmin;
				Emat[r][c][match] = Emat[r][c][match] + TmpE[r][c][match];
				tmpminEmin = tmpminEmin < Emat[r][c][match] ? tmpminEmin : Emat[r][c][match];
			}
			minEmin = tmpminEmin;
		}
	}
	///////////////////////******************右向动态规划**************************////////////////
	for(int r=0;r<lImg.rows;r++)
	{
		float minEmin = FLT_MAX;///截断值防止累积的能量值过大
		for(int d=0;d<Deta;d++)
		{
			TmpE[r][lImg.cols-1][d]=dif[r][lImg.cols-1][d];
			minEmin = minEmin < dif[r][lImg.cols - 1][d] ? minEmin : dif[r][lImg.cols - 1][d];
		}
		for(int c=lImg.cols-2;c>=0;--c)
		{
			float tmpminEmin = FLT_MAX;
			for(int match=0;match<Deta;match++)
			{
				float Emin=FLT_MAX;//////当前状态下路径代价
				for (int pred = 0; pred<Deta; pred++)
				{
					float Esmooth=abs(match-pred)>1?P2:(abs(match-pred)==0?0:P1);//////平滑项
					float E=dif[r][c][match]+Esmooth+TmpE[r][c+1][pred];
					if(E<Emin)
					{
						Emin=E;
					}
				}
				TmpE[r][c][match] = Emin - minEmin;
				Emat[r][c][match] = Emat[r][c][match] + TmpE[r][c][match];
				tmpminEmin = tmpminEmin < TmpE[r][c][match] ? tmpminEmin : TmpE[r][c][match];
			}
			minEmin = tmpminEmin;
		}
	}
	///////////////////////******************下向动态规划**************************////////////////
	for(int c=0;c<lImg.cols;c++)
	{
		float minEmin = FLT_MAX;///截断值防止累积的能量值过大
		for(int d=0;d<Deta;d++)
		{
			TmpE[0][c][d]=dif[0][c][d];
			minEmin = minEmin < dif[0][c][d] ? minEmin : dif[0][c][d];
		}
		for(int r=1;r<lImg.rows;r++)
		{
			float tmpminEmin = FLT_MAX;
			for(int match=0;match<Deta;match++)
			{
				float Emin=FLT_MAX;//////当前状态下路径代价
				for (int pred = 0; pred<Deta; pred++)
				{
					float Esmooth=abs(match-pred)>1?P2:(abs(match-pred)==0?0:P1);//////平滑项
					float E=dif[r][c][match]+Esmooth+TmpE[r-1][c][pred];
					if(E<Emin)
					{
						Emin=E;
					}
				}
				TmpE[r][c][match] = Emin - minEmin;
				Emat[r][c][match] = Emat[r][c][match] + TmpE[r][c][match];
				tmpminEmin = tmpminEmin < TmpE[r][c][match] ? tmpminEmin : TmpE[r][c][match];
			}
			minEmin = tmpminEmin;
		}
	}
	/////////////////////////******************上向动态规划**************************////////////////
	for(int c=0;c<lImg.cols;c++)
	{
		float minEmin = FLT_MAX;///截断值防止累积的能量值过大
		for(int d=0;d<Deta;d++)
		{
			TmpE[lImg.rows-1][c][d]=dif[lImg.rows-1][c][d];
			minEmin = minEmin < dif[lImg.rows - 1][c][d] ? minEmin : dif[lImg.rows - 1][c][d];
		}
		for(int r=lImg.rows-2;r>=0;--r)
		{
			float tmpminEmin = FLT_MAX;
			for(int match=0;match<Deta;match++)
			{
				float Emin=FLT_MAX;//////当前状态下路径代价
				for (int pred = 0; pred<Deta; pred++)
				{
					float Esmooth=abs(match-pred)>1?P2:(abs(match-pred)==0?0:P1);//////平滑项
					float E=dif[r][c][match]+Esmooth+TmpE[r+1][c][pred];
					if(E<Emin)
					{
						Emin=E;
					}
				}
				TmpE[r][c][match] = Emin - minEmin;
				Emat[r][c][match] = Emat[r][c][match] + TmpE[r][c][match];
				tmpminEmin = tmpminEmin < TmpE[r][c][match] ? tmpminEmin : TmpE[r][c][match];
			}
			minEmin = tmpminEmin;
		}
	}
	if (FullPath)
	{
	      /////剩余路径我省略了,原理与上面相同
	}


	Mat dispImg(lImg.size(),CV_8UC1,Scalar::all(0));//////视差图
	for(int i=0;i<lImg.rows;i++)
	{
		for(int j=0;j<lImg.cols;j++)
		{
			float Emind=FLT_MAX;
			int pmind=NULL;
			for(int d=0;d<Deta;d++)
			{
				if(Emat[i][j][d]<Emind)
				{
					Emind=Emat[i][j][d];
					pmind=d;
				}
			}
			if (j - pmind -minDeta >= 0)
			{
				dispImg.ptr<uchar>(i)[j] = (pmind + minDeta);/////3是为了增加对比度
			}
		}
	}
	printf("SGM匹配...ok    \n");


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

猜你喜欢

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