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:
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 unpixel_t
a partir de sus componentesrojo
,verde
yazul
.componente_t pixel_get_rojo(pixel_t p);
que dado el pixelp
devuelva el valor de su componente roja.componente_t pixel_get_verde(pixel_t p);
que dado el pixelp
devuelva el valor de su componente verde.componente_t pixel_get_azul(pixel_t p);
que dado el pixelp
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 |
|
0 |
saturar |
|
1 |
gama |
|
1 |
brillo |
|
1 |
contraste |
|
1 |
mezclar |
|
1 |
sepia |
|
0 |
monocromo |
|
1 |
toaster |
|
0 |
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:
Compilar correctamente con los flags:
-Wall -Werror -std=c99 -pedantic
validar los ejemplos dados,
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.