Antes de falarmos sobre o Teorema da Convolução, precisamos entender a convolução periódica (pconv). Até agora, vimos a convolução linear (conv ou scipy.signal.convolve2d), onde o kernel $h$ tem sua origem no centro e a imagem $f$ tem sua origem no canto superior esquerdo. Na convolução periódica, a origem do kernel $h$ está na origem da imagem $f$. Ambos kernel e imagem são periódicos, com o mesmo período. Como normalmente o kernel $h$ é muito menor que a imagem $f$, ele é preenchido com zeros até o tamanho de $f$.
In [27]:
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
from numpy.fft import *
import sys,os
ia898path = os.path.abspath('../../')
if ia898path not in sys.path:
sys.path.append(ia898path)
import ia898.src as ia
In [28]:
f = np.array([[1,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,0],
[0,0,0,0,0,0,0,0,1],
[0,0,0,0,0,0,0,0,0]])
print("Image (f):")
print(f)
h = np.array([[1,2,3],
[4,5,6]])
print("\n Image Kernel (h):")
print(h)
g1 = ia.pconv(f,h)
print("Image Output (pconv):")
print(g1)
onde $F$ indica o operador da transformada de Fourier, ou seja, $F(f)$ and $F(g)$ são as transformdas de $f$ e $g$. É importante perceber que a convolução usada aqui é a convolução periódica.
Vamos ilustrar o Teorema da Convolução com um exemplo numérico. Primeiro, vamos calcular a convolução periódica de uma imagem $f$ com um kernel $h$
In [29]:
fr = np.linspace(-1,1,6)
f = np.array([fr,2*fr,fr,fr])
print(f)
In [30]:
hh = np.array([-1,0,+1])
h = np.array([hh,2*hh,hh])
print(h)
In [31]:
g = ia.pconv(f,h)
print(g)
Agora, vamos calcular a transformada de Fourier $F(f)$ da imagem e $F(h)$ do kernel. Antes de mais nada, precisamos garantir que a imagem $f$ e o kernel $h$ sejam periódicos e tenham o mesmo tamanho.
In [32]:
# Aumentando h para o tamanho de f
aux = np.zeros(f.shape)
r,c = h.shape
aux[:r,:c] = h
# Calculando a Transformada de Fourier da f e h
F = fft2(f)
H = fft2(aux)
# Multiplicando-se as Tranformadas
G = F * H
# Calculando a Transformada inversa
gg = ifft2(G)
print("Result gg: \n",np.around(gg))
Pelo teorema da convolução, gg e g deveriam ser iguais:
In [33]:
print('O teorema da convolução funcionou?', np.allclose(gg.real,g))