diff --git a/modules/features2d/src/surf.cpp b/modules/features2d/src/surf.cpp index b0a0c75ff2..005608933d 100644 --- a/modules/features2d/src/surf.cpp +++ b/modules/features2d/src/surf.cpp @@ -220,15 +220,15 @@ icvCalcLayerDetAndTrace( const CvMat* sum, int size, int sampleStep, CvMat *det, * point contains the keypoint coordinates and scale to be modified * * Return value is 1 if interpolation was successful, 0 on failure. - */ -CV_INLINE int + */ +CV_INLINE int icvInterpolateKeypoint( float N9[3][9], int dx, int dy, int ds, CvSURFPoint *point ) { int solve_ok; float A[9], x[3], b[3]; CvMat matA = cvMat(3, 3, CV_32F, A); - CvMat _x = cvMat(3, 1, CV_32F, x); - CvMat _b = cvMat(3, 1, CV_32F, b); + CvMat _x = cvMat(3, 1, CV_32F, x); + CvMat _b = cvMat(3, 1, CV_32F, b); b[0] = -(N9[1][5]-N9[1][3])/2; /* Negative 1st deriv with respect to x */ b[1] = -(N9[1][7]-N9[1][1])/2; /* Negative 1st deriv with respect to y */ @@ -442,7 +442,7 @@ struct SURFFindInvoker /* Wavelet size at first layer of first octave. */ const int HAAR_SIZE0 = 9; -/* Wavelet size increment between layers. This should be an even number, +/* Wavelet size increment between layers. This should be an even number, such that the wavelet sizes in an octave are either all even or all odd. This ensures that when looking for the neighbours of a sample, the layers above and below are aligned correctly. */ @@ -455,9 +455,9 @@ static CvSeq* icvFastHessianDetector( const CvMat* sum, const CvMat* mask_sum, CvSeq* points = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvSURFPoint), storage ); /* Sampling step along image x and y axes at first octave. This is doubled - for each additional octave. WARNING: Increasing this improves speed, + for each additional octave. WARNING: Increasing this improves speed, however keypoint extraction becomes unreliable. */ - const int SAMPLE_STEP0 = 1; + const int SAMPLE_STEP0 = 1; int nTotalLayers = (params->nOctaveLayers+2)*params->nOctaves; int nMiddleLayers = params->nOctaveLayers*params->nOctaves; @@ -567,7 +567,6 @@ struct SURFInvoker DW[i*PATCH_SZ+j] = G_desc.at(i,0) * G_desc.at(j,0); } } - void operator()(const BlockedRange& range) const { /* X and Y gradient wavelet data */ @@ -576,7 +575,6 @@ struct SURFInvoker const int dy_s[NY][5] = {{0, 0, 4, 2, 1}, {0, 2, 4, 4, -1}}; const int descriptor_size = params->extended ? 128 : 64; - /* Optimisation is better using nOriSampleBound than nOriSamples for array lengths. Maybe because it is a constant known at compile time */ const int nOriSampleBound =(2*ORI_RADIUS+1)*(2*ORI_RADIUS+1); @@ -591,32 +589,25 @@ struct SURFInvoker int k, k1 = range.begin(), k2 = range.end(); int maxSize = 0; - for( k = k1; k < k2; k++ ) { maxSize = std::max(maxSize, ((CvSURFPoint*)cvGetSeqElem( keypoints, k ))->size); } - maxSize = cvCeil((PATCH_SZ+1)*maxSize*1.2f/9.0f); Ptr winbuf = cvCreateMat( 1, maxSize > 0 ? maxSize*maxSize : 1, CV_8U ); - for( k = k1; k < k2; k++ ) { const int* sum_ptr = sum->data.i; int sum_cols = sum->cols; int i, j, kk, x, y, nangle; - float* vec; CvSurfHF dx_t[NX], dy_t[NY]; - CvSURFPoint* kp = (CvSURFPoint*)cvGetSeqElem( keypoints, k ); int size = kp->size; CvPoint2D32f center = kp->pt; - /* The sampling intervals and wavelet sized for selecting an orientation and building the keypoint descriptor are defined relative to 's' */ float s = (float)size*1.2f/9.0f; - /* To find the dominant orientation, the gradients in x and y are sampled in a circle of radius 6s using wavelets of size 4s. We ensure the gradient wavelet size is even to ensure the @@ -680,32 +671,27 @@ struct SURFInvoker besty = sumy; } } - float descriptor_dir = cvFastArctan( besty, bestx ); kp->dir = descriptor_dir; - if( !descriptors ) continue; - descriptor_dir *= (float)(CV_PI/180); - /* Extract a window of pixels around the keypoint of size 20s */ int win_size = (int)((PATCH_SZ+1)*s); CV_Assert( winbuf->cols >= win_size*win_size ); - CvMat win = cvMat(win_size, win_size, CV_8U, winbuf->data.ptr); float sin_dir = sin(descriptor_dir); float cos_dir = cos(descriptor_dir) ; /* Subpixel interpolation version (slower). Subpixel not required since the pixels will all get averaged when we scale down to 20 pixels */ - /* + /* float w[] = { cos_dir, sin_dir, center.x, -sin_dir, cos_dir , center.y }; CvMat W = cvMat(2, 3, CV_32F, w); cvGetQuadrangleSubPix( img, &win, &W ); */ - + /* Nearest neighbour version (faster) */ float win_offset = -(float)(win_size-1)/2; float start_x = center.x + win_offset*cos_dir + win_offset*sin_dir; @@ -722,11 +708,11 @@ struct SURFInvoker WIN[i*win_size + j] = img->data.ptr[y*img->step + x]; } } - + /* Scale the window to size PATCH_SZ so each pixel's size is s. This makes calculating the gradients with wavelets of size 2s easy */ cvResize( &win, &_patch, CV_INTER_AREA ); - + /* Calculate gradients in x and y with wavelets of size 2s */ for( i = 0; i < PATCH_SZ; i++ ) for( j = 0; j < PATCH_SZ; j++ ) @@ -737,12 +723,12 @@ struct SURFInvoker DX[i][j] = vx; DY[i][j] = vy; } - + /* Construct the descriptor */ vec = (float*)cvGetSeqElem( descriptors, k ); for( kk = 0; kk < (int)(descriptors->elem_size/sizeof(vec[0])); kk++ ) vec[kk] = 0; - double square_mag = 0; + double square_mag = 0; if( params->extended ) { /* 128-bin descriptor */ @@ -797,7 +783,7 @@ struct SURFInvoker vec+=4; } } - + /* unit vector is essential for contrast invariance */ vec = (float*)cvGetSeqElem( descriptors, k ); double scale = 1./(sqrt(square_mag) + DBL_EPSILON); @@ -805,7 +791,7 @@ struct SURFInvoker vec[kk] = (float)(vec[kk]*scale); } } - + /* Parameters */ const CvSURFParams* params; const CvMat* img; @@ -830,7 +816,7 @@ CV_IMPL void cvExtractSURF( const CvArr* _img, const CvArr* _mask, CvSeq** _keypoints, CvSeq** _descriptors, CvMemStorage* storage, CvSURFParams params, - int useProvidedKeyPts) + int useProvidedKeyPts) { CvMat *sum = 0, *mask1 = 0, *mask_sum = 0; @@ -842,7 +828,7 @@ cvExtractSURF( const CvArr* _img, const CvArr* _mask, CvSeq *keypoints, *descriptors = 0; CvMat imghdr, *img = cvGetMat(_img, &imghdr); CvMat maskhdr, *mask = _mask ? cvGetMat(_mask, &maskhdr) : 0; - + int descriptor_size = params.extended ? 128 : 64; const int descriptor_data_type = CV_32F; int i, N; @@ -857,24 +843,24 @@ cvExtractSURF( const CvArr* _img, const CvArr* _mask, sum = cvCreateMat( img->rows+1, img->cols+1, CV_32SC1 ); cvIntegral( img, sum ); - - // Compute keypoints only if we are not asked for evaluating the descriptors are some given locations: - if (!useProvidedKeyPts) - { - if( mask ) - { - mask1 = cvCreateMat( img->height, img->width, CV_8UC1 ); - mask_sum = cvCreateMat( img->height+1, img->width+1, CV_32SC1 ); - cvMinS( mask, 1, mask1 ); - cvIntegral( mask1, mask_sum ); - } - keypoints = icvFastHessianDetector( sum, mask_sum, storage, ¶ms ); - } - else - { - CV_Assert(useProvidedKeyPts && (_keypoints != 0) && (*_keypoints != 0)); - keypoints = *_keypoints; - } + + // Compute keypoints only if we are not asked for evaluating the descriptors are some given locations: + if (!useProvidedKeyPts) + { + if( mask ) + { + mask1 = cvCreateMat( img->height, img->width, CV_8UC1 ); + mask_sum = cvCreateMat( img->height+1, img->width+1, CV_32SC1 ); + cvMinS( mask, 1, mask1 ); + cvIntegral( mask1, mask_sum ); + } + keypoints = icvFastHessianDetector( sum, mask_sum, storage, ¶ms ); + } + else + { + CV_Assert(useProvidedKeyPts && (_keypoints != 0) && (*_keypoints != 0)); + keypoints = *_keypoints; + } N = keypoints->total; if( _descriptors ) @@ -935,8 +921,8 @@ SURF::SURF(double _threshold, int _nOctaves, int _nOctaveLayers, bool _extended) } int SURF::descriptorSize() const { return extended ? 128 : 64; } - - + + static int getPointOctave(const CvSURFPoint& kpt, const CvSURFParams& params) { int octave = 0, layer = 0, best_octave = 0; @@ -955,7 +941,7 @@ static int getPointOctave(const CvSURFPoint& kpt, const CvSURFParams& params) } return best_octave; } - + void SURF::operator()(const Mat& img, const Mat& mask, vector& keypoints) const @@ -999,7 +985,7 @@ void SURF::operator()(const Mat& img, const Mat& mask, kp.push_back(cvSURFPoint(kpt.pt, 1, cvRound(kpt.size), kpt.angle, kpt.response)); } } - + cvExtractSURF(&_img, pmask, &kp.seq, &d, storage, *(const CvSURFParams*)this, useProvidedKeypoints);