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

时间:2018-07-27 08:29:59

标签: opencv protocol-buffers

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

2 个答案:

答案 0 :(得分:2)

要使用Google协议缓冲区序列化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;
}

这是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();

这是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();

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

访问的OcvMat对象的指针
 myComplexObject.mutable_field_name()

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

myComplexObject.field_name().

答案 1 :(得分:1)

那是一个棘手的问题。问题是您是否需要cv :: Mat的所有数据和属性?如果是的话,我表示慰问,因为您需要将所有内容映射到新的protobuf结构。

如果您想要这样的东西:

// make a 7x7 complex matrix filled with 1+3j.
Mat M(7,7,CV_32FC2,Scalar(1,3));

您需要以下内容:

message Mat {
  required uint32 xSize = 1; //7
  required uint32 ySize = 2; //7
  required string encoding = 3; //CV_32FC2

  message Scalar { // this is optional
    required uint32 x = 1; 
    required uint32 y = 2; 
    required uint32 z = 3;
  }

  repeated Scalar matrix = 4; // 49 elements
  //note here that the Scalar is a 4-element vector derived from Vec
  //and the matrix should consist of scalars 
}