保存和加载FlannBasedMatcher

时间:2012-02-12 10:16:50

标签: c++ opencv

如果训练图像集很大,训练OpenCV DescriptorMatcher可能是一项耗时的操作。因此,似乎将训练好的DescriptorMatcher数据保存到磁盘以便以后重新加载将是一件非常明显的事情。

不幸的是,似乎没有任何明显的解决方案来满足这种需求。

我最接近找到答案的是this thread in the OpenCV discussion group。该线程始于2009年,人们仍在寻找2011年的答案!

从该线程获取的代码片段看起来应该从文件重新加载索引:

FileStorage fs("data.xml",FileStorage::READ);
Mat data;
fs["mtx"] >> data;
flann::Index idx(data,"index.bin");

但我无法从中了解如何实现完整的保存/加载功能。

以防它是相关的,我正在使用OpenCV 2.3.1。

4 个答案:

答案 0 :(得分:5)

我在论坛或邮件列表上没有看到答案。我不得不深入研究OpenCV源代码(2.4.5)以了解如何完成这项工作。它需要子类化来获取FlannBasedMatcher的受保护成员。

关键是将算法设置为FLANN_INDEX_SAVED,将文件名设置为indexParams

另外值得注意的是:

  • 描述符必须在readIndex()之前传递给add()

  • 对于要构建的索引,必须先对其进行匹配,然后调用write()。 train()似乎没有做任何事情,除了构造匹配器(不提供描述符)

  • 这适用于SURF描述符。对于完整的解决方案,可能还需要保存/恢复匹配器的IndexParams和/或SearchParams。

接下来要做的是压缩索引(使用gzip),它可以减少3-4倍,并且解压缩的成本相对较低。这必须是OpenCV中的一个补丁。

class SaveableMatcher : public cv::FlannBasedMatcher
{
public:
SaveableMatcher()
{
}

virtual ~SaveableMatcher()
{
}

void printParams()
{
    printf("SaveableMatcher::printParams: \n\t"
        "addedDescCount=%d\n\t"
        "flan distance_t=%d\n\t"
        "flan algorithm_t=%d\n",
        addedDescCount,
        flannIndex->getDistance(),
        flannIndex->getAlgorithm());

    vector<std::string> names;
    vector<int> types;
    vector<std::string> strValues;
    vector<double> numValues;

    indexParams->getAll(names, types, strValues, numValues);

    for (size_t i = 0; i < names.size(); i++)
        printf("\tindex param: %s:\t type=%d val=%s %.2f\n",
                names[i].c_str(), types[i],
                strValues[i].c_str(), numValues[i]);

    names.clear();
    types.clear();
    strValues.clear();
    numValues.clear();
    searchParams->getAll(names, types, strValues, numValues);

    for (size_t i = 0; i < names.size(); i++)
        printf("\tsearch param: %s:\t type=%d val=%s %.2f\n",
                names[i].c_str(), types[i],
                strValues[i].c_str(), numValues[i]);
}

void readIndex(const char* filename)
{
    indexParams->setAlgorithm(cvflann::FLANN_INDEX_SAVED);
    indexParams->setString("filename", filename);

    // construct flannIndex now, so printParams works
    train();

    printParams();
}

void writeIndex(const char* filename)
{
    printParams();
    flannIndex->save(filename);
}
};

答案 1 :(得分:3)

在OpenCV 2.4.0中(但也在2.3.1a中)有:

// Reads matcher object from a file node
virtual void read( const FileNode& );
// Writes matcher object to a file storage
virtual void write( FileStorage& ) const;

至少为FlannDescriptorMatcher实现,但实现似乎只保存匹配器的IndexParams。相反,flann :: Index_有一个保存和加载方法(在2.3.1中有保存,而加载似乎可以使用SavedIndexParams

答案 2 :(得分:3)

很久以前就问过这个问题了,所以你可能已经有了答案,但我只是使用类似你所展示的代码实现了一些东西。我没有保存DescriptorMatcher,但为集合中的每个图像创建了一个descriptors.xml文件,然后将所有这些文件加载​​到Vector中,作为train()调用的输入。 这将程序的运行时间从2分钟减少到5秒,但将描述符加载到Vector中需要3-4秒。 加载整个训练过的索引会很方便。我仍然在寻找一种方法。

答案 3 :(得分:1)

我查看了OpenCV 3.2.0代码,发现基于Flann的匹配器的write()/ read()函数仍然没有保存/加载训练好的数据。受到Wally的回答的启发,我创建了一个类似的可爱的matcher类,继承自FlannBasedMatcher。请注意,这个可保存的匹配器目前仅适用于SURF描述符。

这个可保存的类FlannBasedSavableMatcher将indexParams,searchParams和训练的描述符写入xml / yml文件,但必须将flannIndex写入单独的二进制文件,因为flannIndex的save()方法仅支持原始二进制格式。

以下是课程标题​​。

#ifndef INCLUDES_FLANNBASEDSAVABLEMATCHER_H_
#define INCLUDES_FLANNBASEDSAVABLEMATCHER_H_

#include <string>

#include <opencv2/core.hpp>
#include <opencv2/features2d.hpp>

namespace cv
{

class FlannBasedSavableMatcher : public FlannBasedMatcher
{
private:
    std::vector<std::string> trainedImgFilenameList;
    std::string flannIndexFileDir;
    std::string flannIndexFilename;

public:
    FlannBasedSavableMatcher();
    virtual ~FlannBasedSavableMatcher();

    std::vector<std::string> getTrainedImgFilenameList();
    void setTrainedImgFilenameList(const std::vector<std::string>& imgFilenameList);
    void setFlannIndexFileDir(const std::string& dir);
    void setFlannIndexFilename(const std::string& filename);

    virtual void read(const FileNode& fn);
    virtual void write(FileStorage& fs) const;

    static Ptr<FlannBasedSavableMatcher> create();
};

}

#endif /* INCLUDES_FLANNBASEDSAVABLEMATCHER_H_ */

可以在以下位置找到源文件 https://github.com/renweizhukov/LearningOpenCV/blob/master/FlannKnnSavableMatching1toN/src/FlannBasedSavableMatcher.cpp,同时可以在以下位置找到示例用法 https://github.com/renweizhukov/LearningOpenCV/blob/master/FlannKnnSavableMatching1toN/src/main.cpp