2012-02-12 97 views
7

如果训练图像集较大,则训练OpenCV描述符匹配器可能是一项耗时的操作。因此,将训练有素的DescriptorMatcher数据保存到磁盘以便稍后重新加载似乎是一件非常明显的事情。保存并加载FlannBasedMatcher

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

我找到最接近的答案是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"); 

但我一直无法从这个弄清楚如何实现完整的SAVE/LOAD功能。

为了防万一,我使用的是OpenCV 2.3.1。

回答

5

我在论坛或邮件列表上没有看到这个答案。我不得不深入研究OpenCV源代码(2.4.5),看看如何完成这个任务。它要求子类获取FlannBasedMatcher的受保护成员。

关键是将算法设置为FLANN_INDEX_SAVEDindexParams上的文件名。

另外值得注意的是:

  • 描述符必须通过添加()readIndex()

  • 所要构建索引之前,你必须做一个匹配就可以了,然后再调用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); 
} 
}; 
+0

注意:据我所知,描述符本身必须分别序列化/反序列化。加载时,_prior_调用readIndex,描述符必须被反序列化并添加(即,使用FlannBasedMatcher :: add)。 – sircolinton 2016-11-16 16:34:41

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

+0

是的,读写功能只保存IndexParams。我会看看你提到的其他功能。 – 2012-05-15 06:12:30

3

这个问题很久以前问过,所以你可能已经有你的答案,但我只是用类似于你展示的代码实现了一些东西,我没有保存DescriptorMatcher,而是为集合中的每个图像创建了一个descriptors.xml文件,然后将所有这些加载到一个Vector中作为train()的输入,调用 这会将程序的运行时间从2分钟缩短为5秒,但需要3-4秒才能将描述符加载到向量中。一种方式来做到这一点。

1

我看着OpenCV的3.2.0代码,发现基于弗莱恩-匹配的write()/()函数读取仍然不保存/载入训练的数据。受到wally的回答的启发,我创建了一个类似的可保存匹配器类,继承自FlannBasedMatcher。请注意,这个可保存的匹配器目前仅适用于SURF描述符。

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

以下是课程标题​​。

#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找到。