11 # a BLOCKS x BLOCKS section is correlated with a (BLOCKS + 1) x (BLOCKS + 1)
12 # the maximum allowable shift is BLOCK_SIZE with BLOCKS of surrounding context
21 in_jpg0 = 'tank_battle/down_2364.jpg'
22 in_jpg1 = 'tank_battle/down_2365.jpg'
23 out_jpg0 = 'out0_2364.jpg'
24 out_jpg1 = 'out0_2365.jpg'
26 print(f'read {in_jpg0:s}')
27 image0 = gamma.read_image(in_jpg0)
30 sys.stderr.write(f'write {out_jpg0:s}\n')
31 gamma.write_image(out_jpg0, image0)
33 print(f'read {in_jpg1:s}')
34 image1 = gamma.read_image(in_jpg1)
35 assert image1.shape == shape
38 xb = (xs // BLOCK_SIZE - BLOCKS) // 2
39 yb = (ys // BLOCK_SIZE - BLOCKS) // 2
40 print('xb', xb, 'yb', yb)
43 _, _, cs = image.shape
46 scipy.ndimage.gaussian_filter(image[:, :, i], CUTOFF1, mode = 'mirror') -
47 scipy.ndimage.gaussian_filter(image[:, :, i], CUTOFF0, mode = 'mirror')
53 def correlate(image0_bp, image1_bp, xc, yc):
54 x0 = xc - BLOCKS * BLOCK_SIZE // 2
55 y0 = yc - BLOCKS * BLOCK_SIZE // 2
56 x1 = xc - (BLOCKS + 1) * BLOCK_SIZE // 2
57 y1 = yc - (BLOCKS + 1) * BLOCK_SIZE // 2
60 y0:y0 + BLOCK_SIZE * BLOCKS,
61 x0:x0 + BLOCK_SIZE * BLOCKS,
65 y1:y1 + (BLOCKS + 1) * BLOCK_SIZE,
66 x1:x1 + (BLOCKS + 1) * BLOCK_SIZE,
70 # note: swapping block1, block0 flips the output (subtracts x and y
71 # from BLOCK_SIZE) and we need this to find matching part of image1
75 scipy.signal.correlate(
86 #temp = corr - numpy.mean(corr)
87 #temp /= 10. * numpy.sqrt(numpy.mean(numpy.square(temp)))
88 #gamma.write_image(f'corr_{i:d}_{j:d}.jpg', temp + .5)
90 y, x = numpy.unravel_index(numpy.argmax(corr), corr.shape)
92 (x - BLOCK_SIZE // 2, y - BLOCK_SIZE // 2)
95 x <= BLOCK_SIZE - CUTOFF1 and
97 y <= BLOCK_SIZE - CUTOFF1
103 image0_bp = bandpass(image0)
104 gamma.write_image('image0_bp.jpg', image0_bp + .5)
107 image1_bp = bandpass(image1)
108 gamma.write_image('image1_bp.jpg', image1_bp + .5)
110 print('find corner candidates')
111 buckets = [[[], []], [[], []]]
112 for i in range(yb - BLOCKS):
113 for j in range(xb - BLOCKS):
114 xc = j * BLOCK_SIZE + (BLOCKS + 1) * BLOCK_SIZE // 2
118 corner_candidates = []
121 # correlate blocks in (i, j)-corner
125 yc = k * BLOCK_SIZE + (BLOCKS + 1) * BLOCK_SIZE // 2
129 xc = l * BLOCK_SIZE + (BLOCKS + 1) * BLOCK_SIZE // 2
132 offset = correlate(image0_bp, image1_bp, xc, yc)
133 if offset is not None:
134 offsets.append(offset)
138 #print('i', i, 'j', j, 'k', k, 'l', l, 'x', x, 'y', y)
139 p_all.append(numpy.array([xc, yc], numpy.double))
140 q_all.append(numpy.array([xc1, yc1], numpy.double))
141 blocks.append((xc, yc, xc1, yc1))
143 # find the trend in (i, j)-corner
145 xm = sorted([x for x, _ in offsets])[k]
146 ym = sorted([y for _, y in offsets])[k]
147 #print('i', i, 'j', j, 'xm', xm, 'ym', ym)
149 # choose CORNER_CANDIDATES blocks closest to trend in (i, j)-corner
150 u = numpy.array(offsets, numpy.double)
151 v = numpy.array([xm, ym], numpy.double)
152 dist = numpy.sum(numpy.square(u - v[numpy.newaxis, :]), 1)
153 corner_candidates.append(
155 [(dist[i],) + blocks[i] for i in range(len(blocks))]
156 )[:CORNER_CANDIDATES]
158 p_all = numpy.stack(p_all, 1)
159 q_all = numpy.stack(q_all, 1)
161 # try all combinations of the corner candidates
162 print('try corner candidates')
163 p = numpy.zeros((2, 4), numpy.double)
164 q = numpy.zeros((2, 4), numpy.double)
167 for _, xc00, yc00, xc10, yc10 in corner_candidates[0]:
172 for _, xc01, yc01, xc11, yc11 in corner_candidates[1]:
177 for _, xc02, yc02, xc12, yc12 in corner_candidates[2]:
182 for _, xc03, yc03, xc13, yc13 in corner_candidates[3]:
188 A = perspective.calc_transform(p, q)
191 q_all - perspective.apply_transform_multi(A, p_all)
194 if best_dist is None or dist < best_dist:
199 out_image1 = perspective.remap_image(best_A, image1)
201 sys.stderr.write(f'write {out_jpg1:s}\n')
202 gamma.write_image(out_jpg1, out_image1)