nabu 2024.1.9__py3-none-any.whl → 2024.2.0__py3-none-any.whl
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.
- nabu/__init__.py +1 -1
- nabu/app/bootstrap.py +2 -3
- nabu/app/cast_volume.py +4 -2
- nabu/app/cli_configs.py +5 -0
- nabu/app/composite_cor.py +1 -1
- nabu/app/create_distortion_map_from_poly.py +5 -6
- nabu/app/diag_to_pix.py +7 -19
- nabu/app/diag_to_rot.py +14 -29
- nabu/app/double_flatfield.py +32 -44
- nabu/app/parse_reconstruction_log.py +3 -0
- nabu/app/reconstruct.py +53 -15
- nabu/app/reconstruct_helical.py +2 -2
- nabu/app/stitching.py +27 -13
- nabu/app/tests/test_reduce_dark_flat.py +4 -1
- nabu/cuda/kernel.py +11 -2
- nabu/cuda/processing.py +2 -2
- nabu/cuda/src/cone.cu +77 -0
- nabu/cuda/src/hierarchical_backproj.cu +271 -0
- nabu/cuda/utils.py +0 -6
- nabu/estimation/alignment.py +5 -19
- nabu/estimation/cor.py +173 -599
- nabu/estimation/cor_sino.py +356 -26
- nabu/estimation/focus.py +63 -11
- nabu/estimation/tests/test_cor.py +124 -58
- nabu/estimation/tests/test_focus.py +6 -6
- nabu/estimation/tilt.py +2 -1
- nabu/estimation/utils.py +5 -33
- nabu/io/__init__.py +1 -1
- nabu/io/cast_volume.py +1 -1
- nabu/io/reader.py +416 -21
- nabu/io/tests/test_readers.py +422 -0
- nabu/io/tests/test_writers.py +1 -102
- nabu/io/writer.py +4 -433
- nabu/opencl/kernel.py +14 -3
- nabu/opencl/processing.py +8 -0
- nabu/pipeline/config_validators.py +5 -2
- nabu/pipeline/datadump.py +12 -5
- nabu/pipeline/estimators.py +162 -188
- nabu/pipeline/fullfield/chunked.py +168 -92
- nabu/pipeline/fullfield/chunked_cuda.py +7 -3
- nabu/pipeline/fullfield/computations.py +2 -7
- nabu/pipeline/fullfield/dataset_validator.py +0 -4
- nabu/pipeline/fullfield/nabu_config.py +37 -13
- nabu/pipeline/fullfield/processconfig.py +22 -13
- nabu/pipeline/fullfield/reconstruction.py +13 -9
- nabu/pipeline/helical/helical_chunked_regridded.py +1 -1
- nabu/pipeline/helical/helical_chunked_regridded_cuda.py +1 -0
- nabu/pipeline/helical/helical_reconstruction.py +1 -1
- nabu/pipeline/params.py +21 -1
- nabu/pipeline/processconfig.py +1 -12
- nabu/pipeline/reader.py +146 -0
- nabu/pipeline/tests/test_estimators.py +44 -72
- nabu/pipeline/utils.py +4 -2
- nabu/pipeline/writer.py +10 -2
- nabu/preproc/ccd_cuda.py +1 -1
- nabu/preproc/ctf.py +14 -7
- nabu/preproc/ctf_cuda.py +2 -3
- nabu/preproc/double_flatfield.py +5 -12
- nabu/preproc/double_flatfield_cuda.py +2 -2
- nabu/preproc/flatfield.py +5 -1
- nabu/preproc/flatfield_cuda.py +5 -1
- nabu/preproc/phase.py +24 -73
- nabu/preproc/phase_cuda.py +5 -8
- nabu/preproc/tests/test_ctf.py +11 -7
- nabu/preproc/tests/test_flatfield.py +67 -122
- nabu/preproc/tests/test_paganin.py +54 -30
- nabu/processing/azim.py +206 -0
- nabu/processing/convolution_cuda.py +1 -1
- nabu/processing/fft_cuda.py +15 -17
- nabu/processing/histogram.py +2 -0
- nabu/processing/histogram_cuda.py +2 -1
- nabu/processing/kernel_base.py +3 -0
- nabu/processing/muladd_cuda.py +1 -0
- nabu/processing/padding_opencl.py +1 -1
- nabu/processing/roll_opencl.py +1 -0
- nabu/processing/rotation_cuda.py +2 -2
- nabu/processing/tests/test_fft.py +17 -10
- nabu/processing/unsharp_cuda.py +1 -1
- nabu/reconstruction/cone.py +104 -40
- nabu/reconstruction/fbp.py +3 -0
- nabu/reconstruction/fbp_base.py +7 -2
- nabu/reconstruction/filtering.py +20 -7
- nabu/reconstruction/filtering_cuda.py +7 -1
- nabu/reconstruction/hbp.py +424 -0
- nabu/reconstruction/mlem.py +99 -0
- nabu/reconstruction/reconstructor.py +2 -0
- nabu/reconstruction/rings_cuda.py +19 -19
- nabu/reconstruction/sinogram_cuda.py +1 -0
- nabu/reconstruction/sinogram_opencl.py +3 -1
- nabu/reconstruction/tests/test_cone.py +10 -5
- nabu/reconstruction/tests/test_deringer.py +7 -6
- nabu/reconstruction/tests/test_fbp.py +124 -10
- nabu/reconstruction/tests/test_filtering.py +13 -11
- nabu/reconstruction/tests/test_halftomo.py +30 -4
- nabu/reconstruction/tests/test_mlem.py +91 -0
- nabu/reconstruction/tests/test_reconstructor.py +8 -3
- nabu/resources/dataset_analyzer.py +142 -92
- nabu/resources/gpu.py +1 -0
- nabu/resources/nxflatfield.py +134 -125
- nabu/resources/templates/id16a_fluo.conf +42 -0
- nabu/resources/tests/test_extract.py +10 -0
- nabu/resources/tests/test_nxflatfield.py +2 -2
- nabu/stitching/alignment.py +80 -24
- nabu/stitching/config.py +105 -68
- nabu/stitching/definitions.py +1 -0
- nabu/stitching/frame_composition.py +68 -60
- nabu/stitching/overlap.py +91 -51
- nabu/stitching/single_axis_stitching.py +32 -0
- nabu/stitching/slurm_utils.py +6 -6
- nabu/stitching/stitcher/__init__.py +0 -0
- nabu/stitching/stitcher/base.py +124 -0
- nabu/stitching/stitcher/dumper/__init__.py +3 -0
- nabu/stitching/stitcher/dumper/base.py +94 -0
- nabu/stitching/stitcher/dumper/postprocessing.py +356 -0
- nabu/stitching/stitcher/dumper/preprocessing.py +60 -0
- nabu/stitching/stitcher/post_processing.py +555 -0
- nabu/stitching/stitcher/pre_processing.py +1068 -0
- nabu/stitching/stitcher/single_axis.py +484 -0
- nabu/stitching/stitcher/stitcher.py +0 -0
- nabu/stitching/stitcher/y_stitcher.py +13 -0
- nabu/stitching/stitcher/z_stitcher.py +45 -0
- nabu/stitching/stitcher_2D.py +278 -0
- nabu/stitching/tests/test_config.py +12 -37
- nabu/stitching/tests/test_frame_composition.py +33 -59
- nabu/stitching/tests/test_overlap.py +149 -7
- nabu/stitching/tests/test_utils.py +1 -1
- nabu/stitching/tests/test_y_preprocessing_stitching.py +132 -0
- nabu/stitching/tests/{test_z_stitching.py → test_z_postprocessing_stitching.py} +167 -561
- nabu/stitching/tests/test_z_preprocessing_stitching.py +431 -0
- nabu/stitching/utils/__init__.py +1 -0
- nabu/stitching/utils/post_processing.py +281 -0
- nabu/stitching/utils/tests/test_post-processing.py +21 -0
- nabu/stitching/{utils.py → utils/utils.py} +79 -52
- nabu/stitching/y_stitching.py +27 -0
- nabu/stitching/z_stitching.py +32 -2263
- nabu/testutils.py +1 -152
- nabu/thirdparty/tomocupy_remove_stripe.py +43 -9
- nabu/utils.py +158 -61
- {nabu-2024.1.9.dist-info → nabu-2024.2.0.dist-info}/METADATA +10 -3
- {nabu-2024.1.9.dist-info → nabu-2024.2.0.dist-info}/RECORD +144 -121
- nabu/io/tiffwriter_zmm.py +0 -99
- nabu/pipeline/fallback_utils.py +0 -149
- nabu/pipeline/helical/tests/test_accumulator.py +0 -158
- nabu/pipeline/helical/tests/test_pipeline_elements_full.py +0 -355
- nabu/pipeline/helical/tests/test_strategy.py +0 -61
- nabu/pipeline/helical/utils.py +0 -51
- nabu/pipeline/tests/test_chunk_reader.py +0 -74
- {nabu-2024.1.9.dist-info → nabu-2024.2.0.dist-info}/LICENSE +0 -0
- {nabu-2024.1.9.dist-info → nabu-2024.2.0.dist-info}/WHEEL +0 -0
- {nabu-2024.1.9.dist-info → nabu-2024.2.0.dist-info}/entry_points.txt +0 -0
- {nabu-2024.1.9.dist-info → nabu-2024.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,278 @@
|
|
1
|
+
import numpy
|
2
|
+
from math import ceil
|
3
|
+
from typing import Union, Optional
|
4
|
+
from nabu.stitching.overlap import ImageStichOverlapKernel
|
5
|
+
from nabu.stitching.frame_composition import FrameComposition
|
6
|
+
from nabu.stitching.alignment import align_frame, _Alignment
|
7
|
+
|
8
|
+
|
9
|
+
def stitch_raw_frames(
|
10
|
+
frames: tuple,
|
11
|
+
key_lines: tuple,
|
12
|
+
overlap_kernels: Union[ImageStichOverlapKernel, tuple],
|
13
|
+
output_dtype: numpy.dtype = numpy.float32,
|
14
|
+
check_inputs=True,
|
15
|
+
raw_frames_compositions: Optional[FrameComposition] = None,
|
16
|
+
overlap_frames_compositions: Optional[FrameComposition] = None,
|
17
|
+
return_composition_cls=False,
|
18
|
+
alignment: _Alignment = "center",
|
19
|
+
pad_mode="constant",
|
20
|
+
new_unstitched_axis_size: Optional[int] = None,
|
21
|
+
) -> numpy.ndarray:
|
22
|
+
"""
|
23
|
+
stitches raw frames (already shifted and flat fielded !!!) together using
|
24
|
+
raw stitching (no pixel interpolation, y_overlap_in_px is expected to be a int).
|
25
|
+
Sttiching depends on the kernel used.
|
26
|
+
|
27
|
+
It can be done:
|
28
|
+
|
29
|
+
* vertically:
|
30
|
+
|
31
|
+
X
|
32
|
+
------------------------------------------------------------------>
|
33
|
+
| --------------
|
34
|
+
| | |
|
35
|
+
| | Frame 1 | --------------
|
36
|
+
| | | | Frame 1 |
|
37
|
+
| -------------- | |
|
38
|
+
Y | --> stitching --> |~ stitching ~|
|
39
|
+
| -------------- | |
|
40
|
+
| | | | Frame 2 |
|
41
|
+
| | Frame 2 | --------------
|
42
|
+
| | |
|
43
|
+
| --------------
|
44
|
+
\/
|
45
|
+
|
46
|
+
* horizontally:
|
47
|
+
|
48
|
+
------------------------------------------------------------------>
|
49
|
+
| -------------- -------------- -----------------------
|
50
|
+
| | | | | | ~ ~ |
|
51
|
+
Y | | Frame 1 | | Frame 2 | --> stitching --> | Frame 1 ~ ~ Frame 2 |
|
52
|
+
| | | | | | ~ ~ |
|
53
|
+
| -------------- -------------- -----------------------
|
54
|
+
|
|
55
|
+
\/
|
56
|
+
|
57
|
+
returns stitched_projection, raw_img_1, raw_img_2, computed_overlap
|
58
|
+
proj_0 and pro_1 are already expected to be in a row. Having stitching_height_in_px in common. At top of proj_0
|
59
|
+
and at bottom of proj_1
|
60
|
+
|
61
|
+
:param tuple frames: tuple of 2D numpy array. Expected to be Z up oriented at this stage
|
62
|
+
:param tuple key_lines: for each jonction define the two lines to overlaid (from the upper and the lower frames). In the reference where 0 is the bottom line of the image.
|
63
|
+
:param overlap_kernels: ZStichOverlapKernel overlap kernel to be used or a list of kernel (one per overlap). Define startegy and overlap heights
|
64
|
+
:param numpy.dtype output_dtype: dataset dtype. For now must be provided because flat field corrcetion change data type (numpy.float32 for now)
|
65
|
+
:param bool check_inputs: if True will do more test on inputs parameters like checking frame shapes, coherence of the request.. As it can be time consuming it is optional
|
66
|
+
:param raw_frames_compositions: pre computed raw frame composition. If not provided will compute them. allow providing it to speed up calculation
|
67
|
+
:param overlap_frames_compositions: pre computed stitched frame composition. If not provided will compute them. allow providing it to speed up calculation
|
68
|
+
:param bool return_frame_compositions: if False return simply the stitched frames. Else return a tuple with stitching frame and the dictionnary with the composition frames...
|
69
|
+
:param alignment: how to align frame if two frames have different size along the unstitched axis
|
70
|
+
:param pad_mode: how to pad data for alignment (provided to numpy.pad function)
|
71
|
+
:param new_unstitched_axis_size: size of the image along the axis not stitched. So it will be the frame width if the stitching axis is 0 and the frame height if the stitching axis is 1
|
72
|
+
"""
|
73
|
+
if overlap_kernels is None or len(overlap_kernels) == 0:
|
74
|
+
raise ValueError("overlap kernels must be provided")
|
75
|
+
|
76
|
+
stitched_axis = overlap_kernels[0].stitched_axis
|
77
|
+
unstitched_axis = overlap_kernels[0].unstitched_axis
|
78
|
+
|
79
|
+
if check_inputs:
|
80
|
+
# check frames are 2D numpy arrays
|
81
|
+
def check_frame(proj):
|
82
|
+
if not isinstance(proj, numpy.ndarray) and proj.ndim == 2:
|
83
|
+
raise ValueError(f"frames are expected to be 2D numpy array")
|
84
|
+
|
85
|
+
[check_frame(frame) for frame in frames]
|
86
|
+
for frame_0, frame_1 in zip(frames[:-1], frames[1:]):
|
87
|
+
if not (frame_0.ndim == frame_1.ndim == 2):
|
88
|
+
raise ValueError("Frames are expected to be 2D")
|
89
|
+
|
90
|
+
# check there is coherence between overlap kernels and frames
|
91
|
+
for frame_0, frame_1, kernel in zip(frames[:-1], frames[1:], overlap_kernels):
|
92
|
+
if frame_0.shape[stitched_axis] < kernel.overlap_size:
|
93
|
+
raise ValueError(
|
94
|
+
f"frame_0 height ({frame_0.shape[stitched_axis]}) is less than kernel overlap ({kernel.overlap_size})"
|
95
|
+
)
|
96
|
+
if frame_1.shape[stitched_axis] < kernel.overlap_size:
|
97
|
+
raise ValueError(
|
98
|
+
f"frame_1 height ({frame_1.shape[stitched_axis]}) is less than kernel overlap ({kernel.overlap_size})"
|
99
|
+
)
|
100
|
+
# check key lines are coherent with overlp kernels
|
101
|
+
if not len(key_lines) == len(overlap_kernels):
|
102
|
+
raise ValueError("we expect to have the same number of key_lines then the number of kernel")
|
103
|
+
else:
|
104
|
+
for key_line in key_lines:
|
105
|
+
for value in key_line:
|
106
|
+
if not isinstance(value, (int, numpy.integer)):
|
107
|
+
raise TypeError(f"key_line is expected to be an integer. {type(key_line)} provided")
|
108
|
+
elif value < 0:
|
109
|
+
raise ValueError(f"key lines are expected to be positive values. Get {value} as key line value")
|
110
|
+
|
111
|
+
# check overlap kernel stitching axis are coherent (for now make sure they are all along the same axis)
|
112
|
+
if len(overlap_kernels) > 1:
|
113
|
+
for previous_kernel, next_kernel in zip(overlap_kernels[:-1], overlap_kernels[1:]):
|
114
|
+
if not isinstance(previous_kernel, ImageStichOverlapKernel):
|
115
|
+
raise TypeError(
|
116
|
+
f"overlap kernels must be instances of {ImageStichOverlapKernel}. Get {type(previous_kernel)}"
|
117
|
+
)
|
118
|
+
if not isinstance(next_kernel, ImageStichOverlapKernel):
|
119
|
+
raise TypeError(
|
120
|
+
f"overlap kernels must be instances of {ImageStichOverlapKernel}. Get {type(next_kernel)}"
|
121
|
+
)
|
122
|
+
if previous_kernel.stitched_axis != next_kernel.stitched_axis:
|
123
|
+
raise ValueError(
|
124
|
+
"kernels with different stitching axis provided. For now all kernels must have the same stitchign axis"
|
125
|
+
)
|
126
|
+
|
127
|
+
if new_unstitched_axis_size is None:
|
128
|
+
new_unstitched_axis_size = max([frame.shape[unstitched_axis] for frame in frames])
|
129
|
+
|
130
|
+
frames = tuple(
|
131
|
+
[
|
132
|
+
align_frame(
|
133
|
+
data=frame,
|
134
|
+
alignment=alignment,
|
135
|
+
new_aligned_axis_size=new_unstitched_axis_size,
|
136
|
+
pad_mode=pad_mode,
|
137
|
+
alignment_axis=unstitched_axis,
|
138
|
+
)
|
139
|
+
for frame in frames
|
140
|
+
]
|
141
|
+
)
|
142
|
+
|
143
|
+
# step 1: create numpy array that will contain stitching
|
144
|
+
# if raw composition doesn't exists create it
|
145
|
+
if raw_frames_compositions is None:
|
146
|
+
raw_frames_compositions = FrameComposition.compute_raw_frame_compositions(
|
147
|
+
frames=frames,
|
148
|
+
overlap_kernels=overlap_kernels,
|
149
|
+
key_lines=key_lines,
|
150
|
+
stitching_axis=stitched_axis,
|
151
|
+
)
|
152
|
+
|
153
|
+
new_stitched_axis_size = raw_frames_compositions.global_end[-1] - raw_frames_compositions.global_start[0]
|
154
|
+
if stitched_axis == 0:
|
155
|
+
stitched_projection_shape = (
|
156
|
+
int(new_stitched_axis_size),
|
157
|
+
new_unstitched_axis_size,
|
158
|
+
)
|
159
|
+
else:
|
160
|
+
stitched_projection_shape = (
|
161
|
+
new_unstitched_axis_size,
|
162
|
+
int(new_stitched_axis_size),
|
163
|
+
)
|
164
|
+
|
165
|
+
stitch_array = numpy.empty(stitched_projection_shape, dtype=output_dtype)
|
166
|
+
|
167
|
+
# step 2: set raw data
|
168
|
+
# fill stitch array with raw data raw data
|
169
|
+
raw_frames_compositions.compose(
|
170
|
+
output_frame=stitch_array,
|
171
|
+
input_frames=frames,
|
172
|
+
)
|
173
|
+
|
174
|
+
# step 3 set stitched data
|
175
|
+
|
176
|
+
# 3.1 create stitched overlaps
|
177
|
+
stitched_overlap = []
|
178
|
+
for frame_0, frame_1, kernel, key_line in zip(frames[:-1], frames[1:], overlap_kernels, key_lines):
|
179
|
+
assert kernel.overlap_size >= 0
|
180
|
+
frame_0_overlap, frame_1_overlap = get_overlap_areas(
|
181
|
+
upper_frame=frame_0,
|
182
|
+
lower_frame=frame_1,
|
183
|
+
upper_frame_key_line=key_line[0],
|
184
|
+
lower_frame_key_line=key_line[1],
|
185
|
+
overlap_size=kernel.overlap_size,
|
186
|
+
stitching_axis=stitched_axis,
|
187
|
+
)
|
188
|
+
|
189
|
+
assert (
|
190
|
+
frame_0_overlap.shape[stitched_axis] == frame_1_overlap.shape[stitched_axis] == kernel.overlap_size
|
191
|
+
), f"{frame_0_overlap.shape[stitched_axis]} == {frame_1_overlap.shape[stitched_axis]} == {kernel.overlap_size}"
|
192
|
+
|
193
|
+
stitched_overlap.append(
|
194
|
+
kernel.stitch(
|
195
|
+
frame_0_overlap,
|
196
|
+
frame_1_overlap,
|
197
|
+
)[0]
|
198
|
+
)
|
199
|
+
# 3.2 fill stitched overlap on output array
|
200
|
+
if overlap_frames_compositions is None:
|
201
|
+
overlap_frames_compositions = FrameComposition.compute_stitch_frame_composition(
|
202
|
+
frames=frames,
|
203
|
+
overlap_kernels=overlap_kernels,
|
204
|
+
key_lines=key_lines,
|
205
|
+
stitching_axis=stitched_axis,
|
206
|
+
)
|
207
|
+
overlap_frames_compositions.compose(
|
208
|
+
output_frame=stitch_array,
|
209
|
+
input_frames=stitched_overlap,
|
210
|
+
)
|
211
|
+
if return_composition_cls:
|
212
|
+
return (
|
213
|
+
stitch_array,
|
214
|
+
{
|
215
|
+
"raw_composition": raw_frames_compositions,
|
216
|
+
"overlap_composition": overlap_frames_compositions,
|
217
|
+
},
|
218
|
+
)
|
219
|
+
|
220
|
+
return stitch_array
|
221
|
+
|
222
|
+
|
223
|
+
def get_overlap_areas(
|
224
|
+
upper_frame: numpy.ndarray,
|
225
|
+
lower_frame: numpy.ndarray,
|
226
|
+
upper_frame_key_line: int,
|
227
|
+
lower_frame_key_line: int,
|
228
|
+
overlap_size: int,
|
229
|
+
stitching_axis: int,
|
230
|
+
):
|
231
|
+
"""
|
232
|
+
return the requested area from lower_frame and upper_frame.
|
233
|
+
|
234
|
+
Lower_frame contains at the end of it the 'real overlap' with the upper_frame.
|
235
|
+
Upper_frame contains the 'real overlap' at the end of it.
|
236
|
+
|
237
|
+
For some reason the user can ask the stitching height to be smaller than the `real overlap`.
|
238
|
+
|
239
|
+
Here are some drawing to have a better of view of those regions:
|
240
|
+
|
241
|
+
.. image:: images/stitching/z_stitch_real_overlap.png
|
242
|
+
:width: 600
|
243
|
+
|
244
|
+
.. image:: z_stitch_stitch_height.png
|
245
|
+
:width: 600
|
246
|
+
"""
|
247
|
+
assert stitching_axis in (0, 1)
|
248
|
+
for pf, pn in zip((lower_frame_key_line, upper_frame_key_line), ("lower_frame", "upper_frame")):
|
249
|
+
if not isinstance(pf, (int, numpy.number)):
|
250
|
+
raise TypeError(f"{pn} is expected to be a number. {type(pf)} provided")
|
251
|
+
assert overlap_size >= 0
|
252
|
+
|
253
|
+
lf_start = ceil(lower_frame_key_line - overlap_size / 2)
|
254
|
+
lf_end = ceil(lower_frame_key_line + overlap_size / 2)
|
255
|
+
uf_start = ceil(upper_frame_key_line - overlap_size / 2)
|
256
|
+
uf_end = ceil(upper_frame_key_line + overlap_size / 2)
|
257
|
+
|
258
|
+
lf_start, lf_end = min(lf_start, lf_end), max(lf_start, lf_end)
|
259
|
+
uf_start, uf_end = min(uf_start, uf_end), max(uf_start, uf_end)
|
260
|
+
if lf_start < 0 or uf_start < 0:
|
261
|
+
raise ValueError(
|
262
|
+
f"requested overlap ({overlap_size}) is incoherent with key line positions ({lower_frame_key_line}, {upper_frame_key_line}) - expected to be smaller."
|
263
|
+
)
|
264
|
+
|
265
|
+
if stitching_axis == 0:
|
266
|
+
overlap_upper = upper_frame[uf_start:uf_end]
|
267
|
+
overlap_lower = lower_frame[lf_start:lf_end]
|
268
|
+
elif stitching_axis == 1:
|
269
|
+
overlap_upper = upper_frame[:, uf_start:uf_end]
|
270
|
+
overlap_lower = lower_frame[:, lf_start:lf_end]
|
271
|
+
else:
|
272
|
+
raise NotImplementedError
|
273
|
+
if not overlap_upper.shape == overlap_lower.shape:
|
274
|
+
# maybe in the future: try to reduce one according to the other ????
|
275
|
+
raise RuntimeError(
|
276
|
+
f"lower and upper frame have different overlap size ({overlap_upper.shape} vs {overlap_lower.shape})"
|
277
|
+
)
|
278
|
+
return overlap_upper, overlap_lower
|
@@ -1,33 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
# /*##########################################################################
|
3
|
-
#
|
4
|
-
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
|
5
|
-
#
|
6
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
-
# of this software and associated documentation files (the "Software"), to deal
|
8
|
-
# in the Software without restriction, including without limitation the rights
|
9
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
-
# copies of the Software, and to permit persons to whom the Software is
|
11
|
-
# furnished to do so, subject to the following conditions:
|
12
|
-
#
|
13
|
-
# The above copyright notice and this permission notice shall be included in
|
14
|
-
# all copies or substantial portions of the Software.
|
15
|
-
#
|
16
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
-
# THE SOFTWARE.
|
23
|
-
#
|
24
|
-
# ###########################################################################*/
|
25
|
-
|
26
|
-
__authors__ = ["H. Payno"]
|
27
|
-
__license__ = "MIT"
|
28
|
-
__date__ = "10/05/2022"
|
29
|
-
|
30
|
-
|
31
1
|
import os
|
32
2
|
from tempfile import TemporaryDirectory
|
33
3
|
import pytest
|
@@ -71,12 +41,17 @@ def test_stitching_config(stitching_type, option_level):
|
|
71
41
|
if stitching_type is stiching_config.StitchingType.Z_POSTPROC:
|
72
42
|
assert isinstance(
|
73
43
|
stiching_config.dict_to_config_obj(config),
|
74
|
-
stiching_config.
|
44
|
+
stiching_config.PostProcessedSingleAxisStitchingConfiguration,
|
75
45
|
)
|
76
46
|
elif stitching_type is stiching_config.StitchingType.Z_PREPROC:
|
77
47
|
assert isinstance(
|
78
48
|
stiching_config.dict_to_config_obj(config),
|
79
|
-
stiching_config.
|
49
|
+
stiching_config.PreProcessedSingleAxisStitchingConfiguration,
|
50
|
+
)
|
51
|
+
elif stitching_type is stiching_config.StitchingType.Y_PREPROC:
|
52
|
+
assert isinstance(
|
53
|
+
stiching_config.dict_to_config_obj(config),
|
54
|
+
stiching_config.PreProcessedSingleAxisStitchingConfiguration,
|
80
55
|
)
|
81
56
|
else:
|
82
57
|
raise ValueError("not handled")
|
@@ -98,12 +73,12 @@ def test_stitching_config(stitching_type, option_level):
|
|
98
73
|
if stitching_type is stiching_config.StitchingType.Z_POSTPROC:
|
99
74
|
assert isinstance(
|
100
75
|
config_class_instance,
|
101
|
-
stiching_config.
|
76
|
+
stiching_config.PostProcessedSingleAxisStitchingConfiguration,
|
102
77
|
)
|
103
78
|
elif stitching_type is stiching_config.StitchingType.Z_PREPROC:
|
104
79
|
assert isinstance(
|
105
80
|
config_class_instance,
|
106
|
-
stiching_config.
|
81
|
+
stiching_config.PreProcessedSingleAxisStitchingConfiguration,
|
107
82
|
)
|
108
83
|
|
109
84
|
assert isinstance(config_class_instance.to_dict(), dict)
|
@@ -183,7 +158,7 @@ def test_PreProcessedZStitchingConfiguration(
|
|
183
158
|
stiching_config.OUTPUT_SECTION: {
|
184
159
|
stiching_config.OVERWRITE_RESULTS_FIELD: overwrite_results,
|
185
160
|
},
|
186
|
-
stiching_config.
|
161
|
+
stiching_config.PRE_PROC_SECTION: {
|
187
162
|
stiching_config.DATA_FILE_FIELD: "my_file.nx",
|
188
163
|
stiching_config.DATA_PATH_FIELD: "entry",
|
189
164
|
stiching_config.NEXUS_VERSION_FIELD: None,
|
@@ -219,8 +194,8 @@ def test_description_dict():
|
|
219
194
|
"""
|
220
195
|
make sure the description dict (used for generating the file) is working and generates a dict
|
221
196
|
"""
|
222
|
-
assert isinstance(stiching_config.
|
197
|
+
assert isinstance(stiching_config.PreProcessedSingleAxisStitchingConfiguration.get_description_dict(), dict)
|
223
198
|
assert isinstance(
|
224
|
-
stiching_config.
|
199
|
+
stiching_config.PostProcessedSingleAxisStitchingConfiguration.get_description_dict(),
|
225
200
|
dict,
|
226
201
|
)
|
@@ -1,43 +1,13 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
# /*##########################################################################
|
3
|
-
#
|
4
|
-
# Copyright (c) 2016-2017 European Synchrotron Radiation Facility
|
5
|
-
#
|
6
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
-
# of this software and associated documentation files (the "Software"), to deal
|
8
|
-
# in the Software without restriction, including without limitation the rights
|
9
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
-
# copies of the Software, and to permit persons to whom the Software is
|
11
|
-
# furnished to do so, subject to the following conditions:
|
12
|
-
#
|
13
|
-
# The above copyright notice and this permission notice shall be included in
|
14
|
-
# all copies or substantial portions of the Software.
|
15
|
-
#
|
16
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
-
# THE SOFTWARE.
|
23
|
-
#
|
24
|
-
# ###########################################################################*/
|
25
|
-
|
26
|
-
__authors__ = ["H. Payno"]
|
27
|
-
__license__ = "MIT"
|
28
|
-
__date__ = "17/05/2022"
|
29
|
-
|
30
|
-
|
31
1
|
import pytest
|
32
|
-
from nabu.stitching.frame_composition import
|
2
|
+
from nabu.stitching.frame_composition import FrameComposition
|
33
3
|
import numpy
|
34
4
|
|
35
|
-
from nabu.stitching.overlap import OverlapStitchingStrategy,
|
5
|
+
from nabu.stitching.overlap import OverlapStitchingStrategy, ImageStichOverlapKernel
|
36
6
|
|
37
7
|
|
38
8
|
def test_frame_composition():
|
39
9
|
"""
|
40
|
-
Test
|
10
|
+
Test FrameComposition
|
41
11
|
"""
|
42
12
|
frame_0 = numpy.zeros((100, 1))
|
43
13
|
frame_1 = numpy.ones((98, 1))
|
@@ -48,19 +18,21 @@ def test_frame_composition():
|
|
48
18
|
y_shifts = -20, -10
|
49
19
|
|
50
20
|
kernels = [
|
51
|
-
|
52
|
-
|
21
|
+
ImageStichOverlapKernel(
|
22
|
+
stitching_axis=0,
|
23
|
+
frame_unstitched_axis_size=1,
|
53
24
|
stitching_strategy=OverlapStitchingStrategy.LINEAR_WEIGHTS,
|
54
25
|
overlap_size=4,
|
55
26
|
),
|
56
|
-
|
57
|
-
|
27
|
+
ImageStichOverlapKernel(
|
28
|
+
stitching_axis=0,
|
29
|
+
frame_unstitched_axis_size=1,
|
58
30
|
stitching_strategy=OverlapStitchingStrategy.MEAN,
|
59
31
|
overlap_size=8,
|
60
32
|
),
|
61
33
|
]
|
62
34
|
# check raw composition
|
63
|
-
raw_composition =
|
35
|
+
raw_composition = FrameComposition.compute_raw_frame_compositions(
|
64
36
|
frames=frames,
|
65
37
|
key_lines=(
|
66
38
|
(90, 10),
|
@@ -69,12 +41,12 @@ def test_frame_composition():
|
|
69
41
|
overlap_kernels=kernels,
|
70
42
|
stitching_axis=0,
|
71
43
|
)
|
72
|
-
assert isinstance(raw_composition,
|
44
|
+
assert isinstance(raw_composition, FrameComposition)
|
73
45
|
|
74
|
-
assert raw_composition.
|
75
|
-
assert raw_composition.
|
76
|
-
assert raw_composition.
|
77
|
-
assert raw_composition.
|
46
|
+
assert raw_composition.local_start == (0, 12, 9)
|
47
|
+
assert raw_composition.local_end == (88, 89, 205)
|
48
|
+
assert raw_composition.global_start == (0, 92, 177)
|
49
|
+
assert raw_composition.global_end == (88, 169, 373)
|
78
50
|
|
79
51
|
stitched_data = numpy.empty((100 + 98 + 205 - 30, 1))
|
80
52
|
raw_composition.compose(output_frame=stitched_data, input_frames=frames)
|
@@ -83,7 +55,7 @@ def test_frame_composition():
|
|
83
55
|
assert stitched_data[-1, 0] == 2.0
|
84
56
|
|
85
57
|
# check stitch composition
|
86
|
-
stitch_composition =
|
58
|
+
stitch_composition = FrameComposition.compute_stitch_frame_composition(
|
87
59
|
frames=frames,
|
88
60
|
key_lines=(
|
89
61
|
(90, 10),
|
@@ -93,12 +65,12 @@ def test_frame_composition():
|
|
93
65
|
stitching_axis=0,
|
94
66
|
)
|
95
67
|
|
96
|
-
|
68
|
+
FrameComposition.pprint_composition(raw_composition, stitch_composition)
|
97
69
|
|
98
|
-
assert stitch_composition.
|
99
|
-
assert stitch_composition.
|
100
|
-
assert stitch_composition.
|
101
|
-
assert stitch_composition.
|
70
|
+
assert stitch_composition.local_start == (0, 0)
|
71
|
+
assert stitch_composition.local_end == (4, 8)
|
72
|
+
assert stitch_composition.global_start == (88, 169)
|
73
|
+
assert stitch_composition.global_end == (92, 177)
|
102
74
|
|
103
75
|
stitched_frames = []
|
104
76
|
for frame_0, frame_1, kernel, y_shift in zip(frames[:-1], frames[1:], kernels, y_shifts):
|
@@ -130,13 +102,15 @@ _raw_comp_config = (
|
|
130
102
|
"raw_local_start": (0, 4, 5),
|
131
103
|
"raw_local_end": (16, 34, 20),
|
132
104
|
"kernels": (
|
133
|
-
|
134
|
-
|
105
|
+
ImageStichOverlapKernel(
|
106
|
+
stitching_axis=0,
|
107
|
+
frame_unstitched_axis_size=1,
|
135
108
|
stitching_strategy=OverlapStitchingStrategy.LINEAR_WEIGHTS,
|
136
109
|
overlap_size=3,
|
137
110
|
),
|
138
|
-
|
139
|
-
|
111
|
+
ImageStichOverlapKernel(
|
112
|
+
stitching_axis=0,
|
113
|
+
frame_unstitched_axis_size=1,
|
140
114
|
stitching_strategy=OverlapStitchingStrategy.MEAN,
|
141
115
|
overlap_size=4,
|
142
116
|
),
|
@@ -159,21 +133,21 @@ def test_raw_frame_composition_exotic_config(configuration):
|
|
159
133
|
key_lines = configuration.get("key_lines")
|
160
134
|
kernels = configuration.get("kernels")
|
161
135
|
# check raw composition
|
162
|
-
raw_composition =
|
136
|
+
raw_composition = FrameComposition.compute_raw_frame_compositions(
|
163
137
|
frames=frames,
|
164
138
|
overlap_kernels=kernels,
|
165
139
|
key_lines=key_lines,
|
166
140
|
stitching_axis=0,
|
167
141
|
)
|
168
142
|
|
169
|
-
assert raw_composition.
|
170
|
-
assert raw_composition.
|
171
|
-
assert raw_composition.
|
172
|
-
assert raw_composition.
|
143
|
+
assert raw_composition.global_start == configuration.get("raw_global_start")
|
144
|
+
assert raw_composition.global_end == configuration.get("raw_global_end")
|
145
|
+
assert raw_composition.local_start == configuration.get("raw_local_start")
|
146
|
+
assert raw_composition.local_end == configuration.get("raw_local_end")
|
173
147
|
|
174
148
|
stitched_data = numpy.empty(
|
175
149
|
(
|
176
|
-
(raw_composition.
|
150
|
+
(raw_composition.global_end[-1] - raw_composition.global_start[0]),
|
177
151
|
1,
|
178
152
|
)
|
179
153
|
)
|