Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Línea de compilación: gcc main.c pgm.c -o main
- Ejemplo del uso de:
- pgmread
- pgmwrite
- Las matrices que contienen a las imágenes son declaradas como uchar
- % % % % % % % %
- Ejemplo 1:
- unsigned char Original = (unsigned char )pgmread("entrada.pgm", &Largo, &Alto);
- La imagen PGM se lee de la línea de comando (argv[1]). La función
- pgmread regresa tres valores:
- 1. la imagen leída (Original)
- 2. el largo de la imagen (Largo)
- 3. el alto de la imagen (Alto)
- % % % % % % % %
- Ejemplo 2:
- pgmwrite(Salida, "salida.pgm", Largo, Alto);
- La imagen Salida es escrita al disco con el nombre de negativo.pgm, la
- imagen resulta en formato PGM. La imagen se escribe desde el inicio (0,0)
- hasta (Largo, Alto).
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "pgm.h"
- #include <mpi.h>
- #include <tgmath.h>
- typedef struct
- {
- int start;
- int size;
- } asignacion;
- // Asigna el trabajo que hará cada proceso
- // Cada proceso tendra como MÍNIMO (tamaño del array / procesos) elementos de los que encargarse y además, puede tener 0 o 1 elemento más (nunca más de 1) del que encargarse.
- // empieza en (tamaño / procesos) *procesoActual+min(tamaño%procesos, i)*** El mínimo lo usamos para saber el número de elementos adicionales que se han añadido a cada proceso antes del actual
- // con un tamaño de: (tamaño / procesos) + 1 si (tamaño % procesos) es > procesoActual o +0 en caso contrario
- asignacion reparto(int size, int workers, int i)
- {
- return (asignacion){
- .start = (size / workers) * i + fmin(size % workers, i),
- .size = (size / workers) + (size % workers > i ? 1 : 0)};
- }
- void convolucion(unsigned char *Original, int *nucleo, unsigned char *Salida, int Columnas, int Filas, int nucleoSize, int bordeNucleo)
- {
- int x, y;
- int suma;
- int k = 0; // Serán los pesos para calcular la media ponderada
- int i, j;
- int indiceX, indiceY;
- int iniSalida, finSalida;
- for (x = 0; x < Filas; x++) {
- for (y = 0; y < Columnas; y++) {
- suma = 0;
- k = 0;
- for (i = 0; i < nucleoSize; i++) {
- for (j = 0; j < nucleoSize; j++) {
- indiceX = abs(x - bordeNucleo) + i;
- indiceY = abs(y - bordeNucleo) + j;
- //if (indiceX >= Filas || indiceY < 0 || indiceY >= Columnas || indiceY < 0)
- if (indiceY >= Columnas || indiceY < 0)
- continue; // Si se sale del array, continuamos
- k = k + nucleo[i*Columnas+j];
- suma = suma + Original[indiceX*Columnas+indiceY] * nucleo[i*Columnas+j];
- }
- }
- if (k == 0)
- Salida[x*Columnas+y] = suma;
- else
- Salida[x*Columnas+y] = suma / k;
- }
- }
- }
- /* * * * * * * * * * * * * * * * * * * */
- int main(int argc, char *argv[]) {
- int Columnas, Filas;
- int i, j;
- int totalProc, proc;
- int desde, hasta;
- int nucleoFilas = 0;
- int nucleoColumnas = 0; // Tamaño de la matriz de convolución
- MPI_Init(&argc, &argv);
- MPI_Comm_size(MPI_COMM_WORLD, &totalProc);
- MPI_Comm_rank(MPI_COMM_WORLD, &proc);
- unsigned char **Original;
- unsigned char **Salida;
- // Almacenará los resultados locales (tendrá un tamaño de filas/proceso*columnas)
- unsigned char *OriginalAux;
- unsigned char *SalidaAux;
- unsigned char *Salida1d;
- int * nucleo;
- int sizeNucleo;
- int indices[2];
- int sizeElemen;
- if (proc == 0) {
- if (argc != 3) {
- printf("Introduzca las filas y columnas de la matriz de convolución\n");
- fflush(stdout);
- }
- /*
- Recogemos el tamaño de la matriz de convolución
- */
- nucleoFilas = atoi(argv[1]);
- nucleoColumnas = atoi(argv[2]);
- /*
- Lectura de la imagen
- */
- Original = pgmread("lena_original.pgm", &Columnas, &Filas);
- Salida = (unsigned char **)GetMem2D(Filas, Columnas, sizeof(unsigned char));
- /*
- Creación de la matriz de convolución (Actualmente funciona para matrices impares)
- */
- sizeNucleo = nucleoFilas * nucleoColumnas; // Tamaño total del nucleo
- nucleo = malloc(sizeof(int) * nucleoFilas*nucleoColumnas);
- for (i = 0; i < nucleoFilas; i++)
- for (j = 0; j < nucleoColumnas; j++)
- nucleo[i*nucleoColumnas+j] = -1;
- nucleo[nucleoFilas/2*nucleoColumnas + nucleoColumnas/2] = 1; // Colocamos el 1 en el centro
- // -----------------------------------------------------------------------------------------------
- }
- // Enviamos el nucleo a todos los procesos
- // Tamaño del nucleo
- MPI_Bcast(&sizeNucleo, 1, MPI_INT, 0, MPI_COMM_WORLD);
- if(proc != 0) nucleo = malloc(sizeof(int) * sizeNucleo);
- // Recivimos el nucleo
- MPI_Bcast(nucleo, sizeNucleo, MPI_INT, 0, MPI_COMM_WORLD);
- // Espacio desde el nucleo al borde para no salirnos de la imagen
- int bordeNucleo = (int)sqrt(sizeNucleo) / 2;
- // Enviamos el numero de columnas que tiene la imagen a todos los procesos
- MPI_Bcast(&Columnas, 1, MPI_INT, 0, MPI_COMM_WORLD);
- MPI_Bcast(&Filas, 1, MPI_INT, 0, MPI_COMM_WORLD);
- // El resto de los procesos recive su parte de imagen
- if(proc == 0) {
- // Repartimos la imagen por filas
- asignacion a;
- for (int i = totalProc-1; i >= 0; i--) { // Repartimos para los procesos
- a = reparto(Columnas, totalProc, i); // Cogemos el reparto
- desde = fmax(0, a.start-bordeNucleo);
- hasta = fmin(Filas, (a.start + a.size)+bordeNucleo);
- // printf("asignacion start=%d fin=%d | size=%d | en rank=%d\n", a.start, a.start + a.size, a.size, i);
- OriginalAux = malloc((hasta-desde)*Columnas*sizeof(unsigned char));
- // Recorremos las filas, cogiéndo un trozo más de imagen para que aplique la convolución correctamente.
- for (int x = 0, fila = desde; fila < hasta; fila++, x++) {
- for (int colum = 0; colum < Columnas; colum++) { // Recorremos todas las columnas
- OriginalAux[x*Columnas + colum] = Original[fila][colum]; // Pasamos el contenido de la matriz 2d a una matriz 1d
- }
- }
- // Asignamos los índices de lo que tiene que hacer cada proceso
- indices[0] = a.start; // Inicio
- indices[1] = a.start+a.size; // Final
- if(i != 0){
- // printf("rank[%d] --> desde %d | hasta %d\n",i, indices[0], indices[1]);
- MPI_Send(indices, 2, MPI_INT, i, 0, MPI_COMM_WORLD); // Enviamos sus índices
- MPI_Send(OriginalAux, (hasta-desde)*Columnas, MPI_UNSIGNED_CHAR, i, 0, MPI_COMM_WORLD); // Enviamos la parte que tiene que hacer cada proceso
- }
- }
- } else {
- // Recivimos los indices de inicio y fin de los datos de cada proceso
- MPI_Recv(indices, 2, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
- desde = fmax(0, indices[0]-bordeNucleo);
- hasta = fmin(Filas, (indices[1])+bordeNucleo);
- OriginalAux = malloc((hasta-desde)*Columnas*sizeof(unsigned char));
- // Recivimos el vector con el trozo de imagen correspondiente
- MPI_Recv(OriginalAux, (hasta-desde)*Columnas, MPI_UNSIGNED_CHAR, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
- }
- //printf("rank[%d] --> desde %d | hasta %d\n",proc, desde, hasta);
- // El número de elementos con los que debe trabajar cada proceso
- sizeElemen = indices[1]-indices[0];
- // Resultado de la convolución de cada proceso
- SalidaAux = malloc(sizeElemen*Columnas*sizeof(unsigned char));
- convolucion(OriginalAux, nucleo, SalidaAux, Columnas, sizeElemen, sizeNucleo, bordeNucleo);
- Salida1d = malloc(Filas*Columnas*sizeof(unsigned char));
- MPI_Gather(SalidaAux, sizeElemen*Columnas, MPI_UNSIGNED_CHAR, Salida1d, sizeElemen*Columnas, MPI_UNSIGNED_CHAR, 0, MPI_COMM_WORLD);
- MPI_Barrier(MPI_COMM_WORLD);
- if (proc == 0) {
- printf("Valor obtenido con Gather: %i ", Salida1d[1*Columnas+2]);
- for (int fila = 0; fila < Filas; fila++) {
- for (int col = 0; col < Columnas; col++) {
- Salida[fila][col] = Salida1d[fila*Columnas+col];
- }
- }
- pgmwrite(Salida, "lena_procesada.pgm", Filas, Columnas);
- }
- MPI_Finalize();
- /*free(nucleo);
- free(OriginalAux);
- free(SalidaAux);
- free(Salida1d);
- Free2D((void **)Original, Columnas);
- Free2D((void **)Salida, Columnas);*/
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement