結局、自作してみる… templmatch.cpp 内にある crossCorr 関数で相関平均を計算しているのだが、フーリエ解析を使っているためか値が違う。
後でコードを見直そう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | // 実画像の位置(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 に定義されている
1 2 3 4 5 6 7 | 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 を使わないように展開してやれば、早くなるのではないかなぁと。