当前位置: 代码迷 >> 综合 >> kdnbsp;treenbsp;介绍以及在sift中的应用
  详细解决方案

kdnbsp;treenbsp;介绍以及在sift中的应用

热度:97   发布时间:2024-01-06 02:56:43.0

KD-Tree是一种由二叉搜索树推广而来的用于多维检索的树的结构形式(K即为空间的维数)。它与二叉搜索树不同的是它的每个结点表示k维空间的一个点,并且每一层都根据该层的分辨器(discriminator)对相应对象做出分枝决策。顶层结点按由分辨器决定的一个维度进行划分,第二层则按照该层的分辨器决定的一个维进行划分···,以此类推在余下各维之间不断地划分。直至一个结点中的点数少于给定的最大点数时,结束划分。kd <wbr>tree <wbr>介绍以及在sift中的应用

kd <wbr>tree <wbr>介绍以及在sift中的应用

在KD-tree上找KNN ( K-nearest neighbor)

BBF(Best Bin First)算法,借助优先队列(这里用最小堆)实现。从根开始,在KD-tree上找路子的时候,错过的点先塞到优先队列里,自己先一个劲儿扫到leaf;然后再从队列里取出目前key值最小的(这里是是ki维上的距离最小者),重复上述过程,一个劲儿扫到leaf;直到队列找空了,或者已经重复了200遍了停止。

 

Step1: 将img2的features建KD-tree;  kd_root = kdtree_build( feat2, n2 );。在这里,ki是选取均方差最大的那个维度,kv是各特征点在那个维度上的median值。

struct kd_node{

     int ki;                     

     double kv;                  

     int leaf;                   

     struct feature* features;   

     int n;                      

     struct kd_node* kd_left;    

     struct kd_node* kd_right;   

};
 

Step2: 将img1的每个feat到KD-tree里找k个最近邻,这里k=2。

k = kdtree_bbf_knn( kd_root, feat, 2, &nbrs, KDTREE_BBF_MAX_NN_CHKS );

     min_pq = minpq_init();

     minpq_insert( min_pq, kd_root, 0 );

     while( min_pq->n > 0  &&  t < max_nn_chks ) //队列里有东西就继续搜,同时控制在t<200(即200步内)

     {

         expl = (struct kd_node*)minpq_extract_min( min_pq ); //取出最小的,front & pop

         expl = explore_to_leaf( expl, feat, min_pq ); //从该点开始,explore到leaf,路过的“有意义的点”就塞到最小队列min_pq中。

         for( i = 0; i < expl->n; i++ ) //

         {

              tree_feat = &expl->features[i];

              bbf_data->old_data = tree_feat->feature_data;

              bbf_data->d = descr_dist_sq(feat, tree_feat); //两feat均方差

              tree_feat->feature_data = bbf_data;

              n += insert_into_nbr_array( tree_feat, _nbrs, n, k ); //按从小到大塞到neighbor数组里,到时候取前k个就是 KNN 咯~ n 每次加1或0,表示目前已有的元素个数

         }

         t++;

     }
 

对“有意义的点”的解释:

struct kd_node* explore_to_leaf( struct kd_node* kd_node, struct feature* feat,

                                     struct min_pq* min_pq )//expl, feat, min_pq

{

     struct kd_node* unexpl, * expl = kd_node;

     double kv;

     int ki;

     while( expl  &&  ! expl->leaf )

     {

         ki = expl->ki;

         kv = expl->kv;

         if( feat->descr[ki] <= kv ) {

              unexpl = expl->kd_right;

              expl = expl->kd_left; //走左边,右边点将被记下来

         }

         else {

              unexpl = expl->kd_left;

              expl = expl->kd_right; //走右边,左边点将被记下来

         }

         minpq_insert( min_pq, unexpl, ABS( kv - feat->descr[ki] ) ) ;//将这些点插入进来,key键值为|kv - feat->descr[ki]| 即第ki维上的差值

     }

     return expl;

}
 

         Step3: 如果k近邻找到了(k=2),那么判断是否能作为有效特征,d0/d1<0.49就算是咯~

              d0 = descr_dist_sq( feat, nbrs[0] );//计算两特征间squared Euclidian distance

              d1 = descr_dist_sq( feat, nbrs[1] );

              if( d0 < d1 * NN_SQ_DIST_RATIO_THR )//如果d0/d1小于阈值0.49

              {

                   pt1 = cvPoint( cvRound( feat->x ), cvRound( feat->y ) );

                   pt2 = cvPoint( cvRound( nbrs[0]->x ), cvRound( nbrs[0]->y ) );

                   pt2.y += img1->height;

                   cvLine( stacked, pt1, pt2, CV_RGB(255,0,255), 1, 8, 0 );//画线

                   m++;//matches个数

                   feat1[i].fwd_match = nbrs[0];

              }