Rozmywanie fragmentów obrazu przez różne procesy
-- Sebastian Pawlak, 2000.
Master dzieli obraz na fragmenty i przesyła je do Slave'ów. Slave'y rozmywają obraz w pętli nieskończonej, licząc dla każdego punktu średnią z punktów sąsiednich. Ponieważ do obliczenia punktów leżących na marginesach fragmentów obrazów potrzebne są dane posiadane przez "sąsiadujące" Slave'y, procesy prowadzą pomiędzy sobą nieustanną wymianę informacji.
Kod źródłowy pliku "main.c":
/* Program wczytuje bitmape z pliku *.bmp, dzieli ja na procesy,
* z ktorych kazdy wykonuje na kazdym pikselu zadana operacje.
* Program NIE dziala w architekturze master-slave. Pojecia master-slave
* w tresci programu dotycza tylko tworzenia okna graficznego oraz
* wczytania i podzielenia obrazka.
* s1222 PJWSTK, 2000.06.25
*
* Program przyjmuje parametry:
* [1] - plik zawierajacy obraz *.bmp
*/
#include <stdio.h>
#include "mpi.h"
#include "Xlib.h"
#include "Xutil.h"
#include "bmp.h" /* moje funkcje do bitmapy */
#include <string.h>
/* poniewaz u mnie w domu nie dziala MPI_Dims_create to
* zrobilem wlasna funkcje realizujaca to zadanie dla 2 wymiarow
*/
void _MPI_Dims_create(int n, int kupatka, int *t)
{
int i, j = n - 1, m = 1;
t[0] = n;
t[1] = 1;
for(i = n / 2; i > m ; i--) {
if(!(n % i) && (i + n / i - 2 < j)) {
j = i + n / i - 2;
m = n / i;
t[0] = i;
t[1] = n / i;
}
}
}
int main(int argc, char **argv)
{
int rank, myTopologyRank, size, i, j;
char *bufor;
void *sendBufor;
int sendBuforSize;
unsigned long cc[1000];
unsigned short bmpWidth, bmpHeight, bmpWidthPiece, bmpHeightPiece;
int src, dst;
int dims[2]; /* liczba pol w kazdym z dwoch wymiarow */
MPI_Comm MY_COMM;
int offset, xOffset, yOffset;
int coordinates[2];
MPI_Datatype pieceOfImageType, smallImageType,
verticalMarginOfImageType, horizontalMarginType,
verticalMarginType;
MPI_Status status;
Display *displayHandle; /* Uchwyt display`a X11, tworzony w kazdym procesie */
Window win; /* Numer okienka tworzony w MASTERZE i rozsylany do SLAVE`ow */
GC gc;
XGCValues values;
Colormap theColormap;
XColor *imageBuffer, *smallImageBuffer;
XColor *marginBuffer[4];
XColor left, right, top, bottom;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
/* laczy sie z domyslnym serwerem X */
displayHandle = XOpenDisplay((char *)NULL);
if(displayHandle == NULL) {
printf("blad otwarcia display`a\n");
MPI_Abort(MPI_COMM_WORLD, -1);
}
/* TWORZYMY TOPOGRAFIE */
/* dzieli obszar na najbardziej optymalny */
_MPI_Dims_create(size, 2, dims); /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
/* tworzy nowy komunikator z nowa topografia (8 x "/0" czyli 2 x int) */
MPI_Cart_create(MPI_COMM_WORLD, 2, dims, (int *)"\0\0\0\0\0\0\0\0", 1, &MY_COMM);
if(rank == 0) { /**** WCZYTYWANIE OBRAZKA I TWORZENIE OKNA ****/
if(argc != 2) {
printf("nalezy podac parametr: [plik.bmp]\n");
MPI_Abort(MPI_COMM_WORLD, -1);
}
if(loadBMP(argv[1], &imageBuffer, &bmpWidth, &bmpHeight) == -1) {
printf("blad wczytywania obrazu %s\n", argv[1]);
MPI_Abort(MPI_COMM_WORLD, -1);
}
/* MASTER tworzy okienko i rozsyla jego numer do SLAVE`ow */
win = XCreateSimpleWindow(displayHandle, RootWindow(displayHandle, 0),
0, 0, bmpWidth + dims[0] - 1 + 30,
bmpHeight + dims[1] - 1, 2,
BlackPixel(displayHandle, 0),
WhitePixel(displayHandle, 0));
}
/* zorsyla numer okienka do procesow slave`ow */
MPI_Bcast(&win, 1, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD);
MPI_Bcast(&bmpWidth, 1, MPI_UNSIGNED_SHORT, 0, MPI_COMM_WORLD);
MPI_Bcast(&bmpHeight, 1, MPI_UNSIGNED_SHORT, 0, MPI_COMM_WORLD);
bmpWidthPiece = bmpWidth / dims[0];
bmpHeightPiece = bmpHeight / dims[1];
gc = XCreateGC(displayHandle, win, 0, 0);
XMapWindow(displayHandle, win);
XFlush(displayHandle);
sleep(4);
/* definiuje nowy typ, ktory okresla wycinek duzego obrazu */
/* kazdy czesciowy wiersz obrazka to 1 blok */
MPI_Type_vector(bmpHeightPiece,
bmpWidthPiece * sizeof(XColor),
bmpWidth * sizeof(XColor), MPI_BYTE, &pieceOfImageType);
/* nowy typ stanowiacy samodzielny fragment duzego obrazka */
MPI_Type_vector(bmpHeightPiece,
bmpWidthPiece * sizeof(XColor),
bmpWidthPiece * sizeof(XColor), MPI_BYTE, &smallImageType);
MPI_Type_commit(&pieceOfImageType);
MPI_Type_commit(&smallImageType);
/* bufor dla BSenda */
MPI_Pack_size(bmpWidthPiece * bmpHeightPiece * sizeof(XColor),
MPI_BYTE, MPI_COMM_WORLD, &i);
sendBuforSize = i + MPI_BSEND_OVERHEAD;
sendBufor = (void *)malloc(sendBuforSize);
MPI_Buffer_attach(sendBufor, sendBuforSize);
if(rank == 0) {
for(i = size - 1; i > 0 ; i--) {
MPI_Cart_coords(MY_COMM, i, 2, coordinates);
MPI_Send(imageBuffer + coordinates[0] * bmpWidthPiece +
coordinates[1] * bmpWidth * bmpHeightPiece,
1, pieceOfImageType, i, 0, MPI_COMM_WORLD);
}
MPI_Cart_coords(MY_COMM, 0, 2, coordinates);
MPI_Bsend(imageBuffer + coordinates[0] * bmpWidthPiece +
coordinates[1] * bmpWidth * bmpHeightPiece,
1, pieceOfImageType, 0, 0, MPI_COMM_WORLD);
free(imageBuffer);
}
MPI_Comm_rank(MY_COMM, &myTopologyRank);
MPI_Cart_coords(MY_COMM, myTopologyRank, 2, coordinates);
printf("rank: %d topologyRank: %d coords: %d %d\n", rank, myTopologyRank,
coordinates[0], coordinates[1]);
MPI_Cart_shift(MY_COMM, 0, -1, &src, &dst);
printf("rank %d, oto moi sasiedzi: lewo %d, ", myTopologyRank, dst);
MPI_Cart_shift(MY_COMM, 0, 1, &src, &dst);
printf(" prawo %d, ", dst);
MPI_Cart_shift(MY_COMM, 1, -1, &src, &dst);
printf(" gora %d, ", dst);
MPI_Cart_shift(MY_COMM, 1, 1, &src, &dst);
printf(" dol %d\n", dst);
/* kazdy proces odbiera fragment obrazu */
smallImageBuffer = (XColor *)malloc(bmpWidthPiece * bmpHeightPiece * sizeof(XColor));
MPI_Recv(smallImageBuffer, 1, smallImageType, 0, 0, MPI_COMM_WORLD, &status);
/* kazdy proces wysyla marginesy obrazu do swoich sasiadow */
/* definiuje nowy typ, ktory okresla margines malego obrazu */
MPI_Type_vector(bmpHeightPiece,
sizeof(XColor),
bmpWidthPiece * sizeof(XColor), MPI_BYTE, &verticalMarginOfImageType);
/* nowy typ stanowiacy samodzielny margines obrazka
* margines ten sluzy takze jako margines poziomy HORIZONTAL
*/
MPI_Type_vector(bmpHeightPiece,
sizeof(XColor),
sizeof(XColor), MPI_BYTE, &verticalMarginType);
MPI_Type_vector(bmpWidthPiece,
sizeof(XColor),
sizeof(XColor), MPI_BYTE, &horizontalMarginType);
MPI_Type_commit(&verticalMarginOfImageType);
MPI_Type_commit(&verticalMarginType);
MPI_Type_commit(&horizontalMarginType);
marginBuffer[0] = (XColor *)malloc(bmpHeightPiece * sizeof(XColor));
bzero(marginBuffer[0], bmpHeightPiece * sizeof(XColor));
marginBuffer[1] = (XColor *)malloc(bmpHeightPiece * sizeof(XColor));
bzero(marginBuffer[1], bmpHeightPiece * sizeof(XColor));
marginBuffer[2] = (XColor *)malloc(bmpWidthPiece * sizeof(XColor));
bzero(marginBuffer[2], bmpWidthPiece * sizeof(XColor));
marginBuffer[3] = (XColor *)malloc(bmpWidthPiece * sizeof(XColor));
bzero(marginBuffer[3], bmpWidthPiece * sizeof(XColor));
while(1) {
/* wyslij marginesy */
MPI_Cart_shift(MY_COMM, 0, -1, &src, &dst); /* na lewo */
MPI_Bsend(smallImageBuffer, 1, verticalMarginOfImageType, dst, 1, MY_COMM);
MPI_Cart_shift(MY_COMM, 0, 1, &src, &dst); /* na prawo */
MPI_Bsend(smallImageBuffer + bmpWidthPiece - 1, 1, verticalMarginOfImageType,
dst, 2, MY_COMM);
MPI_Cart_shift(MY_COMM, 1, -1, &src, &dst); /* do gory */
MPI_Bsend(smallImageBuffer, 1, horizontalMarginType, dst, 3, MY_COMM);
MPI_Cart_shift(MY_COMM, 1, 1, &src, &dst); /* na dol */
MPI_Bsend(smallImageBuffer + bmpWidthPiece * (bmpHeightPiece - 1), 1,
horizontalMarginType, dst, 4, MY_COMM);
/* tworzy palete kolorow */
theColormap = DefaultColormap(displayHandle, 0);
/* WYSWIETLANIE OBRAZU */
xOffset = coordinates[0] * bmpWidth / dims[0];
yOffset = coordinates[1] * bmpHeight / dims[1];
offset = 0;
for(j = 0; j < bmpHeightPiece ; j++) {
for(i = 0; i < bmpWidthPiece ; i++) {
XAllocColor(displayHandle, theColormap, &smallImageBuffer[offset]);
cc[i] = smallImageBuffer[offset].pixel;
XSetForeground(displayHandle, gc, smallImageBuffer[offset].pixel);
XDrawPoint(displayHandle, win, gc, i + xOffset /*+ coordinates[0] * 5*/,
j + yOffset /*+ coordinates[1] * 5*/);
offset++;
}
XFreeColors(displayHandle, theColormap, cc, bmpWidthPiece, 0);
XSetForeground(displayHandle, gc, WhitePixel(displayHandle,1));
XDrawPoint(displayHandle, win, gc,
bmpWidth + 10 + coordinates[0] * 3 /*+ coordinates[0] * 5*/,
j + coordinates[1] * bmpHeightPiece);
XSetForeground(displayHandle, gc, BlackPixel(displayHandle,1));
XDrawPoint(displayHandle, win, gc,
bmpWidth + 10 + coordinates[0] * 3 /*+ coordinates[0] * 5*/,
j + 1 + coordinates[1] * bmpHeightPiece);
}
XFreeColormap(displayHandle, theColormap);
MPI_Cart_shift(MY_COMM, 0, -1, &src, &dst); /* z lewej */
MPI_Recv(marginBuffer[0], 1, verticalMarginType, dst, 2, MY_COMM, &status);
MPI_Cart_shift(MY_COMM, 0, 1, &src, &dst); /* z prawej */
MPI_Recv(marginBuffer[1], 1, verticalMarginType, dst, 1, MY_COMM, &status);
MPI_Cart_shift(MY_COMM, 1, -1, &src, &dst); /* z gory */
MPI_Recv(marginBuffer[2], 1, horizontalMarginType, dst, 4, MY_COMM, &status);
MPI_Cart_shift(MY_COMM, 1, 1, &src, &dst); /* z dolu */
MPI_Recv(marginBuffer[3], 1, horizontalMarginType, dst, 3, MY_COMM, &status);
printf("rank %d odebral marginesy\n", myTopologyRank);
/* OBROBKA OBRAZU */
offset = 0;
for(j = 0; j < bmpHeightPiece ; j++) {
for(i = 0; i < bmpWidthPiece ; i++) {
if(i > 0) {
left.red = smallImageBuffer[offset - 1].red;
left.green = smallImageBuffer[offset - 1].green;
left.blue = smallImageBuffer[offset - 1].blue;
}
if(i < bmpWidthPiece - 1) {
right.red = smallImageBuffer[offset + 1].red;
right.green = smallImageBuffer[offset + 1].green;
right.blue = smallImageBuffer[offset + 1].blue;
}
if(i == 0) {
left.red = marginBuffer[0][j].red;
left.green = marginBuffer[0][j].green;
left.blue = marginBuffer[0][j].blue;
} else if(i == bmpWidthPiece - 1) {
right.red = marginBuffer[1][j].red;
right.green = marginBuffer[1][j].green;
right.blue = marginBuffer[1][j].blue;
}
if(j > 0) {
top.red = smallImageBuffer[offset - bmpWidthPiece].red;
top.green = smallImageBuffer[offset - bmpWidthPiece].green;
top.blue = smallImageBuffer[offset - bmpWidthPiece].blue;
}
if(j < bmpHeightPiece - 1) {
bottom.red = smallImageBuffer[offset + bmpWidthPiece].red;
bottom.green = smallImageBuffer[offset + bmpWidthPiece].green;
bottom.blue = smallImageBuffer[offset + bmpWidthPiece].blue;
}
if(j == 0) {
top.red = marginBuffer[2][i].red;
top.green = marginBuffer[2][i].green;
top.blue = marginBuffer[2][i].blue;
} else if(j == bmpHeightPiece - 1) {
bottom.red = marginBuffer[3][i].red;
bottom.green = marginBuffer[3][i].green;
bottom.blue = marginBuffer[3][i].blue;
}
smallImageBuffer[offset].red =
(left.red + right.red + top.red + bottom.red +
smallImageBuffer[offset].red) / 5;
smallImageBuffer[offset].green =
(left.green + right.green + top.green + bottom.green +
smallImageBuffer[offset].green) / 5;
smallImageBuffer[offset].blue =
(left.blue + right.blue + top.blue + bottom.blue +
smallImageBuffer[offset].blue) / 5;
offset++;
}
}
}
free(smallImageBuffer);
XFlush(displayHandle);
if(rank == 0) {
getchar();
XCloseDisplay(displayHandle);
}
MPI_Finalize();
return 0;
}
Kod źródłowy pliku "bmp.h":
/* Wczytywanie 8-bitowego obrazka BMP i palety kolorow do pamieci */ /* s1222 PJWSTK, 2000-06-18 */ int loadBMP(char *name, XColor **imageBuffer, unsigned short *width, unsigned short *height);
Kod źródłowy pliku "bmp.c":
/* Wczytywanie 8-bitowego obrazka BMP i palety kolorow do pamieci */
/* s1222 PJWSTK, 2000-06-18 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <Xlib.h>
/* Funkcja wczytuje bitmape z pliku. Bitmapa przeksztalcana jest z formatu
* koloru indeksowego na format RGB wlasciwy dla X`ow.
*/
int loadBMP(char *name, XColor **imageBuffer, unsigned short *width, unsigned short *height)
{
unsigned short int colorNumber, rowNumber, columnNumber;
unsigned char bufferPal[256 * 4 - 1];
unsigned char *bufferTmp;
unsigned long int offset = 0;
int addWidth;
int file;
if((file = open(name, O_RDONLY)) == -1) /* otwieranie pliku */
return -1;
lseek(file, 18, SEEK_SET); /* odczytuje szerokosc obrazu */
read(file, width, 2);
lseek(file, 22, SEEK_SET); /* odczytuje wysokosc obrazu */
read(file, height, 2);
/* obraz w pliku BMP zapisany jest w taki sposob, aby jego
* szerokosc byla wielokrotnoscia 4 bajtow, dlatego trzeba
* zainicjowac zmienna pomocna przy konwersji danych
*/
if(*width % 4)
addWidth = (*width / 4) + 1;
else
addWidth = *width / 4;
addWidth = addWidth * 4 - *width;
lseek(file, 54, SEEK_SET); /* odczytuje palete kolorow */
read(file, bufferPal, 256 * 4); /* format: B, G, R, pusty */
/* odczytuje obraz */
if(!(bufferTmp = (unsigned char *)malloc(*width)) ||
!(*imageBuffer = (XColor *)malloc(sizeof(XColor) * *width * *height)))
return -1;
printf("wczytuje obraz, szerokosc: %d, wysokosc: %d\n", *width, *height);
/* bitmapa w pliku zapisana jest do gory nogami dlatego
* trzeba ja odwrocic
*/
offset = (*height - 1) * *width;
for(rowNumber = 0; rowNumber < *height ; rowNumber++) {
lseek(file, 1078 + rowNumber * (*width + addWidth), SEEK_SET);
read(file, bufferTmp, *width);
for(columnNumber = 0; columnNumber < *width ; columnNumber++) {
(*imageBuffer + columnNumber + offset)->blue =
(bufferPal[bufferTmp[columnNumber] * 4 + 0] >> 2) * 1000;
(*imageBuffer + columnNumber + offset)->green =
(bufferPal[bufferTmp[columnNumber] * 4 + 1] >> 2) * 1000;
(*imageBuffer + columnNumber + offset)->red =
(bufferPal[bufferTmp[columnNumber] * 4 + 2] >> 2) * 1000;
}
offset -= *width;
}
close(file); /* zamyka plik */
free(bufferTmp);
return 0;
}





