Antes de começarmos a discutir a Transformada de Fourier, vamos fazer a revisão de alguns conceitos importantes, como por exemplo, os números complexos.
O conceito de números complexos surgiu no século XIV basicamente para possibilitar a resolução raiz quadrada. No início, os números complexos não eram vistos como números, mas sim como um artifício algébrico útil para se resolver equações. Descartes, no século XVII, os chamou de números imaginários.
A representação de números complexos se dá na forma cartesiana (parte real e parte imaginária) e a na forma polar (módulo e fase). A equação de Euler dá a uma representação da forma polar em cosseno (parte real) e seno (parte imaginária). A operação de soma de números complexos é mais fácil de ser realizada na forma cartesiana enquanto que as operações de produto e potenciação são mais facilmente realizadas na forma polar. A visualização de um sinal complexo também é mais fácil na forma polar (magnitude e fase).
A representação cartesiana do número complexo $c$ é dada por:
$$ c = x + yj $$onde $x$ é denominada parte Real e $y$ é denominada parte Imaginária. A maneira mais imediata de criar um número complexo usando NumPy e através da função complex, bastando para isso passar os valores das partes real e imaginária do número complexo, como mostra o exemplo abaixo. Veja que a variável C é do tipo complex.
In [1]:
import numpy as np
C = np.complex(3,4)
print('C=', C)
print(type(C))
Porém, como iremos trabalhar com números complexos em imagens, utilizaremos não apenas um
número complexo, mas um array de números complexos. Podemos ver no exemplo a seguir, que
a forma de se criar um array de números complexos é a mesma de se criar um array de números
inteiros ou números reais (em ponto flutuante). Basta então utilizarmos a função array do
NumPy e inserir cada elemento complexo, escrevendo-o da forma :eq:x+yj
. Veja que agora a
variável c é do tipo numpy.ndarray.
In [2]:
c = np.array([3+4j])
#c = 3+4j
print('c=', c)
print(type(c))
print('Parte real:', c.real)
print('Parte imaginária:', c.imag)
print(c.shape)
O conjugado deste mesmo número complexo $c$ é dado por:
$$ \bar{c} = x - yj $$Percebam que a parte real de um número complexo e de seu conjugado é a mesma ($x$), enquanto que a parte imaginária deles são opostas ($y$ e $-y$)
In [3]:
cc = np.conjugate(c)
print('c=', c)
print('Complexo conjugado:', cc)
print('Parte real:', cc.real)
print('Parte imaginária:', cc.imag)
Os números complexos são representados geometricamente no plano complexo. Nele, representa-se a parte real,
:eq:x
, no eixo horizontal e a parte imaginária, :eq:y
, no eixo vertical. Se interpretarmos este número complexo no plano
cartesiano como um vetor, podemos calcular sua magnitude (módulo) e sua fase (argumento).
In [4]:
c3 = np.array(2+2j)
print('c3=', c3)
print('Módulo:', np.abs(c3))
print('Argumento:', np.rad2deg(np.angle(c3)))
np.angle(c3)*180/np.pi
Out[4]:
A representação polar de um número complexo, dada pela fórmula de Euler, é da forma:
$$ c = \rho (\cos \phi + j \sin \phi) $$ou ainda
$$ c = \rho {e}^{j\phi } $$onde $\rho$ é o módulo (magnitude) do número complexo e $\phi$ é o argumento (fase) do número complexo. Também é fácil de ver que $rho \cos \phi$ é a parte real do número complexo e $\rho \sin \phi$ é a parte imaginária do número complexo.
Todo número complexo pode ser representado por sua parte real e sua parte imaginária, ou por seu módulo e argumento. A partir de uma destas representações é possível obter a outra. Para converter um número complexo de sua representação cartesiana, para sua representação polar, basta fazermos:
$$ \rho = \left|z \right| = \sqrt{{x}^{2}+{y}^{2}} $$$$ \phi = \arctan \left(\frac{y}{x} \right) $$Já a conversão do número complexo em sua forma polar para a forma cartesiana é dada por:
$$ x = \rho\cos(\phi) $$$$ y = \rho\sin(\phi) $$Para conversão de um número complexo de suas coordenadas cartesianas para polares, basta usar as funções abs e angle oferecidas pelo NumPy. Já para a conversão inversa (de polar para cartesiana), não função específica do NumPy e é preciso, portanto, realizar o cálculo como descrito acima. É importante também ficar atento ao uso do ângulo em radianos ou em graus.
Até agora, vimos os conceitos relacionados aos números complexos e as principais funções do NumPy para manipular estes números. Percebam que desde o começo operamos em uma array de um único elemento. Mas, no caso das imagens e da transformada de Fourier, ao invés de um único número complexo estaremos manipulando um array de números complexos.
In [5]:
C_array = np.array([[3+4j, 2+2j],[1-2j, -2+2j]])
print('C_array=\n', C_array)
print('Módulo:\n', np.abs(C_array))
print('Argumento:\n', np.rad2deg(np.angle(C_array)))
print('Shape:',C_array.shape)