立体匹配—NCC算法代码

本文详细介绍了使用C++编写的NCC算法在立体匹配中的实现过程,包括窗口定义、均值计算、平方差值计算等步骤,并通过实际代码展示了算法的应用。尽管效果一般,但对初学者理解算法原理具有重要意义。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

              NCC算法是立体匹配较为经典的一个算法,其定义为:

其中Wp为以像素p=(px,py)为中心的匹配窗口。I1为左图匹配窗口内的像素,I2为右图匹配窗口内的像素。


下面是用C++编写的算法:

<pre name="code" class="cpp">/*********************************************** 
 *
 *   left_sq存放了左图窗口内像素与均值差值的平方
 *   right_sq存放了右图窗口内像素与均值差值的平方
 *   left_avg存放了左图窗口内像素的均值
 *   right_avg存放了右图窗口内像素的均值
 *
 **************************************************/
void compute_sq(IplImage* left_img, IplImage* right_img, float *left_sq, float *right_sq, float *left_avg, float *right_avg)
{
	//图像的高度和宽度
	int height = left_img->height;
	int width = left_img->width;
	//窗口半径,为奇数
	int N = 5;
	//图像匹配的起始行和终止行
	int line_start = N;
	int line_end = height-N;
	//图像需要视差搜索的起始列和终止列
	int row_start = N;
	int row_end = width-N;
	int addr = 0;
	float temp_l = 0, temp_r = 0, suml = 0, sumr = 0;


	for (int j = line_start; j < line_end; j++)
	{
		for (int i = row_start; i < row_end; i++)
		{
			suml = 0.0, sumr = 0.0;
			temp_l = 0.0; temp_r = 0.0;
			for (int m = j - N; m <= j + N; m++)
			{
				for (int n = i - N; n <= i + N; n++)
				{
					suml += ((uchar*)(left_img->imageData + m*left_img->widthStep))[n];
					//cout << "l_px:" << (int)((uchar*)(left_img->imageData + m*left_img->widthStep))[n] << endl;
					sumr += ((uchar*)(right_img->imageData + m*right_img->widthStep))[n];
					//cout << "r_px:" << (int)((uchar*)(right_img->imageData + m*right_img->widthStep))[n]<<endl;
				}
			}
			addr = j*width + i;
			left_avg[addr] = suml / pow((2 * N + 1), 2);
			right_avg[addr] = sumr / pow((2 * N + 1), 2);
			//cout << "l_avg:" << (float)left_avg[addr]<<endl;
			//cout << "r_avg:" << (float)right_avg[addr]<<endl;
			for (int m = j - N; m <= j + N; m++)
			{
				for (int n = i - N; n <= i + N; n++)
				{
					temp_l += pow((((uchar*)(left_img->imageData + m*left_img->widthStep))[n] - left_avg[addr]), 2);
					temp_r += pow((((uchar*)(right_img->imageData + m*right_img->widthStep))[n] - right_avg[addr]), 2);
				}

				
			}
			left_sq[addr] = temp_l;
			right_sq[addr] = temp_r;
			//cout << "l_sq:" << (float)left_sq[addr] << endl;
			//cout << "r_sq:" << (float)right_sq[addr] << endl;
		}
		

	}

}
void compute_DP(IplImage* left_img, IplImage* right_img, IplImage* depth_img, float *left_sq, float *right_sq, float *left_avg, float *right_avg)
	{
	    //图像的高度和宽度
		int height = left_img->height;
		int width = left_img->width;
		//窗口半径,为奇数
		int N = 5; 
		//搜索的视差值范围
		int maxD = 10;
		int minD = 1;
		//图像匹配的起始行和终止行
		int line_start = N;
		int line_end = height-N;
		//图像需要视差搜索的起始列和终止列
		int row_start = N;
		int row_end = width-N-maxD;

		int addr;
		float max_tmp, cov_tmp;
		//视差
		int vd = 0;

		for (int j = line_start; j < line_end; j++)
		{
			for (int i = row_start; i < row_end; i++)
			{
				for (int d = minD; d <= maxD; d++)
				{
					cov_tmp = 0.0;
					addr = j*width + i;
					for (int m = j - N; m <= j + N; m++)
					{
						for (int n = i - N; n <= i + N; n++)
						{
							//cout << "l_px:" << (int)((uchar*)(left_img->imageData + m*left_img->widthStep))[n] << endl;
							//cout << "l-avg:" << (float)(((uchar*)(left_img->imageData + m*left_img->widthStep))[n] - left_avg[addr]) << endl;
							//cout << "r_px:" << (int)((uchar*)(right_img->imageData + m*right_img->widthStep))[n + d] << endl;
							//cout << "r-avg:" << (float)(((uchar*)(right_img->imageData + m*right_img->widthStep))[n + d] - right_avg[addr+d])<<endl;
							cov_tmp += (((uchar*)(left_img->imageData + m*left_img->widthStep))[n]-left_avg[addr])*(((uchar*)(right_img->imageData + m*right_img->widthStep))[n + d]-right_avg[addr+d]);
						}
					}
					//cout << "a:" << cov_tmp << endl;		
					cov_tmp = (float)(cov_tmp / sqrt(left_sq[addr] * right_sq[addr+d]));
					//cout << "cov_tmp:" << cov_tmp << endl;
					if (d == minD)
					{
						max_tmp = cov_tmp;
						vd = d;
					}
					else
					{
						if (cov_tmp > max_tmp)
						{
							max_tmp = cov_tmp;
							vd = d;
						}
					}
				}
				vd = vd * 20;
				if (vd > 255)
				{
					vd = 255;
				}
				else if (vd < 0)
				{
					vd = 0;
				}
				//cout << "d:" << vd << endl;
				((uchar*)(depth_img->imageData + j*depth_img->widthStep))[i] = vd;
			}
		}	
}
void NCC_Match(IplImage* left_img, IplImage* right_img, IplImage* depth_img)
{
	float *left_sq, *right_sq, *left_avg, *right_avg;
	int img_size = left_img->height*left_img->width;

	left_sq = (float *)malloc(img_size * sizeof(float));
	right_sq = (float *)malloc(img_size * sizeof(float));
	left_avg = (float *)malloc(img_size * sizeof(float));
	right_avg = (float *)malloc(img_size * sizeof(float));

	memset(left_sq, 0, img_size);
	memset(right_sq, 0, img_size);

	compute_sq(left_img, right_img, left_sq, right_sq,left_avg,right_avg);
	compute_DP(left_img, right_img, depth_img, left_sq, right_sq,left_avg,right_avg);

	free(left_sq);
	free(right_sq);

	return;
}




      在配置好opencv的VS环境下,输出标准的左右图运行即可,注意标准图是不需要做矫正的图,网上可以下到几张经典的图片。

      运行结果:

   

    效果只能说非常的一般,只适合初学者入门学习。

   转载请注明出处:http://blog.youkuaiyun.com/lvlitc/article/details/46431245

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值