pytme 0.2.0b0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytme-0.2.0b0 → pytme-0.2.1}/MANIFEST.in +1 -2
- {pytme-0.2.0b0 → pytme-0.2.1}/PKG-INFO +2 -2
- {pytme-0.2.0b0 → pytme-0.2.1}/pyproject.toml +2 -2
- {pytme-0.2.0b0 → pytme-0.2.1}/pytme.egg-info/SOURCES.txt +8 -1
- pytme-0.2.1/scripts/extract_candidates.py +250 -0
- pytme-0.2.0b0/scripts/match_template_filters.py → pytme-0.2.1/scripts/match_template.py +449 -168
- pytme-0.2.0b0/scripts/match_template.py → pytme-0.2.1/scripts/match_template_filters.py +482 -141
- {pytme-0.2.0b0 → pytme-0.2.1}/scripts/postprocess.py +107 -49
- {pytme-0.2.0b0 → pytme-0.2.1}/scripts/preprocessor_gui.py +4 -1
- pytme-0.2.1/scripts/refine_matches.py +422 -0
- pytme-0.2.1/tme/__version__.py +1 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/analyzer.py +278 -148
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/backends/__init__.py +1 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/backends/cupy_backend.py +20 -13
- pytme-0.2.1/tme/backends/jax_backend.py +218 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/backends/matching_backend.py +25 -10
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/backends/mlx_backend.py +13 -9
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/backends/npfftw_backend.py +22 -12
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/backends/pytorch_backend.py +20 -9
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/density.py +85 -64
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/matching_data.py +86 -60
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/matching_exhaustive.py +245 -166
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/matching_optimization.py +137 -69
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/matching_utils.py +1 -1
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/orientations.py +175 -55
- pytme-0.2.1/tme/preprocessing/__init__.py +2 -0
- pytme-0.2.1/tme/preprocessing/_utils.py +188 -0
- pytme-0.2.1/tme/preprocessing/composable_filter.py +31 -0
- pytme-0.2.1/tme/preprocessing/compose.py +51 -0
- pytme-0.2.1/tme/preprocessing/frequency_filters.py +378 -0
- pytme-0.2.1/tme/preprocessing/tilt_series.py +1017 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/preprocessor.py +17 -7
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/structure.py +4 -1
- pytme-0.2.0b0/scripts/extract_candidates.py +0 -218
- pytme-0.2.0b0/scripts/refine_matches.py +0 -218
- pytme-0.2.0b0/tme/__version__.py +0 -1
- {pytme-0.2.0b0 → pytme-0.2.1}/LICENSE +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/README.md +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/scripts/__init__.py +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/scripts/estimate_ram_usage.py +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/scripts/preprocess.py +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/setup.cfg +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/setup.py +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/src/extensions.cpp +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/__init__.py +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/__init__.py +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48n309.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48n527.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48n9.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u1.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u1153.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u1201.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u1641.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u181.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u2219.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u27.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u2947.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u3733.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u4749.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u5879.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u7111.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u815.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u83.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c48u8649.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c600v.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/c600vc.npy +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/metadata.yaml +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/data/quat_to_numpy.py +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/helpers.py +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/matching_constrained.py +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/matching_memory.py +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/parser.py +0 -0
- {pytme-0.2.0b0 → pytme-0.2.1}/tme/types.py +0 -0
@@ -60,7 +60,6 @@ global-exclude .DS_Store
|
|
60
60
|
global-exclude .gitconfig
|
61
61
|
global-exclude *.pickle
|
62
62
|
prune tme/temp
|
63
|
-
prune tme/preprocessing
|
64
63
|
global-exclude doc/compileApiReference.sh
|
65
64
|
prune public
|
66
65
|
global-exclude tme/matching_backend.py
|
@@ -70,4 +69,4 @@ global-exclude tme/scoring.py
|
|
70
69
|
global-exclude tme/package.py
|
71
70
|
global-exclude tme/transforms.py
|
72
71
|
global-exclude tme/tests/test_packaging.py
|
73
|
-
global-exclude scripts/match_template_devel.py
|
72
|
+
global-exclude scripts/match_template_devel.py
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pytme
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.1
|
4
4
|
Summary: Python Template Matching Engine
|
5
5
|
Author: Valentin Maurer
|
6
6
|
Author-email: Valentin Maurer <valentin.maurer@embl-hamburg.de>
|
@@ -22,7 +22,7 @@ Requires-Dist: scikit_learn>=1.2.1
|
|
22
22
|
Requires-Dist: scipy>=1.9.1
|
23
23
|
Requires-Dist: pybind11
|
24
24
|
Requires-Dist: psutil
|
25
|
-
Requires-Dist: tifffile
|
25
|
+
Requires-Dist: tifffile
|
26
26
|
Requires-Dist: h5py
|
27
27
|
|
28
28
|
# Python Template Matching Engine (PyTME)
|
@@ -7,7 +7,7 @@ name="pytme"
|
|
7
7
|
authors = [
|
8
8
|
{ name = "Valentin Maurer", email = "valentin.maurer@embl-hamburg.de" },
|
9
9
|
]
|
10
|
-
version="0.2.
|
10
|
+
version="0.2.1"
|
11
11
|
description="Python Template Matching Engine"
|
12
12
|
readme="README.md"
|
13
13
|
requires-python = ">=3.11"
|
@@ -23,7 +23,7 @@ dependencies=[
|
|
23
23
|
"scipy>=1.9.1",
|
24
24
|
"pybind11",
|
25
25
|
"psutil",
|
26
|
-
"tifffile
|
26
|
+
"tifffile",
|
27
27
|
"h5py"
|
28
28
|
]
|
29
29
|
license = {text = "Proprietary"}
|
@@ -31,6 +31,7 @@ tme/structure.py
|
|
31
31
|
tme/types.py
|
32
32
|
tme/backends/__init__.py
|
33
33
|
tme/backends/cupy_backend.py
|
34
|
+
tme/backends/jax_backend.py
|
34
35
|
tme/backends/matching_backend.py
|
35
36
|
tme/backends/mlx_backend.py
|
36
37
|
tme/backends/npfftw_backend.py
|
@@ -57,4 +58,10 @@ tme/data/c48u8649.npy
|
|
57
58
|
tme/data/c600v.npy
|
58
59
|
tme/data/c600vc.npy
|
59
60
|
tme/data/metadata.yaml
|
60
|
-
tme/data/quat_to_numpy.py
|
61
|
+
tme/data/quat_to_numpy.py
|
62
|
+
tme/preprocessing/__init__.py
|
63
|
+
tme/preprocessing/_utils.py
|
64
|
+
tme/preprocessing/composable_filter.py
|
65
|
+
tme/preprocessing/compose.py
|
66
|
+
tme/preprocessing/frequency_filters.py
|
67
|
+
tme/preprocessing/tilt_series.py
|
@@ -0,0 +1,250 @@
|
|
1
|
+
#!python3
|
2
|
+
""" Prepare orientations stack for refinement.
|
3
|
+
|
4
|
+
Copyright (c) 2023 European Molecular Biology Laboratory
|
5
|
+
|
6
|
+
Author: Valentin Maurer <valentin.maurer@embl-hamburg.de>
|
7
|
+
"""
|
8
|
+
import argparse
|
9
|
+
from os.path import splitext
|
10
|
+
|
11
|
+
import numpy as np
|
12
|
+
|
13
|
+
from tme import Density, Orientations
|
14
|
+
from tme.matching_utils import (
|
15
|
+
load_pickle,
|
16
|
+
generate_tempfile_name,
|
17
|
+
rotation_aligning_vectors,
|
18
|
+
euler_from_rotationmatrix,
|
19
|
+
euler_to_rotationmatrix,
|
20
|
+
)
|
21
|
+
|
22
|
+
|
23
|
+
class ProgressBar:
|
24
|
+
"""
|
25
|
+
ASCII progress bar.
|
26
|
+
"""
|
27
|
+
|
28
|
+
def __init__(self, message : str, nchars : int, total : int):
|
29
|
+
self._size = nchars - len(message)
|
30
|
+
self._message = message
|
31
|
+
self._total = total
|
32
|
+
|
33
|
+
def update(self, cur):
|
34
|
+
x = int(cur * self._size / self._total)
|
35
|
+
print(
|
36
|
+
"%s[%s%s] %i/%i\r"
|
37
|
+
% (self._message, "#" * x, "." * (self._size - x), cur, self._total),
|
38
|
+
end=''
|
39
|
+
)
|
40
|
+
|
41
|
+
|
42
|
+
def parse_args():
|
43
|
+
parser = argparse.ArgumentParser(
|
44
|
+
description="Extract matching candidates for further refinement."
|
45
|
+
)
|
46
|
+
|
47
|
+
io_group = parser.add_argument_group("Input / Output")
|
48
|
+
io_group.add_argument(
|
49
|
+
"--input_file",
|
50
|
+
required=False,
|
51
|
+
type=str,
|
52
|
+
help="Path to the output of match_template.py.",
|
53
|
+
)
|
54
|
+
io_group.add_argument(
|
55
|
+
"--orientations",
|
56
|
+
required=True,
|
57
|
+
type=str,
|
58
|
+
help="Path to file generated by postprocess.py using output_format orientations.",
|
59
|
+
)
|
60
|
+
io_group.add_argument(
|
61
|
+
"--target",
|
62
|
+
required=False,
|
63
|
+
type=str,
|
64
|
+
help="Extract candidates from this target, can be at different sampling rate.",
|
65
|
+
)
|
66
|
+
io_group.add_argument(
|
67
|
+
"--template",
|
68
|
+
required=False,
|
69
|
+
type=str,
|
70
|
+
help="Extract candidates from this target, can be at different sampling rate.",
|
71
|
+
)
|
72
|
+
io_group.add_argument(
|
73
|
+
"-o",
|
74
|
+
"--output_file",
|
75
|
+
required=True,
|
76
|
+
type=str,
|
77
|
+
help="Path to output HDF5 file.",
|
78
|
+
)
|
79
|
+
|
80
|
+
alignment_group = parser.add_argument_group("Alignment")
|
81
|
+
alignment_group.add_argument(
|
82
|
+
"--align_orientations",
|
83
|
+
action="store_true",
|
84
|
+
required=False,
|
85
|
+
help="Whether to align extracted orientations based on their angles. Allows "
|
86
|
+
"for efficient subsequent sampling of cone angles.",
|
87
|
+
)
|
88
|
+
alignment_group.add_argument(
|
89
|
+
"--angles_are_vector",
|
90
|
+
action="store_true",
|
91
|
+
required=False,
|
92
|
+
help="Considers euler_z euler_y, euler_x as vector that will be rotated to align "
|
93
|
+
"with the z-axis (1,0,0). Only considered when --align_orientations is set."
|
94
|
+
)
|
95
|
+
alignment_group.add_argument(
|
96
|
+
"--interpolation_order",
|
97
|
+
dest="interpolation_order",
|
98
|
+
required=False,
|
99
|
+
type=int,
|
100
|
+
default=1,
|
101
|
+
help="Interpolation order for alignment, less than zero is no interpolation."
|
102
|
+
)
|
103
|
+
|
104
|
+
extraction_group = parser.add_argument_group("Extraction")
|
105
|
+
extraction_group.add_argument(
|
106
|
+
"--box_size",
|
107
|
+
required=False,
|
108
|
+
type=int,
|
109
|
+
help="Box size for extraction, defaults to two times the template.",
|
110
|
+
)
|
111
|
+
extraction_group.add_argument(
|
112
|
+
"--keep_out_of_box",
|
113
|
+
action="store_true",
|
114
|
+
required=False,
|
115
|
+
help="Whether to keep orientations that fall outside the box. If the "
|
116
|
+
"orientations are sensible, it is safe to pass this flag.",
|
117
|
+
)
|
118
|
+
|
119
|
+
args = parser.parse_args()
|
120
|
+
|
121
|
+
data_present = args.target is not None and args.template is not None
|
122
|
+
if args.input_file is None and not data_present:
|
123
|
+
raise ValueError(
|
124
|
+
"Either --input_file or --target and --template need to be specified."
|
125
|
+
)
|
126
|
+
elif args.input_file is not None and data_present:
|
127
|
+
raise ValueError(
|
128
|
+
"Please specific either --input_file or --target and --template."
|
129
|
+
)
|
130
|
+
|
131
|
+
return args
|
132
|
+
|
133
|
+
|
134
|
+
def main():
|
135
|
+
args = parse_args()
|
136
|
+
orientations = Orientations.from_file(args.orientations)
|
137
|
+
|
138
|
+
if args.input_file is not None:
|
139
|
+
data = load_pickle(args.input_file)
|
140
|
+
target_origin, _, sampling_rate, cli_args = data[-1]
|
141
|
+
args.target, args.template = cli_args.target, cli_args.template
|
142
|
+
|
143
|
+
target = Density.from_file(args.target, use_memmap=True)
|
144
|
+
|
145
|
+
try:
|
146
|
+
template = Density.from_file(args.template)
|
147
|
+
except Exception:
|
148
|
+
template = Density.from_structure(args.template, sampling_rate = target.sampling_rate)
|
149
|
+
|
150
|
+
box_size = args.box_size
|
151
|
+
if box_size is None:
|
152
|
+
box_size = np.multiply(template.shape, 2)
|
153
|
+
box_size = np.array(box_size)
|
154
|
+
box_size = np.repeat(box_size, template.data.ndim // box_size.size).astype(int)
|
155
|
+
|
156
|
+
extraction_shape = np.copy(box_size)
|
157
|
+
if args.align_orientations:
|
158
|
+
extraction_shape[:] = int(np.linalg.norm(box_size) + 1)
|
159
|
+
|
160
|
+
orientations, cand_slices, obs_slices = orientations.get_extraction_slices(
|
161
|
+
target_shape=target.shape,
|
162
|
+
extraction_shape=extraction_shape,
|
163
|
+
drop_out_of_box=not args.keep_out_of_box,
|
164
|
+
return_orientations=True,
|
165
|
+
)
|
166
|
+
|
167
|
+
if args.align_orientations:
|
168
|
+
orientations.rotations = orientations.rotations.astype(np.float32)
|
169
|
+
for index in range(orientations.rotations.shape[0]):
|
170
|
+
rotation_matrix = euler_to_rotationmatrix(orientations.rotations[index])
|
171
|
+
rotation_matrix = np.linalg.inv(rotation_matrix)
|
172
|
+
if args.angles_are_vector:
|
173
|
+
rotation_matrix = rotation_aligning_vectors(
|
174
|
+
orientations.rotations[index], target_vector=(1,0,0)
|
175
|
+
)
|
176
|
+
orientations.rotations[index] = euler_from_rotationmatrix(rotation_matrix)
|
177
|
+
|
178
|
+
|
179
|
+
filename = generate_tempfile_name()
|
180
|
+
output_dtype = target.data.dtype
|
181
|
+
if args.align_orientations is not None:
|
182
|
+
output_dtype = np.float32
|
183
|
+
|
184
|
+
target.data = target.data.astype(output_dtype)
|
185
|
+
|
186
|
+
dens = Density(
|
187
|
+
np.memmap(
|
188
|
+
filename,
|
189
|
+
mode="w+",
|
190
|
+
shape=(len(obs_slices), *box_size),
|
191
|
+
dtype=output_dtype,
|
192
|
+
),
|
193
|
+
sampling_rate=(1, *target.sampling_rate),
|
194
|
+
origin=(0, *target.origin),
|
195
|
+
)
|
196
|
+
dens.data[:] = target.metadata["mean"]
|
197
|
+
|
198
|
+
print(target.data.shape)
|
199
|
+
# There appears to be an isseu with the stack creation. Trace this further
|
200
|
+
data_subset = np.zeros(extraction_shape, dtype = target.data.dtype)
|
201
|
+
pbar = ProgressBar(message = "Orientation ", nchars = 80, total = len(obs_slices))
|
202
|
+
for index, (obs_slice, cand_slice) in enumerate(zip(obs_slices, cand_slices)):
|
203
|
+
pbar.update(index + 1)
|
204
|
+
|
205
|
+
data_subset.fill(0)
|
206
|
+
data_subset[cand_slice] = target.data[obs_slice]
|
207
|
+
target_subset = Density(
|
208
|
+
data_subset,
|
209
|
+
sampling_rate=target.sampling_rate,
|
210
|
+
origin=target.origin,
|
211
|
+
)
|
212
|
+
|
213
|
+
if args.align_orientations:
|
214
|
+
rotation_matrix = euler_to_rotationmatrix(orientations.rotations[index])
|
215
|
+
target_subset = target_subset.rigid_transform(
|
216
|
+
rotation_matrix=rotation_matrix,
|
217
|
+
use_geometric_center=True,
|
218
|
+
order=args.interpolation_order,
|
219
|
+
)
|
220
|
+
target_subset.pad(box_size, center=True)
|
221
|
+
|
222
|
+
target_value = target.data[tuple(orientations.translations[index].astype(int))]
|
223
|
+
center = np.divide(target_subset.data.shape, 2).astype(int ) + np.mod(target_subset.shape, 2)
|
224
|
+
print(np.where(target_subset.data == target_value), center)
|
225
|
+
print(target_subset.data[tuple(center.astype(int))],
|
226
|
+
target_value,
|
227
|
+
target_subset.data[tuple(center.astype(int))] == target_value
|
228
|
+
)
|
229
|
+
|
230
|
+
dens.data[index] = target_subset.data
|
231
|
+
print("")
|
232
|
+
|
233
|
+
target_meta = {
|
234
|
+
k: v for k, v in target.metadata.items() if k in ("mean", "max", "min", "std")
|
235
|
+
}
|
236
|
+
dens.metadata.update(target_meta)
|
237
|
+
dens.metadata["batch_dimension"] = (0, )
|
238
|
+
|
239
|
+
dens.to_file(args.output_file)
|
240
|
+
orientations.to_file(
|
241
|
+
f"{splitext(args.output_file)[0]}_aligned.tsv",
|
242
|
+
file_format="text"
|
243
|
+
)
|
244
|
+
orientations.to_file(
|
245
|
+
f"{splitext(args.output_file)[0]}_aligned.star",
|
246
|
+
file_format="relion"
|
247
|
+
)
|
248
|
+
|
249
|
+
if __name__ == "__main__":
|
250
|
+
main()
|