opencv2.4.3中surf代码分析----特征点提取

opencv安装目录/doc 下有个文件:opencv_tutorials.pdf  这个文件给我们提供很多学习代码。。有时间可以好好看下。。很有用的。。。我还没认真看。。。

现在进入正题  

surf特征提取方法:

 
 
  1. std::vector<cv::Keypoint>keypoints;  
  2. cv::SurfFeatureDetector surf(2500.); //阀值  
  3. surf.detect(image,keypoints);  

那么我们看下surf特征点是如何提取的?

在feature2d.hpp中有

typedef SURF SurfFeatureDetector

对于cv::SurfFeatureDetector surf(2500.); -> // SURF类实例化对象surf 传入参数2500

SURF(double hessianThreshold, // = 2500

                  int nOctaves=4, int nOctaveLayers=2,

                  bool extended=true, bool upright=false); ->

SURF::SURF(double _threshold, int _nOctaves, int _nOctaveLayers, bool _extended, bool _upright)

{

    hessianThreshold = _threshold;

    extended = _extended;

    upright = _upright;

    nOctaves = _nOctaves;

    nOctaveLayers = _nOctaveLayers;

}

对于surf.detect(image,keypoints);

SURF类中不存在detect方法,我们发现SURF类是继承Feature2D类,我们可以到Feature2D类中查找相关方法;

class CV_EXPORTS_W SURF : public Feature2D->

         class CV_EXPORTS_W Feature2D : public FeatureDetector, public DescriptorExtractor ->

                   class CV_EXPORTS_W FeatureDetector : public virtual Algorithm

                {

                ......

               CV_WRAP void detect( const Mat& image, CV_OUT vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const;->

                  ......

               virtual void detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask=Mat() ) const = 0;

               }

              detectImpl( image, keypoints, mask );

由于FeatureDector中的detectImpl为纯虚函数 则调用子类中的detectImpl 即调用到

void SURF::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask) const

               (*this)(image, mask, keypoints, noArray(), false);->

                            void SURF::operator()(InputArray _img, InputArray _mask,

                                                                    CV_OUT vector<KeyPoint>& keypoints,

                                                                                     OutputArray _descriptors,

                                                                             bool useProvidedKeypoints) const->

                                          fastHessianDetector( sum, msum, keypoints, nOctaves, nOctaveLayers, (float)hessianThreshold ); //这一步进行了角点提取


fastHessianDetector 开始创建尺度空间 接着调用

parallel_for( BlockedRange(0, nTotalLayers),SURFBuildInvoker(sum, sizes, sampleSteps, dets, traces) );->

                 body(range); ->

                              struct SURFBuildInvoker{

                                           void operator()(const BlockedRange& range) const->

                                }

                              for( int i=range.begin(); i<range.end(); i++ )

                                        calcLayerDetAndTrace( *sum, (*sizes)[i], (*sampleSteps)[i], (*dets)[i], (*traces)[i] ); //这里开始计算矩阵的行列式和迹了

(这个函数式通过对每个像素点(边界点除外)在它9*9领域内的盒子滤波 dxdx ,dydy ,dxdy ) 计算好后通过surf论文公式就能计算出每个像素点的行列式和迹。


 parallel_for( BlockedRange(0, nMiddleLayers),

                      SURFFindInvoker(sum, mask_sum, dets, traces, sizes,

                                      sampleSteps, middleIndices, keypoints,

                                      nOctaveLayers, hessianThreshold) ); ->

                      body(range); ->

                                        findMaximaInLayer( *sum, *mask_sum, *dets, *traces, *sizes,

                                                    *keypoints, octave, layer, hessianThreshold,

                                                            (*sampleSteps)[layer] ); ->

这个函数是读取每个像素的行列式的值,如果值大于threshold,则与该像素领域3*3*3的每个像素比较。。看是否为最大值。。如果为最大值则进行差值,精确极值点的位置

最后保存该极值点

 
 
  1. void SURFFindInvoker::<span style="color:#FF0000;">findMaximaInLayer</span>( const Mat& sum, const Mat& mask_sum,  
  2.                    const vector<Mat>& dets, const vector<Mat>& traces,  
  3.                    const vector<int>& sizes, vector<KeyPoint>& keypoints,  
  4.                    int octave, int layer, float hessianThreshold, int sampleStep )  
  5. {  
  6.     // Wavelet Data  
  7.     const int NM=1;  
  8.     const int dm[NM][5] = { {0, 0, 9, 9, 1} };    
  9.     SurfHF Dm;  
  10.   
  11.     int size = sizes[layer];  
  12.   
  13.     // The integral image 'sum' is one pixel bigger than the source image  
  14.     int layer_rows = (sum.rows-1)/sampleStep;  
  15.     int layer_cols = (sum.cols-1)/sampleStep;  
  16.   
  17.     // Ignore pixels without a 3x3x3 neighbourhood in the layer above  
  18.     int margin = (sizes[layer+1]/2)/sampleStep+1;  
  19.   
  20.     if( !mask_sum.empty() )  
  21.        resizeHaarPattern( dm, &Dm, NM, 9, size, mask_sum.cols );  
  22.   
  23.     int step = (int)(dets[layer].step/dets[layer].elemSize());  
  24.   
  25.     forint i = margin; i < layer_rows - margin; i++ )  
  26.     {  
  27.         const float* det_ptr = dets[layer].ptr<float>(i);  
  28.         const float* trace_ptr = traces[layer].ptr<float>(i);  
  29.         forint j = margin; j < layer_cols-margin; j++ )  
  30.         {  
  31.             float val0 = det_ptr[j];  
  32.             if( val0 > hessianThreshold )           //判断每个像素是否超过阀值  
  33.             {  
  34.                 /* Coordinates for the start of the wavelet in the sum image. There 
  35.                    is some integer division involved, so don't try to simplify this 
  36.                    (cancel out sampleStep) without checking the result is the same */  
  37.                 int sum_i = sampleStep*(i-(size/2)/sampleStep);  
  38.                 int sum_j = sampleStep*(j-(size/2)/sampleStep);  
  39.   
  40.                 /* The 3x3x3 neighbouring samples around the maxima. 
  41.                    The maxima is included at N9[1][4] */  
  42.   
  43.                 const float *det1 = &dets[layer-1].at<float>(i, j);  
  44.                 const float *det2 = &dets[layer].at<float>(i, j);  
  45.                 const float *det3 = &dets[layer+1].at<float>(i, j);  
  46.                 float N9[3][9] = { { det1[-step-1], det1[-step], det1[-step+1],       //以该点为中心的3层,每层9个像素  
  47.                                      det1[-1]  , det1[0] , det1[1],  
  48.                                      det1[step-1] , det1[step] , det1[step+1]  },  
  49.                                    { det2[-step-1], det2[-step], det2[-step+1],  
  50.                                      det2[-1]  , det2[0] , det2[1],  
  51.                                      det2[step-1] , det2[step] , det2[step+1]  },  
  52.                                    { det3[-step-1], det3[-step], det3[-step+1],  
  53.                                      det3[-1]  , det3[0] , det3[1],  
  54.                                      det3[step-1] , det3[step] , det3[step+1]  } };  
  55.   
  56.                 /* Check the mask - why not just check the mask at the center of the wavelet? */  
  57.                 if( !mask_sum.empty() )  
  58.                 {  
  59.                     const int* mask_ptr = &mask_sum.at<int>(sum_i, sum_j);  
  60.                     float mval = calcHaarPattern( mask_ptr, &Dm, 1 );  
  61.                     if( mval < 0.5 )  
  62.                         continue;  
  63.                 }  
  64.   
  65.                 /* Non-maxima suppression. val0 is at N9[1][4]*/  
  66.                 if( val0 > N9[0][0] && val0 > N9[0][1] && val0 > N9[0][2] &&           //计算val0是否为极大值点  
  67.                     val0 > N9[0][3] && val0 > N9[0][4] && val0 > N9[0][5] &&   
  68.                     val0 > N9[0][6] && val0 > N9[0][7] && val0 > N9[0][8] &&  
  69.                     val0 > N9[1][0] && val0 > N9[1][1] && val0 > N9[1][2] &&  
  70.                     val0 > N9[1][3]                    && val0 > N9[1][5] &&  
  71.                     val0 > N9[1][6] && val0 > N9[1][7] && val0 > N9[1][8] &&  
  72.                     val0 > N9[2][0] && val0 > N9[2][1] && val0 > N9[2][2] &&  
  73.                     val0 > N9[2][3] && val0 > N9[2][4] && val0 > N9[2][5] &&  
  74.                     val0 > N9[2][6] && val0 > N9[2][7] && val0 > N9[2][8] )  
  75.                 {  
  76.                     /* Calculate the wavelet center coordinates for the maxima */  
  77.                     float center_i = sum_i + (size-1)*0.5f;  
  78.                     float center_j = sum_j + (size-1)*0.5f;  
  79.   
  80.                     KeyPoint kpt( center_j, center_i, (float)sizes[layer],  
  81.                                   -1, val0, octave, CV_SIGN(trace_ptr[j]) );  
  82.   
  83.                     /* Interpolate maxima location within the 3x3x3 neighbourhood  */  
  84.                     int ds = size - sizes[layer-1];  
  85.                     int interp_ok = <span style="color:#FF0000;">interpolateKeypoint</span>( N9, sampleStep, sampleStep, ds, kpt );    //若为极大值点还要进行插值计算求精  
  86.   
  87.                     /* Sometimes the interpolation step gives a negative size etc. */  
  88.                     if( interp_ok  )  
  89.                     {  
  90.                         /*printf( "KeyPoint %f %f %d\n", point.pt.x, point.pt.y, point.size );*/  
  91. #ifdef HAVE_TBB  
  92.                         tbb::mutex::scoped_lock lock(findMaximaInLayer_m);  
  93. #endif  
  94.                         keypoints.push_back(kpt);             //保存该点  
  95.                     }  
  96.                 }  
  97.             }  
  98.         }  
  99.     }  
  100. }  
对于计算特征点位置精确计算函数如下
  1. <span style="color:#FF0000;">static int interpolateKeypoint</span>( float N9[3][9], int dx, int dy, int ds, KeyPoint& kpt )  
  2. {  
  3.     Vec3f b(-(N9[1][5]-N9[1][3])/2,  // Negative 1st deriv with respect to x      //对该像素点求一阶导。。  
  4.             -(N9[1][7]-N9[1][1])/2,  // Negative 1st deriv with respect to y  
  5.             -(N9[2][4]-N9[0][4])/2); // Negative 1st deriv with respect to s  
  6.   
  7.     Matx33f A(  
  8.         N9[1][3]-2*N9[1][4]+N9[1][5],            // 2nd deriv x, x               //对该像素点求2阶导  
  9.         (N9[1][8]-N9[1][6]-N9[1][2]+N9[1][0])/4, // 2nd deriv x, y  
  10.         (N9[2][5]-N9[2][3]-N9[0][5]+N9[0][3])/4, // 2nd deriv x, s  
  11.         (N9[1][8]-N9[1][6]-N9[1][2]+N9[1][0])/4, // 2nd deriv x, y  
  12.         N9[1][1]-2*N9[1][4]+N9[1][7],            // 2nd deriv y, y  
  13.         (N9[2][7]-N9[2][1]-N9[0][7]+N9[0][1])/4, // 2nd deriv y, s  
  14.         (N9[2][5]-N9[2][3]-N9[0][5]+N9[0][3])/4, // 2nd deriv x, s  
  15.         (N9[2][7]-N9[2][1]-N9[0][7]+N9[0][1])/4, // 2nd deriv y, s  
  16.         N9[0][4]-2*N9[1][4]+N9[2][4]);           // 2nd deriv s, s  
  17.   
  18.     Vec3f x = A.solve(b, DECOMP_LU);            //计算极值点的精确位置        
  19.   
  20.     bool ok = (x[0] != 0 || x[1] != 0 || x[2] != 0) &&  
  21.         std::abs(x[0]) <= 1 && std::abs(x[1]) <= 1 && std::abs(x[2]) <= 1;  
  22.   
  23.     if( ok )  
  24.     {  
  25.         kpt.pt.x += x[0]*dx;  
  26.         kpt.pt.y += x[1]*dy;  
  27.         kpt.size = (float)cvRound( kpt.size + x[2]*ds );  
  28.     }  
  29.     return ok;  
  30. };  
  31.    

理论模型如下图



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值