Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use opencv flann::Index?

Tags:

c++

opencv

knn

I have some problems with opencv flann::Index -

I'm creating 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");

A fter that I'm tryin to load it and find nearest 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));

And have access violation in miniflann.cpp in line

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

Please help

like image 239
USeTi Avatar asked Apr 26 '12 15:04

USeTi


2 Answers

In the accepted answer is somehow not clear and misleading why the input matrix in the cv::flann::Index constructor must have the same dimension as the matrix used for generating the saved Index. I'll elaborate on @Sau's comment with an example.

KDTreeIndex was generated using as input a cv::Mat sample, and then saved. When you load it, you must provide the same sample matrix to generate it, something like (using the templated GenericIndex interface):

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 is the usual Euclidean distance (other types can be found in opencv2/flann/dist.h).

Now the index can be used as shown the find the K nearest neighbours of a query point:

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));

The matrix indices will contain the locations of the nearest neighbours in the matrix sample, which was used at first to generate the index. That's why you need to load the saved index with the very matrix used to generate the index, otherwise the returned vector will contain indices pointing to meaningless "nearest neighbours".

In addition you get a distances matrix containing how far are the found neighbours from your query point, which you can later use to perform some inverse distance weighting, for example.

Please also note that sample_size has to match across sample matrix and query point.

like image 118
Mattia Avatar answered Oct 05 '22 06:10

Mattia


You should not load the flann-file into a Mat(), as it is the place where the index is stored. It is a temporary object destroyed after the constructor was called. That's why the index isn't pointing anywhere useful when you call knnSearch().

I tried following:

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

resulting in:

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

which means, that the matrix has to be initialized with the correct dimensions (seems very stupid to me, as I don't necessarily know, how many elements are stored in my index).

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

does the trick.

like image 38
Ben Avatar answered Oct 05 '22 08:10

Ben