I am trying to learn MPI in C++. I have some knowledge of OpenCV so I tried writing a program using both MPI and OpenCV. This may sound stupid but for the purpose of learning I
Currently each process tries to open the camera. That is very likely to cause problems. Try to move the opening into the root specific section like so:
int main(int argc, char **argv) {
cv::Mat_<uint> img(640,480);
cv::Mat_<uint> gray(640,480);
cv::VideoCapture cam;
/* ... */
if (rank == 0) {
cam.open(0);
/* ... */
}
/* ... */
}
Update:
I think the problem with your code is, that you can't simply transfer objects with MPI_Send
. Also is the sizeof
operator not valid on objects in general. If you want to transfer an object, you need to transfer the underlying data.
You could achieve this in your case by sending img.data
with a size of img.rows * img.cols * sizeof(uint)
. Then you can also use MPI_BYTE as data type and no custom types are required.
Some details about the internal structure of cv::Mat_
can be found here.
As noticed by @user0851 , in your code, all processes try to open the camera and the opening of the camera can be perform by the root process alone.
The Mat
object of openCV is quite complex and defining the corresponding MPI_Datatype
may be complex too. Instead, sending the array of pixels img.data
is much easier. Here is a little piece of code demonstrating how it could be done. It is compiled by mpiCC main.cpp -o main -lopencv_highgui -lopencv_imgproc -lopencv_core
and run by mpirun -np 2 main
#include <opencv2/opencv.hpp>
#include <mpi.h>
using namespace cv;
int main(int argc, char **argv) {
Mat img;
Mat gray;
int rank, nproc, j=0;
size_t total;
size_t elemsize;
int sizes[3];
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &nproc); // number of processes
MPI_Comm_rank(MPI_COMM_WORLD, &rank); // rank of the current process
/*
* Thread 0 captures the image from camera
* and sends the image to process 1 for processing
* thread 1 converts the image to grayscale and
* displays the image
*/
if (rank == 0) {
VideoCapture cam(0);
if(!cam.isOpened()){
fprintf(stderr,"unable to open camera.\n");
exit(1);
}
// capture the image and send to thread 1
while (1) {
cam >> img;
cv::imshow("proc 0", img);
if(j==0){
sizes[2]=img.elemSize();
Size s = img.size();
sizes[0] = s.height;
sizes[1] = s.width;
MPI_Send( sizes, 3, MPI_INT, 1,0, MPI_COMM_WORLD);
}
MPI_Send( img.data, sizes[0]*sizes[1]*3, MPI_CHAR,1,1, MPI_COMM_WORLD);
cv::waitKey(40);
j++;
}
}
else if (rank == 1) {
// receive the image, convert to grayscale and display
while (1) {
if(j==0){
MPI_Recv( sizes,3, MPI_INT,0,0, MPI_COMM_WORLD,&status);
img.create(sizes[0],sizes[1],CV_8UC3);
}
MPI_Recv( img.data, sizes[0]*sizes[1]*3, MPI_CHAR,0,1, MPI_COMM_WORLD,&status);
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
cv::imshow("proc 1", gray);
cv::waitKey(20);
j++;
}
}
MPI_Finalize();
return 0;
}
Mat object is only a header structure that points to the memory that stores the image.
So you have some problems:
First, you create a Mat
object sized 640X640 and than you read from the camera into that object. But Mat
is just a header it is not a pointer to the data, The Mat object can be now of any width and height.
Second, sizeof(Mat)
does not return the amount of memory allocated to the image, only the amount of memory the Mat object itself. The amount of memory needed for the image is Mat.total()*Mat.elemSize()