在 OpenCV 中高效地将大型 Mat 加载到内存中
Efficiently load a large Mat into memory in OpenCV
有没有比 OpenCV 中的 FileStorage 方法更有效地将大型 Mat 对象加载到内存中的方法?
我有一个包含 192 列和 100 万行的大型 Mat 我想将其本地存储在文件中并加载到内存中,然后我的应用程序启动。使用 FileStorage 没有问题,但我想知道是否存在更有效的方法来执行此操作。目前Visual Studio使用Debug模式将Mat加载到内存中需要大约5分钟,Release模式需要大约3分钟,数据文件的大小约为1.2GB。
FileStorage 方法是唯一可用于完成此任务的方法吗?
你接受 100x 加速吗?
您应该以二进制格式保存和加载图像。您可以使用下面代码中的 matwrite
和 matread
函数来实现。
我测试了从 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
注意
- 永远不要在 debug.
中测量性能
- 3 分钟加载一个矩阵似乎太多了,即使是
FileStorage
秒。但是,切换到二进制模式你会收获很多。
这里是函数 matwrite
和 matread
的代码,以及测试:
#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;
}
有没有比 OpenCV 中的 FileStorage 方法更有效地将大型 Mat 对象加载到内存中的方法?
我有一个包含 192 列和 100 万行的大型 Mat 我想将其本地存储在文件中并加载到内存中,然后我的应用程序启动。使用 FileStorage 没有问题,但我想知道是否存在更有效的方法来执行此操作。目前Visual Studio使用Debug模式将Mat加载到内存中需要大约5分钟,Release模式需要大约3分钟,数据文件的大小约为1.2GB。
FileStorage 方法是唯一可用于完成此任务的方法吗?
你接受 100x 加速吗?
您应该以二进制格式保存和加载图像。您可以使用下面代码中的 matwrite
和 matread
函数来实现。
我测试了从 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
注意
- 永远不要在 debug. 中测量性能
- 3 分钟加载一个矩阵似乎太多了,即使是
FileStorage
秒。但是,切换到二进制模式你会收获很多。
这里是函数 matwrite
和 matread
的代码,以及测试:
#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;
}