Ejercicio obligatorio 2

Fecha de entrega: Lunes 19 de septiembre

Nota

Nunca es buena idea empezar por un ejercicio integrador antes de tener practicados los temas que el trabajo integra.

Se sugiere antes de desarrollar este trabajo resolver, al menos, los siguientes ejercicios de la guía de Arreglos:

  • Ejercicio 3 (operaciones con vectores).

  • Ejercicio 9 (copia de vectores).

  • Ejercicio 18 (matrices) incisos d, e, h.

  • Ejercicio 19 (buscaminas).

Introducción

Imágenes

Ya sabemos todo lo que necesitamos saber sobre imágenes 🙄, sabemos que son discretizaciones en píxeles, conocemos el formato PGM, todo. Ahora lo que queremos es almacenar estas imágenes en la memoria. Para esto podemos usar matrices, que en principio es el tipo natural para modelar este problema.

Los píxeles en principio pueden representarse de múltiples maneras, para abstraernos de eso en principio usaremos un tipo pixel_t definido como:

typedef uint8_t pixel_t;

luego las imágenes serán matrices de una determinada cantidad de pixeles de ancho por píxeles de alto, estando representado el ancho por sus columnas y el alto por sus filas, siendo la fila 0, la columna 0 el píxel de arriba a la izquierda creciendo estos valores hacia abajo y hacia la derecha respectivamente.

Dado que en el formato PGM el valor máximo de los píxeles es un valor arbitrario de entre 1 y 65535 definiremos además un máximo para este problema como:

#define PIXEL_MAXIMO 15

Escalado

En muchas aplicaciones es necesario cambiar las dimensiones de una imagen. Si bien hay muchas maneras de hacer esto, la forma más sencilla de hacerlo es sencillamente asignando a cada píxel de la nueva imagen valores de otro píxel de la imagen original.

Para simplificar el problema planteémoslo de forma unidimensional. Se tiene un vector original \(O\) de tamaño \(t_o\) y se quiere redimensionar a un nuevo vector destino \(D\) de tamaño \(t_d\). Es decir, hay que completar cada uno de los elementos \(D_i\) del vector \(D\) con elementos \(O_i\) provenientes de \(O\).

Si definimos:

\(e = \frac{t_o}{t_d},\)

como la escala, entonces podemos asignar cada elemento \(D_i\) según:

\(D_i = O_{\lfloor e \cdot i \rfloor},\)

con \(i \in [0, t_d)\), donde el operador \(\lfloor \cdots \rfloor\) es el operador "piso", es decir, el truncamiento entero.

Para escalar una imagen es el mismo procedimiento en dos dimensiones, admitiéndose diferentes escalas para el ancho y el alto.

Trabajo

Implementar una función void inicializar_imagen(size_t ancho, size_t alto, pixel_t imagen[alto][ancho], pixel_t valor); que reciba la matriz imagen que representa una imagen de tamaño ancho por alto e incialice cada uno de los píxeles de la misma con el valor dado.

Imprimir PGM

Se pide implementar la función void imprimir_pgm(size_t ancho, size_t alto, pixel_t imagen[alto][ancho]); que reciba una imagen de ancho`x`alto y la imprima por stdout en formato PGM.

Pegar imagen

Implementar una función

void pegar_imagen(
        size_t ancho_destino, size_t alto_destino, pixel_t destino[alto_destino][ancho_destino],
        size_t ancho_origen, size_t alto_origen, pixel_t origen[alto_origen][ancho_origen],
        int x, int y
    );`

que reciba dos imágenes, una imagen destino de tamaño ancho_destino`x`alto_destino y una imagen origen de tamaño ancho_destino`x`alto_destino y "pegue" la imagen origen en la imagen destino de forma tal que la coordenada [0][0] de origen termine en la posición [x][y] de destino (es decir, x e y representan dónde pegar la esquina superior izquierda de destino en origen). Si el valor de un pixel de origen valiera 0 se debe considerar ese pixel como "transparente" y NO debe ser pegado en la imagen.

Escalar imagen

Implementar una función

void escalar_imagen(
        size_t ancho_destino, size_t alto_destino, pixel_t destino[alto_destino][ancho_destino],
        size_t ancho_origen, size_t alto_origen, pixel_t origen[alto_origen][ancho_origen]
    );`

que partiendo de la imagen origen cree la imagen destino escalándola adecuadamente al tamaño de la misma.

Validación

Se provee el siguiente main()

#include <stdio.h>
#include <stdint.h>

#define MAXIMO 15

typedef uint8_t pixel_t;

#define ANCHO_IMAGEN 160
#define ALTO_IMAGEN 120

#define ANCHO_PEPE 46
#define ALTO_PEPE 38

pixel_t pepe[ALTO_PEPE][ANCHO_PEPE] = {
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 6, 6, 6, 6, 6, 6, 2, 3, 0, 0, 0, 0, 2, 2, 6, 6, 6, 2, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 0, 0, 3, 6, 6, 6, 6, 6, 6, 6, 6, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 6, 6, 6, 6, 6, 1, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 6, 6, 3, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 3, 0, 0},
    {0, 0, 0, 0, 0, 0, 2, 2, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 6, 6, 2, 0},
    {0, 0, 0, 0, 0, 3, 6, 6, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 2, 3, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 2, 0},
    {0, 0, 0, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 3, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 3, 0},
    {0, 0, 0, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 12, 12, 3, 12, 13, 13, 13, 13, 13, 12, 2, 2, 12, 13, 13, 12, 12, 3},
    {0, 0, 0, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 12, 12, 2, 12, 13, 13, 13, 13, 13, 12, 2, 2, 12, 13, 13, 12, 12, 3},
    {0, 0, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 3, 12, 13, 13, 13, 13, 13, 13, 12, 12, 13, 13, 13, 12, 4, 0},
    {0, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 3, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 4, 0, 0},
    {0, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 1, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 2, 2, 3, 0, 0, 0},
    {0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 1, 1, 1, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 5, 2, 0, 0, 0, 0},
    {0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 5, 3, 0, 0, 0, 0, 0},
    {2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0},
    {2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 0, 0, 0, 0, 0},
    {2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 0, 0, 0, 0},
    {2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 0, 0, 0, 0},
    {2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 0, 0, 0},
    {2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 0, 0, 0},
    {2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 2, 0, 0, 0},
    {2, 6, 6, 6, 8, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 7, 7, 3, 0, 0},
    {0, 2, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 7, 7, 7, 3, 0, 0},
    {0, 2, 6, 6, 9, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 7, 1, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 3, 0, 0, 0},
    {0, 0, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 6, 7, 7, 7, 7, 7, 7, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 2, 0, 0, 0, 0},
    {0, 0, 0, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 0, 0, 0, 0},
    {0, 0, 0, 0, 2, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 3, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 2, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
    {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};


int main(void) {
    pixel_t imagen[ALTO_IMAGEN][ANCHO_IMAGEN];

    inicializar_imagen(ANCHO_IMAGEN, ALTO_IMAGEN, imagen, MAXIMO);

    pegar_imagen(ANCHO_IMAGEN, ALTO_IMAGEN, imagen, ANCHO_PEPE, ALTO_PEPE, pepe, 60, 40);
    pegar_imagen(ANCHO_IMAGEN, ALTO_IMAGEN, imagen, ANCHO_PEPE, ALTO_PEPE, pepe, 140, 40);
    pegar_imagen(ANCHO_IMAGEN, ALTO_IMAGEN, imagen, ANCHO_PEPE, ALTO_PEPE, pepe, -20, 40);
    pegar_imagen(ANCHO_IMAGEN, ALTO_IMAGEN, imagen, ANCHO_PEPE, ALTO_PEPE, pepe, 60, 100);
    pegar_imagen(ANCHO_IMAGEN, ALTO_IMAGEN, imagen, ANCHO_PEPE, ALTO_PEPE, pepe, 60, -20);

    pixel_t escalada1[19][23];
    escalar_imagen(23, 19, escalada1, ANCHO_PEPE, ALTO_PEPE, pepe);
    pegar_imagen(ANCHO_IMAGEN, ALTO_IMAGEN, imagen, 23, 19, escalada1, 10, 10);

    pixel_t escalada2[60][60];
    escalar_imagen(60, 60, escalada2, ANCHO_PEPE, ALTO_PEPE, pepe);
    pegar_imagen(ANCHO_IMAGEN, ALTO_IMAGEN, imagen, 60, 60, escalada2, 100, 80);

    imprimir_pgm(ANCHO_IMAGEN, ALTO_IMAGEN, imagen);

    return 0;
}

el cual debe generar la siguiente imagen:

../_images/20222_ej2.png

Probar las funciones realizadas contra esta referencia.

Entrega

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

El programa debe compilar correctamente con los flags:

-Wall -Werror -std=c99 -pedantic

y validar la salida esperada sin errores.

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

El ejercicio es de entrega individual.