Мне удалось заставить работать SIFT в VlFeat, и я хотел бы попробовать сопоставить два набора дескрипторов изображений.
Векторы функций SIFT — это 128-элементные массивы с плавающей точкой, я сохранил списки дескрипторов в std::vector
s, как показано в фрагменте ниже:
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;
}
Насколько я могу сказать, это должно работать, но все, что я получаю, для расстояний, nan
«S. Длина извлечения массивов дескрипторов, так что, похоже, данные идут в дерево. Я наметил ключевые точки, и они также выглядят разумно, так что данные довольно нормальные.
Что мне не хватает?
Довольно скудная документация здесь (ссылки на API): http://www.vlfeat.org/api/kdtree.html
Что мне не хватает?
Второй аргумент vl_kdforestsearcher_query
принимает указатель на VlKDForestNeighbor
:
vl_size
vl_kdforestsearcher_query(
VlKDForestSearcher *self,
VlKDForestNeighbor *neighbors,
vl_size numNeighbors,
void const *query
);
Но здесь вы заявили VlKDForestNeighbor neighbours[2];
а потом прошло &neighbours
как 2-й параметр, который не является правильным — ваш компилятор, вероятно, выдал incompatible pointer types
предупреждение.
Поскольку вы объявили массив, вы должны вместо этого либо явно передать указатель на 1-го соседа:
int nvisited = vl_kdforestsearcher_query(searcher, &neighbours[0], 2, qrys[i]);
Или, в качестве альтернативы, пусть компилятор сделает это за вас:
int nvisited = vl_kdforestsearcher_query(searcher, neighbours, 2, qrys[i]);
РЕДАКТИРОВАТЬ
Существует действительно вторая (главная) проблема, связанная с тем, как вы строите kd-дерево с помощью ldescriptors.data()
,
Здесь вы проходите std::vector<float>*
указатель, когда VLFeat ожидает float *
непрерывный массив, содержащий все ваши точки данных в главном порядке строк. Итак, что вы можете сделать, это скопировать ваши данные в этом формате:
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;`