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 nucleoFilas, int nucleoColumnas) {
- 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 (int x = 0; x < Filas; x++) {
- for (int y = 0; y < Columnas; y++) {
- suma = 0;
- k = 0;
- for (int i0 = -nucleoFilas / 2; i0 < nucleoFilas / 2; i0++) {
- for (int j0 = -nucleoColumnas / 2; j0 < nucleoColumnas / 2; j0++) {
- int i = i0 + x;
- int j = j0 + y;
- if (i < 0)
- i = 0;
- else if (i > nucleoFilas / 2 - 1)
- i = nucleoFilas / 2 - 1;
- if (j < 0)
- j = 0;
- else if (j > nucleoColumnas / 2 - 1)
- j = nucleoColumnas / 2 - 1;
- suma += Original[i * Columnas + j] * nucleo[i * nucleoColumnas + j];
- k += nucleo[i * nucleoColumnas + 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 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)
- 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(&nucleoColumnas, 1, MPI_INT, 0, MPI_COMM_WORLD);
- MPI_Bcast(&nucleoFilas, 1, MPI_INT, 0, MPI_COMM_WORLD);
- if (proc != 0)
- nucleo = malloc(sizeof(int) * nucleoColumnas*nucleoFilas);
- // Recibimos el nucleo
- MPI_Bcast(nucleo, nucleoColumnas*nucleoFilas, MPI_INT, 0, MPI_COMM_WORLD);
- // 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(Filas, totalProc, i); // Cogemos el reparto
- desde = fmax(0, a.start - nucleoFilas / 2);
- hasta = fmin(Filas, (a.start + a.size) + nucleoFilas / 2);
- // 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] - nucleoFilas);
- hasta = fmin(Filas, (indices[1]) + nucleoFilas);
- printf("proceso[%i] -> desde [%i] | hasta [%i]\n", proc, desde, hasta);
- 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("Elemento aleatorio de OriginalAux[%i][%i]=%i\n", 2, 20, OriginalAux[2*(hasta-desde)+20]);
- }
- //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, nucleoFilas, nucleoColumnas);
- printf("Valor obtenido con Gather: %i ", SalidaAux[1 * Columnas + 2]);
- 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