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; }