如何在 OpenCV 中将 Float Mat 写入文件

问题描述 投票:0回答:6

我有一个矩阵,

Mat B(480,640,CV_32FC1);

包含浮点值。我想将此矩阵写入一个文件,该文件可以在 NotepadMicrosoft WordExcel 中打开以查看内部值和存储,但 imwrite 函数 可以保存 8 位或 16 位只有图像...

这能做到吗?如果是,如何?

c++ opencv file-io floating-point mat
6个回答
62
投票

使用纯 OpenCV API 调用:

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

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

文件扩展名可以是xmlyml。 在这两种情况下,您都会得到一个可以轻松删除/解析的小标题,然后您可以访问浮点格式的数据。 我成功地使用这种方法(使用 yml 文件)将数据导入 Matlab 和 Matplotlib

获取数据:

  1. 使用任何编辑器打开文件
  2. 然后抑制除数据标签内容(即像素值)之外的所有文本和数字。
  3. 完成后,使用 txt 或 csv 扩展名保存文件,然后使用 matlab(拖放操作)打开它。

瞧。如果它没有正确猜测图像大小,您可能必须在 matlab 命令行中重塑结果矩阵。


18
投票

您可以使用简单的 C++ 文件处理将

cv::Mat
写入文本文件。

这里是你如何做到的:

#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);

}

5
投票

OpenCV 可以将其对象序列化(保存)为 JSONXMLYAML 格式。您可以使用任何理解这些格式的编辑器来读取这些文件,或使用 OpenCV 从这些文件中下载数据(反序列化)。有关如何完成此操作的详细说明,请参见here。简而言之,要将数据存储到 XML 文件中,您必须调用

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.

如果您想使用 JSON 或 YAML,只需将扩展名更改为

.json
.yaml/.yml
- OpenCV 会自动理解您的意图。

重要的是命令

fs << "cameraMatrix" << cameraM;

字符串

"cameraMatrix"
是标签名称,该矩阵将存储在该标签名称下,稍后可以在文件中找到该矩阵。

请注意,

xml
格式不允许您使用带有空格和一些特殊字符的标签名称,因为只允许使用字母数字值、点、破折号和下划线(有关详细信息,请参阅
XML
规范),而在
YAML
JSON
你可以有类似的东西

fs << "Camera Matrix" << cameraM;

3
投票

我写了这段代码:

#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;
}

2
投票

使用写二进制:

FILE* FP = fopen("D.bin", "wb");
int sizeImg[2] = { D.cols, D.rows };
fwrite(sizeImg, 2, sizeof(int), FP);
fwrite(D.data, D.cols * D.rows, sizeof(float), FP);
fclose(FP);

然后你可以在MATLAB中阅读它。

读取尺寸然后整形(type=single):

fp = fopen(fname);
data = fread(fp, 2, 'int');
width = data(1); height = data(2);
B = fread(fp, Inf, type);

imageOut = reshape(B, [width, height])';

fclose(fp);

0
投票

从OpenCV 3.4.4开始,

imwrite
可以序列化TIFF格式的CV_32F图像。虽然比“原始”代码慢,但它确保文件可以跨所有架构移植。

© www.soinside.com 2019 - 2024. All rights reserved.