在OpenCV中有效地将大Mat加载到内存中

时间:2015-09-01 13:27:48

标签: c++ opencv mat opencv3.0

有没有比OpenCV中的FileStorage方法更有效的方法将大型Mat对象加载到内存中?

我有一个包含192列和100万行的大型Mat我想在本地存储在一个文件中并加载到内存中然后我的应用程序启动。使用FileStorage没有问题,但我想知道是否存在更有效的方法来执行此操作。目前,使用Visual Studio中的调试模式将Mat加载到内存大约需要5分钟,在发布模式下大约需要3分钟,数据文件的大小约为1.2GB。

FileStorage方法是唯一可用于执行此任务的方法吗?

1 个答案:

答案 0 :(得分:30)

您是否可以 100x 加速?

您应该以二进制格式保存和加载图像。您可以使用以下代码中的matwritematread函数执行此操作。

我测试了FileStorage和二进制文件的加载,对于250K行的较小图像,192列,类型CV_8UC1我得到了这些结果(时间以毫秒为单位):

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

在使用我得到的二进制模式的1M行和192列的图像上(时间以毫秒为单位):

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

注意

  1. 永远不要在 debug 中衡量效果。
  2. 加载矩阵3分钟似乎太过分了,即使FileStorage也是如此。但是,您将获得很多切换到二进制模式。
  3. 此处包含函数matwritematread的代码以及测试:

    #include <opencv2\opencv.hpp>
    #include <iostream>
    #include <fstream>
    
    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<char>(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<char>(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;
    }