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