相関係数を計算を自作する(途中)

結局、自作してみる… templmatch.cpp 内にある crossCorr 関数で相関平均を計算しているのだが、フーリエ解析を使っているためか値が違う。

後でコードを見直そう。

// 実画像の位置(dx,dy)に対して、相関係数を計算する
double crossCorr( const cv::Mat& img, const cv::Mat& templ, const cv::Mat& mask, int dx, int dy )
{
	int cnt = 0;

	double templMean = 0.0;	// テンプレートの相加平均
	double imgMean   = 0.0;	// 実画像の相加平均 
	
	for ( int y=0; y<templ.rows; ++y ) {
		for ( int x=0; x<templ.cols; ++x ) {
			if ( mask.at<char>(y,x) == 0 ) 
				continue;
			cv::Vec3b v1 = templ.at<cv::Vec3b>(y,x);
			cv::Vec3b v2 = img.at<cv::Vec3b>(y+dy,x+dx);
			templMean += v1[0] + v1[1] + v1[2];
			imgMean += v2[0] + v2[1] + v2[2];
			cnt += 3;
		}
	}
	templMean = templMean/(double)cnt;
	imgMean = imgMean/(double)cnt;

	// 分子(numerator)
	double numerator = 0.0;
	for ( int y=0; y<templ.rows; ++y ) {
		for ( int x=0; x<templ.cols; ++x ) {
			if ( mask.at<char>(y,x) == 0 ) 
				continue;

			cv::Vec3b v1 = templ.at<cv::Vec3b>(y,x);
			cv::Vec3b v2 = img.at<cv::Vec3b>(y+dy,x+dx);
			numerator += (v1[0] - templMean)*(v2[0] - imgMean);
			numerator += (v1[1] - templMean)*(v2[1] - imgMean);
			numerator += (v1[2] - templMean)*(v2[2] - imgMean);
		}
	}
	// 分母(denominator)
	double denominator_templ = 0.0;
	double denominator_img   = 0.0;
	for ( int y=0; y<templ.rows; ++y ) {
		for ( int x=0; x<templ.cols; ++x ) {
			if ( mask.at<char>(y,x) == 0 ) 
				continue;
			cv::Vec3b v1 = templ.at<cv::Vec3b>(y,x);
			cv::Vec3b v2 = img.at<cv::Vec3b>(y+dy,x+dx);

			denominator_templ += (v1[0] - templMean)*(v1[0] - templMean);
			denominator_templ += (v1[1] - templMean)*(v1[1] - templMean);
			denominator_templ += (v1[2] - templMean)*(v1[2] - templMean);
			denominator_img += (v2[0] - imgMean)*(v2[0] - imgMean);
			denominator_img += (v2[1] - imgMean)*(v2[1] - imgMean);
			denominator_img += (v2[2] - imgMean)*(v2[2] - imgMean);
		}
	}
	double denominator = sqrt(denominator_templ)*sqrt(denominator_img);

	return numerator/denominator;
}

// 実画像のすべてに対して相関係数を計算する
void MatchTemplate( const cv::Mat& img, const cv::Mat& templ, cv::Mat& result, const cv::Mat& mask )
{
	cv::Size corrsize(img.cols-templ.cols, img.rows-templ.rows);
	result.create(corrsize, CV_64F); 

	for ( int y=0; y<corrsize.height; ++y ) {
		for ( int x=0; x<corrsize.width; ++x ) {
			double corr = crossCorr( img, templ, mask,x,y );
			result.at<double>(y,x) = corr ;
		}
	}
}

ちなみに、Mat:at<> を使うとデバッグ実行ではひどく遅いのだが、Release ビルドをすると結構速い。
おそらく、mat.hpp に定義されている

template<typename _Tp> inline _Tp& Mat::at(int i0, int i1)
{
    CV_DbgAssert( dims <= 2 && data && (unsigned)i0 < (unsigned)size.p[0] &&
        (unsigned)(i1*DataType<_Tp>::channels) < (unsigned)(size.p[1]*channels()) &&
        CV_ELEM_SIZE1(DataType<_Tp>::depth) == elemSize1());
    return ((_Tp*)(data + step.p[0]*i0))[i1];
}

で設定されている CV_DbgAssert の関数が遅いわけで、これはリリースモードでは外れるようになっている。
この部分を、CV_DbgAssert を使わないように展開してやれば、早くなるのではないかなぁと。

カテゴリー: 開発, 雑談, C++, OpenCV パーマリンク