Skip to content

Commit 56dc5c5

Browse files
authored
Merge pull request #50 from AllenInstitute/kt_stitch
Kt stitch
2 parents aace92c + 5338431 commit 56dc5c5

File tree

7 files changed

+634
-0
lines changed

7 files changed

+634
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import numpy
2+
from acpreprocessing.stitching_modules.acstitch.rtccorr import get_point_correspondence
3+
4+
5+
def get_correspondences(A1_ds,A2_ds,A1_pts,A2_pts,w,r=1,pad=False,cc_threshold=0.8,min_value=0):
6+
cc_threshold /= r # TODO: is this the correct rescaling accounting for expanding reference?
7+
w = numpy.asarray(w,dtype=int)
8+
if len(A1_pts.shape)<2:
9+
A1_pts = numpy.array([A1_pts])
10+
A2_pts = numpy.array([A2_pts])
11+
pm1 = []
12+
pm2 = []
13+
for p,q in zip(A1_pts.astype(int),A2_pts.astype(int)):
14+
A2sub = A2_ds[0,0,(q-r*w)[0]:(q+r*w)[0],(q-r*w)[1]:(q+r*w)[1],(q-r*w)[2]:(q+r*w)[2]]
15+
A1sub = A1_ds[0,0,(p-w)[0]:(p+w)[0],(p-w)[1]:(p+w)[1],(p-w)[2]:(p+w)[2]]
16+
if r > 1:
17+
pw = numpy.asarray([((r-1)*wi,(r-1)*wi) for wi in w],dtype=int)
18+
A1sub = numpy.pad(A1sub,pw)
19+
p1,p2 = get_point_correspondence(p,q,A1sub,A2sub,autocorrelation_threshold=cc_threshold,padarray=pad,value_threshold=min_value)
20+
if not p1 is None:
21+
pm1.append(p1)
22+
pm2.append(p2)
23+
if pm1:
24+
return numpy.asarray(pm1),numpy.asarray(pm2)
25+
return None,None
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
Created on Mon Jul 31 13:33:46 2023
4+
5+
@author: kevint
6+
"""
7+
8+
import json
9+
import gzip
10+
import numpy
11+
12+
class NumpyEncoder(json.JSONEncoder):
13+
def default(self, obj):
14+
if isinstance(obj, numpy.ndarray):
15+
return obj.tolist()
16+
return json.JSONEncoder.default(self, obj)
17+
18+
19+
def save_pointmatch_file(pmdata,jsonpath):
20+
with gzip.open(jsonpath, 'w') as fout:
21+
fout.write(json.dumps(pmdata,cls=NumpyEncoder).encode('utf-8'))
22+
23+
24+
def read_pointmatch_file(jsonpath):
25+
with gzip.open(jsonpath, 'r') as fin:
26+
data = json.loads(fin.read().decode('utf-8'))
27+
if data:
28+
for tspec in data:
29+
for key in ["p_pts","q_pts"]:
30+
if not tspec[key] is None:
31+
tspec[key] = numpy.asarray(tspec[key])
32+
return data
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
2+
import numpy
3+
import scipy.ndimage
4+
5+
def correlate_fftns(fft1, fft2):
6+
prod = fft1 * fft2.conj()
7+
res = numpy.fft.ifftn(prod)
8+
9+
corr = numpy.fft.fftshift(res).real
10+
return corr
11+
12+
13+
def ccorr_fftn(img1, img2):
14+
# TODO do we want to pad this?
15+
fft1 = numpy.fft.fftn(img1)
16+
fft2 = numpy.fft.fftn(img2)
17+
18+
return correlate_fftns(fft1, fft2)
19+
20+
21+
def autocorr_fftn(img):
22+
fft = numpy.fft.fftn(img)
23+
return correlate_fftns(fft, fft)
24+
25+
26+
def ccorr_and_autocorr_fftn(img1, img2):
27+
# TODO do we want to pad this?
28+
fft1 = numpy.fft.fftn(img1)
29+
fft2 = numpy.fft.fftn(img2)
30+
ccorr = correlate_fftns(fft1, fft2)
31+
acorr1 = correlate_fftns(fft1, fft1)
32+
acorr2 = correlate_fftns(fft2, fft2)
33+
return ccorr, acorr1, acorr2
34+
35+
36+
def subpixel_maximum(arr):
37+
max_loc = numpy.unravel_index(numpy.argmax(arr), arr.shape)
38+
39+
sub_arr = arr[
40+
tuple(slice(ml-1, ml+2) for ml in max_loc)
41+
]
42+
43+
# get center of mass of sub_arr
44+
subpixel_max_loc = numpy.array(scipy.ndimage.center_of_mass(sub_arr)) - 1
45+
return subpixel_max_loc + max_loc
46+
47+
48+
def ccorr_disp(img1, img2, autocorrelation_threshold=None, padarray=False, value_threshold=0):
49+
if padarray:
50+
d = numpy.ceil(numpy.array(img1.shape) / 2)
51+
pw = numpy.asarray([(di,di) for di in d],dtype=int)
52+
img1 = numpy.pad(img1,pw)
53+
img2 = numpy.pad(img2,pw)
54+
if value_threshold:
55+
img1[img1<value_threshold] = 0
56+
img2[img2<value_threshold] = 0
57+
if autocorrelation_threshold is not None:
58+
cc, ac1, ac2 = ccorr_and_autocorr_fftn(img1, img2)
59+
ac1max = ac1.max()
60+
ac2max = ac2.max()
61+
if (not numpy.isnan(ac1max) and ac1max > 0) and (not numpy.isnan(ac2max) and ac2max > 0):
62+
autocorrelation_ratio = cc.max() / (numpy.sqrt(ac1max*ac2max))
63+
if autocorrelation_ratio < autocorrelation_threshold:
64+
# what to do here?
65+
print("ratio below threshold: " + str(autocorrelation_ratio))
66+
return None
67+
else:
68+
return None
69+
else:
70+
cc = ccorr_fftn(img1, img2)
71+
max_loc = subpixel_maximum(cc)
72+
mid_point = numpy.array(img1.shape) // 2
73+
return max_loc - mid_point
74+
75+
76+
def get_point_correspondence(src_pt, dst_pt, src_patch, dst_patch, autocorrelation_threshold=0.8,padarray=False,value_threshold=0):
77+
disp = ccorr_disp(src_patch, dst_patch, autocorrelation_threshold, padarray,value_threshold)
78+
if disp is not None:
79+
return src_pt, dst_pt - disp
80+
return None,None

0 commit comments

Comments
 (0)