I'm using magick++ library to manage images. I want to distribute my algorithm using openMPI, is it possible to send objects?
for example in my code I have
Image image(imgName);
int w = image.columns();
int h = image.rows();
PixelPacket *pixels = image.getPixels(0, 0, w, h);
Can I send pixels
with MPI_Send or Scatter of whatever? if yes with which datatype?
In general, unless you have a special library that's doing packing for you, it's never possible to send a specialized object in MPI. The built-in datatypes are listed in the MPI Standard (MPI 3.0 page 665, Defined Values and Handles has a list), but at a high level, they're:
MPI_CHAR
MPI_INT
MPI_FLOAT
MPI_DOUBLE
MPI_BYTE
There are a lot more than that, but most of them end up being something like that.
You can take those types and put them together to make your own custom datatypes. For instance, if you know that you're going to send a bunch of structs that contain something like:
{
int index;
char[100] name;
double value;
}
You can construct a type to hold that, it would be a contiguous type for the name and then a struct type for the overall datatype (which would contain the int, the type you construct for the name, and the double).
All you'd have to do is create a datatype which describes your PixelPacket
.
I am no C++ programmer, but the following does what you are asking. Basically, I start 8 MPI process (I happen to use mpich
) and the master reads in an image (Lena of course, from a PNG
file) using Magick++ and then sends her to each of the slaves. The slaves receive Lena and rebuild her from the data they receive and each slave writes out its own local copy as a JPEG
under a different name.
I cheated on the sizes because working out the sizes and passing those is easy but not germane to what I am demonstrating.
#include <cstdlib>
#include <iostream>
#include <Magick++.h>
#include "mpi.h"
using namespace std;
int main ( int argc, char *argv[] )
{
int id,p;
int number;
// Initialise MPI
MPI::Init (argc,argv);
// Initialize ImageMagick and image processing stuff
Magick::InitializeMagick(*argv);
int row,col;
Magick::Image image;
int bytes=512*512*3; // I happen to know Lena is 512x512 and RGB - i.e. 3 bytes/pixel
unsigned char buffer[bytes];
// Get the number of processes
p = MPI::COMM_WORLD.Get_size();
// Get the individual process ID
id = MPI::COMM_WORLD.Get_rank();
// Master will read in Lena and send her to all slaves
if(id==0)
{
cout << "MASTER: The number of processes is " << p << endl;
// Read in Lena and put her in a buffer to send via MPI
image.read("lena.png");
// Convert Lena to a bunch of bytes
image.write(0,0,512,512,"RGB",Magick::CharPixel,buffer);
// Send the luscious Lena to all slaves
for(int z=1;z<p;z++){
cout << "MASTER: Sending Lena to slave " << z << endl;
MPI_Send(buffer,bytes,MPI_BYTE,z,0,MPI_COMM_WORLD);
}
}else{
// All slaves will receive Lena and write her out as a JPEG
cout << "Process:" << id << " Started and waiting for Lena..." << endl;
MPI_Recv(buffer,bytes,MPI_BYTE,0,0,MPI_COMM_WORLD,MPI_STATUS_IGNORE);
cout << "Process:" << id << " Received Lena" << endl;
// Rebuild Lena from the bunch of bytes and write to "Lena-Rebuilt-<id>.jpg"
Magick::Image rebuilt(512,512,"RGB",Magick::CharPixel,buffer);
char filename[100];
sprintf(filename,"Lena-Rebuilt-%d.jpg",id);
rebuilt.write(filename);
}
// Terminate MPI
MPI::Finalize();
return 0;
}
My Makefile
looks like this:
all: main
run: main
mpirun -n 8 ./main
main: main.cpp
mpic++ main.cpp -o main $$(Magick++-config --cxxflags --libs)
It runs like this:
make run
mpirun -n 8 ./main
MASTER: The number of processes is 8
Process:1 Started and waiting for Lena...
Process:3 Started and waiting for Lena...
Process:4 Started and waiting for Lena...
Process:5 Started and waiting for Lena...
Process:7 Started and waiting for Lena...
Process:6 Started and waiting for Lena...
Process:2 Started and waiting for Lena...
MASTER: Sending Lena to slave 1
MASTER: Sending Lena to slave 2
Process:1 Received Lena
MASTER: Sending Lena to slave 3
Process:2 Received Lena
MASTER: Sending Lena to slave 4
Process:3 Received Lena
MASTER: Sending Lena to slave 5
Process:4 Received Lena
MASTER: Sending Lena to slave 6
Process:5 Received Lena
MASTER: Sending Lena to slave 7
Process:6 Received Lena
Process:7 Received Lena
And the outputs look like this:
-rw-r--r--@ 1 mark staff 150467 23 Oct 15:34 lena.png
-rw-r--r-- 1 mark staff 1786 23 Oct 17:04 main.cpp
-rwxr-xr-x 1 mark staff 51076 23 Oct 17:14 main
-rw-r--r--@ 1 mark staff 64755 23 Oct 17:14 Lena-Rebuilt-7.jpg
-rw-r--r--@ 1 mark staff 64755 23 Oct 17:14 Lena-Rebuilt-6.jpg
-rw-r--r--@ 1 mark staff 64755 23 Oct 17:14 Lena-Rebuilt-5.jpg
-rw-r--r--@ 1 mark staff 64755 23 Oct 17:14 Lena-Rebuilt-4.jpg
-rw-r--r--@ 1 mark staff 64755 23 Oct 17:14 Lena-Rebuilt-3.jpg
-rw-r--r--@ 1 mark staff 64755 23 Oct 17:14 Lena-Rebuilt-2.jpg
-rw-r--r--@ 1 mark staff 64755 23 Oct 17:14 Lena-Rebuilt-1.jpg