Exercício 7 - Convolução (Parte 2)

Autor: Wagner Machado do Amaral
Data: 27/04/2009

Enunciado: ia636-2009:exercicio7

Parte 1

Equação que é de fato implementada pela rotina iaconv da toolbox ia636:

Onde AxB e CxD são as dimensões de f(x,y) e h(x,y) respectivamente.

Parte 2

convolucao

Alguns conceitos básicos de convolução digital.

Filtros lineares e invariantes à translação.

Resposta ao impulso da convolução:

Suponha que h(x,y) seja desconhecido e que aplicamos um impulso unitário I ao sistema. O resultado dessa convolução deve ser h(x,y), em uma sistema linear invariante a posição.

onde I é uma imagem impulso.

Isto significa que para se caracterizar um filtro linear e invariante à translação desconhecido, basta buscar sua resposta ao impulso. Conforme demonstrado abaixo:

1 I = zeros([5,5]);I[2,2]=1;
2 print 'I = '
3 print I
4 h = [-1,0,1]
5 print 'h = '
6 print h
7 g = iaconv(I,h)
8 print 'I * h = '
9 print g
I = 
[[ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  1.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]]
h = 
[-1, 0, 1]
I * h = 
[[ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0. -1.  0.  1.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]]

Observe que o resultado dessa convolução é h na posição do impulso unitário em I.

Invariante à translação:

Toda transformação linear e invariante por translação pode ser escrita sob a forma de uma convolução.

Se h for uma transformação linear e invariante por translação, então a convolução de h por f transladado é igual a convolução transladada de h por f

Veja abaixo a demonstração da equação acima:

 1 from machadowma_iaffine import *
 2 
 3 f = zeros([5,5]);f[2,2]=1;
 4 h = [-1,0,1]
 5 Tx=1; Ty=2; T = asarray([[1,0,Tx],[0,1,Ty],[0,0,1]])
 6 
 7 print 'f = '
 8 print f
 9 
10 print 'h = '
11 print h
12 
13 print 'Matriz de translação T = '
14 print T
15 
16 print 'h * T(f) = '
17 print iaconv( h , machadowma_iaffine(f,T) )
18 
19 print 'T(h * f) = '
20 print machadowma_iaffine( iaconv(h,f) ,T )
f = 
[[ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  1.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]]
h = 
[-1, 0, 1]
Matriz de translação T = 
[[1 0 1]
 [0 1 2]
 [0 0 1]]
h * T(f) = 
[[ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0. -1.  0.  1.  0.]]
T(h * f) = 
[[ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0. -1.  0.  1.  0.]]

Decomposição da máscara de convolução

Quando h pode ser decomposto na forma h1 * h2, a implementação usando a forma decomposta é usualmente mais rápida:

Por exemplo, a máscara de média de 9 pixels pode ser decomposta pela convolução da máscara horizontal de média de 3 pixels pela máscara de média vertical de 3 pixels. No primeiro caso, haverá uma operação com 9 imagens enquanto que no segundo, apenas 6 imagens.

 1 imagename='MVBook/club.png'
 2 f = mmreadgray(imagename)
 3 iashow(f,title='(a) ' + imagename)
 4 
 5 h = ones([3,3])/9
 6 t1 = time.time()
 7 g = iaconv(f,h)
 8 t2 = time.time()
 9 iashow(g,title='(b) Suavização, Tempo: ' + str(t2-t1))
10 print 'Máscara 3x3 da média de 9 pixels'
11 print h
12 
13 
14 h1 = ones([1,3])/3
15 h2 = ones([3,1])/3
16 t1 = time.time()
17 g = iaconv(f,h1)
18 g = iaconv(g,h2)
19 t2 = time.time()
20 iashow(g,title='(c) Suavização, Tempo: ' + str(t2-t1))
21 h = iaconv(h1,h2)
22 print 'Máscara 3x1 da média de 3 pixels convoluida com a máscara 1x3 da média de 3 pixels'
23 print h
Warning: downcasting image from double to uint16 (may lose precision)
Máscara 3x3 da média de 9 pixels
[[ 0.11111111  0.11111111  0.11111111]
 [ 0.11111111  0.11111111  0.11111111]
 [ 0.11111111  0.11111111  0.11111111]]
Warning: downcasting image from double to uint16 (may lose precision)
Máscara 3x1 da média de 3 pixels convoluida com a máscara 1x3 da média de 3 pixels
[[ 0.11111111  0.11111111  0.11111111]
 [ 0.11111111  0.11111111  0.11111111]
 [ 0.11111111  0.11111111  0.11111111]]

(a) MVBook/club.png

(b) Suavização, Tempo: 0.00362610816956

(c) Suavização, Tempo: 0.00184798240662

A imagem (b) foi gerada pela convolução da imagem original com uma máscara de média de 9 pixels.

A imagem (c) foi gerada pela convolução da imagem original com uma máscara horizontal de média de 3 pixels e uma máscara vertical de média 3 pixels.

Observe que o resultado foi o mesmo para os dois casos, mas a convolução com as máscaras decompostas (imagem c) obteve menor tempo de execução.

Parte 3

Segue abaixo um exemplo da utilização dos filtros suavização e realce de detalhes.

 1 imagename='morph_data/soil.tif'
 2 f = mmreadgray(imagename)
 3 iashow(f,title='(a) Imagem original: '+imagename)
 4 
 5 h = ones([5,5])/25
 6 g_suav = iaconv(f,h) #suavizacao
 7 n,m = g_suav.shape
 8 g_suav = g_suav[2:n-2,2:m-2]
 9 iashow(g_suav,title='(b) Suavização aplicada na imagem original')
10 
11 
12 h = ones([3,3])*-1; h[1,1]=8
13 g_sharp = iaconv(g_suav,h) #Sharpenig
14 n,m = g_sharp.shape
15 g_sharp = g_sharp[1:n-1,1:m-1]
16 iashow(ianormalize(g_sharp, [0,255]),title='(c) Sharpenig aplicado na suavização')
17 
18 g = g_suav + g_sharp
19 g = ianormalize(g, [0,255])
20 iashow(g,title='(d) Suavização + Sharpenig')
Warning: downcasting image from double to uint16 (may lose precision)
Warning: downcasting image from double to uint16 (may lose precision)
Warning: downcasting image from double to uint16 (may lose precision)

(a) Imagem original: morph_data/soil.tif

(b) Suavização aplicada na imagem original

(c) Sharpenig aplicado na suavização

(d) Suavização + Sharpenig

A imagem (a) é uma fotografia de uma rachadura típica em terras áridas, foi aplicado à essa foto um filtro 5x5 de suavização gerando a imagem (b).

Máscara 5x5 do filtro de suavização aplicado na imagem (a) para gerar a imagem (b).

Observe na imagem (b) que houve uma perda de detalhes, porque o filtro de suavização aplica uma média dos pixels na região da máscara.

O objetivo dos filtros Sharpening é realçar os detalhes de uma imagem. A imagem (c) mostra o resultado desse filtro aplicado à imagem (b) na tentativa de recuperar os detalhes da image (a) perdidos na suavização.

Máscara 3x3 do filtro Sharpening aplicado na imagem (b) para gerar a imagem (c).

A imagem (d) é a soma da imagem (c) e (b) normalizada para valores entre 0 e 255. Compare a imagem (d) e (b), observe que o filtro Shapening foi capaz de recuperar detalhes que foram perdidos durante a suavização.

comparando iaconv machadowma_conv

Para efeitos de comparação segue abaixo exatamente o mesmo procedimento realizado acima, mas agora com a minha função de convolução do exercício anterior (ia636-2009:machadowma_conv).

 1 from machadowma_conv import *
 2 
 3 imagename='morph_data/soil.tif'
 4 f = mmreadgray(imagename)
 5 iashow(f,title='(a) Imagem origina: '+imagename)
 6 
 7 h = ones([5,5])/25
 8 g_suav = machadowma_conv(f,h) #suavizacao
 9 n,m = g_suav.shape
10 g_suav = g_suav[2:n-2,2:m-2]
11 iashow(g_suav,title='(b) Suavização aplicada na imagem original')
12 
13 
14 h = ones([3,3])*-1; h[1,1]=8
15 g_sharp = machadowma_conv(g_suav,h) #Sharpenig
16 n,m = g_sharp.shape
17 g_sharp = g_sharp[1:n-1,1:m-1]
18 iashow(ianormalize(g_sharp, [0,255]),title='(c) Sharpenig aplicado na suavização')
19 
20 g = g_suav + g_sharp
21 g = ianormalize(g, [0,255])
22 iashow(g,title='(d) Suavização + Sharpenig')
Warning: downcasting image from double to uint16 (may lose precision)
Warning: downcasting image from double to uint16 (may lose precision)
Warning: downcasting image from double to uint16 (may lose precision)

(a) Imagem origina: morph_data/soil.tif

(b) Suavização aplicada na imagem original

(c) Sharpenig aplicado na suavização

(d) Suavização + Sharpenig

Observe que o resultado da suavização é semelhante ao resultado anterior exceto pela borda. Diferentemente do exemplo anterior, agora a borda da imagem (b) possui valor 0 em todos os pixels e está a direita e abaixo da imagem porque a origem da máscara, em machadowma_conv, não está no centro como é o caso da iaconv.

O resultado do Sharpening exibido na imagem (c) não é como esperado quando normalizado para valores entre 0 e 255 devido a borda da imagem (b) possuir valor 0.

A imagem (d) não apresenta o resultado esperado devido ao problema ocorrido na normalização do Sharpening contendo a borda e também pelo fato de machadowma_conv não tomar o centro como origem da mascara.

Para que o resultado seja satisfatório, o procedimento deve ser realizado levando-se em consideração como a convolução trata as bordas e a origem da máscara.