在C++中将cv::Mat的向量写入二进制文件

5

如标题所述,我有一个std ::vector<cv::Mat> matrices,我想将其写入/从二进制文件中读取。

现在,遵循答案,我所要做的就是进行以下操作:

 ofstream fout("matrices.bin", ios::out | ios::binary);
 size_t size = matrices.size();
 fout.write((char*)&size, sizeof(size));
 fout.write((char*)&matrices[0], v.size() * sizeof(cv::Mat));
 fout.close();

然而,根据这个答案,写入cv::Mat对象似乎有点棘手,在答案中,matReadmatWrite完成了工作。因此,我想知道是否应该像下面这样做,而不是上面的代码:
ofstream fout("matrices.bin", ios::out | ios::binary);
size_t size = matrices.size();
fout.write((char*)&size, sizeof(size));
for(size_t i = 0 ; i < matrices.size() ; i++)
  matWrite("matrices.bin", matrices[i]);

然而,由于matWrite()在每个周期都会覆盖matrices.bin,所以这段代码无法正常工作,因此在写入矩阵本身之前,我应该附加matrices[i]的大小作为偏移量。

我该怎么办?

更新:

我想到了这个解决方案,使用可选参数重写matWritematRead,用于在写入期间追加矩阵并从特定点开始读取:

void matwrite(const std::string& filename, const cv::Mat& mat, const bool append = false) {

    std::ofstream fs;
    if(append)
        fs.open(filename.c_str(), std::fstream::binary | std::fstream::app);
    else
        fs.open(filename.c_str(), std::fstream::binary);

//the rest of matwrite is the same...

}

cv::Mat matRead(const std::string& filename, size_t &offset = 0)
{
    std::ifstream fs(filename, std::fstream::binary);
    fs.seekg(offset);
    ...
    offset += 4 * sizeof(int) + CV_ELEM_SIZE(type) * rows * cols; //update offset //move offset of 4 ints and mat size
    return mat;
}

函数的调用方式如下:

//writing:
for(size_t i = 0 ; i<v.size() ; i++)
  writemat(filename, v[i], true);
//reading:
size_t offset = 0;
for(size_t i = 0 ; i<size ; i++){ // size = v.size() during writing
  cv::Mat mat = matRead(filename, offset);
  v.push_back(mat);
}

我真的很好奇为什么有人对这个问题给了我一个负评。 - justHelloWorld
关于重复的说明。您可以遍历向量中的每个矩阵,并使用“matappend”。 - Miki
如果复制品没有帮助,请告诉我。然而,现在你应该能够自己编写一个正确的函数了。 - Miki
很抱歉,但这并没有帮助。使用matAppend我们可以编写一个大矩阵,该矩阵是向量中所有矩阵的串联。然而,从获得的.bin文件开始重建原始向量是不可能的。简而言之,我们可以将std::vector<cv :: Mat>作为一个大的cv :: Mat写入文件,但我们无法再次获得std::vector<cv :: Mat> - justHelloWorld
@Miki 请看一下我的 更新 部分,然后告诉我你的想法。 - justHelloWorld
1
明天...... ;) - Miki
2个回答

2
您可以将matreadmatwrite的代码进行调整,以便与向量一起使用,如果用单个Mat代替,则需要修改。下面的函数vecmatreadvecmatwrite允许将std::vector<cv::Mat>写入文件,并读取向量。
#include <opencv2\opencv.hpp>
#include <vector>
#include <iostream>
#include <fstream>

using namespace std;
using namespace cv;

void vecmatwrite(const string& filename, const vector<Mat>& matrices)
{
    ofstream fs(filename, fstream::binary);

    for (size_t i = 0; i < matrices.size(); ++i)
    {
        const Mat& mat = matrices[i];

        // 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);
            }
        }
    }
}

vector<Mat> vecmatread(const string& filename)
{
    vector<Mat> matrices;
    ifstream fs(filename, fstream::binary);

    // Get length of file
    fs.seekg(0, fs.end);
    int length = fs.tellg();
    fs.seekg(0, fs.beg);

    while (fs.tellg() < length)
    {
        // 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);

        matrices.push_back(mat);
    }
    return matrices;
}


int main()
{
    vector<Mat> matrices;

    // Fill vector...
    Mat1f m1(3,3);
    randu(m1, 0, 1);

    Mat3b m2(4, 5);
    randu(m2, Scalar(0,0,0), Scalar(256,256,256));

    Mat2d m3(2, 3);
    randu(m3, Scalar(0, 0), Scalar(1, 1));

    matrices.push_back(m1);
    matrices.push_back(m2);
    matrices.push_back(m3);

    // Write the vector to file
    vecmatwrite("test.bin", matrices);

    // Read the vector from file
    vector<Mat> matrices2 = vecmatread("test.bin");

    return 0;
}

0

我使用这个:

string   name_1c;
ofstream outFile_1st;
name_1c = "m_scripts/labeled_1.bin";
outFile_1st.open(name_1c, std::ios::binary);

Mat data = Mat::zeros(100, 1024, CV_32FC);
vector<Mat> labeled_1(6);
// initialization of vector
for(int i = 0; i < 6; i ++)
    labeled_1.push_back(randn(data, Scalar(128), Scalar(10)));


for (int i = 0; i < labeled_1.size(); i ++)
{
 outFile_1st.write(reinterpret_cast<char*>(&labeled_1[i]), sizeof(float) * 100 * 1024);
}
outFile_1st.close();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接