问题 如何使用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");

我试图加载它并找到最近的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));

请帮忙


926
2018-04-26 15:27


起源



答案:


你不应该将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
);

诀窍。


12
2018-05-10 17:39



需要注意的一点是,您需要提供实际的原始数据集,而不仅仅是具有正确尺寸的Mat。在OpenCV文档中并不是很清楚,但是在3.3.4节中提到了 flann文档 - Sau
@Sau不是第3.3.4节谈论Matlab而不是C ++?您是否在OpenCV或Flann的C ++版本中验证了您的评论? - t2k32316


答案:


你不应该将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
);

诀窍。


12
2018-05-10 17:39



需要注意的一点是,您需要提供实际的原始数据集,而不仅仅是具有正确尺寸的Mat。在OpenCV文档中并不是很清楚,但是在3.3.4节中提到了 flann文档 - Sau
@Sau不是第3.3.4节谈论Matlab而不是C ++?您是否在OpenCV或Flann的C ++版本中验证了您的评论? - t2k32316


在接受的答案中,某种程度上不清楚和误导为什么输入矩阵在 cv::flann::Index 构造函数必须与用于生成已保存索引的矩阵具有相同的维度。我将以一个例子详细说明@ Sau的评论。

KDTreeIndex 是使用输入a生成的 cv::Mat sample,然后保存。加载时,必须提供相同的内容 sample 生成它的矩阵,类似于(使用模板化的 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 点。


1
2017-12-07 09:23