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

kru*_*son 19 c++ opencv mat opencv3.0

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

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

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

Mik*_*iki 33

加速100倍你还好吗?


您应该以二进制格式保存和加载图像.您可以使用下面的代码中的matwriteand matread功能执行此操作.

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

// Mat: 250K rows, 192 cols, type CV_8UC1
Using FileStorage: 5523.45
Using Raw:         50.0879    
Run Code Online (Sandbox Code Playgroud)

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

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

注意

  1. 切勿在调试中测量性能.
  2. 加载矩阵3分钟似乎太多了,即使是FileStorages.但是,您将获得很多切换到二进制模式.

这里的代码包含函数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;
}
Run Code Online (Sandbox Code Playgroud)

  • @sturkmen 1) 我有这个版本的生产代码,我不想停止它 2) 通道信息对于加载图像很有用,比如,matlab 3) 保存一个字节,这没什么大不了的 4)在没有渠道的情况下更新代码非常容易;) (2认同)