Exercício 4 de IA639-2009

Autor:Matias
Data:02/04/2009

Questão 1

Supondo que temos uma "imagem" da seguinte forma:

1 imagem = reshape(range(15),[3,5])
2 print imagem
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]

A forma utilizada no exercício anterior, usando o meshgrid para mapear essa imagem em uma nova (nesse caso, identica), era:

1 X,Y=meshgrid(range(0,5),range(0,3))
2 A=imagem[Y,X]
3 
4 print "X =",X
5 print "Y =",Y
6 A=imagem[Y,X]
7 print "A =",A
X = [[0 1 2 3 4]
 [0 1 2 3 4]
 [0 1 2 3 4]]
Y = [[0 0 0 0 0]
 [1 1 1 1 1]
 [2 2 2 2 2]]
A = [[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]

Ou, se quisermos reduzir o mapeamento no eixo X:

1 X=X/2
2 print "X =",X
3 print "Y =",Y
4 A=imagem[Y,X]
5 print "A =",A
X = [[0 0 1 1 2]
 [0 0 1 1 2]
 [0 0 1 1 2]]
Y = [[0 0 0 0 0]
 [1 1 1 1 1]
 [2 2 2 2 2]]
A = [[ 0  0  1  1  2]
 [ 5  5  6  6  7]
 [10 10 11 11 12]]

O python faz portanto, uma busca, indice a indice, nos valores das matrizes X e Y, e utiliza esses valores como indices para pegar um valor da matriz B.

Isso implica em:
  • As dimensões de X e Y devem ser iguais, e será a mesma das dimensões de A.
  • Os valores presentes nas matrizes X,Y, não podem exceder as dimensões da matriz IMAGEM que eles representam.

Tentando colocar matemáticamente:

Temos as seguintes matrizes:

Com as seguintes restrições:

Finalmente, os elementos da matriz A, são dados da seguinte forma:

Questão 2

A função iaffine() da toolbox de IA636 realiza transformações afins em uma imagem. Essas transformações são passadas já na forma matricial para a função, que então a aplica sobre as coordenadas da imagem.

Para facilitar o estudo, foram criadas as seguintes pequenas funções para retornar matrizes de transformações:

 1 def rotate(angulo):
 2     return [[cos(angulo),-sin(angulo),0],
 3             [sin(angulo),cos(angulo),0],
 4             [0,0,1]]
 5 
 6 def scale(Sx,Sy):
 7     return [[Sx,0,0],
 8             [0,Sy,0],
 9             [0,0,1]]
10 
11 def trans(Dx,Dy):
12     return [[1,0,Dx],
13             [0,1,Dy],
14             [0,0,1]]

Utilizando a função iaffine(), vamos, como no exercício 3, reduzir e aumentar uma imagem:

1 imagem = mmreadgray('boat.ppm')
2 T = scale(0.5,0.5)
3 adshow(iaffine(imagem,T),title = "iaffine(): Escalonamento de 0.5 nos dois eixos.")
4 T = scale(2,2)
5 adshow(iaffine(imagem,T),title = "iaffine(): Escalonamento de 2 nos dois eixos.")

iaffine(): Escalonamento de 0.5 nos dois eixos.

iaffine(): Escalonamento de 2 nos dois eixos.

Com esse pequeno exemplo, já se pode fazer algumas observações importantes sobre a função:

  • As dimensões da imagem não são alteradas, mesmo que a imagem transformada ocupe mais ou menos pixels que a original.
  • Todos os pixels na imagem transformada são preenchidos, o que é esperado já que essa função faz mapeamento inverso.
  • Pixels da imagem transformada que não tem mapeamento na imagem original, são colocados como tendo uma cor igual ao do pixel vizinho.

Agora vejamos mais alguns exemplos da função affine():

1 T = scale(-1,1)
2 adshow(iaffine(imagem,T),title = "iaffine(): Escaloamento -1x 1y")
3 
4 T = trans(-30,80)
5 adshow(iaffine(imagem,T),title = "iaffine(): Deslocamento -30px em X e 80px em Y")
6 
7 T = rotate(math.pi/6)
8 adshow(iaffine(imagem,T),title = "iaffine(): Rotação PI/6")

iaffine(): Escaloamento -1x 1y

iaffine(): Deslocamento -30px em X e 80px em Y

iaffine(): Rotação PI/6

As duas limitações importantes que apareceram foram:

  • Não suporte para deslocamento.
  • Mesmo que a imagem esteja praticamente toda oculta, a resolução e coordednadas da imagem original são mantidas.

Somadas, essas limitações implicam que não se pode usar somente a função iaffine para cirar uma imagem invertida no eixo X por exemplo.

Questão 3

A seguinte função foi criada para fazer o mapeamento direto.

 1 def iaffine_2(imagem, transf,manter_tamanho):
 2     tamanho_y,tamanho_x = imagem.shape
 3 
 4     # Mapea as coorednadas originais em dois vetores de forma a ser de ter uma dupla para cada
 5     # coordenada. Da seguinte forma:
 6     #  [ 0 1 2 0 1 2 ]
 7     #  [ 0 0 1 1 2 2 ]
 8     coords_x = resize(range(tamanho_x),[1,tamanho_x*tamanho_y])
 9     coords_y = repeat(range(tamanho_y),tamanho_x,axis=0)
10 
11     # Adicionada um terceiro vertor com as coordedanadas homogeneas e então monta uma matriz com
12     # esses três vetores.
13     coords = vstack((coords_x,coords_y,ones([1,tamanho_x*tamanho_y],dtype=integer)))
14 
15     # Finalmente, aplica a multiplicação matricial para obter as novas coordenadas
16     coords_transformadas = dot(transf,coords).astype(integer)
17 
18     # Calcula as menores e maiores coordendas da nova imagem.
19     min_x=min(coords_transformadas[0,:])
20     min_y=min(coords_transformadas[1,:])
21     coords_transformadas[0,:] =coords_transformadas[0,:] - min_x
22     coords_transformadas[1,:] =coords_transformadas[1,:] - min_y
23     max_x=max(coords_transformadas[0,:])
24     max_y=max(coords_transformadas[1,:])
25 
26     # Cria a nova imagem, *não* mantendo as dimensões e origem da imagem original.
27     imagem_nova = zeros([max_y+1,max_x+1])
28     imagem_nova[coords_transformadas[1,:],coords_transformadas[0,:]] = imagem[coords[1,:],coords[0,:]]
29 
30     # Se a opção de manter_tamanho foi passada, recalcula para gerar a imagem tendo como a original como referência.
31     if (manter_tamanho):
32         imagem_aux=zeros([tamanho_y,tamanho_x])
33         if ((abs(min_y)<tamanho_y) and (abs(min_x)<tamanho_x)):
34             imagem_aux=iapad(imagem_nova,[max(1,abs(min_y)),max(1,abs(min_x))])
35             imagem_aux=imagem_aux[2*max(0,-min_y):2*max(0,-min_y)+tamanho_y,2*max(0,-min_x):2*max(0,-min_x)+tamanho_x]
36         imagem_nova=imagem_aux
37     return imagem_nova
Sobre essa função:
  • Ao contrário da iaffine, ela cria a nova imagem de acordo com as coordenadas de pixels usadas.
  • Foi adicionado a opção (terceiro argumento), de manter as dimensões e origiem da imagem original.
  • O mapeamento é direto. O que quer dizer que dependendo da transformação nem todos os pixels da imagem nova serão preenchidos.
1 T = rotate(math.pi/6)
2 adshow(iaffine_2(imagem,T,0),title = "iaffine_2(): Rotação PI/6")
3 adshow(iaffine_2(imagem,T,1),title = "iaffine_2(): Rotação PI/6, mantento ref. da imagem original.")

iaffine_2(): Rotação PI/6

iaffine_2(): Rotação PI/6, mantento ref. da imagem original.

Para encerrar, demonstra-se o funcionamento de deslocamento (que é mostrado com a opção de manter a imagem original como referência) e escalonamento:

 1 T = scale(2,1)
 2 adshow(iaffine_2(imagem,T,1),title = "iaffine(): Escaloamento 2x 1y")
 3 
 4 T = scale(0.5,0.5)
 5 adshow(iaffine_2(imagem,T,0),title = "iaffine(): Escaloamento 0.5x 0.5y")
 6 
 7 T = scale(-1,1)
 8 adshow(iaffine_2(imagem,T,0),title = "iaffine(): Escaloamento -1x 1y")
 9 
10 T = trans(-30,80)
11 adshow(iaffine_2(imagem,T,1),title = "iaffine(): Deslocamento -30px em X e 80px em Y")

iaffine(): Escaloamento 2x 1y

iaffine(): Escaloamento 0.5x 0.5y

iaffine(): Escaloamento -1x 1y

iaffine(): Deslocamento -30px em X e 80px em Y