結局、自作してみる… 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 を使わないように展開してやれば、早くなるのではないかなぁと。
