114 |
114 |
CvSURFParams params;
|
115 |
115 |
params.hessianThreshold = threshold;
|
116 |
116 |
params.extended = extended;
|
|
117 |
params.upright = 0;
|
117 |
118 |
params.nOctaves = 4;
|
118 |
119 |
params.nOctaveLayers = 2;
|
119 |
120 |
return params;
|
... | ... | |
575 |
576 |
DW[i*PATCH_SZ+j] = G_desc.at<float>(i,0) * G_desc.at<float>(j,0);
|
576 |
577 |
}
|
577 |
578 |
}
|
578 |
|
|
579 |
579 |
void operator()(const BlockedRange& range) const
|
580 |
580 |
{
|
581 |
581 |
/* X and Y gradient wavelet data */
|
... | ... | |
630 |
630 |
kp->size = -1;
|
631 |
631 |
continue;
|
632 |
632 |
}
|
633 |
|
icvResizeHaarPattern( dx_s, dx_t, NX, 4, grad_wav_size, sum->cols );
|
634 |
|
icvResizeHaarPattern( dy_s, dy_t, NY, 4, grad_wav_size, sum->cols );
|
635 |
|
for( kk = 0, nangle = 0; kk < nOriSamples; kk++ )
|
636 |
|
{
|
637 |
|
const int* ptr;
|
638 |
|
float vx, vy;
|
639 |
|
x = cvRound( center.x + apt[kk].x*s - (float)(grad_wav_size-1)/2 );
|
640 |
|
y = cvRound( center.y + apt[kk].y*s - (float)(grad_wav_size-1)/2 );
|
641 |
|
if( (unsigned)y >= (unsigned)(sum->rows - grad_wav_size) ||
|
642 |
|
(unsigned)x >= (unsigned)(sum->cols - grad_wav_size) )
|
|
633 |
|
|
634 |
float descriptor_dir;
|
|
635 |
if (params->upright == 0) {
|
|
636 |
|
|
637 |
icvResizeHaarPattern( dx_s, dx_t, NX, 4, grad_wav_size, sum->cols );
|
|
638 |
icvResizeHaarPattern( dy_s, dy_t, NY, 4, grad_wav_size, sum->cols );
|
|
639 |
for( kk = 0, nangle = 0; kk < nOriSamples; kk++ )
|
|
640 |
{
|
|
641 |
const int* ptr;
|
|
642 |
float vx, vy;
|
|
643 |
x = cvRound( center.x + apt[kk].x*s - (float)(grad_wav_size-1)/2 );
|
|
644 |
y = cvRound( center.y + apt[kk].y*s - (float)(grad_wav_size-1)/2 );
|
|
645 |
if( (unsigned)y >= (unsigned)(sum->rows - grad_wav_size) ||
|
|
646 |
(unsigned)x >= (unsigned)(sum->cols - grad_wav_size) )
|
|
647 |
continue;
|
|
648 |
ptr = sum_ptr + x + y*sum_cols;
|
|
649 |
vx = icvCalcHaarPattern( ptr, dx_t, 2 );
|
|
650 |
vy = icvCalcHaarPattern( ptr, dy_t, 2 );
|
|
651 |
X[nangle] = vx*aptw[kk]; Y[nangle] = vy*aptw[kk];
|
|
652 |
nangle++;
|
|
653 |
}
|
|
654 |
if ( nangle == 0 )
|
|
655 |
{
|
|
656 |
/* No gradient could be sampled because the keypoint is too
|
|
657 |
* near too one or more of the sides of the image. As we
|
|
658 |
* therefore cannot find a dominant direction, we skip this
|
|
659 |
* keypoint and mark it for later deletion from the sequence. */
|
|
660 |
kp->size = -1;
|
643 |
661 |
continue;
|
644 |
|
ptr = sum_ptr + x + y*sum_cols;
|
645 |
|
vx = icvCalcHaarPattern( ptr, dx_t, 2 );
|
646 |
|
vy = icvCalcHaarPattern( ptr, dy_t, 2 );
|
647 |
|
X[nangle] = vx*aptw[kk]; Y[nangle] = vy*aptw[kk];
|
648 |
|
nangle++;
|
649 |
|
}
|
650 |
|
if ( nangle == 0 )
|
651 |
|
{
|
652 |
|
/* No gradient could be sampled because the keypoint is too
|
653 |
|
* near too one or more of the sides of the image. As we
|
654 |
|
* therefore cannot find a dominant direction, we skip this
|
655 |
|
* keypoint and mark it for later deletion from the sequence. */
|
656 |
|
kp->size = -1;
|
657 |
|
continue;
|
658 |
|
}
|
659 |
|
matX.cols = matY.cols = _angle.cols = nangle;
|
660 |
|
cvCartToPolar( &matX, &matY, 0, &_angle, 1 );
|
|
662 |
}
|
|
663 |
matX.cols = matY.cols = _angle.cols = nangle;
|
|
664 |
cvCartToPolar( &matX, &matY, 0, &_angle, 1 );
|
661 |
665 |
|
662 |
|
float bestx = 0, besty = 0, descriptor_mod = 0;
|
663 |
|
for( i = 0; i < 360; i += ORI_SEARCH_INC )
|
664 |
|
{
|
665 |
|
float sumx = 0, sumy = 0, temp_mod;
|
666 |
|
for( j = 0; j < nangle; j++ )
|
|
666 |
float bestx = 0, besty = 0, descriptor_mod = 0;
|
|
667 |
for( i = 0; i < 360; i += ORI_SEARCH_INC )
|
667 |
668 |
{
|
668 |
|
int d = std::abs(cvRound(angle[j]) - i);
|
669 |
|
if( d < ORI_WIN/2 || d > 360-ORI_WIN/2 )
|
|
669 |
float sumx = 0, sumy = 0, temp_mod;
|
|
670 |
for( j = 0; j < nangle; j++ )
|
670 |
671 |
{
|
671 |
|
sumx += X[j];
|
672 |
|
sumy += Y[j];
|
|
672 |
int d = std::abs(cvRound(angle[j]) - i);
|
|
673 |
if( d < ORI_WIN/2 || d > 360-ORI_WIN/2 )
|
|
674 |
{
|
|
675 |
sumx += X[j];
|
|
676 |
sumy += Y[j];
|
|
677 |
}
|
673 |
678 |
}
|
|
679 |
temp_mod = sumx*sumx + sumy*sumy;
|
|
680 |
if( temp_mod > descriptor_mod )
|
|
681 |
{
|
|
682 |
descriptor_mod = temp_mod;
|
|
683 |
bestx = sumx;
|
|
684 |
besty = sumy;
|
|
685 |
}
|
674 |
686 |
}
|
675 |
|
temp_mod = sumx*sumx + sumy*sumy;
|
676 |
|
if( temp_mod > descriptor_mod )
|
677 |
|
{
|
678 |
|
descriptor_mod = temp_mod;
|
679 |
|
bestx = sumx;
|
680 |
|
besty = sumy;
|
681 |
|
}
|
|
687 |
|
|
688 |
descriptor_dir = cvFastArctan( besty, bestx );
|
|
689 |
kp->dir = descriptor_dir;
|
|
690 |
} else {
|
|
691 |
descriptor_dir = 0;
|
|
692 |
kp->dir = 0;
|
682 |
693 |
}
|
683 |
|
float descriptor_dir = cvFastArctan( besty, bestx );
|
684 |
|
kp->dir = descriptor_dir;
|
685 |
694 |
if( !descriptors )
|
686 |
695 |
continue;
|
687 |
696 |
descriptor_dir *= (float)(CV_PI/180);
|
... | ... | |
689 |
698 |
int win_size = (int)((PATCH_SZ+1)*s);
|
690 |
699 |
CV_Assert( winbuf->cols >= win_size*win_size );
|
691 |
700 |
CvMat win = cvMat(win_size, win_size, CV_8U, winbuf->data.ptr);
|
692 |
|
float sin_dir = sin(descriptor_dir);
|
693 |
|
float cos_dir = cos(descriptor_dir) ;
|
694 |
701 |
|
695 |
|
/* Subpixel interpolation version (slower). Subpixel not required since
|
696 |
|
the pixels will all get averaged when we scale down to 20 pixels */
|
697 |
|
/*
|
698 |
|
float w[] = { cos_dir, sin_dir, center.x,
|
699 |
|
-sin_dir, cos_dir , center.y };
|
700 |
|
CvMat W = cvMat(2, 3, CV_32F, w);
|
701 |
|
cvGetQuadrangleSubPix( img, &win, &W );
|
702 |
|
*/
|
|
702 |
if (params->upright == 0) {
|
703 |
703 |
|
704 |
|
/* Nearest neighbour version (faster) */
|
705 |
|
float win_offset = -(float)(win_size-1)/2;
|
706 |
|
float start_x = center.x + win_offset*cos_dir + win_offset*sin_dir;
|
707 |
|
float start_y = center.y - win_offset*sin_dir + win_offset*cos_dir;
|
708 |
|
uchar* WIN = win.data.ptr;
|
709 |
|
for( i = 0; i < win_size; i++, start_x += sin_dir, start_y += cos_dir )
|
710 |
|
{
|
711 |
|
float pixel_x = start_x;
|
712 |
|
float pixel_y = start_y;
|
713 |
|
for( j = 0; j < win_size; j++, pixel_x += cos_dir, pixel_y -= sin_dir )
|
|
704 |
float sin_dir = sin(descriptor_dir);
|
|
705 |
float cos_dir = cos(descriptor_dir) ;
|
|
706 |
|
|
707 |
/* Subpixel interpolation version (slower). Subpixel not required since
|
|
708 |
the pixels will all get averaged when we scale down to 20 pixels */
|
|
709 |
/*
|
|
710 |
float w[] = { cos_dir, sin_dir, center.x,
|
|
711 |
-sin_dir, cos_dir , center.y };
|
|
712 |
CvMat W = cvMat(2, 3, CV_32F, w);
|
|
713 |
cvGetQuadrangleSubPix( img, &win, &W );
|
|
714 |
*/
|
|
715 |
|
|
716 |
/* Nearest neighbour version (faster) */
|
|
717 |
float win_offset = -(float)(win_size-1)/2;
|
|
718 |
float start_x = center.x + win_offset*cos_dir + win_offset*sin_dir;
|
|
719 |
float start_y = center.y - win_offset*sin_dir + win_offset*cos_dir;
|
|
720 |
uchar* WIN = win.data.ptr;
|
|
721 |
for( i = 0; i < win_size; i++, start_x += sin_dir, start_y += cos_dir )
|
714 |
722 |
{
|
715 |
|
int x = std::min(std::max(cvRound(pixel_x), 0), img->cols-1);
|
716 |
|
int y = std::min(std::max(cvRound(pixel_y), 0), img->rows-1);
|
717 |
|
WIN[i*win_size + j] = img->data.ptr[y*img->step + x];
|
|
723 |
float pixel_x = start_x;
|
|
724 |
float pixel_y = start_y;
|
|
725 |
for( j = 0; j < win_size; j++, pixel_x += cos_dir, pixel_y -= sin_dir )
|
|
726 |
{
|
|
727 |
int x = std::min(std::max(cvRound(pixel_x), 0), img->cols-1);
|
|
728 |
int y = std::min(std::max(cvRound(pixel_y), 0), img->rows-1);
|
|
729 |
WIN[i*win_size + j] = img->data.ptr[y*img->step + x];
|
|
730 |
}
|
718 |
731 |
}
|
|
732 |
} else {
|
|
733 |
/* extract rect - slightly optimized version of the code above
|
|
734 |
TODO: find faster code, as this is simply an extract rect operation,
|
|
735 |
e.g. by using cvGetSubRect, problem is the border processing */
|
|
736 |
|
|
737 |
float win_offset = -(float)(win_size-1)/2;
|
|
738 |
int start_x = cvRound(center.x + win_offset);
|
|
739 |
int start_y = cvRound(center.y + win_offset);
|
|
740 |
uchar* WIN = win.data.ptr;
|
|
741 |
for( i=0; i<win_size; i++, start_y++ )
|
|
742 |
{
|
|
743 |
int pixel_x = start_x;
|
|
744 |
for( j=0; j<win_size; j++, pixel_x++ )
|
|
745 |
{
|
|
746 |
x = MAX( pixel_x, 0 );
|
|
747 |
y = MAX( start_y, 0 );
|
|
748 |
x = MIN( x, img->cols-1 );
|
|
749 |
y = MIN( y, img->rows-1 );
|
|
750 |
WIN[i*win_size + j] = img->data.ptr[y*img->step+x];
|
|
751 |
}
|
|
752 |
}
|
719 |
753 |
}
|
720 |
|
|
721 |
754 |
/* Scale the window to size PATCH_SZ so each pixel's size is s. This
|
722 |
755 |
makes calculating the gradients with wavelets of size 2s easy */
|
723 |
756 |
cvResize( &win, &_patch, CV_INTER_AREA );
|
... | ... | |
886 |
919 |
cv::parallel_for(cv::BlockedRange(0, N),
|
887 |
920 |
cv::SURFInvoker(¶ms, keypoints, descriptors, img, sum) );
|
888 |
921 |
#else
|
889 |
|
cv::SURFInvoker invoker(¶ms, keypoints, descriptors, img, sum);
|
890 |
|
invoker(cv::BlockedRange(0, N));
|
|
922 |
cv::SURFInvoker invoker(¶ms, keypoints, descriptors, img, sum);
|
|
923 |
invoker(cv::BlockedRange(0, N));
|
891 |
924 |
#endif
|
892 |
925 |
}
|
893 |
926 |
|
... | ... | |
924 |
957 |
{
|
925 |
958 |
hessianThreshold = 100;
|
926 |
959 |
extended = 1;
|
|
960 |
upright = 0;
|
927 |
961 |
nOctaves = 4;
|
928 |
962 |
nOctaveLayers = 2;
|
929 |
963 |
}
|
930 |
964 |
|
931 |
|
SURF::SURF(double _threshold, int _nOctaves, int _nOctaveLayers, bool _extended)
|
|
965 |
SURF::SURF(double _threshold, int _nOctaves, int _nOctaveLayers, bool _extended, bool _upright)
|
932 |
966 |
{
|
933 |
967 |
hessianThreshold = _threshold;
|
934 |
968 |
extended = _extended;
|
|
969 |
upright = _upright;
|
935 |
970 |
nOctaves = _nOctaves;
|
936 |
971 |
nOctaveLayers = _nOctaveLayers;
|
937 |
972 |
}
|