/* Explores a kd tree from a given node to a leaf. Branching decisions are made at each node based on the descriptor of a given feature. Each node examined but not explored is put into a priority queue to be explored later, keyed based on the distance from its partition key value to the given feature's desctiptor. @param kd_node root of the subtree to be explored @param feat feature upon which branching decisions are based @param min_pq a minimizing priority queue into which tree nodes are placed as described above @return Returns a pointer to the leaf node at which exploration ends or NULL on error. */ static struct kd_node* explore_to_leaf( struct kd_node* kd_node, struct feature* feat, struct min_pq* min_pq ) { struct kd_node* unexpl, * expl = kd_node; double kv; int ki; while( expl && ! expl->leaf ) { ki = expl->ki; kv = expl->kv; if( ki >= feat->d ) { fprintf( stderr, "Warning: comparing imcompatible descriptors, %s" \ " line %d\n", __FILE__, __LINE__ ); return NULL; } if( feat->descr[ki] <= kv ) { unexpl = expl->kd_right; expl = expl->kd_left; } else { unexpl = expl->kd_left; expl = expl->kd_right; } if( minpq_insert( min_pq, unexpl, ABS( kv - feat->descr[ki] ) ) ) { fprintf( stderr, "Warning: unable to insert into PQ, %s, line %d\n", __FILE__, __LINE__ ); return NULL; } } return expl; }
/* Finds an image feature's approximate k nearest neighbors in a kd tree using Best Bin First search. @param kd_root root of an image feature kd tree @param feat image feature for whose neighbors to search @param k number of neighbors to find @param nbrs pointer to an array in which to store pointers to neighbors in order of increasing descriptor distance @param max_nn_chks search is cut off after examining this many tree entries @return Returns the number of neighbors found and stored in nbrs, or -1 on error. */ int kdtree_bbf_knn( struct kd_node* kd_root, struct feature* feat, int k, struct feature*** nbrs, int max_nn_chks ) { struct kd_node* expl; struct min_pq* min_pq; struct feature* tree_feat, ** _nbrs; struct bbf_data* bbf_data; int i, t = 0, n = 0; if( ! nbrs || ! feat || ! kd_root ) { fprintf( stderr, "Warning: NULL pointer error, %s, line %d\n", __FILE__, __LINE__ ); return -1; } _nbrs = calloc( k, sizeof( struct feature* ) ); min_pq = minpq_init(); minpq_insert( min_pq, kd_root, 0 ); while( min_pq->n > 0 && t < max_nn_chks ) { expl = (struct kd_node*)minpq_extract_min( min_pq ); if( ! expl ) { fprintf( stderr, "Warning: PQ unexpectedly empty, %s line %d\n", __FILE__, __LINE__ ); goto fail; } expl = explore_to_leaf( expl, feat, min_pq ); if( ! expl ) { fprintf( stderr, "Warning: PQ unexpectedly empty, %s line %d\n", __FILE__, __LINE__ ); goto fail; } for( i = 0; i < expl->n; i++ ) { tree_feat = &expl->features[i]; bbf_data = malloc( sizeof( struct bbf_data ) ); if( ! bbf_data ) { fprintf( stderr, "Warning: unable to allocate memory," " %s line %d\n", __FILE__, __LINE__ ); goto fail; } bbf_data->old_data = tree_feat->feature_data; bbf_data->d = descr_dist_sq(feat, tree_feat); tree_feat->feature_data = bbf_data; n += insert_into_nbr_array( tree_feat, _nbrs, n, k ); } t++; } minpq_release( &min_pq ); for( i = 0; i < n; i++ ) { bbf_data = _nbrs[i]->feature_data; _nbrs[i]->feature_data = bbf_data->old_data; free( bbf_data ); } *nbrs = _nbrs; return n; fail: minpq_release( &min_pq ); for( i = 0; i < n; i++ ) { bbf_data = _nbrs[i]->feature_data; _nbrs[i]->feature_data = bbf_data->old_data; free( bbf_data ); } free( _nbrs ); *nbrs = NULL; return -1; }