Geometria Primitiva e Transformações 2D com Python
- Vinicius Goia
- 25 de set. de 2023
- 5 min de leitura

Entender como as imagens são formadas e o que as compõem são conhecimentos necessários para uma jornada em Visão Computacional. A partir do momento em que a principal matéria-prima do trabalho é baseada em imagem, fixar os princípios e as transformações tornam-se elementos úteis.
Aqui neste breve artigo você verá alguns conceitos, fórmulas e algumas aplicações simples utilizando a linguagem de programação Python.
Ponto, Linha e Formas Geométricas
Um ponto 2D, que também pode ser considerado um pixel em uma imagem, é representado por um par de valores:
Em geometria computacional, costuma-se utilizar as coordenadas homogêneas, que nada mais é do que uma maneira de facilitar certas operações e representações. Sendo assim, um ponto 2D representado através de coordenadas homogêneas possui a seguinte forma:
O elemento de valor 1 comumente é representado pela letra w.
Uma equação linear homogênea é representada pela seguinte equação:
Em Python, podemos representar um ponto em um gráfico através dos seguintes comandos:
#Importação de bibliotecas necessárias
import numpy as np
import matplotlib.pyplot as plt
#Definição da matriz de um ponto
ponto = np.array([5,3,1]).transpose()
#Definição do plano de imagem
fig, ax = plt.subplots()
#Plotagem da figura original
plt.plot(ponto[0],ponto[1],'r*')
fig.tight_layout()
plt.show()
Como observado acima, através do numpy array criou-se a matriz de um ponto homogêneo e aplicou-se a transposta para que nossos valores assumissem o formato padrão apresentado no início do artigo. Na plotagem, indicamos em qual posição se encontra o elemento x e y, obtendo o seguinte resultado.

Seguindo esta lógica, iremos criar uma matriz para 3 pontos que simulem um triângulo equilátero. Para melhorar a visualização, iremos adicionar um parâmetro na plotagem que realiza a ligação dos pontos através de uma reta. Um detalhe importante aqui é que adicionaremos o primeiro par de pontos ao final de nossa matriz para que a figura seja devidamente representada.
#Definição de uma matriz qualquer. Neste caso, um triângulo. Observe que adicionamos o primeiro par de pontos ao final da matriz para uma melhor representação na plotagem.
triangle = np.array([[1,1,1],[1,2,1],[2,1,1],[1,1,1]]).transpose()
#Definição do plano de imagem
fig, ax = plt.subplots()
#Plotagem da figura original
plt.plot(triangle[0],triangle[1],'r')
fig.tight_layout()
plt.show()

Transformações 2D
TRANSLAÇÃO
A translação é a movimentação da figura pelo gráfico, preservando sua orientação, tamanho, ângulos, paralelismos e linhas retas. Desta maneira, tem-se apenas dois graus de liberdade: a movimentação pelo eixo x e y.
É representada pela seguinte equação:
Sendo I uma matriz identidade. Desta forma, temos:
Utilizando nossa matriz que representa um triângulo, criaremos uma função que recebe os pares de coordenadas x e y de cada ponto e aplica a transformação de translação. Ao final, é plotado a imagem original e a imagem transformada.
def translation (matriz,x,y):
"""Função para translação. Retorna um gráfico com a figura original e a figura deslocada"""
#Definição do elemento de translação
tf = np.array([[1,0,x],[0,1,y],[0,0,1]])
#Definição do plano de imagem
fig, ax = plt.subplots()
#Fixação dos eixos para que as imagens possuam a mesma proporção.
ax.axis('equal')
#Novos elementos vazios para receber os valores deslocados
newx= []
newy= []
#Loop de deslocamento para cada ponto
for i in matriz.transpose():
#Operação de deslocamento
new = tf @ i
#Novos elementos fixados
newx.append(new[0])
newy.append(new[1])
#Plotagem da nova figura deslocada
plt.plot(newx,newy,'go-')
#Plotagem da figura original
plt.plot(matriz[0],matriz[1],'ro-')
fig.tight_layout()
plt.show()
#Execução da função
translation(triangle,1,1)

ROTAÇÃO E TRANSLAÇÃO
Neste caso, o desenho é movido e rotacionado no gráfico a partir do ponto de origem, preservando seu tamanho, ângulos, paralelismos e linhas retas. Desta maneira, tem-se 3 graus de liberdade: a movimentação pelo eixo x e y e a orientação.
É representada pela seguinte equação:
Desta forma, temos:
Através da criação de uma função em Python, testaremos a fórmula acima para transformar nossa matriz inicial, a qual referencia a forma de um triângulo.
#Importação de biblioteca necessária para conversão de ângulos
import math
def rotation_translation (matriz,x,y,an):
"""Função para rotação juntamente com translação. Retorna um gráfico com a figura original e a figura rotacionada e deslocada"""
#Conversão do ângulo de rotação em radianos
rad = math.radians (an)
#Definição do elemento de rotação e translação
tf = np.array([[math.cos(rad),-math.sin(rad),x],[math.sin(rad),math.cos(rad),y],[0,0,1]])
#Definição do plano de imagem
fig, ax = plt.subplots()
#Fixação dos eixos para que as imagens possuam a mesma proporção.
ax.axis('equal')
#Novos elementos vazios para receber os valores deslocados
newx= []
newy= []
#Loop de deslocamento e rotação para cada ponto
for i in matriz.transpose():
#Operação de deslocamento e rotação
new = tf @ i.transpose()
#Novos elementos fixados
newx.append(new[0])
newy.append(new[1])
#Plotagem da nova figura rotacionada e deslocada
plt.plot(newx,newy,'go-')
#Plotagem da figura original
plt.plot(matriz[0],matriz[1],'ro-')
fig.tight_layout()
plt.show()
#Execução da função
rotation_translation(triangle,0.5,0.5,10)

Observa-se que a figura foi deslocada e rotacionada a partir de ponto de origem (0,0). Nessa operação vale atentar-se na transformação do ângulo para radianos.
ESCALA, ROTAÇÃO E TRANSLAÇÃO
Adicionaremos às nossas transformações um coeficiente de escala. Representado pela letra s, é um número arbitrário que multiplica os valores da matriz, aumentando ou diminuindo seu tamanho.
A sequência de transformações é representada pela seguinte equação:
Desta forma, com a nossa função anterior escrita em Python, conseguimos adicionar esse coeficiente multiplicador e ajustar a equação para aumentar a imagem, preservando ângulos, paralelismos e linhas retas.
def scale_rotation_translation (matriz,x,y,an,s):
"""Função para escala e rotação juntamente com translação. Retorna um gráfico com a figura original e a figura em escala, rotacionada e deslocada"""
#Conversão do ângulo de rotação em radianos
rad = math.radians (an)
#Definição do elemento de rotação e translação
tf = np.array([[math.cos(rad),-math.sin(rad),x],[math.sin(rad),math.cos(rad),y],[0,0,1]])
#Definição do plano de imagem
fig, ax = plt.subplots()
#Fixação dos eixos para que as imagens possuam a mesma proporção.
ax.axis('equal')
#Novos elementos vazios para receber os valores deslocados
newx= []
newy= []
#Loop de escala, deslocamento e rotação para cada ponto
for i in matriz.transpose():
#Operação de escala, deslocamento e rotação
new = s*tf @ i.transpose()
#Novos elementos fixados
newx.append(new[0])
newy.append(new[1])
#Plotagem da nova figura rotacionada e deslocada
plt.plot(newx,newy,'go-')
#Plotagem da figura original
plt.plot(matriz[0],matriz[1],'ro-')
fig.tight_layout()
plt.show()
#Execução da função
scale_rotation_translation(triangle,0.5,0.5,10,2)

TRANSFORMAÇÃO AFIM
Consiste na deformação da imagem através da multiplicação de uma matriz arbitrária. Diferentemente da escala, onde mantinha-se a proporção da multiplicação para todos os componentes da matriz, essa transformação altera os pontos através da matriz de entrada.
A transformação afim é representada pela equação abaixo:
Onde A é uma matriz arbitrária.
Desta maneira, iremos definir uma matriz qualquer para criarmos uma função de transformação afim, desta vez na representação de um quadrado.
#Criação de uma matriz (quadrado)
square = np.array([[1,1,1],[1,2,1],[2,2,1],[2,1,1],[1,1,1]]).transpose()
#Criação de uma matriz qualquer
matriz_a = np.array([[1,2,1],[3,3,1],[3,1,1],[3,2,1]])
def affine (square,matriz_a):
"""Função para deformação. Retorna um gráfico com a figura original e a figura deformada"""
#Definição do plano de imagem
fig, ax = plt.subplots()
#Fixação dos eixos para que as imagens possuam a mesma proporção
ax.axis('equal')
#Novos elementos vazios para receber os valores deslocados
newx= []
newy= []
#Loop de deformação
for i in matriz.transpose():
#Operação de deformação
new = matriz_a @ i.transpose()
#Novos elementos fixados
newx.append(new[0])
newy.append(new[1])
#Plotagem da nova figura rotacionada e deslocada
plt.plot(newx,newy,'go-')
#Plotagem da figura original
plt.plot(matriz[0],matriz[1],'ro-')
#Execução da função
affine (triangle,matriz_a)

Observa-se, na transformação, que mantivemos apenas os paralelismos e linhas retas.
Conclusão
Apesar dos conceitos e funções apresentados possuírem uma abordagem simples, serão de extrema utilidade nas aplicações de Visão Computacional e Processamento de Imagens. Estas são áreas as quais as tecnologias atuais tornam o processo de desenvolvimento mais dinâmico e prático. Porém, a base deve ser solidificada para que as implementações sejam realizadas de forma ágil, precisa e criativa, o que, sem essas ferramentas, não seriam possíveis.
Comments