void cv::crossCorr( const Mat& img, const Mat& templ, Mat& corr, Point anchor, double delta, int borderType ) { CvMat _img = img, _templ = templ, _corr = corr; icvCrossCorr( &_img, &_templ, &_corr, anchor, delta, borderType ); }
CV_IMPL void cvMatchTemplate( const CvArr* _img, const CvArr* _templ, CvArr* _result, int method ) { cv::Ptr<CvMat> sum, sqsum; int coi1 = 0, coi2 = 0; int depth, cn; int i, j, k; CvMat stub, *img = (CvMat*)_img; CvMat tstub, *templ = (CvMat*)_templ; CvMat rstub, *result = (CvMat*)_result; CvScalar templ_mean = cvScalarAll(0); double templ_norm = 0, templ_sum2 = 0; int idx = 0, idx2 = 0; double *p0, *p1, *p2, *p3; double *q0, *q1, *q2, *q3; double inv_area; int sum_step, sqsum_step; int num_type = method == CV_TM_CCORR || method == CV_TM_CCORR_NORMED ? 0 : method == CV_TM_CCOEFF || method == CV_TM_CCOEFF_NORMED ? 1 : 2; int is_normed = method == CV_TM_CCORR_NORMED || method == CV_TM_SQDIFF_NORMED || method == CV_TM_CCOEFF_NORMED; img = cvGetMat( img, &stub, &coi1 ); templ = cvGetMat( templ, &tstub, &coi2 ); result = cvGetMat( result, &rstub ); if( CV_MAT_DEPTH( img->type ) != CV_8U && CV_MAT_DEPTH( img->type ) != CV_32F ) CV_Error( CV_StsUnsupportedFormat, "The function supports only 8u and 32f data types" ); if( !CV_ARE_TYPES_EQ( img, templ )) CV_Error( CV_StsUnmatchedSizes, "image and template should have the same type" ); if( CV_MAT_TYPE( result->type ) != CV_32FC1 ) CV_Error( CV_StsUnsupportedFormat, "output image should have 32f type" ); if( img->rows < templ->rows || img->cols < templ->cols ) { CvMat* t; CV_SWAP( img, templ, t ); } if( result->rows != img->rows - templ->rows + 1 || result->cols != img->cols - templ->cols + 1 ) CV_Error( CV_StsUnmatchedSizes, "output image should be (W - w + 1)x(H - h + 1)" ); if( method < CV_TM_SQDIFF || method > CV_TM_CCOEFF_NORMED ) CV_Error( CV_StsBadArg, "unknown comparison method" ); depth = CV_MAT_DEPTH(img->type); cn = CV_MAT_CN(img->type); icvCrossCorr( img, templ, result ); if( method == CV_TM_CCORR ) return; inv_area = 1./((double)templ->rows * templ->cols); sum = cvCreateMat( img->rows + 1, img->cols + 1, CV_MAKETYPE( CV_64F, cn )); if( method == CV_TM_CCOEFF ) { cvIntegral( img, sum, 0, 0 ); templ_mean = cvAvg( templ ); q0 = q1 = q2 = q3 = 0; } else { CvScalar _templ_sdv = cvScalarAll(0); sqsum = cvCreateMat( img->rows + 1, img->cols + 1, CV_MAKETYPE( CV_64F, cn )); cvIntegral( img, sum, sqsum, 0 ); cvAvgSdv( templ, &templ_mean, &_templ_sdv ); templ_norm = CV_SQR(_templ_sdv.val[0]) + CV_SQR(_templ_sdv.val[1]) + CV_SQR(_templ_sdv.val[2]) + CV_SQR(_templ_sdv.val[3]); if( templ_norm < DBL_EPSILON && method == CV_TM_CCOEFF_NORMED ) { cvSet( result, cvScalarAll(1.) ); return; } templ_sum2 = templ_norm + CV_SQR(templ_mean.val[0]) + CV_SQR(templ_mean.val[1]) + CV_SQR(templ_mean.val[2]) + CV_SQR(templ_mean.val[3]); if( num_type != 1 ) { templ_mean = cvScalarAll(0); templ_norm = templ_sum2; } templ_sum2 /= inv_area; templ_norm = sqrt(templ_norm); templ_norm /= sqrt(inv_area); // care of accuracy here q0 = (double*)sqsum->data.ptr; q1 = q0 + templ->cols*cn; q2 = (double*)(sqsum->data.ptr + templ->rows*sqsum->step); q3 = q2 + templ->cols*cn; } p0 = (double*)sum->data.ptr; p1 = p0 + templ->cols*cn; p2 = (double*)(sum->data.ptr + templ->rows*sum->step); p3 = p2 + templ->cols*cn; sum_step = sum ? sum->step / sizeof(double) : 0; sqsum_step = sqsum ? sqsum->step / sizeof(double) : 0; for( i = 0; i < result->rows; i++ ) { float* rrow = (float*)(result->data.ptr + i*result->step); idx = i * sum_step; idx2 = i * sqsum_step; for( j = 0; j < result->cols; j++, idx += cn, idx2 += cn ) { double num = rrow[j], t; double wnd_mean2 = 0, wnd_sum2 = 0; if( num_type == 1 ) { for( k = 0; k < cn; k++ ) { t = p0[idx+k] - p1[idx+k] - p2[idx+k] + p3[idx+k]; wnd_mean2 += CV_SQR(t); num -= t*templ_mean.val[k]; } wnd_mean2 *= inv_area; } if( is_normed || num_type == 2 ) { for( k = 0; k < cn; k++ ) { t = q0[idx2+k] - q1[idx2+k] - q2[idx2+k] + q3[idx2+k]; wnd_sum2 += t; } if( num_type == 2 ) num = wnd_sum2 - 2*num + templ_sum2; } if( is_normed ) { t = sqrt(MAX(wnd_sum2 - wnd_mean2,0))*templ_norm; if( fabs(num) < t ) num /= t; else if( fabs(num) < t*1.125 ) num = num > 0 ? 1 : -1; else num = method != CV_TM_SQDIFF_NORMED ? 0 : 1; } rrow[j] = (float)num; } } }
CV_IMPL void cvMatchTemplate( const CvArr* _img, const CvArr* _templ, CvArr* _result, int method ) { CvMat* sum = 0; CvMat* sqsum = 0; CV_FUNCNAME( "cvMatchTemplate" ); __BEGIN__; int coi1 = 0, coi2 = 0; int depth, cn; int i, j, k; CvMat stub, *img = (CvMat*)_img; CvMat tstub, *templ = (CvMat*)_templ; CvMat rstub, *result = (CvMat*)_result; CvScalar templ_mean = cvScalarAll(0); double templ_norm = 0, templ_sum2 = 0; int idx = 0, idx2 = 0; double *p0, *p1, *p2, *p3; double *q0, *q1, *q2, *q3; double inv_area; int sum_step, sqsum_step; int num_type = method == CV_TM_CCORR || method == CV_TM_CCORR_NORMED ? 0 : method == CV_TM_CCOEFF || method == CV_TM_CCOEFF_NORMED ? 1 : 2; int is_normed = method == CV_TM_CCORR_NORMED || method == CV_TM_SQDIFF_NORMED || method == CV_TM_CCOEFF_NORMED; CV_CALL( img = cvGetMat( img, &stub, &coi1 )); CV_CALL( templ = cvGetMat( templ, &tstub, &coi2 )); CV_CALL( result = cvGetMat( result, &rstub )); if( CV_MAT_DEPTH( img->type ) != CV_8U && CV_MAT_DEPTH( img->type ) != CV_32F ) CV_ERROR( CV_StsUnsupportedFormat, "The function supports only 8u and 32f data types" ); if( !CV_ARE_TYPES_EQ( img, templ )) CV_ERROR( CV_StsUnmatchedSizes, "image and template should have the same type" ); if( CV_MAT_TYPE( result->type ) != CV_32FC1 ) CV_ERROR( CV_StsUnsupportedFormat, "output image should have 32f type" ); if( img->rows < templ->rows || img->cols < templ->cols ) { CvMat* t; CV_SWAP( img, templ, t ); } if( result->rows != img->rows - templ->rows + 1 || result->cols != img->cols - templ->cols + 1 ) CV_ERROR( CV_StsUnmatchedSizes, "output image should be (W - w + 1)x(H - h + 1)" ); if( method < CV_TM_SQDIFF || method > CV_TM_CCOEFF_NORMED ) CV_ERROR( CV_StsBadArg, "unknown comparison method" ); depth = CV_MAT_DEPTH(img->type); cn = CV_MAT_CN(img->type); if( is_normed && cn == 1 && templ->rows > 8 && templ->cols > 8 && img->rows > templ->cols && img->cols > templ->cols ) { CvTemplMatchIPPFunc ipp_func = depth == CV_8U ? (method == CV_TM_SQDIFF_NORMED ? (CvTemplMatchIPPFunc)icvSqrDistanceValid_Norm_8u32f_C1R_p : method == CV_TM_CCORR_NORMED ? (CvTemplMatchIPPFunc)icvCrossCorrValid_Norm_8u32f_C1R_p : (CvTemplMatchIPPFunc)icvCrossCorrValid_NormLevel_8u32f_C1R_p) : (method == CV_TM_SQDIFF_NORMED ? (CvTemplMatchIPPFunc)icvSqrDistanceValid_Norm_32f_C1R_p : method == CV_TM_CCORR_NORMED ? (CvTemplMatchIPPFunc)icvCrossCorrValid_Norm_32f_C1R_p : (CvTemplMatchIPPFunc)icvCrossCorrValid_NormLevel_32f_C1R_p); if( ipp_func ) { CvSize img_size = cvGetMatSize(img), templ_size = cvGetMatSize(templ); IPPI_CALL( ipp_func( img->data.ptr, img->step ? img->step : CV_STUB_STEP, img_size, templ->data.ptr, templ->step ? templ->step : CV_STUB_STEP, templ_size, result->data.ptr, result->step ? result->step : CV_STUB_STEP )); for( i = 0; i < result->rows; i++ ) { float* rrow = (float*)(result->data.ptr + i*result->step); for( j = 0; j < result->cols; j++ ) { if( fabs(rrow[j]) > 1. ) rrow[j] = rrow[j] < 0 ? -1.f : 1.f; } } EXIT; } } CV_CALL( icvCrossCorr( img, templ, result )); if( method == CV_TM_CCORR ) EXIT; inv_area = 1./((double)templ->rows * templ->cols); CV_CALL( sum = cvCreateMat( img->rows + 1, img->cols + 1, CV_MAKETYPE( CV_64F, cn ))); if( method == CV_TM_CCOEFF ) { CV_CALL( cvIntegral( img, sum, 0, 0 )); CV_CALL( templ_mean = cvAvg( templ )); q0 = q1 = q2 = q3 = 0; } else { CvScalar _templ_sdv = cvScalarAll(0); CV_CALL( sqsum = cvCreateMat( img->rows + 1, img->cols + 1, CV_MAKETYPE( CV_64F, cn ))); CV_CALL( cvIntegral( img, sum, sqsum, 0 )); CV_CALL( cvAvgSdv( templ, &templ_mean, &_templ_sdv )); templ_norm = CV_SQR(_templ_sdv.val[0]) + CV_SQR(_templ_sdv.val[1]) + CV_SQR(_templ_sdv.val[2]) + CV_SQR(_templ_sdv.val[3]); if( templ_norm < DBL_EPSILON && method == CV_TM_CCOEFF_NORMED ) { cvSet( result, cvScalarAll(1.) ); EXIT; } templ_sum2 = templ_norm + CV_SQR(templ_mean.val[0]) + CV_SQR(templ_mean.val[1]) + CV_SQR(templ_mean.val[2]) + CV_SQR(templ_mean.val[3]); if( num_type != 1 ) { templ_mean = cvScalarAll(0); templ_norm = templ_sum2; } templ_sum2 /= inv_area; templ_norm = sqrt(templ_norm); templ_norm /= sqrt(inv_area); // care of accuracy here q0 = (double*)sqsum->data.ptr; q1 = q0 + templ->cols*cn; q2 = (double*)(sqsum->data.ptr + templ->rows*sqsum->step); q3 = q2 + templ->cols*cn; } p0 = (double*)sum->data.ptr; p1 = p0 + templ->cols*cn; p2 = (double*)(sum->data.ptr + templ->rows*sum->step); p3 = p2 + templ->cols*cn; sum_step = sum ? sum->step / sizeof(double) : 0; sqsum_step = sqsum ? sqsum->step / sizeof(double) : 0; for( i = 0; i < result->rows; i++ ) { float* rrow = (float*)(result->data.ptr + i*result->step); idx = i * sum_step; idx2 = i * sqsum_step; for( j = 0; j < result->cols; j++, idx += cn, idx2 += cn ) { double num = rrow[j], t; double wnd_mean2 = 0, wnd_sum2 = 0; if( num_type == 1 ) { for( k = 0; k < cn; k++ ) { t = p0[idx+k] - p1[idx+k] - p2[idx+k] + p3[idx+k]; wnd_mean2 += CV_SQR(t); num -= t*templ_mean.val[k]; } wnd_mean2 *= inv_area; } if( is_normed || num_type == 2 ) { for( k = 0; k < cn; k++ ) { t = q0[idx2+k] - q1[idx2+k] - q2[idx2+k] + q3[idx2+k]; wnd_sum2 += t; } if( num_type == 2 ) num = wnd_sum2 - 2*num + templ_sum2; } if( is_normed ) { t = sqrt(MAX(wnd_sum2 - wnd_mean2,0))*templ_norm; if( t > DBL_EPSILON ) { num /= t; if( fabs(num) > 1. ) num = num > 0 ? 1 : -1; } else num = method != CV_TM_SQDIFF_NORMED || num < DBL_EPSILON ? 0 : 1; } rrow[j] = (float)num; } } __END__; cvReleaseMat( &sum ); cvReleaseMat( &sqsum ); }