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 __author__ = "$Author: bolme $"
35 __version__ = "$Rev: 625 $"
36 __info__ = "$Id: PhaseCorrelation.py 625 2008-03-24 20:24:37Z bolme $"
37 __copyright__ = "Copyright 2006 David S Bolme"
38
39 import numpy as np
40 import pyvision as pv
41
42
44 '''
45 Uses phase correlation to estimate the best integer displacement to align the images.
46 Also fits a quadradic to the correltaion surface to determine a sub pixel estimate of
47 displacement.
48
49 Returns four values as a tuple: max_corr, max_displacement, est_corr, est_displacement
50 max_corr - maximum correlation value.
51 max_displacement - displacement needed to obtain the maximum correlation. (full pixel)
52 est_corr - estimated corelation value if subpixel displacement is used.
53 est_displacement - estimated displacement (subpixel)
54
55 see http://en.wikipedia.org/wiki/Phase_correlation
56 '''
57 if isinstance(tile1,pv.Image):
58 tile1 = tile1.asMatrix2D()
59 else:
60 tile1 = pv.Image(tile1).asMatrix2D()
61 raise TypeError("Please pass in a numpy array or a pyvision image.")
62
63 if isinstance(tile2,pv.Image):
64 tile2 = tile2.asMatrix2D()
65 else:
66 tile2 = pv.Image(tile2).asMatrix2D()
67
68 if tile1.shape != tile2.shape:
69 raise ValueError("Image tiles must have the same shape. [tile1 %s] != [tile2 %s]"%(tile1.shape,tile2.shape))
70
71
72 tile1 = tile1.copy()
73 tile2 = tile2.copy()
74
75
76 tile1 = pv.meanUnit(tile1)
77 tile2 = pv.meanUnit(tile2)
78
79
80 Ia = np.fft.fft2(tile1)
81 Ib = np.conjugate(np.fft.fft2(tile2))
82
83
84 ncs = Ia*Ib
85
86 if phase_only:
87 ncs = ncs/np.abs(ncs)
88
89
90 pc = np.real(np.fft.ifft2(ncs))
91
92 if ilog != None:
93 ilog.log(pv.Image(tile1),label="Tile1")
94 ilog.log(pv.Image(tile2),label="Tile2")
95 ilog.log(pv.Image(np.fft.fftshift(pc)),label="Correlation")
96
97 max_corr = pc.max()
98 max_elem = (pc == max_corr).nonzero()
99 max_elem = max_elem[0][0],max_elem[1][0]
100
101 max_point = list(max_elem)
102 if max_elem[0]*2 > tile1.shape[0]:
103 max_point[0] = -tile1.shape[0] + max_elem[0]
104 if max_elem[1]*2 > tile1.shape[1]:
105 max_point[1] = -tile1.shape[1] + max_elem[1]
106
107 est_corr, est_point = QuadradicEstimation(pc,max_point)
108
109 return max_corr, max_point, est_corr, est_point
110
111
112
114 '''
115 Estimate the subpixel displacement based on fitting a quadradic surface
116 to area surrounding the max point.
117
118 returns the estimated power spectrum at the subpixel point, and the displacement.
119 '''
120
121
122 def create_row(x,y):
123 return [x*x, y*y, x, y, 1]
124
125 A = []
126 b = []
127
128 x = max_point[0]
129 y = max_point[1]
130 A.append(create_row(x,y))
131 b.append([pc[x,y]])
132
133 x = max_point[0]+1
134 y = max_point[1]
135 A.append(create_row(x,y))
136 b.append([pc[x,y]])
137
138 x = max_point[0]-1
139 y = max_point[1]
140 A.append(create_row(x,y))
141 b.append([pc[x,y]])
142
143 x = max_point[0]
144 y = max_point[1]+1
145 A.append(create_row(x,y))
146 b.append([pc[x,y]])
147
148 x = max_point[0]
149 y = max_point[1]-1
150 A.append(create_row(x,y))
151 b.append([pc[x,y]])
152
153 A = np.array(A)
154 b = np.array(b)
155
156 lss = np.linalg.lstsq(A,b)
157 assert lss[2] == 5
158 x = lss[0]
159
160 a = x[0,0]
161 b = x[1,0]
162 c = x[2,0]
163 d = x[3,0]
164 e = x[4,0]
165
166
167
168
169 x = -c/(2*a)
170 y = -d/(2*b)
171
172
173 emax = a*x*x + b*y*y + c*x + d*y + e
174
175 return emax, [x,y]
176
177
178 import unittest
179
181
183 import os.path
184
185 filename_a = os.path.join(pv.__path__[0],'data','test','registration1a.jpg')
186 filename_b = os.path.join(pv.__path__[0],'data','test','registration1b.jpg')
187
188 im_a = pv.Image(filename_a)
189 im_b = pv.Image(filename_b)
190
191 out = PhaseCorrelation(im_a,im_b,phase_only=False)
192
193 self.assertAlmostEqual(out[0],0.87382160686468002,places=3)
194 self.assertEqual(out[1][0],20)
195 self.assertEqual(out[1][1],20)
196 self.assertAlmostEqual(out[2],0.87388092414032315,places=3)
197 self.assertAlmostEqual(out[3][0],19.978881341260816,places=3)
198 self.assertAlmostEqual(out[3][1],19.986396178942329,places=3)
199
201 import os.path
202
203 filename_a = os.path.join(pv.__path__[0],'data','test','registration1a.jpg')
204 filename_b = os.path.join(pv.__path__[0],'data','test','registration1b.jpg')
205
206 im_a = pv.Image(filename_a)
207 im_b = pv.Image(filename_b)
208
209 out = PhaseCorrelation(im_a,im_b,phase_only=False)
210
211 self.assertAlmostEqual(out[0],0.87382160686468002,places=3)
212 self.assertEqual(out[1][0],20)
213 self.assertEqual(out[1][1],20)
214 self.assertAlmostEqual(out[2],0.87388092414032315,places=3)
215 self.assertAlmostEqual(out[3][0],19.978881341260816,places=3)
216 self.assertAlmostEqual(out[3][1],19.986396178942329,places=3)
217