【问题标题】:What is an optimal way to send OPENCV Mat over MPI什么是通过 MPI 发送 OPENCV Mat 的最佳方式
【发布时间】:2017-04-19 17:21:54
【问题描述】:

通过 MPI 发送 OPENCV Mat 的最佳方式是什么?现在我通过将Mat 转换为int** 来完成它,但这有点慢。

A = alloc2d(n , m);
for (int i = 0; i < n ; ++i)
    for (int j = 0; j < m ; ++j)
        A[i][j] = img.at<uchar>(i , j);

/////////////////////////////////////
int ** alloc2d(int rows, int cols) {
    int * data = (int *)malloc(rows * cols * sizeof(int));
    int ** arr = (int **)malloc(rows * sizeof(int *));
    for (int i = 0; i < rows; ++i)
        arr[i] = &(data[cols * i]);
    return arr;
}

【问题讨论】:

  • 请显示您使用转换为int**的代码以及您认为的具体测量结果?
  • 我已经发布了代码
  • 我没有看到任何 MPI 或性能测量结果。

标签: c++ opencv parallel-processing mpi


【解决方案1】:

首先检查原始Mat是否连续,如果不是,则克隆它。

然后得到:

  • 类型
  • 频道

原始Mat 并以该顺序保存,每个为 4 个字节,位于缓冲区的开头。然后从原始Matdata 指针中附加适当数量的字节并发送整个批次。

在接收端做相反的事情......从缓冲区中读取前四个整数并创建一个相应大小的Mat并将其余数据加载到其中。


@Miki 提供了一个很好的相关答案here,它演示了上面建议的大多数技术的详细信息 - 请特别查看 Mat2str()str2Mat()

我不怎么做 C++ 或 MPI,我相信任何经常使用 MPI 或 C++ 的人都可以收紧它,但是下面的工作也很快!

#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <ctime>
#include <iostream>
#include <string>
#include <chrono>
#include <thread>
#include <opencv2/opencv.hpp>
#include "opencv2/highgui/highgui.hpp"
#include "mpi.h"

using namespace std;
using namespace cv;

const int MAXBYTES=8*1024*1024;
uchar buffer[MAXBYTES];

void matsnd(const Mat& m,int dest){
      int rows  = m.rows;
      int cols  = m.cols;
      int type  = m.type();
      int channels = m.channels();
      memcpy(&buffer[0 * sizeof(int)],(uchar*)&rows,sizeof(int));
      memcpy(&buffer[1 * sizeof(int)],(uchar*)&cols,sizeof(int));
      memcpy(&buffer[2 * sizeof(int)],(uchar*)&type,sizeof(int));

      // See note at end of answer about "bytes" variable below!!!
      int bytespersample=1; // change if using shorts or floats
      int bytes=m.rows*m.cols*channels*bytespersample;
cout << "matsnd: rows=" << rows << endl;
cout << "matsnd: cols=" << cols << endl;
cout << "matsnd: type=" << type << endl;
cout << "matsnd: channels=" << channels << endl;
cout << "matsnd: bytes=" << bytes << endl;

      if(!m.isContinuous())
      { 
         m = m.clone();
      }
      memcpy(&buffer[3*sizeof(int)],m.data,bytes);
      MPI_Send(&buffer,bytes+3*sizeof(int),MPI_UNSIGNED_CHAR,dest,0,MPI_COMM_WORLD);
}

Mat matrcv(int src){
      MPI_Status status;
      int count,rows,cols,type,channels;

      MPI_Recv(&buffer,sizeof(buffer),MPI_UNSIGNED_CHAR,src,0,MPI_COMM_WORLD,&status);
      MPI_Get_count(&status,MPI_UNSIGNED_CHAR,&count);
      memcpy((uchar*)&rows,&buffer[0 * sizeof(int)], sizeof(int));
      memcpy((uchar*)&cols,&buffer[1 * sizeof(int)], sizeof(int));
      memcpy((uchar*)&type,&buffer[2 * sizeof(int)], sizeof(int));

cout << "matrcv: Count=" << count << endl;
cout << "matrcv: rows=" << rows << endl;
cout << "matrcv: cols=" << cols << endl;
cout << "matrcv: type=" << type << endl;

      // Make the mat
      Mat received= Mat(rows,cols,type,(uchar*)&buffer[3*sizeof(int)]);
      return received;
}

int main ( int argc, char *argv[] )
{
   // Initialise MPI
   MPI::Init (argc,argv);

   //  Get our rank
   int id = MPI::COMM_WORLD.Get_rank();
   if(id==0) 
   {
      // MASTER - wait to receive image from slave and write to disk for checking
      Mat received=matrcv(1);
      imwrite("received.jpg",received);
   }else{
      // Slave - read Mat from disk and send to master
      Mat image=imread("image.jpg",IMREAD_COLOR);
      matsnd(image,0);
   }

   //  Terminate MPI
   MPI::Finalize();
}

我放置了一个包含 10,000 次迭代的循环:

  • matsnd() 在从站中,并且
  • matrcv()在大师里

10,000 次迭代耗时 1.9 秒。我无法比较,因为您没有显示任何时间。

所有左对齐的cout 语句都只是可以安全删除的调试内容。

注意:

虽然我已经使用并测试了上述内容,但后来我了解到在某些情况下(可能存在对齐限制)我发送的字节数的计算可能不正确。如果您有兴趣,请查看this answer

关键字:MPI、MPI_Send、MPI_Recv、OpenCV、Mat、图像

【讨论】:

  • 前几天我看到了@Miki 的相关答案(我想),但暂时找不到它,而且已经很晚了,所以我明天再打猎,如果可以的话,添加一个链接.
  • 如果矩阵很大,注册一个包含多个元素的 MPI 结构数据类型并使用它直接发送描述符和数据而不需要将所有内容打包在一个数组中会更便宜。在接收端,MPI_ProbeMPI_Get_count 可用于确定数据的大小并用于预分配矩阵。
  • 这是我为类似问题编写的一段代码stackoverflow.com/questions/28782951/… 发送im.data 指向的大小和缓冲区它可能会启发你...
猜你喜欢
  • 2021-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-15
  • 2014-12-17
  • 1970-01-01
  • 2011-03-12
相关资源
最近更新 更多