Saltar a contenido

Trabajo Práctico 2 — Estilización de Imágenes Digitales#

Introducción#

En el desarrollo de software, y especialmente en áreas como gráficos, visualización de datos y videojuegos, es común transformar imágenes para obtener distintos estilos visuales. Estas transformaciones pueden simplificar la información, resaltar patrones o generar efectos artísticos.

En este trabajo práctico se propone explorar dos técnicas de transformación de imágenes con fuerte identidad visual:

  • Pixel Art, que simplifica imágenes reduciendo su resolución y cantidad de colores.
  • ASCII Art, que representa imágenes mediante caracteres de texto.

El objetivo es implementar ambas técnicas, comprender cómo se modelan imágenes como estructuras de datos y analizar el impacto visual de cada transformación.

Intro

Figura 1: Imagen conceptual generada con ChatGPT

Imágenes#

Las imágenes se representan como matrices de píxeles. En una imagen en escala de grises, esta matriz tiene dos dimensiones (ancho y alto) con valores entre 0 y 255, donde 0 representa el negro y 255 el blanco. En el caso de imágenes a color, se utilizan tres matrices correspondientes a los canales rojo, verde y azul (RGB), cada uno con valores en el mismo rango. La combinación de estos tres canales define el color final de cada píxel.

Representación matricial de una imagen a color

Figura 2: Escala de grises

Representación matricial de una imagen a color

Figura 3: Representación matricial de una imagen a color

Rueda de colores RGB

Figura 4: Rueda de colores RGB

Para trabajar con imágenes en este proyecto se puede utilizar la función Image.open de la librería Pillow en conjunto con NumPy. Uno de los objetivos es profundizar en el manejo de estas herramientas.

Edición de Imágenes#

Cuando se edita una imagen, se modifican los valores de sus matrices de píxeles para conseguir el efecto deseado. Por ejemplo, se puede oscurecer la imagen disminuyendo los valores de la matriz o se puede modificar su tonalidad alterando los valores de un canal específico.

Pixel Art#

El Pixel Art busca simplificar una imagen mediante: - reducción de resolución (bloques), - reducción de colores (cuantización).

Idea general - Agrupar píxeles en bloques de tamaño fijo. - Reemplazar cada bloque por su color promedio. - Reducir la cantidad de colores disponibles.

Pasos para implementar:

  1. Dividir la imagen en bloques de tamaño tam_bloque × tam_bloque.
  2. Se arma la valores posibles de cada canal según la cantidad de niveles de color deseados (por ejemplo, para 2 niveles: [0, 255], para 4 niveles: [0, 85, 170, 255]).
  3. Para cada bloque:
    1. Calcular el color promedio (RGB)
    2. Calcular cual es el color más cercano de la paleta
  4. Pintar todo el bloque con ese color.

Imagen original Ejemplo de Pixel Art

Figura 5: Filtro Pixel Art (tamaño de bloque = 10 y cantidad de niveles de color = 2)

ASCII Art#

El ASCII Art consiste en representar una imagen utilizando caracteres de texto. Cada carácter tiene una “densidad visual” distinta, lo que permite aproximar zonas claras y oscuras.

Idea general

  • Píxeles oscuros → caracteres densos (@, #)
  • Píxeles claros → caracteres livianos (., espacio)

Para este ejercicio vamos a usar la siguiente paleta de 70 caracteres ordenada por intensidad:

PALETA = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "

Pasos para implementar este filtro:

  1. Convertir la imagen a escala de grises. Para esto puede usar el metodo convert de la clase Image de Pillow.
  2. Normalizar los valores de intensidad entre 0 y 255.

    Normalización de intensidad

    Para normalizar, se puede usar la fórmula:

    \[ p_{xy} = \frac{p_{xy} - \min}{\max - \min} \times 255 \]

    donde \(p_{xy}\) es el valor de intensidad del píxel en la posición \((x, y)\); \(\min\) y \(\max\) son los valores de intensidad más bajo y más alto que aparecen en la imagen respectivamente.

  3. Redimensionar la imagen:

    1. Calcular el nuevo alto manteniendo la relación de aspecto (la división entre ancho y alto debe ser la misma que la imagen original).
    2. A este nuevo alto multiplicarle 0.45 que corrige el hecho de que los caracteres no son cuadrados como los pixeles.
    3. Se puede usar la función resize de Pillow para redimensionar la imagen a este nuevo tamaño.
  4. Mapear cada píxel a un carácter según su valor:

    1. Teniendo en cuenta que la paleta tiene 70 caracteres donde el primer carácter corresponde a intensidad 255 y el último a intensidad 0, queremos mapear cada valor de intensidad a un índice de la paleta. Para esto, se puede usar la fórmula:
    \[ i = \text{round}\left((1 - \frac{p_{xy}}{255}) \times (N - 1)\right) \]

    donde \(N\) es la cantidad de caracteres en la paleta (en este caso, 70).

  5. Construir un string final con saltos de línea.

Imagen original Ejemplo de Pixel Art

Figura 6: Filtro ASCII Art (ancho = 80)

Requerimientos del Programa#

Se te pide escribir un script en Python que:

  1. Solicite al usuario:

    1. La ruta de la imagen a procesar.
    2. El método a aplicar: pixel o ascii.
    3. En caso de elegir pixel:
      1. El tamaño del bloque (default=10).
      2. La cantidad de niveles de color (default=4).
    4. En caso de elegir ascii:
      1. El ancho de la imagen ASCII. Si no especifica, usar por defecto 100.
  2. Procese la imagen:

    • Si el método es pixel, aplicar el filtro de Pixel Art.
    • Si el método es ascii, aplicar la transformación a caracteres ASCII.
  3. Genere y guarde:

    • Si el método es pixel, guardar la imagen procesada.
    • Si el método es ascii, guardar el resultado en un archivo de texto.

      Archivo de texto

      Para escribir el resultado en un archivo de texto, se puede usar la siguiente función:

      # No es necesario entender el código a continuación.
      # Se verá en detalle en la clase después de los parciales
      def guardar_ascii_art(ascii_art: str, ruta_salida: str):
          with open(ruta_salida, 'w') as f:
              f.write(ascii_art)
      

Ejemplos de ejecución del programa

Ingrese la ruta de la imagen: img/marilyn.jpeg
Seleccione el método (pixel/ascii): pixel
Ingrese el tamaño del bloque (default=10): 10
Ingrese la cantidad de niveles de color (default=4): 4
Seleccione la ruta para guardar la imagen procesada: out/marilyn_pixel.png
Ingrese la ruta de la imagen: img/marilyn.jpeg
Seleccione el método (pixel/ascii): ascii
Ingrese el ancho de la imagen ASCII (default=100): 100
Seleccione la ruta para guardar el resultado: out/marilyn_ascii.txt
Ingrese la ruta de la imagen: img/desconocida.png

No se encontró la imagen. Por favor, verifique la ruta e intente nuevamente.
Ingrese la ruta de la imagen: img/marilyn.jpeg
Seleccione el método (pixel/ascii): ascii
Ingrese el ancho de la imagen ASCII (default=100): -5

El ancho de la imagen ASCII debe ser un número positivo.

Imágenes de prueba#

Se pueden descargar imágenes de prueba de esta carpeta.

Entrega#

El trabajo se realizará en grupos de hasta dos estudiantes. El desarrollo del trabajo se llevará a cabo en un repositorio privado de Github, el cual debe ser compartido con los docentes de la materia (se pueden encontrar los usuarios de los docentes aquí). La entrega del trabajo se realizará subiendo el link del repositorio a la tarea correspondiente en el campus del curso. La fecha de entrega se encuentra en la misma tarea y en el calendario del curso.

Importante: Se recuerda a los estudiantes que las entregas deben ser un producto original de cada grupo, por lo que se les pide revisar la sección 6 del programa de la materia y el Código de Honor y Ética. En caso de sospecha de copia, se citará a los grupos involucrados para una defensa oral para verificar la autoría de la entrega. En caso de no poder defender la autoría, los profesores estarán obligados a elevar el caso al comité de ética de la universidad.