2012-02-12 96 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找到。