-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathMTF.py
152 lines (128 loc) · 5.13 KB
/
MTF.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
# -*- coding: utf-8 -*-
"""
Script to calculate the Modulation transfer function of a edge target.
Kickstarted from from https://gist.github.com/stefanv/2051954 and additional
info from http://www.normankoren.com/Tutorials/MTF.html which tells us that
"MTF can be defined as the magnitude of the Fourier transform of the point or
line spread function. And some wikipedia lookup.
"""
import numpy as np
import scipy
import scipy.ndimage
import matplotlib.pylab as plt
import time
def MTF(edgespreadfunction):
'''
Compute the modulation transfer function (MTF).
The MTF is defined as the FFT of the line spread function.
The line spread function is defined as the derivative of the edge spread
function. The edge spread function are the values along an edge, ideally a
knife-edge test target. See an explanation here: http://is.gd/uSC5Ve
'''
linespreadfunction = np.diff(edgespreadfunction)
return np.abs(np.fft.fft(linespreadfunction))
def LSF(edgespreadfunction):
'''
Compute the modulation transfer function (MTF).
The MTF is defined as the FFT of the line spread function.
The line spread function is defined as the derivative of the edge spread
function. The edge spread function are the values along an edge, ideally a
knife-edge test target. See an explanation here: http://is.gd/uSC5Ve
'''
return np.abs(np.diff(edgespreadfunction))
def polynomialfit(data, order):
'''
calculate the polynomial fit of an input for a defined degree
'''
x, y = range(len(data)), data
coefficients = np.polyfit(x, y, order)
return np.polyval(coefficients, x)
# Generate edge for N points
N = 250
dirac = np.zeros(N)
dirac[:N / 2] = 1
# Filter edge
sigma = [0.4, 0.6, 1]
gauss_1 = scipy.ndimage.gaussian_filter(dirac, sigma=sigma[0])
gauss_2 = scipy.ndimage.gaussian_filter(dirac, sigma=sigma[1])
gauss_3 = scipy.ndimage.gaussian_filter(dirac, sigma=sigma[2])
SaveFigure = False
# Total = 55
# for iteration in range(Total):
# print 'Plotting', iteration, 'of', Total
noise_sigma = 0.001
gauss_1_noise = gauss_1 + noise_sigma * np.random.randn(len(dirac))
gauss_2_noise = gauss_2 + noise_sigma * np.random.randn(len(dirac))
gauss_3_noise = gauss_3 + noise_sigma * np.random.randn(len(dirac))
'''
Save the plots in a dictionary, so we can iterate through it afterwards. See
http://stackoverflow.com/a/2553532/323100 and http://is.gd/d008ai for reference
'''
plots = dict((name, eval(name)) for name in ['dirac',
'gauss_1', 'gauss_1_noise',
'gauss_2', 'gauss_2_noise',
'gauss_3', 'gauss_3_noise'])
plt.figure(figsize=(16, 16))
counter = 0
ShowRegion = 10
for name, data in sorted(plots.iteritems()):
counter += 1
plt.subplot(4, len(plots), counter)
plt.plot(data)
plt.ylim(-0.1, 1.1)
# plt.xlim(len(dirac) / 2 - ShowRegion / 2, len(dirac) / 2 + ShowRegion /
# 2)
if name == 'dirac':
plt.ylabel('Edge response')
plt.title(name)
if name == 'gauss_1':
plt.title(name + '\nSigma=' + str(sigma[0]))
if name == 'gauss_2':
plt.title(name + '\nSigma=' + str(sigma[1]))
if name == 'gauss_3':
plt.title(name + '\nSigma=' + str(sigma[2]))
plt.subplot(4, len(plots), counter + len(plots))
plt.plot(LSF(data))
plt.ylim(-0.1, 1.1)
if name == 'dirac':
plt.ylabel('Edge response')
plt.subplot(4, len(plots), counter + 2 * len(plots))
plt.plot(MTF(data))
plt.plot(np.ones(N) * MTF(data)[len(dirac) / 2])
plt.ylim(-0.1, 1.1)
plt.xlim(0, len(dirac) / 2)
if name == 'dirac':
plt.ylabel('MTF @ Nyquist')
plt.text(0.618 * len(dirac) / 2, MTF(data)[len(dirac) / 2] - 0.1,
' '.join([str(np.round(MTF(data)[len(dirac) / 2], 3) * 100),
'%']),
fontsize=12, backgroundcolor='w')
plt.subplot(4, len(plots), counter + 3 * len(plots))
plt.plot(MTF(data), label='orig')
# for degree in range(10,25):
# plt.plot(polynomialfit(MTF(data), degree), label=str(degree))
# plt.legend()
degree = 4
plt.plot(polynomialfit(MTF(data), degree), label=str(degree), color='r')
plt.plot(np.ones(N) * polynomialfit(MTF(data), degree)[len(dirac) / 2],
color='g')
plt.ylim(-0.1, 1.1)
plt.xlim(0, len(dirac) / 2)
if name == 'dirac':
plt.ylabel(' '.join(['polynomial fit of order', str(degree),
'\nfitted MTF @ Nyquist']))
plt.text(0.618 * len(dirac) / 2, MTF(data)[len(dirac) / 2] - 0.1,
' '.join([str(np.round(polynomialfit(MTF(data),
degree)[len(dirac) / 2],
3) * 100), '%']),
fontsize=12, backgroundcolor='w')
plt.subplot(4, len(plots), 1)
plt.plot(dirac, 'b')
plt.ylim(-0.1, 1.1)
plt.axvspan(len(dirac) / 2 - ShowRegion / 2, len(dirac) / 2 + ShowRegion / 2,
facecolor='r', alpha=0.5)
plt.title('Ideal knife edge\n red zoom-region\n is shown right')
if SaveFigure:
plt.savefig('MTF_' + str(int(time.time() * 10)) + '.png')
else:
plt.show()