Fazendo a arte generativa “Schotter” em Python com numpy e opencv
Arte generativa é um tipo de arte que é feito em partes ou totalmente de forma automatizada. Neste Artigo vamos implementar uma arte generativa bem conhecida(“Georg Ness, Schotter”) em Python sem utilizar bibliotecas próprias para isso, apenas com manipulação de array com Numpy.
Para fazer artes generativas em Python podemos utilizar algumas bibliotecas próprias para isso, mas acredito que fazer com manipulação de array seja uma boa forma de fazer, pois permite aprender vários conceitos e técnicas de programação que podemos utilizar em outros contextos.
Nesse artigo vamos utilizar a biblioteca Numpy, caso você já conheça Python a algum tempo provavelmente já utilizou essa biblioteca alguma vez, os conceitos básicos da linguagem são indispensáveis para esse tutorial, recomendo especialmente esse artigo sobre listas em python.
Preparando o ambiente para o desenvolvimento da arte generativa
Antes de começarmos a desenvolver a arte generativa, precisamos preparar o ambiente para isso, vamos utilizar apenas duas bibliotecas, que são “opencv-python” e “numpy”. Para instalar as bibliotecas utilizaremos pip, mas você pode fazer com anaconda ou de outras formas caso queira, com pip faríamos da seguinte forma:
pip install opencv-python
pip install numpy
Além disso vamos criar um arquivo chamado main.py
Iniciando o desenvolvimento da arte generativa criando a imagem
Vamos começar a desenvolver a arte generativa, primeiro vamos importar as bibliotecas:
import cv2
import numpy as np
Além disso vamos utilizar as bibliotecas padrões do Pyhon math
e random
.
import math
import random
Primeiramente vamos criar uma imagem de 2340px de altura por 1080px de largura, após iremos colorir essa imagem de branco.
img = np.zeros((2340, 1080, 1), np.uint8)
img[:, :] = 255
Função para desenhar o retângulo
Vamos fazer uma função que desenha um retângulo angulado na imagem, vamos utilizar a biblioteca “cv2”, para isso vamos criar uma função chamada “draw_angled_rec”:
def draw_angled_rec(x0, y0, width, height, angle, img, color, line_w):
_angle = angle * math.pi / 180.0
b = math.cos(_angle) * 0.5
a = math.sin(_angle) * 0.5
pt0 = (int(x0 - a * height - b * width),
int(y0 + b * height - a * width))
pt1 = (int(x0 + a * height - b * width),
int(y0 - b * height - a * width))
pt2 = (int(2 * x0 - pt0[0]), int(2 * y0 - pt0[1]))
pt3 = (int(2 * x0 - pt1[0]), int(2 * y0 - pt1[1]))
cv2.line(img, pt0, pt1, color, line_w, lineType=cv2.LINE_AA)
cv2.line(img, pt1, pt2, color, line_w, lineType=cv2.LINE_AA)
cv2.line(img, pt2, pt3, color, line_w, lineType=cv2.LINE_AA)
cv2.line(img, pt3, pt0, color, line_w, lineType=cv2.LINE_AA)
return img
Gerando a arte
Agora vamos gerar a arte, primeiro iremos calcular a largura da imagem dividindo por 13 para termos o valor do lado dos quadrados:
lado_q = img.shape[1] / 13
Faremos dois loops, um para cada linha e outro para cada coluna, para desenhar os quadrados vamos utilizar a função “draw_angled_rec”, e iremos gerar o ângulo baseado em uma variável chamada “emb” de embaralhamento, que será incrementada no final de cada linha da imagem, ou seja, ficará mais embaralhado cada vez que uma linha foi desenhada.
emb = 0
for y in range(int(lado_q // 2), img.shape[0] - int(lado_q), int(lado_q)):
for x in range(int(lado_q // 2), img.shape[1] - int(lado_q), int(lado_q)):
img = draw_angled_rec(random.randint((x + lado_q // 2) -
emb, (x + lado_q // 2) + emb),
random.randint((y + lado_q // 2) -
emb, (y + lado_q // 2) + emb),
lado_q, lado_q,
random.uniform(float(f"-{emb}"), emb),
img, 0, 4)
emb += random.randint(0, 3)
Agora vamos salvar a imagem em um arquivo, para isso vamos utilizar a biblioteca “cv2”, da seguinte forma:
cv2.imwrite("art.png", img)
Conclusão
O código final completo está logo abaixo:
import math
import random
import cv2
import numpy as np
img = np.zeros((2340, 1080, 1), np.uint8)
img[:, :] = 255
def draw_angled_rec(x0, y0, width, height, angle, img, color, line_w):
_angle = angle * math.pi / 180.0
b = math.cos(_angle) * 0.5
a = math.sin(_angle) * 0.5
pt0 = (int(x0 - a * height - b * width),
int(y0 + b * height - a * width))
pt1 = (int(x0 + a * height - b * width),
int(y0 - b * height - a * width))
pt2 = (int(2 * x0 - pt0[0]), int(2 * y0 - pt0[1]))
pt3 = (int(2 * x0 - pt1[0]), int(2 * y0 - pt1[1]))
cv2.line(img, pt0, pt1, color, line_w, lineType=cv2.LINE_AA)
cv2.line(img, pt1, pt2, color, line_w, lineType=cv2.LINE_AA)
cv2.line(img, pt2, pt3, color, line_w, lineType=cv2.LINE_AA)
cv2.line(img, pt3, pt0, color, line_w, lineType=cv2.LINE_AA)
return img
lado_q = img.shape[1] / 13
emb = 0
for y in range(int(lado_q // 2), img.shape[0] - int(lado_q), int(lado_q)):
for x in range(int(lado_q // 2), img.shape[1] - int(lado_q), int(lado_q)):
img = draw_angled_rec(random.randint((x + lado_q // 2) -
emb, (x + lado_q // 2) + emb),
random.randint((y + lado_q // 2) -
emb, (y + lado_q // 2) + emb),
lado_q, lado_q,
random.uniform(float(f"-{emb}"), emb),
img, 0, 4)
emb += random.randint(0, 3)
cv2.imwrite("art.png", img)
Ao final da execução do código, a imagem gerada será salva em um arquivo chamado “art.png”, o resultado será semelhante( porém diferente) ao da imagem abaixo: