giovani_ex2 - Função iaramp

Enunciado:

Estudar as várias funções sintéticas da toolbox ia636, utilizando-as com parâmetros interessantes. Escolher uma ou duas para implementá-la, utilizando o meshgrid.

Estudo e implementação da função iaramp

Bom, conforme visto e estudado algumas funções do toolbox ia636, optou-se por apresentar a função iaramp devido a sua simplicidade e entendimento em uma perspectiva matricial.

A função é chamada desta forma:

g = iaramp( [H,W] , n , [kmin,kmax] )

onde:

  • H,W: são as dimensões da imagem de saida
  • n: numero de bandas que deseja
  • kmin,kmax: é a variação de escala de cinza entre as bandas
  • g = imagem resultante

Seguindo a seguinte equação:

Apresentando um exemplo didático, temos:

1 a = iaramp([5,7], 3, [4,10])
2 print a
[[ 4  4  4  7  7 10 10]
 [ 4  4  4  7  7 10 10]
 [ 4  4  4  7  7 10 10]
 [ 4  4  4  7  7 10 10]
 [ 4  4  4  7  7 10 10]]

Portanto, como disse anteriormente, nota-se que esta técnica é bem simples e fácil de se implementar como visto este exemplo didático, que possibilitou a melhor compreensão do processamento.

Agora temos um exemplo mais completo:

1 a = iaramp([200,300], 10, [0,255])
2 
3 mmshow(uint16(a),title='a - Exemplo de iaramp, sentido horizontal')

a - Exemplo de iaramp, sentido horizontal

Em um segundo momento, após estudo da função, a implementação se da visando a abordagem matricial utilizando o meshgrid para confecção da matriz base. Com o intuito de tornar o código mais dinâmico e com melhor entendimento, desenvolveu se uma função basicamente nos padrões visto da função "original" e com os trechos dos códigos bem documentados.

Uma alternativa que encontrei, para trabalhar melhor a questão do aprendizado e consequentimente seu desenvolvimento, foi acrescentado na função a técnica de retornar uma imagem no sentido horizontal e outra vertical, visto que na função padrão só é retornado a imagem no sentido horizontal. Esta alteração foi bem simples substituindo a variável W pela H da equação apresentada anteriormente.

Segue abaixo a função implementada:
 1 # -------------------------------------------------------------------------------------------------------------------
 2 def iaramp_alt (shap,     # Variável para as dimensões
 3                 n,        # Numero de Bandas
 4                 variat):  # Variação entre as bandas (k_min,k_max)
 5 
 6     # Atribui os parametros passados para variável padronizada da função
 7     H = shap[0]
 8     W = shap[1]
 9     kmin = variat[0]
10     kmax = variat[1]
11 
12     # Utilizando o meshgrid para gerar a matriz a ser manipulada
13     mesh_w,mesh_h = iameshgrid(range(W),range(H))
14 
15     # realiza o processamento segundo a equação apresentanda.
16     a = (floor(mesh_w * (n /float(W))))*((kmax - kmin)/(n-1)) + kmin # Sentido horizontal
17     b = (floor(mesh_h * (n /float(W))))*((kmax - kmin)/(n-1)) + kmin # Sentido vertical
18 
19     return a.astype(int),b.astype(int)
20 # -------------------------------------------------------------------------------------------------------------------

Neste momento, os exemplos são apresentados...

ex1_w - Horizontal 
[[ 4  4  4  7  7 10 10]
 [ 4  4  4  7  7 10 10]
 [ 4  4  4  7  7 10 10]
 [ 4  4  4  7  7 10 10]
 [ 4  4  4  7  7 10 10]]

 ex1_h - Vertical 
[[4 4 4 4 4 4 4]
 [4 4 4 4 4 4 4]
 [4 4 4 4 4 4 4]
 [7 7 7 7 7 7 7]
 [7 7 7 7 7 7 7]]

ex2_w - Exemplo de iaramp, sentido horizontal

ex2_h - Exemplo de iaramp, sentido vertical

ex3 - Unindo as duas imagens

Uma alternativa a ser acrescentada também na função, seria a escolha do sentido das bandas tendo os sentidos left-right,top-bottom,right-left e bottom-top. Onde podemos parametrizar com as iniciais de cada caso apresentado respectivamente como l,t,r,b...

Tornando a função caracterizada abaixo como:

 1 # -------------------------------------------------------------------------------------------------------------------
 2 def iaramp_ltrb  (shap,     # Variável para as dimensões
 3                   n,        # Numero de Bandas
 4                   variat,   # Variação entre as bandas (k_min,k_max)
 5                   sent      # Sentido do deslocamento das bandas
 6                   ):
 7 
 8     # Atribui os parametros passados para variável padronizada da função
 9     H = shap[0]
10     W = shap[1]
11     kmin = variat[0]
12     kmax = variat[1]
13 
14     # realiza o processamento segundo a equação apresentanda e seu sentido.
15     if sent == "L" or sent =="T":
16             # Utilizando o meshgrid para gerar a matriz a ser manipulada
17             mesh_w,mesh_h = iameshgrid(range(W),range(H))
18 
19             if sent == "L": # Sentido Left-Right
20                 a = (floor(mesh_w * (n /float(W))))*((kmax - kmin)/(n-1)) + kmin # Sentido horizontal
21 
22             if sent == "T": # Sentido Top-Bottom
23                 a = (floor(mesh_h * (n /float(W))))*((kmax - kmin)/(n-1)) + kmin # Sentido vertical
24 
25     # realiza o processamento segundo a equação apresentanda e seu sentido.
26     if sent == "R" or sent =="B":
27             # Utilizando o meshgrid para gerar a matriz invertida a ser manipulada
28             mesh_w,mesh_h = iameshgrid(range(W-1,-1,-1),range(H-1,-1,-1))
29 
30             if sent == "R": # Sentido Left-Right
31                 a = (floor(mesh_w * (n /float(W))))*((kmax - kmin)/(n-1)) + kmin # Sentido horizontal
32 
33             if sent == "B": # Sentido Top-Bottom
34                 a = (floor(mesh_h * (n /float(W))))*((kmax - kmin)/(n-1)) + kmin # Sentido vertical
35 
36     return uint16(a.astype(int))
37 # -------------------------------------------------------------------------------------------------------------------

Portanto, os exemplos são apresentados...

ex1 - Sentido Bottom-Top: 
[[7 7 7 7 7 7 7]
 [7 7 7 7 7 7 7]
 [4 4 4 4 4 4 4]
 [4 4 4 4 4 4 4]
 [4 4 4 4 4 4 4]]

ex2 - Sentido Bottom-Top

ex3 - Sentido Top-Bottom

ex4 - Sentido Right-Left

ex5 - Sentido Left-Right

ex6 - Intersecao do ex2 com ex3

ex7 - Intersecao do ex4 com ex5

ex8 - União do ex6 + ex7

Utilizando estes operadores de interseção e união, pode-se aproximar os resultados a uma gaussiana discretizada!!!

Observando mais uma vez como a função iaramp trabalhava, me surgiu mais uma ideia de realizar esta mesma abordagem de separação por bandas aplicado a imagens em escala de cinza. onde esta função tornaria um tipo de filtro interessante. E aproveitando a ideia matricial, todo o código da função esta no modo matricial para processamento.

A função chamada de filtro_divisor_banda possui 2 argumentos:
  • img: sendo uma imagem de entrada e em escala de cinza
  • bands: número de bandas que a imagem de saida irá retornar

Veja abaixo:

 1 #------------------------------------------------------------------
 2 def filtro_divisor_banda (img,bands):
 3 
 4     va,md = divmod(img.max()-img.min(),float(bands)) # Faz a variação de cada banda.
 5     lsi = arange(img.min(),img.max(),va+1)           # Monta a faixa inicial de cada banda
 6     lsf = lsi + va                                   # Monta a faixa final de cada banda
 7     valor,b = divmod((lsf-lsi),2.0)+lsi              # Monta o valor do pixel para cada banda
 8     valor.astype(int)                                # Converte de float para int
 9     valor = resize(valor,(valor.size,1))             # Inverte o vetor de linha para coluna
10     ind,b = divmod(img.max(),bands)                  # Variavel para calcular o indice do novo valor
11     a,b = divmod(img,ind)                            # Atribui os indices para cada pixel da imagem
12     a = ravel(a)                                     # Converte a matriz n x n para vetor 1D
13     limite,b = divmod(a,valor.shape[0])              # Verifica se algum indice-valor esta passando do total da banda
14     a = a - limite                                   # Decrementa o valor que nao esta contido na banda...
15     mat = ones([valor.size,a.size])                  # Gera uma matriz auxiliar de valor 1
16     valor = valor * mat                              # Atribui a essa matriz de uns os reais valores das bandas
17     a = valor[a]                                     # Gera uma matriz resultante em função dos indices do vetor criado
18     resp = a[:,1]                                    # A resposta será a primeira coluna da matriz gerada no passo anterior
19     resp = resize(resp,img.shape)                    # Redimensiona a matriz para igualar a imagem de entrada.
20 
21     return uint16(resp)
22 #------------------------------------------------------------------

A partir desta, exemplificaremos com valores simbólicos para efeito didático de entendimento e uma com real aplicação.

imgd - Imagem de entrada (didático):

[[10 20 22 23]
 [21 21 23 24]
 [24 25 24 50]
 [11 15 30 40]]

 ex1 - Imagem de saida 3 bandas(didático):

[[16 30 30 30]
 [30 30 30 30]
 [30 30 30 44]
 [16 16 30 44]]

 Numero de bandas em funcao do desvio padrão:  4.19467013342

 ex1f - Imagem de saida 5 bandas (didático):

[[23 32 32 32]
 [32 32 32 32]
 [32 32 32 50]
 [23 23 41 50]]


 Numero de bandas em funcao do desvio padrão:  2.8603029339

img - Imagem de entrada

ex2 - Filtro 15 bandas

ex3 - Filtro 10 bandas

ex4 - Filtro 3 bandas

Pelos resultados obtidos, percebe-se que melhorias podem e devem ser feitas, agilizando seu desempenho e também corrigindo algumas imperfeições encontras no ambito de arredondamento dos valores, gerando então um erro!

A meu ver, ficou uma função interessante com principios e técnicas que necessitam ser aprendidas como por exemplo o meshgrid.

Abraços.