Aula8 - Continuação DFT

Correção dos Exercícios

DFT Decompose


In [5]:
import numpy as np
np.set_printoptions(suppress=True, precision=1)
fw = np.array([200,200,50,50,50,50,200,200])
f = np.array([fw,fw,fw,fw])
print(f)


[[200 200  50  50  50  50 200 200]
 [200 200  50  50  50  50 200 200]
 [200 200  50  50  50  50 200 200]
 [200 200  50  50  50  50 200 200]]

In [6]:
F = np.fft.fft2(f)
print(F)


[[ 4000.0  +0.j  1448.5+600.j     0.0  +0.j  -248.5-600.j     0.0  +0.j
   -248.5+600.j     0.0  +0.j  1448.5-600.j]
 [    0.0  +0.j     0.0  +0.j     0.0  +0.j     0.0  +0.j     0.0  +0.j
      0.0  +0.j     0.0  +0.j     0.0  +0.j]
 [    0.0  +0.j     0.0  +0.j     0.0  +0.j     0.0  +0.j     0.0  +0.j
      0.0  +0.j     0.0  +0.j     0.0  +0.j]
 [    0.0  +0.j     0.0  +0.j     0.0  +0.j     0.0  +0.j     0.0  +0.j
      0.0  +0.j     0.0  +0.j     0.0  +0.j]]

In [7]:
frestaurado = np.fft.ifft2(F)
print(frestaurado)


[[ 200.+0.j  200.+0.j   50.+0.j   50.+0.j   50.+0.j   50.-0.j  200.-0.j
   200.-0.j]
 [ 200.+0.j  200.+0.j   50.+0.j   50.+0.j   50.+0.j   50.-0.j  200.-0.j
   200.-0.j]
 [ 200.+0.j  200.+0.j   50.+0.j   50.+0.j   50.+0.j   50.-0.j  200.-0.j
   200.-0.j]
 [ 200.+0.j  200.+0.j   50.+0.j   50.+0.j   50.+0.j   50.-0.j  200.-0.j
   200.-0.j]]

In [10]:
Faux = np.zeros_like(F)
Faux[0,0] = F[0,0]
print(Faux)
fr0 = np.fft.ifft2(Faux)
print(fr0.real)


[[ 4000.+0.j     0.+0.j     0.+0.j     0.+0.j     0.+0.j     0.+0.j
      0.+0.j     0.+0.j]
 [    0.+0.j     0.+0.j     0.+0.j     0.+0.j     0.+0.j     0.+0.j
      0.+0.j     0.+0.j]
 [    0.+0.j     0.+0.j     0.+0.j     0.+0.j     0.+0.j     0.+0.j
      0.+0.j     0.+0.j]
 [    0.+0.j     0.+0.j     0.+0.j     0.+0.j     0.+0.j     0.+0.j
      0.+0.j     0.+0.j]]
[[ 125.  125.  125.  125.  125.  125.  125.  125.]
 [ 125.  125.  125.  125.  125.  125.  125.  125.]
 [ 125.  125.  125.  125.  125.  125.  125.  125.]
 [ 125.  125.  125.  125.  125.  125.  125.  125.]]

In [11]:
Faux = np.zeros_like(F)
Faux[0,1] = F[0,1]
Faux[0,-1] = F[0,-1]
print(Faux)
fr1 = np.fft.ifft2(Faux)
print(fr1.real)


[[    0.0  +0.j  1448.5+600.j     0.0  +0.j     0.0  +0.j     0.0  +0.j
      0.0  +0.j     0.0  +0.j  1448.5-600.j]
 [    0.0  +0.j     0.0  +0.j     0.0  +0.j     0.0  +0.j     0.0  +0.j
      0.0  +0.j     0.0  +0.j     0.0  +0.j]
 [    0.0  +0.j     0.0  +0.j     0.0  +0.j     0.0  +0.j     0.0  +0.j
      0.0  +0.j     0.0  +0.j     0.0  +0.j]
 [    0.0  +0.j     0.0  +0.j     0.0  +0.j     0.0  +0.j     0.0  +0.j
      0.0  +0.j     0.0  +0.j     0.0  +0.j]]
[[ 90.5  37.5 -37.5 -90.5 -90.5 -37.5  37.5  90.5]
 [ 90.5  37.5 -37.5 -90.5 -90.5 -37.5  37.5  90.5]
 [ 90.5  37.5 -37.5 -90.5 -90.5 -37.5  37.5  90.5]
 [ 90.5  37.5 -37.5 -90.5 -90.5 -37.5  37.5  90.5]]

In [12]:
Faux = np.zeros_like(F)
Faux[0,3] = F[0,3]
Faux[0,-3] = F[0,-3]
print(Faux)
fr3 = np.fft.ifft2(Faux)
print(fr3.real)


[[   0.0  +0.j    0.0  +0.j    0.0  +0.j -248.5-600.j    0.0  +0.j
  -248.5+600.j    0.0  +0.j    0.0  +0.j]
 [   0.0  +0.j    0.0  +0.j    0.0  +0.j    0.0  +0.j    0.0  +0.j
     0.0  +0.j    0.0  +0.j    0.0  +0.j]
 [   0.0  +0.j    0.0  +0.j    0.0  +0.j    0.0  +0.j    0.0  +0.j
     0.0  +0.j    0.0  +0.j    0.0  +0.j]
 [   0.0  +0.j    0.0  +0.j    0.0  +0.j    0.0  +0.j    0.0  +0.j
     0.0  +0.j    0.0  +0.j    0.0  +0.j]]
[[-15.5  37.5 -37.5  15.5  15.5 -37.5  37.5 -15.5]
 [-15.5  37.5 -37.5  15.5  15.5 -37.5  37.5 -15.5]
 [-15.5  37.5 -37.5  15.5  15.5 -37.5  37.5 -15.5]
 [-15.5  37.5 -37.5  15.5  15.5 -37.5  37.5 -15.5]]

In [13]:
fr = fr0 + fr1 + fr3
print(fr)


[[ 200.+0.j  200.+0.j   50.+0.j   50.+0.j   50.+0.j   50.-0.j  200.-0.j
   200.-0.j]
 [ 200.+0.j  200.+0.j   50.+0.j   50.+0.j   50.+0.j   50.-0.j  200.-0.j
   200.-0.j]
 [ 200.+0.j  200.+0.j   50.+0.j   50.+0.j   50.+0.j   50.-0.j  200.-0.j
   200.-0.j]
 [ 200.+0.j  200.+0.j   50.+0.j   50.+0.j   50.+0.j   50.-0.j  200.-0.j
   200.-0.j]]

In [14]:
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(fr3.real[0])


Out[14]:
[<matplotlib.lines.Line2D at 0x7fb09d5df7f0>]

In [15]:
x = np.arange(80)
y = np.cos(2*np.pi*x*3/80)
plt.plot(y)


Out[15]:
[<matplotlib.lines.Line2D at 0x7fb09d4ca630>]

Aprendizados

  • Nunca tirar o valor absoluto do resultado do filtro, para eliminar do resíduo da parte imaginária. Como é esperado que o resultado do filtro seja uma imagem real, e pelo fato de erros de cálculo numérico, o resultado é complexo, com valores imaginários muito próximos a zero. A melhor forma de fazer este resultado ser real é apenas tirar a parte da real: f.real e nunca np.abs(f).
  • Fazer caso numérico pequeno é sempre importante no aprendizado e para encontrar erros.
  • sempre que houver uma borda na imagem, ela dá origem a uma linha no espectro de Fourier e se esta imagem for filtrada de forma ideal, existe um efeito de ring (ondulação) na imagem. Não esquecer que a imagem é periódica e muitas vezes este degrau acontece na borda, por exemplo, a parte de baixo da imagem é branca e parte de cima é escura.
  • Na filtragem no domínio da frequência é sempre importante verificar se a transformada de Fourier resultante exibe a propriedade do simetria de complexo conjugado.

In [22]:
import matplotlib.image as mpimg
f = mpimg.imread('../data/keyb.tif')
plt.imshow(f[:50,:50],cmap='gray')


Out[22]:
<matplotlib.image.AxesImage at 0x7fb09c11e8d0>

In [20]:
F = np.fft.fft2(f)
H,W = F.shape
import sys,os
sys.path.append('/home/lotufo')
import ia898.src as ia
Fview = np.abs(np.log(ia.ptrans(F,(H//2,W//2))+1))
plt.imshow(Fview,cmap='gray')


Out[20]:
<matplotlib.image.AxesImage at 0x7fb09c1ff160>

In [27]:
x = np.arange(4).reshape(4,1)
A = x.dot(x.T)
print(2**A*1.j)


[[ 0.  +1.j  0.  +1.j  0.  +1.j  0.  +1.j]
 [ 0.  +1.j  0.  +2.j  0.  +4.j  0.  +8.j]
 [ 0.  +1.j  0.  +4.j  0. +16.j  0. +64.j]
 [ 0.  +1.j  0.  +8.j  0. +64.j  0.+512.j]]

Rotação

Escala

Implementando a DFT matricialmente

A implementação da DFT é muito fácil de ser feita matricialmente usando a operação matricial de potenciação a**B onde B é uma matriz. Com isso, evita-se a necessidade de laço explícitopara fazer a soma dos produtos. A DFT multidimensional pode ser calculada a partir da DFT unidimensional. Como a implementação matricial tem complexidade proporcional a $N^2$, existe implementação muito famosa denominada FFT Fast Fourier Transform cuja complexidade é proporcional a $ N log(N)$.

Filtros

Filtro ideal passa baixas

É feito multipliando-se a transformada de Fourier por uma máscara de multiplicação que elimina (zera) as "telhas" de frequencia menor que (U,V) ciclos na imagem. A ideia é que a imagem resultante só contenha componentes de telhas com períodos menor ou igual a (U,V). Por exemplo poderia ser (10,5).


In [29]:
plt.imshow(f,cmap='gray')


Out[29]:
<matplotlib.image.AxesImage at 0x7fb09c05d048>

In [30]:
F = np.fft.fft2(f)
Fview = np.abs(np.log(ia.ptrans(F,(H//2,W//2))+1))
plt.imshow(Fview,cmap='gray')


Out[30]:
<matplotlib.image.AxesImage at 0x7fb0977b67b8>

Processamento


In [38]:
U,V = (6,4)
H,W = F.shape
FW = np.zeros_like(F)
FW[0:U,0:V] = 1.
FW[-U:,-V:] = 1.
FW[0:U,-V:] = 1.
FW[-U:,0:V] = 1.
fw = np.fft.ifft2(F * FW)
print((fw.imag).sum())  # cheque para verificar se o resultado é real


-1.25510268845e-09

Visualização


In [39]:
plt.imshow(ia.ptrans(np.log(1+ np.abs(F*FW)),(H//2,W//2)),cmap='gray')


Out[39]:
<matplotlib.image.AxesImage at 0x7fb0a2bc2780>

In [40]:
plt.imshow(fw.real,cmap='gray')


Out[40]:
<matplotlib.image.AxesImage at 0x7fb096dba550>

Teorema da Convolução

Exercícios

  1. Implementar a função isccsym (is complex conjugade symmetric?) para testar simetria de uma imagem complexa
  2. Mudar a demonstração filtroidealdemo feito em classe do filtro ideal e usar agora um elipse de raios (U,V) como filtro ideal. Testar para imagens com dimensoes pares e impares
  3. Demonstração do teorema da convolução: convteo

In [ ]: