Как использовать opencv flann::Index?

у меня есть некоторые проблемы с opencv flann:: Index -

Я создаю индекс

    Mat samples = Mat::zeros(vfv_net_quie.size(),24,CV_32F);
        for (int i =0; i < vfv_net_quie.size();i++)
        {
           for (int j = 0;j<24;j++)
           {
              samples.at<float>(i,j)=(float)vfv_net_quie[i].vfv[j];
           }
        }
    cv::flann::Index flann_index(
            samples,
            cv::flann::KDTreeIndexParams(4),
            cvflann::FLANN_DIST_EUCLIDEAN
               );
    flann_index.save("c:index.fln");

fter, что я пытаюсь загрузить его и найти ближайшие neiborhoods

cv::flann::Index flann_index(Mat(),
    cv::flann::SavedIndexParams("c:index.fln"),
    cvflann::FLANN_DIST_EUCLIDEAN
    );

cv::Mat resps(vfv_reg_quie.size(), K, CV_32F);
cv::Mat nresps(vfv_reg_quie.size(), K, CV_32S);
cv::Mat dists(vfv_reg_quie.size(), K, CV_32F);

flann_index.knnSearch(sample,nresps,dists,K,cv::flann::SearchParams(64));

и имеют нарушение доступа в miniflann.cpp в строке

((IndexType*)index)->knnSearch(_query, _indices, _dists, knn,
                          (const ::cvflann::SearchParams&)get_params(params));

пожалуйста, помогите

2 ответов


вы не должны загружать файл flann в Mat(), так как это место, где хранится индекс. Это временный объект, уничтоженный после вызова конструктора. Вот почему индекс не указывает на что-либо полезное, когда вы вызываете knnSearch().

я попробовал следующее:

cv::Mat indexMat;
cv::flann::Index flann_index(
    indexMat,
    cv::flann::SavedIndexParams("c:\index.fln"),
    cvflann::FLANN_DIST_EUCLIDEAN
);

в результате:

Reading FLANN index error: the saved data size (100, 64) or type (5) is different from the passed one (0, 0), 0

что означает, что матрица должна быть инициализирована с правильными размерами (мне кажется очень глупым, так как я не знаю, как многие элементы хранятся в моем индексе).

cv::Mat indexMat(samples.size(), CV_32FC1);
cv::flann::Index flann_index(
    indexMat,
    cv::flann::SavedIndexParams("c:\index.fln"),
    cvflann::FLANN_DIST_EUCLIDEAN
);

делает трюк.


в принятом ответе как-то не понятно и вводит в заблуждение, почему входная матрица в cv::flann::Index конструктор должен иметь то же измерение, что и матрица, используемая для создания сохраненного индекса. Я подробно остановлюсь на комментарии @Sau с примером.

KDTreeIndex был сгенерирован с использованием в качестве ввода a cv::Mat sample, а потом спас. Когда вы загружаете его, вы должны предоставить то же самое sample matrix для его генерации, что-то вроде (используя templated GenericIndex интерфейс):

cv::Mat sample(sample_num, sample_size, ... /* other params */);
cv::flann::SavedIndexParams index_params("c:\index.fln");
cv::flann::GenericIndex<cvflann::L2<float>> flann_index(sample, index_params);

L2 - обычное Евклидово расстояние (другие типы можно найти в opencv2/flann/dist.h).

теперь индекс можно использовать, как показано на рисунке найти K ближайшие соседи query точка:

std::vector<float> query(sample_size);
std::vector<int> indices(K);
std::vector<float> distances(K);

flann_index.knnSearch(query, indices, distances, K, cv::flann::SearchParams(64));

матрица indices содержит мест на ближайших соседей в матрице sample, который сначала использовался для создания индекса. Вот почему вам нужно загрузить сохраненный индекс с самой матрицей, используемой для генерации индекса, иначе возвращаемый вектор будет содержать индексы, указывающие на бессмысленные "ближайшие соседи".

кроме того, вы получаете distances матрица, содержащая, как далеко находятся найденные соседи от вашего query точка, которую вы можете позже использовать для выполнения некоторых обратных взвешенных расстояний, например.

обратите внимание, что sample_size чтобы соответствовать через sample матрица и query точка.