2012-02-12 13 views
7

Entrenar un OpenCV DescriptorMatcher puede ser una operación lenta si el conjunto de imágenes de entrenamiento es grande. Por lo tanto, parece que guardar los datos entrenados de DescriptorMatcher en el disco para volver a cargarlos más tarde sería algo bastante obvio de querer hacer.Guardar y cargar FlannBasedMatcher

Desafortunadamente, no parece haber ninguna solución obvia a esta necesidad.

Lo más parecido que he encontrado para encontrar una respuesta es this thread in the OpenCV discussion group. El hilo comenzó en 2009, ¡y la gente todavía está buscando una respuesta en 2011!

Este fragmento de código tomado de ese hilo parece que debería volver a cargar un índice de un archivo:

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

pero no he sido capaz de averiguar de este cómo implementar la funcionalidad completa de salvar/carga.

Solo en caso de que sea relevante, estoy usando OpenCV 2.3.1.

Respuesta

5

No vi una respuesta a esto en foros o listas de correo. Tuve que profundizar en el código fuente de OpenCV (2.4.5) para ver cómo se debe hacer esto. Requiere subclassing para llegar a los miembros protegidos de FlannBasedMatcher.

La clave es establecer el algoritmo en FLANN_INDEX_SAVED y el nombre del archivo en el indexParams.

También hay que resaltar:

  • se deben pasar los descriptores para añadir() antes de readIndex()

  • Para el índice que se construirá, se debe hacer un partido en el que en primer lugar, a continuación, llamar a write(). train() no parece hacer nada excepto construir el emparejador (no lo alimenta descriptores)

  • Esto funciona con los descriptores de SURF. Para una solución completa, puede ser necesario guardar/restaurar los Parámetros de índice y/o losParámetros de búsqueda del comparador también.

Lo siguiente que hacer es comprimir el índice (con gzip), puede ser 3-4 veces más pequeño y el coste para descomprimir es relativamente bajo. Esto debería ser un parche en 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

Nota: según tengo entendido, los descriptores deben ser serializados/deserializados por separado. Al cargar, _prior_ para llamar a readIndex, los descriptores deben ser deserializados y agregados (es decir, con FlannBasedMatcher :: add). – sircolinton

3

En OpenCV 2.4.0 (pero también en 2.3.1a) hay:

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

que se implementan al menos por el FlannDescriptorMatcher pero la implementación parece guardar sólo los IndexParams del emparejador. En cambio, flann :: Index_ tiene un método de guardar y cargar (en 2.3.1 hay guardado mientras la carga parece estar disponible usando un SavedIndexParams

+0

Sí, las funciones de lectura y escritura solo guardan el IndexParams. Echaré un vistazo a las otras funciones que mencionaste. –

3

Esta pregunta fue hecha hace mucho tiempo, por lo que probablemente ya tenga su respuesta, pero yo simplemente implementé algo usando un código similar al que se muestra. No guardé DescriptorMatcher, sino que creé un archivo descriptors.xml para cada imagen en la colección, y luego cargué todo esto en un Vector para ser utilizado como entrada para el tren() llame al Esto redujo el tiempo de ejecución del programa de 2 minutos a 5 segundos, pero se tardan de 3 a 4 segundos en cargar los descriptores en el Vector. Sería útil cargar todo el índice entrenado. Todavía estoy buscando una forma de hacerlo.

1

Miré el código de OpenCV 3.2.0 y encontraron que la escritura de la matcher basada en Flann()/función de lectura() sigue sin guardar/cargar los datos entrenados. Inspirado por la respuesta de wally, creé una clase de matcher salvable similar heredada de FlannBasedMatcher. Tenga en cuenta que este matcher salvable actualmente solo funciona con descriptores de SURF.

Esta clase savable FlannBasedSavableMatcher escribe indexParams, searchParams, y descriptores entrenados en un archivo XML/yml pero tiene que escribir flannIndex en un archivo binario separado ya que el método save() de flannIndex sólo es compatible con el formato binario.

A continuación se muestra el encabezado de clase.

#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_ */ 

El archivo de origen se puede encontrar en https://github.com/renweizhukov/LearningOpenCV/blob/master/FlannKnnSavableMatching1toN/src/FlannBasedSavableMatcher.cpp, mientras que un ejemplos de uso se puede encontrar en https://github.com/renweizhukov/LearningOpenCV/blob/master/FlannKnnSavableMatching1toN/src/main.cpp.

Cuestiones relacionadas