【问题标题】:OpenCV C++ Convert Byte array to MatOpenCV C++ 将字节数组转换为 Mat
【发布时间】:2018-11-04 05:10:16
【问题描述】:

如何将字节数组转换为从套接字接收的 Mat ?。

我的客户端应用程序会像这样发送彩色图像数据

Mat frame; //colour image
int imgSize = frame.total()*frame.elemSize();
int bytes = send(clientSock, frame.data, imgSize, 0));//write to the socket

服务器会收到类似的数据

    char sockData[imgSize];
    Mat img;
    for (int i = 0; i < imgSize; i += bytes) {
        bytes = recv(connectSock, sockData +i, imgSize  - i, 0));
    }

   // Write to mat
    for (int i = 0;  i < img.rows; i++) {
      for (int j = 0; j < img.cols; j++) {
         (img.row(i)).col(j) = (uchar)sockData[((img.cols)*i)+j];
       }
     }

接收器的图像失真。我的代码有什么问题吗? 提前谢谢.......

【问题讨论】:

  • 为什么 sockData 是一个 char 数组而不是 uchar?
  • 为什么不使用 cv::Mat::at(x,y) 方法?请记住,x 是从左到右的列,y 是从上到下的行
  • 如果图像是彩色的 -> CV_8UC3 每个像素都有 3 个 8 位通道

标签: opencv


【解决方案1】:

如果你有彩色图像,你可以用 3 个 uchar 通道在数学中读取它,所以更改这段代码:

for (int i = 0;  i < img.rows; i++) {
  for (int j = 0; j < img.cols; j++) {
     (img.row(i)).col(j) = (uchar)sockData[((img.cols)*i)+j];
   }
 }

用这个:

int baseIndex = 0;
for (int i = 0;  i < img.rows; i++) {
  for (int j = 0; j < img.cols; j++) {
     img.at<cv::Vec3b>(i,j) = cv::Vec3b(sockData[baseIndex + 0],
                                        sockData[baseIndex + 1],
                                        sockData[baseIndex + 2]);
     baseIndex = baseIndex + 3;
   }
 }

也许这应该可行。

【讨论】:

  • 您好,感谢您的回复....我测试了您的代码,但图像仍然失真,我找到了 sockData 指针增加的原因,如 (0,1,2),(1,2,3 ),(2,3,4)....在 for 循环上,它应该像 (0,1,2),(3,4,5),(6,7,8),...任何方式你给我提示。我刚刚解决了这个问题,我将在下面发布......
  • 哦对了不好意思,我没看索引是怎么递增的,复制粘贴就行了!
【解决方案2】:

这不行吗?

cv::Mat frame(img.rows, img.cols, CV_8UC3, sockData);

只需将 CV_8UC3 替换为正确的图像格式即可:

CV_<bit-depth>{U|S|F}C(<number_of_channels>)

https://docs.opencv.org/2.4/modules/core/doc/basic_structures.html


编辑:还有第 5 个附加字段很有用。每行的字节数(如果有几个填充字节)。今天在使用 V4L2 时,我成功使用了这个 cv::Mat 构造函数:

v4l2_format camera_format = ...; // see https://linuxtv.org/downloads/v4l-dvb-apis/uapi/v4l/vidioc-g-fmt.html#description
cv::Mat mat(camera_format.fmt.pix.height,
            camera_format.fmt.pix.width,
            CV_8UC3,
            raw_data_ptr,
            camera_format.fmt.pix.bytesperline);

【讨论】:

    【解决方案3】:

    我用下面的代码解决了这个问题。

    int ptr=0;
    
     for (int i = 0;  i < img.rows; i++) {
       for (int j = 0; j < img.cols; j++) { 
    
            img.at<cv::Vec3b>(i,j) = cv::Vec3b(sockData[ptr+0],sockData[ptr+1],sockData[ptr+2]);
            ptr=ptr+3;
        }
      }
    

    【讨论】:

      【解决方案4】:

      添加到 Michele 的答案,也可以使用 MatIterator 来解决这个问题。

      cv::Mat m;
      m.create(10, 10, CV_32FC3);
      
      // This is the socket data.
      float *array = (float *)malloc( 3*sizeof(float)*10*10 );
      
      cv::MatIterator_<cv::Vec3f> it = m.begin<cv::Vec3f>();
      for (unsigned i = 0; it != m.end<cv::Vec3f>(); it++ ) {
          for ( unsigned j = 0; j < 3; j++ ) {
              (*it)[j] = *(array + i );
              i++;
          }
      }
      
      Now you have a float cv::Mat. In case of 8 bit, simply change float to uchar and Vec3f to Vec3b and CV_32FC3 to CV_8UC3
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-04
        • 1970-01-01
        • 2013-02-18
        • 1970-01-01
        • 1970-01-01
        • 2016-11-24
        相关资源
        最近更新 更多