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;
}
w3cw3c
automatyka przemysłowa