如何使用 protobuf 序列化 cv::Mat 对象?

jin*_*nge 2 opencv protocol-buffers

有温和的解决方案吗?(例如现有的 Mat.proto 文件。)

Pie*_*ier 5

要使用 Google Protocol Buffers 序列化 OpenCV 矩阵,可以使用 FileStorage 类从 OpenCV 中可用的 XML/YAML/JSON 序列化中获得灵感。所需的所有信息是行数、列数、元素类型、元素大小和矩阵的原始数据。

这是 .proto 定义:

syntax = "proto3";

package opencv;

message OcvMat {
    int32 rows = 1;
    int32 cols = 2;
    int32 elt_type = 3;
    int32 elt_size = 4;
    bytes mat_data = 5;
}
Run Code Online (Sandbox Code Playgroud)

这是 C++ 中的序列化代码,假设我们要将矩阵保存在一个仅包含此数据的文件中:

cv::Mat m = cv::Mat::ones(480, 640, CV_8UC3);

//open a file in output, overwrite and binary mode
fstream output("path/to/file.extention", ios::out | ios::trunc | ios::binary);

//create an instance of the class generated by the compilation of the .proto file
opencv::OcvMat serializableMat;

//set the trivial fields
serializableMat.set_rows(m.rows);
serializableMat.set_cols(m.cols);
serializableMat.set_elt_type(m.type());
serializableMat.set_elt_size((int)m.elemSize());

//set the matrix's raw data
size_t dataSize = m.rows * m.cols * m.elemSize();
serializableMat.set_mat_data(m.data, dataSize);

//write to file
if(!serializableMat.SerializeToOstream(&output))
{
    cerr << "error" << endl;
}

output.close();
Run Code Online (Sandbox Code Playgroud)

这是 C++ 中的反序列化代码:

//open the file where the data was written in input and binary mode
fstream input("path/to/file.extension", ios::in | ios::binary);

//create an instance of the class generated automatically by the compilation of the .proto file
opencv::OcvMat serializableMat;

//create an empty OpenCV matrix
cv::Mat m;

//read the data from the input file into the OcvMat object
if(serializableMat.ParseFromIstream(&input))
{
    //allocate the matrix
    m.create(serializableMat.rows(),
    serializableMat.cols(),
    serializableMat.elt_type());

    //set the matrix's data
    size_t dataSize = serializableMat.rows() *  serializableMat.cols() * serializableMat.elt_size();

    std::copy(reinterpret_cast<unsigned char *>(
            const_cast<char *>(serializableMat.mat_data().data())),
        reinterpret_cast<unsigned char *>(
            const_cast<char *>(serializableMat.mat_data().data()) + dataSize),
        m.data);
}
else
{
    cerr << "error" << endl;
}

input.close();
Run Code Online (Sandbox Code Playgroud)

然后可以将 OpenCV 矩阵序列化为更复杂的序列化对象的属性。序列化的唯一区别是必须将数据设置为指向使用访问的 OcvMat 对象的指针

 myComplexObject.mutable_field_name()
Run Code Online (Sandbox Code Playgroud)

,其中“filed_name”是指定给 OcvMat 类型字段的名称。对于反序列化,它将完全相同。反序列化的复杂对象中包含的 OcvMat 对象通过调用访问

myComplexObject.field_name().
Run Code Online (Sandbox Code Playgroud)