Cómo crear arte generativo en menos de 100 líneas de código

El arte generativo, como cualquier tema de programación, puede resultar intimidante si nunca lo ha probado antes. Siempre me ha interesado porque me encanta encontrar nuevas formas de utilizar la programación de manera creativa. Además, creo que cualquiera puede apreciar el concepto de obra de arte que literalmente se crea a sí misma.

¿Qué es el arte generativo?

El arte generativo es el resultado de un sistema que toma sus propias decisiones sobre la pieza, en lugar de un humano. El sistema podría ser tan simple como un solo programa de Python, siempre que tenga reglas y algún aspecto de aleatoriedad.

Con la programación, es bastante sencillo crear reglas y restricciones. Eso es todo lo que son las declaraciones condicionales. Habiendo dicho eso, encontrar formas de hacer que estas reglas creen algo interesante puede ser complicado.

El Juego de la Vida es un famoso conjunto de cuatro reglas simples que determinan el "nacimiento" y la "muerte" de cada célula del sistema. Cada una de las reglas juega un papel en el avance del sistema a través de cada generación. Aunque las reglas son simples y fáciles de entender, rápidamente comienzan a surgir patrones complejos que, en última instancia, generan resultados fascinantes.

Las reglas pueden ser responsables de crear la base de algo interesante, pero incluso algo tan emocionante como el Juego de la vida de Conway es predecible. Dado que las cuatro reglas son los factores determinantes de cada generación, la forma de producir resultados imprevisibles es introducir la aleatorización en el estado inicial de las células. Comenzar con una matriz aleatoria hará que cada ejecución sea única sin necesidad de cambiar las reglas.

Los mejores ejemplos de arte generativo son los que encuentran una combinación de previsibilidad y aleatoriedad para crear algo interesante que también es estadísticamente irreproducible .

¿Por qué deberías probarlo?

No todos los proyectos paralelos son iguales, y el arte generativo puede no ser algo en lo que te sientas inclinado a dedicar tiempo. Sin embargo, si decide trabajar en un proyecto, puede esperar estos beneficios:

  • Experiencia : el arte generativo es solo otra oportunidad para perfeccionar algunas habilidades nuevas y antiguas. Puede servir como puerta de entrada a la práctica de conceptos como algoritmos, estructuras de datos e incluso nuevos lenguajes.
  • Resultados tangibles : en el mundo de la programación rara vez vemos algo físico que surja de nuestros esfuerzos, o al menos yo no. En este momento tengo algunos carteles en mi sala de estar que muestran impresiones de mi arte generativo y me encanta que la programación sea responsable de eso.
  • Proyectos atractivos : todos hemos tenido la experiencia de explicar un proyecto personal a alguien, posiblemente incluso durante una entrevista, sin una manera fácil de transmitir el esfuerzo y los resultados del proyecto. El arte generativo habla por sí mismo, y la mayoría de las personas quedarán impresionadas con sus creaciones, incluso si no pueden comprender completamente los métodos.

¿Por dónde deberías empezar?

Comenzar con el arte generativo es el mismo proceso que cualquier proyecto, el paso más importante es tener una idea o encontrar una sobre la que construir. Una vez que tenga un objetivo en mente, podrá comenzar a trabajar en la tecnología necesaria para lograrlo.

La mayoría de mis proyectos de arte generativo se han realizado en Python. Es un lenguaje bastante fácil de acostumbrar y tiene algunos paquetes increíbles disponibles para ayudar con la manipulación de imágenes, como Pillow.

Afortunadamente para ti, no hay necesidad de buscar muy lejos un punto de partida, porque a continuación te proporcioné un código para que juegues.

Generador de Sprite

Este proyecto comenzó cuando vi una publicación que mostraba un generador de sprites escrito en Javascript. El programa creó sprites artísticos de 5x5 píxeles con algunas opciones de colores aleatorias y su salida se asemejaba a los invasores espaciales multicolores.

Sabía que quería practicar la manipulación de imágenes en Python, así que pensé que podría intentar recrear este concepto por mi cuenta. Además, pensé que podría ampliarlo ya que el proyecto original era tan limitado en el tamaño de los sprites. Quería poder especificar no solo el tamaño, sino también el número de ellos e incluso el tamaño de la imagen.

Aquí hay un vistazo a dos resultados diferentes de la solución con la que terminé:

Estas dos imágenes no se parecen en absoluto, pero ambas son el resultado del mismo sistema. Sin mencionar que, debido a la complejidad de la imagen y la aleatoriedad de la generación de sprites, existe una probabilidad extremadamente alta de que incluso con los mismos argumentos, estas imágenes siempre serán únicas. Me encanta.

El entorno

Si quieres empezar a jugar con el generador de sprites, primero tienes que hacer un pequeño trabajo de base.

Configurar un entorno adecuado con Python puede ser complicado. Si no ha trabajado con Python antes, probablemente necesite descargar Python 2.7.10. Inicialmente tuve problemas para configurar el entorno, por lo que si comienza a tener problemas, puede hacer lo que hice y buscar entornos virtuales. Por último, pero no menos importante, asegúrese de tener Pillow instalado también.

Una vez que haya configurado el entorno, puede copiar mi código en un archivo con extensión .py y ejecutarlo con el siguiente comando:

python spritething.py [SPRITE_DIMENSIONS] [NUMBER] [IMAGE_SIZE]

Por ejemplo, el comando para crear la primera matriz de sprites desde arriba sería:

python spritething.py 7 30 1900

El código

import PIL, random, sysfrom PIL import Image, ImageDraw
origDimension = 1500
r = lambda: random.randint(50,215)rc = lambda: (r(), r(), r())
listSym = []
def create_square(border, draw, randColor, element, size): if (element == int(size/2)): draw.rectangle(border, randColor) elif (len(listSym) == element+1): draw.rectangle(border,listSym.pop()) else: listSym.append(randColor) draw.rectangle(border, randColor)
def create_invader(border, draw, size): x0, y0, x1, y1 = border squareSize = (x1-x0)/size randColors = [rc(), rc(), rc(), (0,0,0), (0,0,0), (0,0,0)] i = 1
 for y in range(0, size): i *= -1 element = 0 for x in range(0, size): topLeftX = x*squareSize + x0 topLeftY = y*squareSize + y0 botRightX = topLeftX + squareSize botRightY = topLeftY + squareSize
 create_square((topLeftX, topLeftY, botRightX, botRightY), draw, random.choice(randColors), element, size) if (element == int(size/2) or element == 0): i *= -1; element += i
def main(size, invaders, imgSize): origDimension = imgSize origImage = Image.new('RGB', (origDimension, origDimension)) draw = ImageDraw.Draw(origImage)
 invaderSize = origDimension/invaders padding = invaderSize/size
 for x in range(0, invaders): for y in range(0, invaders): topLeftX = x*invaderSize + padding/2 topLeftY = y*invaderSize + padding/2 botRightX = topLeftX + invaderSize - padding botRightY = topLeftY + invaderSize - padding
 create_invader((topLeftX, topLeftY, botRightX, botRightY), draw, size)
 origImage.save("Examples/Example-"+str(size)+"x"+str(size)+"-"+str(invaders)+"-"+str(imgSize)+".jpg")
if __name__ == "__main__": main(int(sys.argv[1]), int(sys.argv[2]), int(sys.argv[3]))

Esta solución está lejos de ser perfecta, pero muestra que crear arte generativo no requiere mucho código. Haré todo lo posible para explicar las piezas clave.

La función principal comienza creando la imagen inicial y determinando el tamaño de los sprites. Los dos bucles for se encargan de definir un borde para cada sprite, básicamente dividiendo las dimensiones de la imagen por la cantidad de sprites solicitados. Estos valores se utilizan para determinar las coordenadas de cada uno.

Ignoremos el relleno y echemos un vistazo a la imagen de abajo. Imagina que cada uno de los cuatro cuadrados representa un objeto con un tamaño de 1. El borde que se pasa a la siguiente función se refiere a las coordenadas superior izquierda e inferior derecha. Entonces, la tupla del sprite superior izquierdo sería (0,0,1,1) mientras que la tupla del sprite superior derecho sería (1,0,2,1). Estos se utilizarán como las dimensiones y las coordenadas base para los cuadrados de cada objeto.

La función create_invader determina el borde de cada cuadrado dentro del sprite. El mismo proceso para determinar el borde se aplica aquí y se representa a continuación, solo que en lugar de la imagen completa, estamos usando un borde predeterminado para trabajar dentro. Estas coordenadas finales para cada cuadrado se usarán en la siguiente función para dibujar el sprite.

Para determinar el color, se utiliza una matriz simple de tres tuplas RGB aleatorias y tres negros para simular un 50% de probabilidad de ser dibujado. Las funciones lambda cerca de la parte superior del código son responsables de generar los valores RGB.

El verdadero truco de esta función es crear simetría. Cada cuadrado está emparejado con un valor de elemento. En la imagen a continuación, puede ver que los valores de los elementos aumentan a medida que alcanzan el centro y luego disminuyen. Los cuadrados con valores de elementos coincidentes se dibujan con el mismo color.

Cuando create_square recibe sus parámetros de create_invader , utiliza una cola y los valores de los elementos anteriores para garantizar la simetría. La primera aparición de los valores tiene sus colores empujados a la cola y los cuadrados reflejados hacen saltar los colores.

Me doy cuenta de lo difícil que es leer y comprender la solución de otra persona para un problema, y ​​la aspereza del código ciertamente no ayuda con su complejidad, pero espero que tenga una idea bastante buena de cómo funciona. En última instancia, sería increíble si pudiera eliminar mi código por completo y encontrar una solución completamente diferente.

Conclusión

El arte generativo lleva tiempo para apreciarlo completamente, pero vale la pena. Me encanta poder combinar la programación con un visual más tradicional, y definitivamente he aprendido mucho en cada uno de mis proyectos.

En general, puede haber proyectos más útiles para realizar y el arte generativo puede no ser algo con lo que necesite experiencia, pero es muy divertido y nunca se sabe cómo podría separarse de la multitud.

¡Gracias por leer!