Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Contenidos
Transformada 2D de Fourier
Aplicación: compresión de imágenes
Aplicación: orientación de vehículos
Transformada 2D de Fourier
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 1/23
5/4/2021 Fourier2D
M −1 N −1
1 x y
F (m, n) = ∑ ∑ f (x, y) exp(−2πi( m + n)),
MN M N
x=0 y=0
con m = 0, 1, 2, … , M − 1 y n = 0, 1, 2, … , N − 1.
M −1 N −1
m n
f (x, y) = M N ∑ ∑ F (m, n) exp(2πi( x + y)),
M N
m=0 n=0
con x = 0, 1, 2, … , M − 1 y y = 0, 1, 2, … , N − 1 .
Nota. Hay otras formas de normalizar la DFT y su inversa por medio de los factores
1/M N y M N . El que hemos escogido es el que se usa habitualmente en Python.
donde ¯
F es el conjugado del complejo F.
Para calcular el espectro de potencia usamos la función Numpy abs que nos da el
módulo del complejo. Para mover el origen de la transformada al centro del rectángulo
de frecuencias usamos fftshift. Finalmente, si queremos ver mejor el resultado,
usaremos una escala logarítmica.
Ejemplo
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 2/23
5/4/2021 Fourier2D
In [1]:
In [2]:
%matplotlib inline
Empezamos creando una imagen periódica de tamaño (601, 1201). El periodo, 10.5,
In [3]:
[X,Y] = np.meshgrid(x,y)
A = np.sin(hFrec*2*np.pi*X)
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 3/23
5/4/2021 Fourier2D
In [4]:
xx = np.linspace(0,1,1200)
plt.plot(xx,np.sin(hFrec*2*np.pi*xx))
plt.show()
1
que es una función periódica de frecuencia f = 10.5 Hz y periodo T =
f
In [5]:
T = 0.0952380952381
El paso siguiente es calcular la DFT centrada en el origen y mostrar la figura del espectro
de potencia (su raíz cuadrada).
In [6]:
F = fft2(A)/(W*H)
F = fftshift(F)
P = np.abs(F)
plt.imshow(P, extent = [-hW,hW,-hH,hH]);
Hacemos zoom (nos acercamos) para ver mejor los valores altos de P a las frecuenccias
±hF req
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 4/23
5/4/2021 Fourier2D
In [7]:
plt.imshow(P[hH-25:hH+25,hW-25:hW+25], extent=[-25,25,-25,25]);
tenemos
In [8]:
plt.plot(range(-25,25),P[hH,hW-25:hW+25])
plt.show()
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 5/23
5/4/2021 Fourier2D
In [9]:
A1 = np.sin(hFrec*2*np.pi*X) + np.sin(vFrec*2*np.pi*Y)
plt.figure()
plt.imshow(A1, cmap = 'gray', extent=[0,1,0,1]);
In [10]:
xx = np.linspace(0,1,1200)
yy = 0.5*np.ones(1200)
plt.plot(xx,np.sin(hFrec*2*np.pi*xx) + np.sin(vFrec*2*np.pi*yy))
plt.show()
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 6/23
5/4/2021 Fourier2D
In [11]:
yy = np.linspace(0,1,1200)
xx = 0.5*np.ones(1200)
plt.plot(yy,np.sin(hFrec*2*np.pi*xx) + np.sin(vFrec*2*np.pi*yy))
plt.show()
In [12]:
F1 = fft2(A1)/(W*H)
F1 = fftshift(F1)
P1 = np.abs(F1)
plt.figure()
plt.imshow(P1[hH-25:hH+25,hW-25:hW+25], extent=[-25,25,-25,25]);
Si cortamos la superficie con un plano perpendicular al plano OXY que contiene al eje
OX
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 7/23
5/4/2021 Fourier2D
In [13]:
plt.plot(range(-25,25),P1[hH,hW-25:hW+25])
plt.show()
In [14]:
plt.plot(range(-25,25),P1[hH-25:hH+25,hW])
plt.show()
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 8/23
5/4/2021 Fourier2D
In [15]:
A2 = np.sin(hFrec*2*np.pi*X + vFrec*2*np.pi*Y)
plt.figure()
plt.imshow(A2, cmap = 'gray',extent=[0,1,0,1]);
F2 = fft2(A2)/(W*H)
F2 = fftshift(F2)
P2 = np.abs(F2)
r = 25
plt.figure()
plt.imshow(P2[hH-r:hH+r,hW-r:hW+r], extent=[-r,r,-r,r]);
Finalmente vamos a usar una imagen real, con una frecuencia alta a lo largo del eje
horizontal, lo que se puede ver porque el máximo relativo se alínea con el eje horizontal:
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 9/23
5/4/2021 Fourier2D
In [16]:
I = Image.open("canes.jpg")
I = I.convert('L') # 'L' para convertir a escala de grises
A3 = np.asarray(I, dtype = np.float32) # Convertimos la imagen I en
# un array Numpy A3 con elementos tipo flo
at32
H,W = np.shape(A3)
plt.imshow(A3, cmap = 'gray');
In [17]:
F3 = fft2(A3)/float(W*H)
F3 = fftshift(F3)
P3 = np.abs(F3)
r = 100
mW = int(np.fix(0.5*W)) # Entero que vale, aproximadamente, la mitad de W
mH = int(np.fix(0.5*H)) # Entero que vale, aproximadamente, la mitad de H
plt.figure()
plt.imshow(np.log(1+P3[mH-r:mH+r,mW-r:mW+r]), extent=[-r,r,-r,r]);
Inicio
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 10/23
5/4/2021 Fourier2D
ST = {0 ≤ m ≤ M − 1, 0 ≤ n ≤ N − 1 : |F (m, n)| ≥ T } .
Llamemos g(T ) al número de elementos del array (m, n) , contenidos en ST . Por una
parte, para T = 0 tenemos g(0) = M N , porque |F (m, n)| son no negativos. Por otra
parte, para T > max |F (m, n)| tenemos g(T ) = 0 . Observar que g es una función de T
que es decreciente. Construiremos un plot de g usando la función count_nonzero, que da
el número de elementos no nulos de una matriz.
In [18]:
puntos = 100
Trango = np.linspace(0.05,1,puntos)
g = np.zeros(puntos, dtype = 'float32')
n = 0
plt.plot(Trango,g);
plt.xlabel('T (valor del umbral de corte)',fontsize=14)
plt.title('Elementos no nulos en la matriz P3',fontsize=14);
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 11/23
5/4/2021 Fourier2D
Ahora aplicamos el método del valor umbral, es decir, mandamos a cero los coeficientes
menores que un T dado. ¿Cómo escogemos T ?
In [19]:
T = 0.1
c = F3 * (P3 >= T)
fM = ifft2(c)*W*H
plt.imshow(np.abs(fM), cmap = 'gray');
In [20]:
out1 = np.count_nonzero(F3)
out2 = np.count_nonzero(c)
print 'Número inicial de elementos distintos de cero = ',out1
print 'Número final de elementos distintos de cero = ',out2
print 'Relación de compresión = ',out1/out2
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 12/23
5/4/2021 Fourier2D
Ejercicio
g(T )
Dicho de otra manera, queremos calcular T de forma que se cumpla que = r.
WH
In [21]:
%run compresion.py
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 13/23
5/4/2021 Fourier2D
Inicio
In [24]:
rot_angulo = -65
B = I.rotate(rot_angulo, expand = True) # rotamos sin recortar
B4 = np.asarray(B,dtype=np.float32)
sY,sX = np.shape(B4)
plt.figure()
plt.imshow(B,cmap = 'gray');
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 14/23
5/4/2021 Fourier2D
In [25]:
F4 = fft2(B4)/(sX*sY)
F4 = fftshift(F4)
P4 = np.abs(F4)
plt.figure()
plt.imshow(P4[cY-25:cY+25,cX-25:cX+25], extent=[-25,25,-25,25]);
Como hay una región grande de valor constante (negro), el valor del espectro de
potencia en el origen es alto, haciendo que no resalten los valores de las frecuencias
importantes. Eliminamos este efecto restando el valor medio de la imagen.
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 15/23
5/4/2021 Fourier2D
In [26]:
F4 = fft2(B4-B4.mean())/(sX*sY)
F4 = fftshift(F4)
P4 = np.abs(F4)
plt.figure()
plt.imshow(P4[cY-25:cY+25,cX-25:cX+25], extent=[-25,25,-25,25]);
In [27]:
alpha=np.arctan(maxY/maxX)*180/np.pi
alpha = 65.1189251526
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 16/23
5/4/2021 Fourier2D
In [28]:
C=B.rotate(alpha)
plt.figure()
plt.imshow(C,cmap = 'gray');
Ejercicio
In [29]:
%run angulo.py
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 17/23
5/4/2021 Fourier2D
In [30]:
I5 = Image.open("surcos1.jpg")
print alpha5
plt.figure()
plt.imshow(I5);
plt.figure()
plt.imshow(C5);
plt.figure()
plt.imshow(P5);
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 18/23
5/4/2021 Fourier2D
-30.865815124
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 19/23
5/4/2021 Fourier2D
En este ejemplo, el algoritmo funcionó bien. Fijarse en que los valores altos de P5 están
lejos del origen.
Sin embargo, en el ejemplo siguiente, el algoritmo no funciona. ¿Por qué? ¿Cómo podría
arreglarse?
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 20/23
5/4/2021 Fourier2D
In [31]:
I6 = Image.open("surcos2.jpg")
alpha6, C6, P6 = angulo(I6)
print alpha6
plt.figure()
plt.imshow(I6);
plt.figure()
plt.imshow(C6);
plt.figure()
plt.imshow(P6);
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 21/23
5/4/2021 Fourier2D
-90.0
<string>:26: RuntimeWarning: divide by zero encountered in double_sc
alars
Inicio
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 22/23
5/4/2021 Fourier2D
Imágenes
(http://www.unioviedo.es/compnum/laboratorios_
https://www.unioviedo.es/compnum/laboratorios_py/Fourier/Fourier2D.html 23/23