-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathfft.py
163 lines (127 loc) · 4.36 KB
/
fft.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# Python 2.7
#
# Pre-requisite packages:
# Opencv 3
# Numpy
# Scipy
#
# How to execute:
# 1. Run a single image
# python fft.py [-h] [--dir DIR] [--filename FILENAME]
# Ex:
# python fft.py --filename Q1.tif
#
# 2. You can put Q1.tif~Q4.tif into "images" folder and execute
# ./run.sh
#
#
# optional arguments:
# -h, --help show this help message and exit
# --filename FILENAME Specify the input image's name
# --dir DIR Specify location of the input image. Default value will be current directory [Default: current dir]
#
import argparse, os
import cv2
import numpy as np
from scipy import ndimage, misc
def zero_padding(image):
"""
Zero padding the image two the nearest power-of-2 rows and cols
"""
assert len(image.shape) == 2
M, N = image.shape
new_row = M
new_col = N
while new_row&(new_row-1):
new_row+=1
while new_col&(new_col-1):
new_col+=1
padded_image = np.zeros((new_row, new_col))
padded_image[:M,:N] = image[:,:]
return padded_image
def cooley_tukey_dit_fft(x, inverse=False):
"""
1. This transform is based on Cooley-Tukey decimation-in-time radix-2 algorithm.
2. Require the input x's length to be the power-of-2. In order to compute the FFT of the input x.
"""
# Returns the integer whose value is the reverse of the lowest 'bits' bits of the integer 'x'.
def bit_reversal_permutation(_x, bits):
y = 0
for i in xrange(bits):
y = (y << 1) | (_x & 1)
_x >>= 1
return y
N = x.shape[0]
levels = N.bit_length()-1 # levels = log2(n)
if 2 ** levels != N:
raise ValueError("Length is not a power of 2")
coef = (2j if inverse else -2j) * np.pi / N
W_exp = np.exp(np.arange(N//2) * coef)
# Copy with bit-reversed permutation
x = [x[bit_reversal_permutation(i, levels)] for i in range(N)]
# Radix-2 decimation-in-time FFT
size = 2
while size <= N:
half_size = size // 2
table_step = N // size
for i in xrange(0, N, size):
k = 0
for j in range(i, i + half_size):
temp = x[j + half_size] * W_exp[k]
x[j + half_size] = x[j] - temp
x[j] += temp
k += table_step
size *= 2
return np.asarray(x)
def FFT2D(image):
""" implementation of 2-D Fast Fourier Transform """
M, N = image.shape
FFT_result = np.zeros_like(image, dtype=complex)
for i in xrange(M):
FFT_result[i,:] = cooley_tukey_dit_fft(image[i,:])
for j in xrange(N):
FFT_result[:, j] = cooley_tukey_dit_fft(FFT_result[:, j])
return FFT_result
def FFT2D_shift(fft):
""" Shift the zero frequency to the center of the 2-D Fourier Transform """
rows, cols = fft.shape
tmp = np.zeros_like(fft)
ret = np.zeros_like(fft)
for i in xrange(rows):
for j in xrange(cols):
index = (cols/2 + j) % cols
tmp[i, index] = fft[i, j]
for j in xrange(cols):
for i in xrange(rows):
index = (rows/2 + i) % rows
ret[index, j] = tmp[i, j]
return ret
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument(
'--dir',
type=str,
help='Specify location of the input image. Default value will be current directory',
)
parser.add_argument(
'--filename',
type=str,
help='Specify the input image\'s name',
)
args = parser.parse_args()
filename = "noname.png" if not args.filename else args.filename
if args.dir is None:
cwd = os.getcwd()
image_path = os.path.join(cwd, "images", filename)
else:
image_path = os.path.join(args.dir, filename)
img = ndimage.imread(image_path, flatten=True)
padded_img = zero_padding(img)
# Compute the unshifted FFT of the padded image
unshifted_fft = FFT2D(padded_img)
spectrum = np.log10(np.absolute(unshifted_fft) + np.ones_like(padded_img))
misc.imsave("images/%s_unshifted_fft.png" % filename.split('.')[0], spectrum)
# Compute the shifted FFT of the padded image
shifted_fft = FFT2D_shift(unshifted_fft)
spectrum = np.log10(np.absolute(shifted_fft) + np.ones_like(padded_img))
misc.imsave("images/%s_shifted_fft.png" % filename.split('.')[0], spectrum)