Carica in modo efficiente un grande Mat in memoria in OpenCV

Esiste un modo più efficiente di caricare un object Mat di grandi dimensioni in memoria rispetto al metodo FileStorage in OpenCV?

Ho un grande Mat con 192 colonne e 1 milione di righe che voglio archiviare localmente in un file e caricare in memoria, quindi inizia la mia applicazione. Non ci sono problemi nell’uso di FileStorage, ma mi chiedevo se esiste un metodo più efficiente per farlo. Al momento ci vogliono circa 5 minuti per caricare il Mat in memoria usando la modalità Debug in Visual Studio e circa 3 minuti nella modalità Rilascio e la dimensione del file dati è di circa 1,2 GB.

Il metodo FileStorage è l’unico metodo disponibile per eseguire questa attività?

Stai bene con uno speedup 100x ?


Dovresti salvare e caricare le tue immagini in formato binario. Puoi farlo con la matwrite e la funzione matread nel codice qui sotto.

Ho testato sia il caricamento da un FileStorage e il file binario, e per un’immagine più piccola con 250K righe, 192 colonne, tipo CV_8UC1 Ho ottenuto questi risultati (tempo in ms):

 // Mat: 250K rows, 192 cols, type CV_8UC1 Using FileStorage: 5523.45 Using Raw: 50.0879 

Su un’immagine con 1M righe e 192 colonne usando la modalità binaria che ho ottenuto (tempo in ms):

 // Mat: 1M rows, 192 cols, type CV_8UC1 Using FileStorage: (can't load, out of memory) Using Raw: 197.381 

NOTA

  1. Non misurare mai le prestazioni in debug .
  2. 3 minuti per caricare una matrice sembra troppo, anche per FileStorage . Tuttavia, guadagnerai molto passando alla modalità binaria.

Qui il codice con le funzioni matwrite e matread e il test:

 #include  #include  #include  using namespace std; using namespace cv; void matwrite(const string& filename, const Mat& mat) { ofstream fs(filename, fstream::binary); // Header int type = mat.type(); int channels = mat.channels(); fs.write((char*)&mat.rows, sizeof(int)); // rows fs.write((char*)&mat.cols, sizeof(int)); // cols fs.write((char*)&type, sizeof(int)); // type fs.write((char*)&channels, sizeof(int)); // channels // Data if (mat.isContinuous()) { fs.write(mat.ptr(0), (mat.dataend - mat.datastart)); } else { int rowsz = CV_ELEM_SIZE(type) * mat.cols; for (int r = 0; r < mat.rows; ++r) { fs.write(mat.ptr(r), rowsz); } } } Mat matread(const string& filename) { ifstream fs(filename, fstream::binary); // Header int rows, cols, type, channels; fs.read((char*)&rows, sizeof(int)); // rows fs.read((char*)&cols, sizeof(int)); // cols fs.read((char*)&type, sizeof(int)); // type fs.read((char*)&channels, sizeof(int)); // channels // Data Mat mat(rows, cols, type); fs.read((char*)mat.data, CV_ELEM_SIZE(type) * rows * cols); return mat; } int main() { // Save the random generated data { Mat m(1024*256, 192, CV_8UC1); randu(m, 0, 1000); FileStorage fs("fs.yml", FileStorage::WRITE); fs << "m" << m; matwrite("raw.bin", m); } // Load the saved matrix { // Method 1: using FileStorage double tic = double(getTickCount()); FileStorage fs("fs.yml", FileStorage::READ); Mat m1; fs["m"] >> m1; double toc = (double(getTickCount()) - tic) * 1000. / getTickFrequency(); cout << "Using FileStorage: " << toc << endl; } { // Method 2: usign raw binary data double tic = double(getTickCount()); Mat m2 = matread("raw.bin"); double toc = (double(getTickCount()) - tic) * 1000. / getTickFrequency(); cout << "Using Raw: " << toc << endl; } int dummy; cin >> dummy; return 0; }