giovani_ex4 - Transformações Geométricas

  1. Equação matemática do uso indexado imagens no Python.

2. Estudar a função iaffine da toolbox ia636. Ver como funciona exercitando com valores interessantes. Entender como funciona a sua codificação.

 1 print "\n :: EXEMPLO COM TRANSLAÇÃO :: \n"
 2 img = array([[0, 0, 0, 0, 0],[0, 1, 2, 3, 0],[0, 4, 5, 6, 0],[0, 0, 0, 0, 0]])
 3 
 4 print "\n img - Imagem simples: \n",img
 5 print "Origem img[0,0] : ",img[0,0]
 6 
 7 # Translada a imagem para o conteudo 4 ser a origem...
 8 Tt = array([[1, 0, 2],[0, 1, 1],[0, 0, 1]])
 9 print "\n Tt - Matriz de Translação: \n",Tt
10 
11 ex1 = iaffine(img,Tt)
12 
13 print "\n ex1 - Resultado da função iaffine: \n",ex1
14 print "Origem ex1[0,0] : ",ex1[0,0]
:: EXEMPLO COM TRANSLAÇÃO :: 


 img - Imagem simples: 
[[0 0 0 0 0]
 [0 1 2 3 0]
 [0 4 5 6 0]
 [0 0 0 0 0]]
Origem img[0,0] :  0

 Tt - Matriz de Translação: 
[[1 0 2]
 [0 1 1]
 [0 0 1]]

 ex1 - Resultado da função iaffine: 
[[0 0 0 0 0]
 [0 1 2 3 0]
 [0 4 5 6 0]
 [0 0 0 0 0]]
Origem ex1[0,0] :  0
  • Visto o exemplo acima, provavelmente exista alguma incompatibilidade que não estou descobrindo, pois o resultado da função deveria retornar a origem ex1[0,0] = 4,o que não esta ocorrendo. Algumas observações foram avaliadas como as origens da imagem sendo X o eixo das linhas e Y o eixo das colunas, bem como montar a matriz de transformação de tal modo que ao aplicar a equação descrita em iaffine pudesse retornar o esperado, coisa que não aconteceu!

  • A intenção deste segundo exemplo é rotacionar a imagem em 180 graus na posição img[2,3] cujo valor é 6. Conforme visto em sala, para realizar esta operação a matriz de transformação deverá executar os seguintes passo:

    1° translação [-2,-3]

    2° Rotação de 180°

    3° translação [2,3]

:: EXEMPLO COM ROTAÇÃO E TRANSLAÇÃO :: 


 img - Imagem simples: 
[[0 0 0 0 0]
 [0 1 2 3 0]
 [0 4 5 6 0]
 [0 0 0 0 0]]
Origem img[0,0] :  0

 T1 - Matriz de Translação: 
[[ 1  0 -2]
 [ 0  1 -3]
 [ 0  0  1]]

 T2 - Matriz de Rotação: 
[[-0.59846007 -0.80115264  0.        ]
 [ 0.80115264 -0.59846007  0.        ]
 [ 0.          0.          1.        ]]

 T3 - Matriz de Translação: 
[[1 0 2]
 [0 1 3]
 [0 0 1]]

 T - matriz de Transformação: 
[[-0.59846007 -0.80115264  5.60037805]
 [ 0.80115264 -0.59846007  3.19307494]
 [ 0.          0.          1.        ]]

 T_inv - matriz inv. de Transformação: 
[[-0.59846007  0.80115264  0.79346223]
 [-0.80115264 -0.59846007  6.39768548]
 [ 0.          0.          1.        ]]

 ex2_T - Resultado do exemplo 2: 
[[0 0 0 0 0]
 [0 0 0 0 0]
 [0 0 0 0 0]
 [0 0 0 0 0]]

 ex2_T_inv - Resultado do exemplo 2: 
[[0 0 0 0 0]
 [0 0 0 0 0]
 [0 0 0 0 0]
 [0 0 0 0 0]]
  • Como pode perceber as respostas obtidas são bastante diferentes da resposta desejada, um simples ponto que comprovaria isso seria a origem da rotação que em todos os casos ela deveria estar na mesma posição.
  1. Fazer uma nova função, utilizando o mapeamento direto.
  2. Opcionalmente, melhorar a função iaffine.
 1 from numpy import *
 2 
 3 #----------------------------------------------------------------------------
 4 def giffine(f,T,option='INVERSE'):
 5 
 6     nlin,ncol = iameshgrid(arange(f.shape[0]),arange(f.shape[1]))
 7 
 8     # Transforma matriz em vetor
 9     nlin = ravel(nlin)
10     ncol = ravel(ncol)
11     uns = ones(ncol.size)
12 
13     # Monta os indices para multiplicação
14     indices = concatenate((nlin,ncol,uns))
15     indices = resize(indices,(3,nlin.size))    #print"\n Indices: \n", indices
16                                                #print nlin,ncol
17 
18     # Verifica o modo de operaçao: 'INVERSE' or 'DIRECT'
19     if option == 'INVERSE':
20         t = linalg.inv(T)
21     else:
22         t = T
23 
24     # Realiza a Transformação dos indices
25     transf_xy = around(dot(t,indices))
26     xy = transf_xy[0:2,:]                       # Recebe o vetor de indices do eixo x e y
27                                                 #print "\n xy : \n", xy
28 
29     # Verifica se algum indice-valor esta menor do que 0
30     limite = zeros(xy.shape)                    # Assume o limite sendo 0
31     mini = minimum(xy,limite)                   # Minimo entre as coordenas existentes e a posição inicial [0,0]
32                                                 #print "\n mini : \n", mini
33     soma = mini.sum(axis=0)                     # Soma os eixos X e Y para saber qual a coordenada fora do plano
34                                                 #print "\n soma : \n", soma
35     id_nozero = soma.nonzero()                  # Pega o indice das coordenadas fora do limite em X e Y
36                                                 #print "\n id_nozero : \n", id_nozero[0]
37                                                 #print"\n coordenadas: \n", xy[0,id_nozero[0]]
38     # Atribui a essas coordenadas o indice do ultimo pixel
39     xy[0,id_nozero[0]] = f.shape[0]-1
40     xy[1,id_nozero[0]] = f.shape[1]-1
41                                                 #print "\n shape[0]:",f.shape[0]
42                                                 #print "\n shape[1]:",f.shape[0]
43                                                 #print "\n xy: \n",xy
44     # Verifica se algum indice-valor esta passando do max de linhas ou colunas
45     limite = zeros(xy.shape)                    # Cria o vetor de manipulação
46     limite[0,:] = f.shape[0]-1
47     limite[1,:] = f.shape[1]-1
48                                                 #print "\n limite : \n", limite
49     maxi = maximum(xy,limite)                   # Maximo entre as coordenas existentes e a posição final [0,0]
50                                                 #print "\n maxi : \n", maxi
51     variacao = maxi - limite                    # Verifica qual a variação em relação ao quanto excedeu...
52                                                 #print "\n variacao : \n", variacao
53     soma_sup = variacao.sum(axis=0)             # Soma os eixos X e Y para saber qual a coordenada fora do plano
54     id_nozero = soma_sup.nonzero()              # Pega o indice das coordenadas fora do limite em X e Y
55     xy[0,id_nozero[0]] = f.shape[0]-1
56     xy[1,id_nozero[0]] = f.shape[1]-1
57                                                 #print "\n id_nozero superior: \n",id_nozero[0]
58                                                 #print "\n xy: \n",xy
59                                                 #print "\n antes variacao : \n", variacao
60     x = resize(xy[0:],(f.shape[1],f.shape[0]) )
61     x = x.transpose()
62     y = resize(xy[1:],(f.shape[1],f.shape[0]) )
63     y = y.transpose()
64                                                 #print "\n result x: \n", x
65                                                 #print "\n result y: \n", y
66     g = zeros(f.shape)
67 
68     if option == 'INVERSE':
69         g = f[x.astype(int),y.astype(int)]
70     else:
71         g[x.astype(int),y.astype(int)] = f
72 
73     return g
74 
75 #----------------------------------------------------------------------------
  • Uma das considerações ao se fazer esta função, foi justamente o fato das coordenadas cairem fora do espaço dominio da imagem... Realmente isso não é tão trivial de ser solucionado tomando como base a lógica de programação matricial. A função criada ficou bastante interessante, porém alguns erros são visíveis! Como podemos observar no exemplo didático que segue abaixo:
img - Imagem simples: 
[[0 0 0 0 0]
 [0 1 2 3 0]
 [0 4 5 6 0]
 [0 0 0 0 7]]

 T1 - Matriz de Translação: 
[[ 1  0 -2]
 [ 0  1 -3]
 [ 0  0  1]]

 Resultado com T1: 
[[ 6.  0.  0.  0.  0.]
 [ 0.  7.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]]

 T3 - Matriz de Translação: 
[[1 0 2]
 [0 1 3]
 [0 0 1]]

 Resultado com T2: 
[[ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  7.]]
  • No entanto, este erro não é expressivo quando trabalhado com imagens grande... segue o exemplo:

imagem original

imagem Transladada

imagem Rotacionada 12°

imagem Rotacionada 12° (inversa)

imagem Transladada (inversa)