Ejemplo de carga de una imagen en C#
Instalemos algunas librerías útiles.#
!sudo apt-get update
!sudo apt-get install libpng-dev
!sudo apt-get install libjpeg-dev
0% [Working]
Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease
0% [Waiting for headers] [Connecting to security.ubuntu.com] [Waiting for heade
Get:2 https://cloud.r-project.org/bin/linux/ubuntu jammy-cran40/ InRelease [3,626 B]
0% [Waiting for headers] [Connecting to security.ubuntu.com] [Connecting to ppa
Get:3 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64 InRelease [1,581 B]
0% [Waiting for headers] [Connecting to security.ubuntu.com (91.189.91.83)] [Co
0% [Waiting for headers] [Connecting to security.ubuntu.com (91.189.91.83)] [Co
Get:4 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [119 kB]
Get:5 http://security.ubuntu.com/ubuntu jammy-security InRelease [110 kB]
Get:6 http://archive.ubuntu.com/ubuntu jammy-backports InRelease [109 kB]
Get:7 https://cloud.r-project.org/bin/linux/ubuntu jammy-cran40/ Packages [47.6 kB]
Get:8 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64 Packages [632 kB]
Get:9 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages [1,535 kB]
Get:10 http://security.ubuntu.com/ubuntu jammy-security/restricted amd64 Packages [1,494 kB]
Hit:11 https://ppa.launchpadcontent.net/c2d4u.team/c2d4u4.0+/ubuntu jammy InRelease
Get:12 http://archive.ubuntu.com/ubuntu jammy-updates/restricted amd64 Packages [1,520 kB]
Get:13 http://archive.ubuntu.com/ubuntu jammy-updates/universe amd64 Packages [1,292 kB]
Get:14 http://security.ubuntu.com/ubuntu jammy-security/universe amd64 Packages [1,027 kB]
Get:15 http://security.ubuntu.com/ubuntu jammy-security/main amd64 Packages [1,265 kB]
Get:16 http://archive.ubuntu.com/ubuntu jammy-backports/universe amd64 Packages [32.6 kB]
Hit:17 https://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu jammy InRelease
Hit:18 https://ppa.launchpadcontent.net/graphics-drivers/ppa/ubuntu jammy InRelease
Hit:19 https://ppa.launchpadcontent.net/ubuntugis/ppa/ubuntu jammy InRelease
Fetched 9,186 kB in 1s (8,125 kB/s)
Reading package lists... Done
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
libpng-dev is already the newest version (1.6.37-3build5).
0 upgraded, 0 newly installed, 0 to remove and 19 not upgraded.
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
libjpeg-dev is already the newest version (8c-2ubuntu10).
libjpeg-dev set to manually installed.
0 upgraded, 0 newly installed, 0 to remove and 19 not upgraded.
Ejemplo de como se deben escribir los programas en c para cargar imégenes#
Este código permite cargar cualquier tipo de imagen .PNG. Se le carga de manera dinámica la imagen en el momento de la ejecución por linea de comando.
%%writefile cargar_imagen.c
#include <png.h>
#include <stdio.h>
#include <stdlib.h>
// Función para leer la imagen PNG y obtener su tamaño
void read_png_file(char *filename, int *width, int *height) {
FILE *file = fopen(filename, "rb");
if(!file) abort();
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) abort();
png_infop info = png_create_info_struct(png);
if (!info) abort();
if (setjmp(png_jmpbuf(png))) abort();
png_init_io(png, file);
png_read_info(png, info);
*width = png_get_image_width(png, info);
*height = png_get_image_height(png, info);
// Aquí podrías expandir el código para leer los datos de los píxeles si lo necesitas
fclose(file);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Uso: %s <ruta de la imagen>\n", argv[0]);
return 1;
}
int width, height;
read_png_file(argv[1], &width, &height);
printf("Tamaño de la imagen: %d x %d\n", width, height);
return 0;
}
Overwriting cargar_imagen.c
Compilamos el archivo en C con las respectivas librerías.#
!gcc cargar_imagen.c -o imagen -lpng
!ls
cargar_imagen.c gato.png imagen imagen.jpg sample_data
Ejecutamos el archivo que se genera del programa#
y le pasamos como argumento la ruta de la imágen
!wget -O imagen.png https://w7.pngwing.com/pngs/36/440/png-transparent-homer-simpson-computer-icons-technology-homero-miscellaneous-text-hand.png
!wget -O imagen.jpeg https://w7.pngwing.com/pngs/36/440/png-transparent-homer-simpson-computer-icons-technology-homero-miscellaneous-text-hand.png
--2023-11-30 10:38:28-- https://w7.pngwing.com/pngs/36/440/png-transparent-homer-simpson-computer-icons-technology-homero-miscellaneous-text-hand.png
Resolving w7.pngwing.com (w7.pngwing.com)... 172.67.165.106, 104.21.73.185, 2606:4700:3037::6815:49b9, ...
Connecting to w7.pngwing.com (w7.pngwing.com)|172.67.165.106|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 33266 (32K) [image/png]
Saving to: ‘imagen.png’
imagen.png 0%[ ] 0 --.-KB/s
imagen.png 100%[===================>] 32.49K --.-KB/s in 0.01s
2023-11-30 10:38:29 (2.95 MB/s) - ‘imagen.png’ saved [33266/33266]
--2023-11-30 10:38:29-- https://w7.pngwing.com/pngs/36/440/png-transparent-homer-simpson-computer-icons-technology-homero-miscellaneous-text-hand.png
Resolving w7.pngwing.com (w7.pngwing.com)... 172.67.165.106, 104.21.73.185, 2606:4700:3037::6815:49b9, ...
Connecting to w7.pngwing.com (w7.pngwing.com)|172.67.165.106|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 33266 (32K) [image/png]
Saving to: ‘imagen.jpeg’
imagen.jpeg 100%[===================>] 32.49K --.-KB/s in 0.01s
2023-11-30 10:38:29 (2.77 MB/s) - ‘imagen.jpeg’ saved [33266/33266]
!./imagen "/content/imagen.png"
Tamaño de la imagen: 920 x 719
Estrategia paralela de filtrado.#
Para este vamos a aplicarle el filtro de sobel (vertical y horizontal) a la imágen y usando una estrategia paralela.
Primero veamos como es el código de manera secuencial para este caso
%%writefile filtro_image.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define STB_IMAGE_IMPLEMENTATION //Librerias para cargar imagen
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION //libreria para guardar imagenes.
#include "stb_image_write.h"
void aplicar_filtro_bordes(unsigned char *input, unsigned char *output, int width, int height, int channels) {
int kernel_x[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}};
int kernel_y[3][3] = {{1, 2, 1}, {0, 0, 0}, {-1, -2, -1}};
for (int y = 1; y < height - 1; y++) {
for (int x = 1; x < width - 1; x++) {
float gx = 0, gy = 0;
for (int ky = -1; ky <= 1; ky++) {
for (int kx = -1; kx <= 1; kx++) {
int p = input[(y + ky) * width + (x + kx)];
gx += p * kernel_x[ky + 1][kx + 1];
gy += p * kernel_y[ky + 1][kx + 1];
}
}
int magnitude = (int)sqrt(gx * gx + gy * gy);
magnitude = magnitude > 255 ? 255 : magnitude;
output[y * width + x] = (unsigned char)magnitude;
}
}
}
int main() {
int width, height, channels;
unsigned char *img = stbi_load("imagen.jpeg", &width, &height, &channels, 1);
if (img == NULL) {
printf("Error al cargar la imagen\n");
return 1;
}
unsigned char *output_img = malloc(width * height * sizeof(unsigned char));
if (output_img == NULL) {
printf("No se pudo asignar memoria para la imagen de salida\n");
stbi_image_free(img);
return 1;
}
clock_t start, end;
double cpu_time_used;
start = clock();
aplicar_filtro_bordes(img, output_img, width, height, channels);
end = clock();
cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
stbi_write_jpg("imagen_con_bordes.jpg", width, height, 1, output_img, 100);
printf("Tiempo de ejecución: %f segundos\n", cpu_time_used);
stbi_image_free(img);
free(output_img);
return 0;
}
Writing filtro_image.c
Descargamos los archivos de las librerías externas#
!wget https://raw.githubusercontent.com/nothings/stb/master/stb_image.h
!wget https://raw.githubusercontent.com/nothings/stb/master/stb_image_write.h
--2023-11-30 10:38:46-- https://raw.githubusercontent.com/nothings/stb/master/stb_image.h
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.109.133, 185.199.108.133, 185.199.110.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 284733 (278K) [text/plain]
Saving to: ‘stb_image.h’
stb_image.h 0%[ ] 0 --.-KB/s
stb_image.h 100%[===================>] 278.06K --.-KB/s in 0.04s
2023-11-30 10:38:46 (6.97 MB/s) - ‘stb_image.h’ saved [284733/284733]
--2023-11-30 10:38:46-- https://raw.githubusercontent.com/nothings/stb/master/stb_image_write.h
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.109.133, 185.199.110.133, 185.199.111.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.109.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 71221 (70K) [text/plain]
Saving to: ‘stb_image_write.h’
stb_image_write.h 100%[===================>] 69.55K --.-KB/s in 0.02s
2023-11-30 10:38:47 (3.00 MB/s) - ‘stb_image_write.h’ saved [71221/71221]
Verificamos que se descarguen los archivos.#
!ls -l
total 456
-rw-r--r-- 1 root root 1034 Nov 30 10:30 cargar_imagen.c
-rw-r--r-- 1 root root 2028 Nov 30 10:38 filtro_image.c
-rwxr-xr-x 1 root root 16696 Nov 30 10:27 imagen
-rw-r--r-- 1 root root 33266 Feb 18 2020 imagen.jpeg
-rw-r--r-- 1 root root 33266 Feb 18 2020 imagen.png
drwxr-xr-x 1 root root 4096 Nov 28 14:27 sample_data
-rw-r--r-- 1 root root 284733 Nov 30 10:38 stb_image.h
-rw-r--r-- 1 root root 71221 Nov 30 10:38 stb_image_write.h
Se compila el programa con los respectivas banderas para tomar las librerias#
-lm es para que compile la libreria de funciones matemática como sqrt()
!gcc filtro_image.c -o filtro_image -lm
!./filtro_image
Tiempo de ejecución: 0.039270 segundos
Ahora con OpenMP#
Descargamos las librerías útiles.#
!sudo apt-get update
!sudo apt-get install build-essential
0% [Working]
Hit:1 https://cloud.r-project.org/bin/linux/ubuntu jammy-cran40/ InRelease
0% [Connecting to archive.ubuntu.com (91.189.91.81)] [Waiting for headers] [Con
Hit:2 https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64 InRelease
0% [Waiting for headers] [Waiting for headers] [Connected to ppa.launchpadconte
Hit:3 http://archive.ubuntu.com/ubuntu jammy InRelease
Hit:4 http://archive.ubuntu.com/ubuntu jammy-updates InRelease
Get:5 http://security.ubuntu.com/ubuntu jammy-security InRelease [110 kB]
Hit:6 http://archive.ubuntu.com/ubuntu jammy-backports InRelease
Hit:7 https://ppa.launchpadcontent.net/c2d4u.team/c2d4u4.0+/ubuntu jammy InRelease
Hit:8 https://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu jammy InRelease
Hit:9 https://ppa.launchpadcontent.net/graphics-drivers/ppa/ubuntu jammy InRelease
Hit:10 https://ppa.launchpadcontent.net/ubuntugis/ppa/ubuntu jammy InRelease
Get:11 http://security.ubuntu.com/ubuntu jammy-security/main amd64 Packages [1,265 kB]
Get:12 http://security.ubuntu.com/ubuntu jammy-security/restricted amd64 Packages [1,494 kB]
Fetched 2,868 kB in 2s (1,758 kB/s)
Reading package lists... Done
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
build-essential is already the newest version (12.9ubuntu3).
0 upgraded, 0 newly installed, 0 to remove and 17 not upgraded.
Escribimos el programa usando openMP.#
Note que la diferencia respecto al secuencial es la línea:
#pragma omp parallel for collapse(2)
#pragma omp parallel for
es una directiva de OpenMP que se utiliza para paralelizar un bucle for. Hace que el bucle se ejecute en varios hilos en paralelo, lo que puede acelerar significativamente el procesamiento si tienes un procesador de múltiples núcleos.collapse(2)
: Este modificador especifica que los dos bucles for anidados más cercanos (en este caso, los bucles que iteran sobre y y x) deben colapsarse en un solo bucle iterativo para fines de paralelización. Esto es útil cuando cada bucle por sí solo no proporciona suficientes iteraciones para aprovechar completamente las capacidades de paralelización, pero combinados, ofrecen un número significativo de tareas independientes que pueden ser distribuidas entre los hilos disponibles.
Verifique que el bucle externo itera a través de las filas (y) de la imagen y el bucle interno a través de las columnas (x). Al usar collapse(2), se trata la combinación de estas dos dimensiones como un único conjunto de iteraciones, lo que permite una distribución más eficiente de las iteraciones entre los hilos de OpenMP.
%%writefile tu_programa.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <omp.h>
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
void aplicar_filtro_bordes(unsigned char *input, unsigned char *output, int width, int height, int channels) {
int kernel_x[3][3] = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}};
int kernel_y[3][3] = {{1, 2, 1}, {0, 0, 0}, {-1, -2, -1}};
#pragma omp parallel for collapse(2)
for (int y = 1; y < height - 1; y++) {
for (int x = 1; x < width - 1; x++) {
float gx = 0, gy = 0;
for (int ky = -1; ky <= 1; ky++) {
for (int kx = -1; kx <= 1; kx++) {
int p = input[(y + ky) * width + (x + kx)];
gx += p * kernel_x[ky + 1][kx + 1];
gy += p * kernel_y[ky + 1][kx + 1];
}
}
int magnitude = (int)sqrt(gx * gx + gy * gy);
magnitude = magnitude > 255 ? 255 : magnitude;
output[y * width + x] = (unsigned char)magnitude;
}
}
}
int main() {
int width, height, channels;
unsigned char *img = stbi_load("imagen.jpeg", &width, &height, &channels, 1);
if (img == NULL) {
printf("Error al cargar la imagen\n");
return 1;
}
unsigned char *output_img = malloc(width * height * sizeof(unsigned char));
if (output_img == NULL) {
printf("No se pudo asignar memoria para la imagen de salida\n");
stbi_image_free(img);
return 1;
}
clock_t start, end;
double cpu_time_used;
start = clock();
aplicar_filtro_bordes(img, output_img, width, height, channels);
end = clock();
cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;
stbi_write_jpg("imagen_con_bordes.jpg", width, height, 1, output_img, 100);
printf("Tiempo de ejecución: %f segundos\n", cpu_time_used);
stbi_image_free(img);
free(output_img);
return 0;
}
Overwriting tu_programa.c
!gcc tu_programa.c -o tu_programa -fopenmp -lm
!./tu_programa
Tiempo de ejecución: 0.060102 segundos