【问题标题】:How to write a Float Mat to a file in OpenCV如何在 OpenCV 中将 Float Mat 写入文件
【发布时间】:2013-04-25 03:23:38
【问题描述】:

我有一个矩阵

Mat B(480,640,CV_32FC1);

包含浮动值..我想将此矩阵写入可以在记事本或 Ms word 或 Excel 中打开的文件以查看内部值并进行存储....imwrite function 可以保存 8 位或 16仅位图..

如果可以这样做,请提出您的建议?如果是,如何??

【问题讨论】:

标签: c++ opencv file-io floating-point mat


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    OpenCV 可以以JSONXMLYAML 格式序列化(保存)其对象。您可以使用任何理解这些格式的编辑器来读取这些文件,或使用 OpenCV 从这些文件中下载数据(反序列化)。可以在here 找到详细说明。简而言之,要将数据存储到xml-file 中,您必须调用

    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.
    

    如果您想使用JSONYAML,只需将扩展名更改为.json.yaml/.yml - openCV 会自动理解您的意图。

    重要的是命令

    fs << "cameraMatrix" << cameraM;
    

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

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

    fs << "Camera Matrix" << cameraM;
    

    【讨论】:

      【解决方案3】:

      使用纯 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 命令行中重塑生成的矩阵。

      【讨论】:

      • 谢谢...我可以使用gedit打开文件..你能告诉我如何在Matlab或Excel中加载这个xml文件吗???..
      • 我觉得你需要给矩阵起个名字,比如file &lt;&lt; "matName" &lt;&lt; someMatrixOfAnyType;否则我会收到此错误:OpenCV Error: Unspecified error (No element name has been given) in operator&lt;&lt;, file /usr/local/include/opencv2/core/operations.hpp, line 2910
      • 这应该跟file.release()。作为一般经验法则,最好关闭和释放任何文件 IO 的资源。
      • @dev_nut:FileStorage 析构函数调用 release(),无需显式调用。
      【解决方案4】:

      我写了这段代码:

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

      【讨论】:

        【解决方案5】:

        使用写入二进制文件:

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

        【讨论】:

          【解决方案6】:

          您可以使用简单的 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);
          
          }
          

          【讨论】:

          • 也想接受这个答案...但是只能给出1个...无论如何这个简单的方法也很有效!1
          • @smttsp 我不这么认为。 OpenCV 实现可能会被优化。
          • 谢谢,我怀疑编译器优化是否可以使两种方法具有相同的速度。
          • 我已经检查了两个答案,对于要写入 xml 文件的 1024x1024 双矩阵,您的答案比其他答案慢 50-60%。
          • @sgarizvi,与接受的答案相比,您的解决方案对批处理更有帮助。如果我们需要将 100 个 cv::mat 对象写入文件,则很难按照接受的答案的建议打开和修改每个 xml/yml 文件,除非我们再次编写一些代码来自动修改。
          猜你喜欢
          • 2011-09-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-10-12
          • 1970-01-01
          • 1970-01-01
          • 2021-11-14
          相关资源
          最近更新 更多