daniel_chiu_Ex6

Autor: daniel_chiu
Data: 23/04/2009

Convolução bidimensional

A equação da convolução bidimensional discreta é dada por:

Onde, o tamanho de f é dado por AxB e w, por CxD. O resultado da convolução terá dimensões MxN, onde M<=A+C-1 e N<=B+D-1. É possível que bordas apareçam na imagem convoluída. Tais bordas seriam do tamanho (C-1)/2 no eixo x e (D-1)/2 no eixo y. Dessa maneira, deve-se cortá-las na imagem final. Por esta razão, é interessante que a máscara tenha tamanho ímpar, para que as bordas sejam cortadas corretamente.

A implementação da convolução está feita abaixo:

 1 def dwsc_convolute(F,W,crop=1):
 2 
 3      b,a=F.shape
 4      d,c=W.shape
 5      m=a+c-1
 6      n=b+d-1
 7 
 8      G=zeros((n,m))
 9 
10      for s in range(0,c):
11          for t in range(0,d):
12             AUX=F
13 
14             # padding nos índices fora do limite das dimensões de f
15             if s>0:
16                 AUX=hstack((zeros((a,s)) ,AUX))
17             if c-1-s>0:
18                 AUX=hstack((AUX, zeros((a,c-1-s))))
19             if t>0:
20                 AUX=vstack((zeros((t,m)), AUX))
21             if d-1-t>0:
22                 AUX=vstack((AUX, zeros((d-1-t,m))))
23 
24             G=G+AUX*W[t,s]
25 
26      if crop==1:
27          G=G[(d-1)/2:n-(d-1)/2,(c-1)/2:m-(c-1)/2]
28 
29      return G
 1 #Exemplo numérico
 2 
 3 F1=zeros((5,5))
 4 F1[0,4]=1
 5 W=arange(9)+1
 6 W.resize((3,3))
 7 
 8 print '\nF1\n',F1
 9 print '\nW\n',W
10 
11 G1=dwsc_convolute(F1,W,0)
12 print '\nG1=F1*W\n',G1
13 
14 F2=zeros((5,5))
15 F2[2,2]=1
16 
17 print '\nF2\n',F2
18 
19 G2=dwsc_convolute(F2,W,0)
20 print '\nG2=F2*W\n',G2
F1
[[ 0.  0.  0.  0.  1.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]]

W
[[1 2 3]
 [4 5 6]
 [7 8 9]]

G1=F1*W
[[ 0.  0.  0.  0.  1.  2.  3.]
 [ 0.  0.  0.  0.  4.  5.  6.]
 [ 0.  0.  0.  0.  7.  8.  9.]
 [ 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.]]

F2
[[ 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.]]

G2=F2*W
[[ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  1.  2.  3.  0.  0.]
 [ 0.  0.  4.  5.  6.  0.  0.]
 [ 0.  0.  7.  8.  9.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]]

Aplicação: suavização de imagem

 1 IMG=mmreadgray('lenina.pgm')
 2 SMOOTH3_3=1.0/9 * ones((3,3))
 3 SMOOTH5_5=1.0/25 * ones((5,5))
 4 SMOOTH15_15=1.0/225 * ones((15,15))
 5 
 6 SMOOTHED_IMG=dwsc_convolute(IMG,SMOOTH3_3).astype(int32)
 7 adshow(IMG, title='Imagem original')
 8 adshow(SMOOTHED_IMG, title='Imagem suavizada com máscara 3x3')
 9 
10 SMOOTHED_IMG=dwsc_convolute(IMG,SMOOTH5_5).astype(int32)
11 adshow(SMOOTHED_IMG, title='Imagem suavizada com máscara 5x5')
12 
13 SMOOTHED_IMG=dwsc_convolute(IMG,SMOOTH15_15).astype(int32)
14 adshow(SMOOTHED_IMG, title='Imagem suavizada com máscara 15x15')

Imagem original

Imagem suavizada com máscara 3x3

Imagem suavizada com máscara 5x5

Imagem suavizada com máscara 15x15

Aplicação: realce de imagem utilizando Laplaciano

1 LAP=array([[0,1,0],[1,-4,1],[0,1,0]])
2 LAP_COMPONENT=dwsc_convolute(IMG,LAP).astype(int32)
3 SHARPENED_IMG=IMG-LAP_COMPONENT
4 
5 adshow(LAP_COMPONENT, title='Componente Laplaciano')

Componente Laplaciano

1 adshow(IMG, title='Imagem original')
2 adshow(SHARPENED_IMG, title='Imagem realçada')

Imagem original

Imagem realçada

Convolução periódica bidimensional

A equação da convolução periódica bidimensional é dada por:

Sendo f e w funções periódicas. Nesse caso, f e w tem que ter o mesmo tamanho. Dessa maneira, deve-se fazer o padding da máscara.

 1 def dwsc_periodic_convolute(F,W):
 2 
 3     n,m=F.shape
 4     b,a=W.shape
 5 
 6     H=zeros((n,m))
 7 
 8     # padding
 9     W_padded=W
10     W_padded=hstack((W_padded,zeros((b,m-a))))
11     W_padded=vstack((W_padded,zeros((n-b,m))))
12 
13     for x in range(0,m):
14         for y in range(0,n):
15             elemento=0
16             for s in range(0,m):
17                 for t in range(0,n):
18                     elemento+=F[t,s]*W_padded[(y-t)%n,(x-s)%m]
19             H[y,x]=elemento
20 
21     return H
 1 #Exemplo numérico
 2 
 3 F1=zeros((5,5))
 4 F1[2,2]=1
 5 W=arange(9)+1
 6 W.resize((3,3))
 7 
 8 print '\nF1\n',F1
 9 print '\nW\n',W
10 
11 H1=dwsc_periodic_convolute(F1,W)
12 print '\nH1=F1*W\n',H1
13 
14 F2=zeros((5,5))
15 F2[0,4]=1
16 
17 print '\nF2\n',F2
18 
19 H2=dwsc_periodic_convolute(F2,W)
20 print '\nH2=F2*W\n',H2
21 
22 F3=zeros((5,5))
23 F3[4,0]=1
24 
25 print '\nF3\n',F3
26 
27 H3=dwsc_periodic_convolute(F3,W)
28 print '\nH3=F3*W\n',H3
29 
30 F4=zeros((5,5))
31 F4[4,4]=1
32 
33 print '\nF4\n',F4
34 
35 H4=dwsc_periodic_convolute(F4,W)
36 print '\nH4=F4*W\n',H4
F1
[[ 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.]]

W
[[1 2 3]
 [4 5 6]
 [7 8 9]]

H1=F1*W
[[ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  1.  2.  3.]
 [ 0.  0.  4.  5.  6.]
 [ 0.  0.  7.  8.  9.]]

F2
[[ 0.  0.  0.  0.  1.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]]

H2=F2*W
[[ 2.  3.  0.  0.  1.]
 [ 5.  6.  0.  0.  4.]
 [ 8.  9.  0.  0.  7.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]]

F3
[[ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 1.  0.  0.  0.  0.]]

H3=F3*W
[[ 4.  5.  6.  0.  0.]
 [ 7.  8.  9.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 1.  2.  3.  0.  0.]]

F4
[[ 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.]]

H4=F4*W
[[ 5.  6.  0.  0.  4.]
 [ 8.  9.  0.  0.  7.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 2.  3.  0.  0.  1.]]

Percebe-se nesse exemplo que a máscara de convolução pode contornar a imagem, cruzando do final do eixo x e/ou eixo y ao seu início.

Código melhorado da convolução periódica

 1 def dwsc_pconvolute(F,W):
 2 
 3     b,a=F.shape
 4     d,c=W.shape
 5 
 6     m,n=max(a,c),max(b,d)
 7 
 8     F_aux=F
 9     W_aux=W
10 
11     if a>c:
12         W_aux=hstack((W_aux,zeros((d,m-c))))
13     else:
14         F_aux=hstack((F_aux,zeros((b,m-a))))
15 
16     if b>d:
17         W_aux=vstack((W_aux,zeros((n-d,m))))
18     else:
19         F_aux=vstack((F_aux,zeros((n-b,m))))
20 
21     H=zeros((n,m))
22 
23     for s in range(0,m):
24         for t in range(0,n):
25             W_aux_shifted=W_aux
26             W_aux_shifted=hstack((W_aux_shifted[0:n,m-s:m],W_aux_shifted[0:n,0:m-s]))
27             W_aux_shifted=vstack((W_aux_shifted[n-t:n,0:m],W_aux_shifted[0:n-t,0:m]))
28             H=H+F_aux[t,s]*W_aux_shifted
29 
30     return H
 1 #Exemplo numérico
 2 
 3 F1=zeros((5,5))
 4 F1[2,2]=1
 5 W=arange(9)+1
 6 W.resize((3,3))
 7 
 8 H1=dwsc_pconvolute(F1,W)
 9 print '\nH1=F1*W\n',H1
10 
11 F2=zeros((5,5))
12 F2[0,4]=1
13 
14 print '\nF2\n',F2
15 
16 H2=dwsc_pconvolute(F2,W)
17 print '\nH2=F2*W\n',H2
18 
19 F3=zeros((5,5))
20 F3[4,0]=1
21 
22 print '\nF3\n',F3
23 
24 H3=dwsc_pconvolute(F3,W)
25 print '\nH3=F3*W\n',H3
26 
27 F4=zeros((5,5))
28 F4[4,4]=1
29 
30 print '\nF4\n',F4
31 
32 H4=dwsc_pconvolute(F4,W)
33 print '\nH4=F4*W\n',H4
H1=F1*W
[[ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  1.  2.  3.]
 [ 0.  0.  4.  5.  6.]
 [ 0.  0.  7.  8.  9.]]

F2
[[ 0.  0.  0.  0.  1.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]]

H2=F2*W
[[ 2.  3.  0.  0.  1.]
 [ 5.  6.  0.  0.  4.]
 [ 8.  9.  0.  0.  7.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]]

F3
[[ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 1.  0.  0.  0.  0.]]

H3=F3*W
[[ 4.  5.  6.  0.  0.]
 [ 7.  8.  9.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 1.  2.  3.  0.  0.]]

F4
[[ 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.]]

H4=F4*W
[[ 5.  6.  0.  0.  4.]
 [ 8.  9.  0.  0.  7.]
 [ 0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.]
 [ 2.  3.  0.  0.  1.]]