How to write a Float Mat to a file in OpenCV

OpenCV can serialize (save) its objects in JSON, XML or YAML formats. You can use any editors, which understand these formats, in order to read these files, or use OpenCV to download data (de-serialize) from these files. Detailed explanation how this is done can be found here. In short, to store the data into xml-file, you have to call

cv::FileStorage fs("/path/to/file.xml", cv::FileStorage::WRITE); // create FileStorage object
cv::Mat cameraM; // matrix, which you need to save, do not forget to fill it with some data
fs << "cameraMatrix" << cameraM; // command to save the data
fs.release(); // releasing the file.

If you want to use JSON or YAML, just change the extension to .json or .yaml/.yml - openCV will automatically understand your intentions.

The important thing is the command

fs << "cameraMatrix" << cameraM;

the string "cameraMatrix" is the tag name, under which this matrix will be stored and using which this matrix can be found later in the file.

Note that xml format will not allow you to use tag names with spaces and some special characters, since only alphanumeric values, dots, dashes and underscores are allowed (see XML specification for details), while in YAML and JSON you can have something like

fs << "Camera Matrix" << cameraM;

Using pure OpenCV API calls:

// Declare what you need
cv::FileStorage file("some_name.ext", cv::FileStorage::WRITE);
cv::Mat someMatrixOfAnyType;

// Write to file!
file << "matName" << someMatrixOfAnyType;

The file extension can be xml or yml. In both cases you get a small header that you can easily remove/parse, then you have access to the data in a floating point format. I used this approach successfully (with yml files) to get data into Matlab and Matplotlib

To get the data:

  1. open the file with any editor
  2. then suppress all the text and numbers except the content of the data tag (i.e., the pixel values).
  3. When done, save your file with a txt or csv extension and open it with matlab (drag-and-drop works).

Voilà. You may have to reshape the resulting matrix in matlab command line if it didn't guess correctly the image size.


I wrote this code:

#include "opencv2/opencv.hpp"

using namespace cv;
using namespace std;

/*
Will save in the file:
cols\n
rows\n
elemSize\n
type\n
DATA
*/
void serializeMatbin(cv::Mat& mat, std::string filename){
    if (!mat.isContinuous()) {
        std::cout << "Not implemented yet" << std::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, /* how many elements */ 4, /* size of each element */ sizeof(int), /* file */ FP);
    fwrite(mat.data, mat.cols * mat.rows, elemSizeInBytes, FP);
    fclose(FP);
}

cv::Mat deserializeMatbin(std::string filename){
    FILE* fp = fopen(filename.c_str(), "rb");
    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];

    //std::cout << "rows="<<rows<<" cols="<<cols<<" elemSizeInBytes=" << elemSizeInBytes << std::endl;

    cv::Mat outputMat = cv::Mat::ones(rows, cols, elemType);

    size_t result = fread(outputMat.data, elemSizeInBytes, (size_t)(cols * rows), fp);

    if (result != (size_t)(cols * rows)) {
        fputs ("Reading error", stderr);
    }

    std::cout << ((float*)outputMat.data)[200] << std::endl;
    fclose(fp);
    return outputMat;
}

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

You can write cv::Mat to text file using simple C++ file handling.

Here is how you can do it:

#include <iostream>
#include <fstream>

using namespace std;

void writeMatToFile(cv::Mat& m, const char* filename)
{
    ofstream fout(filename);

    if(!fout)
    {
        cout<<"File Not Opened"<<endl;  return;
    }

    for(int i=0; i<m.rows; i++)
    {
        for(int j=0; j<m.cols; j++)
        {
            fout<<m.at<float>(i,j)<<"\t";
        }
        fout<<endl;
    }

    fout.close();
}

int main()
{
    cv::Mat m = cv::Mat::eye(5,5,CV_32FC1);

    const char* filename = "output.txt";

    writeMatToFile(m,filename);

}