Ask Your Question
3

cv::Mat serialization to binary file

asked 2013-01-24 01:50:48 -0600

mrgloom gravatar image

How can I read\write cv::Mat from binary file in C++?

Also I'm using C# with OpencvSharp and I need serialization\deserialization IplImage from binary file how can I do it?

edit retag flag offensive close merge delete

5 answers

Sort by ยป oldest newest most voted
5

answered 2013-01-24 02:33:19 -0600

Michael Burdinov gravatar image

Let me answer you with the question: are you completely sure you need to serialize Mat object? You can simply store it in one of commonly used formats that does not perform data compresion. For example 'pgm' for gray images or 'ppm' for color images. Your task will be complete and this way you will have no need to write functions of your own.

edit flag offensive delete link more

Comments

I need some kind of DB with images+meta data in binary format.

mrgloom gravatar imagemrgloom ( 2013-01-24 03:34:40 -0600 )edit

Why it must be in binary format? The only thing that is not binary is tiny header with width, height and type of the image (and optionally some comments). The rest is the image itself stored as single chunk of data.

Michael Burdinov gravatar imageMichael Burdinov ( 2013-01-24 06:17:57 -0600 )edit

Maybe it can be in another format, but I want to store all my images and my own metadata(rects, point coordinates etc.) in one file, I don't know what will be the best\simple choice.

mrgloom gravatar imagemrgloom ( 2013-01-24 23:54:58 -0600 )edit

Yeah why not serializing the mats as image and save it as blob in a database, the additional meta data goes into separate table with foreign key to image entry- done!

I really like this solution most as it feels "natural". Your read a Mat from an image with imread - the corresponding method is imwrite. Its symmetric and humans tend to find symmetry beautiful and elegant.

holger gravatar imageholger ( 2018-08-09 05:01:13 -0600 )edit
2

answered 2016-06-28 10:19:19 -0600

logidelic gravatar image

updated 2016-06-28 10:33:18 -0600

I know this is an old question, but I had to do this recently... There's a great/easy answer on stackoverflow, which I make use of in the below snippet. serializeMat() saves to a binary file and deserializeMat() loads from the same file.

Note that, by default (using binary_xarchive), the files are not platform-independant. Use the equivalent text_xarchive instead if you require multi-platform-compatibility of the saved files.

#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>


void serializeMat(const string& filename, Mat& mat) {
    ofstream ofs(filename.c_str());
    boost::archive::binary_oarchive oa(ofs);
    serialize(oa, mat, 0);
}

void deserializeMat(Mat& mat, const string& filename) {
    std::ifstream ifs(filename.c_str());
    boost::archive::binary_iarchive ia(ifs);
    serialize(ia, mat, 0);
}


// http://stackoverflow.com/a/21444792/1072039
template<class Archive>
void serialize(Archive &ar, cv::Mat& mat, const unsigned int)
{
    int cols, rows, type;
    bool continuous;

    if (Archive::is_saving::value) {
        cols = mat.cols; rows = mat.rows; type = mat.type();
        continuous = mat.isContinuous();
    }

    ar & cols & rows & type & continuous;

    if (Archive::is_loading::value)
        mat.create(rows, cols, type);

    if (continuous) {
        const unsigned int data_size = rows * cols * mat.elemSize();
        ar & boost::serialization::make_array(mat.ptr(), data_size);
    } else {
        const unsigned int row_size = cols*mat.elemSize();
        for (int i = 0; i < rows; i++) {
            ar & boost::serialization::make_array(mat.ptr(i), row_size);
        }
    }
}
edit flag offensive delete link more

Comments

unfortunately, this counts as an "link only answer" (which is a terrible thing)

berak gravatar imageberak ( 2016-06-28 10:22:34 -0600 )edit
3

It's possibly one of the most terrible things I've done (and I've done many terrible things). That said, I didn't want to just copy-paste to avoid taking credit...

I will edit my answer in a moment with a bit of my own code in addition to the original.

logidelic gravatar imagelogidelic ( 2016-06-28 10:24:52 -0600 )edit

hehe, yea, right thing (imho)

berak gravatar imageberak ( 2016-06-28 10:56:04 -0600 )edit
0

answered 2013-01-25 17:07:00 -0600

AlexanderShishkov gravatar image

You can save it to the file with fwrite(..) function. It is sample for 16U one-channel Mat:

FILE *imageFile = fopen(imageName, "wb");
fwrite(image.data, camFrameWidth*camFrameHeight, sizeof(u_int16_t), imageFile);

For reading(but you should know rows and cols count):

 FILE * pFile;
    long lSize;
    char * buffer;
    size_t result;

    pFile = fopen ( imagePath.c_str() , "rb" );
    if (pFile==NULL) {fputs ("File error",stderr); exit (1);}

    // obtain file size:
    fseek (pFile , 0 , SEEK_END);
    lSize = ftell (pFile);
    rewind (pFile);

    // allocate memory to contain the whole file:
    buffer = (char*) malloc (sizeof(char)*lSize);

    if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}

    // copy the file into the buffer:
    result = fread (buffer,1,lSize,pFile);
    if (result != lSize) {fputs ("Reading error",stderr); exit (3);}

    // clean up
    fclose (pFile);

    Mat image;
    uint16_t *imageMap = (uint16_t*)buffer;
    image.create( rows, cols, CV_16UC1 );
    memcpy( image.data, imageMap, rows*cols*sizeof(uint16_t) );
edit flag offensive delete link more
0

answered 2016-06-28 12:50:13 -0600

updated 2018-08-09 05:23:41 -0600

there is a great code at stackoverflow.com by Miki

#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;
}
edit flag offensive delete link more
0

answered 2018-08-09 03:22:54 -0600

NadavB gravatar image

I wrote this short code:

/* Will save in the file: cols\n rows\n elemSize\n type\n DATA */ void serializeMatbin(Mat& mat, std::string filename){ if (!mat.isContinuous()) { cout << "Not implemented yet" << endl; exit(1); } int elemSizeInBytes = (int)mat.elemSize(); int elemType = (int)mat.type(); int dataSize = (int)(mat.cols * mat.rows * mat.elemSize());

FILE* FP = fopen(filename.c_str(), "wb");
int sizeImg[4] = {mat.cols, mat.rows, elemSizeInBytes, elemType };
fwrite(/*buffer*/ sizeImg, /*howmanyelements*/ 4, /* size of each element */ sizeof(int), /*file*/ FP);
fwrite(mat.data, mat.cols * mat.rows, elemSizeInBytes, FP);
fclose(FP);

}

Mat deserializeMatbin(std::string filename){ FILE* fp = fopen(filename.c_str(), "r"); int header[4]; fread(header, sizeof(int), 4, fp); int cols = header[0]; int rows = header[1]; int elemSizeInBytes = header[2]; int elemType = header[3];

Mat outputMat = Mat(rows, cols, elemType);

fread(outputMat.data, elemSizeInBytes, cols * rows, fp);
fclose(fp);
return outputMat;

}

void testSerializeMatbin(){ Mat a = Mat::ones(/cols/ 10, /* rows */ 5, CV_8U) * 2; std::string filename = "test.matbin"; serializeMatbin(a, filename); Mat b = deserializeMatbin(filename); cout << "Rows: " << b.rows << " Cols: " << b.cols << " type: " << b.type()<< endl; }

edit flag offensive delete link more

Question Tools

Stats

Asked: 2013-01-24 01:50:48 -0600

Seen: 21,823 times

Last updated: Aug 09 '18