Ejercicio obligatorio 4

Fecha de entrega: Martes 8 de diciembre

Introducción

El formato Portable Pixel Map (PPM) es el pináculo de la evolución del paquete Netpbm. El mismo permite la codificación de imágenes a color en un archivo sencillo.

El formato es similar al PGM ya analizado con la diferencia de que ahora por cada pixel en vez de tener un único valor de grises tendremos tres valores, uno para cada componente RGB del color.

Por ejemplo el siguiente archivo

P3
# Este es un ejemplo de PPM
4 4
# Asumimos que el máximo es siempre 255
255
#   Rojo                                     Verde
255   0   0   170  85   0    85 170   0     0 255   0
170   0  85   141  85  85   113 170  85    85 255  85
 85   0 170   113  85 170   141 170 170   170 255 170
  0   0 255    85  85 255   170 170 255   255 255 255
#   Azul                                     Blanco

genera la siguiente imagen:

../_images/20202_ej4.png

Resumiendo: El encabezado es P3, hay 3 valores numéricos por cada pixel.

Trabajo

pixel_t y componente_t

Se pide implementar el tipo componente_t sobre un tipo entero del tamaño adecuado de tal forma que se permita el almacenamiento de la componente de un color de 8 bits.

Se pide implementar el tipo pixel_t sobre un tipo entero del tamaño adecuado de tal forma que se permita el almacenamiento de un color RGB de 24 bits.

El tipo irá acompañado de las siguientes primitivas:

  • pixel_t pixel_desde_rgb(componente_t rojo, componente_t verde, componente_t azul); que devuelve un pixel_t a partir de sus componentes rojo, verde y azul.

  • componente_t pixel_get_rojo(pixel_t p); que dado el pixel p devuelva el valor de su componente roja.

  • componente_t pixel_get_verde(pixel_t p); que dado el pixel p devuelva el valor de su componente verde.

  • componente_t pixel_get_azul(pixel_t p); que dado el pixel p devuelva el valor de su componente azul.

Colores con nombre

Teniendo la siguiente tabla:

Color

(R, G, B)

black

(0, 0, 0)

white

(255, 255, 255)

red

(255, 0, 0)

lime

(0, 255, 0)

blue

(0, 0, 255)

yellow

(255, 255, 0)

cyan

(0, 255, 255)

magenta

(255, 0, 255)

silver

(192, 192, 192)

gray

(128, 128, 128)

maroon

(128, 0, 0)

olive

(128, 128, 0)

green

(0, 128, 0)

purple

(128, 0, 128)

teal

(0, 128, 128)

navy

(0, 0, 128)

Implementar una primitiva pixel_t pixel_desde_nombre(const char *nombre); que dado el nombre del color, devuelva un pixel con ese valor. En caso de que el nombre sea incorrecto, devolver el color negro ("black").

Nota

Para resolver este problema hay que utilizar tablas de búsqueda.

Siendo que esta función es interna al tipo pixel_t se permite, de ser necesario, inicializar los valores con la representación interna del tipo (por ejemplo, que "white" se corresponda con 0xFFFFFF).

Filtros

Se provee una serie de filtros ya implementados. Todos los filtros son funciones que reciben un pixel_t y un entero y que devuelven un pixel_t. Estas funciones transforman el pixel recibido según su funcionalidad y pueden o no necesitar el parámetro.

La siguiente es la lista de filtros con su nombre, su función asociada y con la cantidad de parámetros que requiere:

Nombre

Función

Parámetros

invertir

filtro_invertir

0

saturar

filtro_saturar

1

gama

filtro_cambiar_gama

1

brillo

filtro_cambiar_brillo

1

contraste

filtro_cambiar_contraste

1

mezclar

filtro_mezclar

1

sepia

filtro_sepia

0

monocromo

filtro_monocromo

1

toaster

filtro_toaster

0

valencia

filtro_valencia

0

Se pide definir un tipo enumerativo filtro_t que permita codificar cada uno de estos filtros.

Implementar la función bool cadena_a_filtro(const char *nombre, filtro_t *filtro); que dado el nombre de un filtro devuelva, a través del parámetro filtro la etiqueta correspondiente del tipo enumerativo. La función debe devolver true si pudo convertir la cadena en etiqueta o false en caso contrario.

Implementar la función int numero_de_parametros(filtro_t filtro); que reciba una etiqueta del enumerativo en filtro y devuelva el número de parámetros que requiere ese filtro.

Implementar una función void aplicar_filtro(pixel_t imagen[MAX_ALTO][MAX_ANCHO], size_t ancho, size_t alto, filtro_t filtro, int parametro); que reciba una imagen PPM como una matriz estática que ocupa ancho por alto píxeles y un enumerativo filtro. La función debe aplicar la función que implementa el filtro pasándole el parametro recibido para cada uno de los pixeles de la imagen. Cada uno de los pixeles se debe reemplazar por lo que devuelva la función.

Nota

Todas estas funciones deben ser resueltas utilizando tablas de búsqueda.

Aplicación y validación

Se provee de un código fuente que contiene tanto el main() como funciones para leer y escribir un PPM (no así leer_entero()), como funciones para convertir del espacio RGB al espacio HSV, como los filtros mencionados.

Se deben completar las funciones y tipos pedidos en este enunciado y mantener el código entregado por la cátedra.

El fuente y los ejemplos se descargan de acá: archivos_20202_ej4.tar.gz

Cada uno de los archivos de entrada se proporciona con un archivo de salida y cada uno de los ejemplos se corresponde con un filtro en particular. El filtro utilizado está en un comentario en el archivo de salida. Por ejemplo para el archivo gatito_color_9_salida.ppm dice # Generado con "monocromo 60", esto significa que el mismo fue ejecutado:

$ ./20202_ej4 monocromo 60 < gatito_color_9.ppm > gatito_color_9_salida.ppm

Entrega

Deberá entregarse el código fuente del programa desarrollado.

El programa debe:

  1. Compilar correctamente con los flags:

    -Wall -Werror -std=c99 -pedantic
    
  2. validar los ejemplos dados,

  3. estar implementado, donde requiera, con tablas de búsqueda y manejo de bits conforme a cómo se desarrolló en las clases.

Nota

Si bien no es obligatorio para esta entrega se permite que la misma se haga modularizada. En dicho caso deberá entregarse el archivo Makefile correspondiente.

La entrega se realiza a través del sistema de entregas.

El ejercicio es de entrega individual.