楼主: CDA网校
768 0

[每天一个数据分析师] KD树近邻搜索改进之BBF算法 [推广有奖]

管理员

已卖:189份资源

泰斗

3%

还不是VIP/贵宾

-

威望
3
论坛币
117887 个
通用积分
10251.9608
学术水平
278 点
热心指数
286 点
信用等级
253 点
经验
228049 点
帖子
6913
精华
19
在线时间
4375 小时
注册时间
2019-9-13
最后登录
2026-1-4

初级热心勋章

楼主
CDA网校 学生认证  发表于 2022-6-29 15:44:57 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币
KD树近邻搜索改进之BBF算法

    原理在上文第二部分已经阐述明白,结合大顶堆找最近的K个近邻思想,相关主体代码如下:
  1. //KD树近邻搜索改进之BBF算法  

  2. int kdtree_bbf_knn( struct kd_node* kd_root, struct feature* feat, int k,  

  3.                     struct feature*** nbrs, int max_nn_chks )                  //2  

  4. {                                               //200  

  5.     struct kd_node* expl;  

  6.     struct min_pq* min_pq;  

  7.     struct feature* tree_feat, ** _nbrs;  

  8.     struct bbf_data* bbf_data;  

  9.     int i, t = 0, n = 0;  

  10.   

  11.     if( ! nbrs  ||  ! feat  ||  ! kd_root )  

  12.     {  

  13.         fprintf( stderr, "Warning: NULL pointer error, %s, line %d\n",  

  14.                 __FILE__, __LINE__ );  

  15.         return -1;  

  16.     }  

  17.   

  18.     _nbrs = (feature**)(calloc( k, sizeof( struct feature* ) )); //2  

  19.     min_pq = minpq_init();   

  20.     minpq_insert( min_pq, kd_root, 0 ); //把根节点加入搜索序列中  

  21.   

  22.     //队列有东西就继续搜,同时控制在t<200步内  

  23.     while( min_pq->n > 0  &&  t < max_nn_chks )  

  24.     {                  

  25.         //刚进来时,从kd树根节点搜索,exp1是根节点   

  26.         //后进来时,exp1是min_pq差值最小的未搜索节点入口  

  27.         //同时按min_pq中父,子顺序依次检验,保证父节点的差值比子节点小.这样减少返回搜索时间  

  28.         expl = (struct kd_node*)minpq_extract_min( min_pq );  

  29.         if( ! expl )                                          

  30.         {                                                     

  31.             fprintf( stderr, "Warning: PQ unexpectedly empty, %s line %d\n",  

  32.                     __FILE__, __LINE__ );                           

  33.             goto fail;  

  34.         }  

  35.   

  36.         //从根节点(或差值最小节点)搜索,根据目标点与节点模值的差值(小)  

  37.         //确定在kd树的搜索路径,同时存储各个节点另一入口地址\同级搜索路径差值.  

  38.         //存储时比较父节点的差值,如果子节点差值比父节点差值小,交换两者存储位置,  

  39.         //使未搜索节点差值小的存储在min_pq的前面,减小返回搜索的时间.  

  40.         expl = explore_to_leaf( expl, feat, min_pq );   

  41.         if( ! expl )                                    

  42.         {                                               

  43.             fprintf( stderr, "Warning: PQ unexpectedly empty, %s line %d\n",  

  44.                     __FILE__, __LINE__ );                     

  45.             goto fail;                                    

  46.         }                                               

  47.   

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

  49.         {   

  50.             //使用exp1->n原因:如果是叶节点,exp1->n=1,如果是伪叶节点,exp1->n=0.  

  51.             tree_feat = &expl->features[i];  

  52.             bbf_data = (struct bbf_data*)(malloc( sizeof( struct bbf_data ) ));  

  53.             if( ! bbf_data )  

  54.             {  

  55.                 fprintf( stderr, "Warning: unable to allocate memory,"  

  56.                     " %s line %d\n", __FILE__, __LINE__ );  

  57.                 goto fail;  

  58.             }  

  59.             bbf_data->old_data = tree_feat->feature_data;  

  60.             bbf_data->d = descr_dist_sq(feat, tree_feat); //计算两个关键点描述器差平方和  

  61.             tree_feat->feature_data = bbf_data;  

  62.   

  63.             //取前k个  

  64.             n += insert_into_nbr_array( tree_feat, _nbrs, n, k );//  

  65.         }                                                  //2  

  66.         t++;  

  67.     }  

  68.   

  69.     minpq_release( &min_pq );  

  70.     for( i = 0; i < n; i++ ) //bbf_data为何搞个old_data?  

  71.     {  

  72.         bbf_data = (struct bbf_data*)(_nbrs[i]->feature_data);  

  73.         _nbrs[i]->feature_data = bbf_data->old_data;  

  74.         free( bbf_data );  

  75.     }  

  76.     *nbrs = _nbrs;  

  77.     return n;  

  78.   

  79. fail:  

  80.     minpq_release( &min_pq );  

  81.     for( i = 0; i < n; i++ )  

  82.     {  

  83.         bbf_data = (struct bbf_data*)(_nbrs[i]->feature_data);  

  84.         _nbrs[i]->feature_data = bbf_data->old_data;  

  85.         free( bbf_data );  

  86.     }  

  87.     free( _nbrs );  

  88.     *nbrs = NULL;  

  89.     return -1;  

  90. }  

  91.    依据上述函数kdtree_bbf_knn从上而下看下来,注意几点:



  92.     1、上述函数kdtree_bbf_knn中,explore_to_leaf的代码如下:



  93. static struct kd_node* explore_to_leaf( struct kd_node* kd_node, struct feature* feat,  

  94.                                         struct min_pq* min_pq )       //kd tree          //the before   

  95. {  

  96.     struct kd_node* unexpl, * expl = kd_node;  

  97.     double kv;  

  98.     int ki;  

  99.   

  100.     while( expl  &&  ! expl->leaf )  

  101.     {                    //0  

  102.         ki = expl->ki;  

  103.         kv = expl->kv;  

  104.   

  105.         if( ki >= feat->d )  

  106.         {  

  107.             fprintf( stderr, "Warning: comparing imcompatible descriptors, %s" \  

  108.                     " line %d\n", __FILE__, __LINE__ );  

  109.             return NULL;  

  110.         }  

  111.         if( feat->descr[ki] <= kv )  //由目标点描述器确定搜索向kd tree的左边或右边  

  112.         {                            //如果目标点模值比节点小,搜索向tree的左边进行  

  113.             unexpl = expl->kd_right;  

  114.             expl = expl->kd_left;  

  115.         }  

  116.         else  

  117.         {  

  118.             unexpl = expl->kd_left;    //else   

  119.             expl = expl->kd_right;  

  120.         }  

  121.   

  122.         //把未搜索数分支入口,差值存储在min_pq,  

  123.         if( minpq_insert( min_pq, unexpl, ABS( kv - feat->descr[ki] ) ) )  

  124.         {                                       

  125.             fprintf( stderr, "Warning: unable to insert into PQ, %s, line %d\n",  

  126.                     __FILE__, __LINE__ );  

  127.             return NULL;  

  128.         }  

  129.     }  

  130.     return expl;  

  131. }  
复制代码
2、上述查找函数kdtree_bbf_knn中的参数k可调,代表的是要查找近邻的个数,即number of neighbors to find,在sift特征匹配中,k一般取2

k = kdtree_bbf_knn( kd_root_0, feat, 2, &nbrs, KDTREE_BBF_MAX_NN_CHKS_0 );//点匹配函数(核心)  
        if( k == 2 ) //只有进行2次以上匹配过程,才算是正常匹配过程  
    3、上述函数kdtree_bbf_knn中“bbf_data->d = descr_dist_sq(feat, tree_feat); //计算两个关键点描述器差平方和”,使用的计算方法是本文第一部分1.2节中所述的欧氏距离。

      相关帖子DA内容精选
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Unexpected compatible Comparing CDA LEVEL Expected

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群
GMT+8, 2026-1-5 01:41