I've managed to get VlFeat's SIFT implmentation working and I'd like to try matching two sets of image descriptors.
SIFT's feature vectors are 128 element float arrays, I've stored the descriptor lists in std::vector
s as shown in the snippet below:
std::vector<std::vector<float> > ldescriptors = leftImage->descriptors;
std::vector<std::vector<float> > rdescriptors = rightImage->descriptors;
/* KDTree, L1 comparison metric, dimension 128, 1 tree, L1 metric */
VlKDForest* forest = vl_kdforest_new(VL_TYPE_FLOAT, 128, 1, VlDistanceL1);
/* Build the tree from the left descriptors */
vl_kdforest_build(forest, ldescriptors.size(), ldescriptors.data());
/* Searcher object */
VlKDForestSearcher* searcher = vl_kdforest_new_searcher(forest);
VlKDForestNeighbor neighbours[2];
/* Query the first ten points for now */
for(int i=0; i < 10; i++){
int nvisited = vl_kdforestsearcher_query(searcher, &neighbours, 2, rdescriptors[i].data());
cout << nvisited << neighbours[0].distance << neighbours[1].distance;
}
As far as I can tell that should work, but all I get out, for the distances, are nan
's. The length of the descriptor arrays checkout so there does seem to be data going into the tree. I've plotted the keypoints and they also look reasonable, so the data is fairly sane.
What am I missing?
Rather sparse documentation here (links to the API): http://www.vlfeat.org/api/kdtree.html
What am I missing?
The 2nd argument of vl_kdforestsearcher_query
takes a pointer to VlKDForestNeighbor
:
vl_size
vl_kdforestsearcher_query(
VlKDForestSearcher *self,
VlKDForestNeighbor *neighbors,
vl_size numNeighbors,
void const *query
);
But here you declared VlKDForestNeighbor neighbours[2];
and then passed &neighbours
as 2nd parameter which is not correct - your compiler probably issued a incompatible pointer types
warning.
Since you declared an array, what you must do instead is either pass explicitly a pointer to the 1st neighbor:
int nvisited = vl_kdforestsearcher_query(searcher, &neighbours[0], 2, qrys[i]);
Or alternatively let the compiler do it for you:
int nvisited = vl_kdforestsearcher_query(searcher, neighbours, 2, qrys[i]);
EDIT
There is indeed a second (major) problem related to the way you build the kd-tree with ldescriptors.data()
.
Here you pass a std::vector<float>*
pointer when VLFeat expects a float *
contiguous array containing all your data points in row major order. So what you can do is copying your data in this format:
float *data = new float[128*ldescriptors.size()];
for (unsigned int i = 0; i < ldescriptors.size(); i++)
std::copy(ldescriptors[i].begin(), ldescriptors[i].end(), data + 128*i);
vl_kdforest_build(forest, ldescriptors.size(), data);
// ...
// then, right after `vl_kdforest_delete(forest);`
// do a `delete[] data;`