nabu 2024.1.10__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/__init__.py +0 -0
- 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 -2281
- nabu/testutils.py +1 -152
- nabu/thirdparty/tomocupy_remove_stripe.py +43 -9
- nabu/utils.py +158 -61
- {nabu-2024.1.10.dist-info → nabu-2024.2.0.dist-info}/METADATA +24 -17
- {nabu-2024.1.10.dist-info → nabu-2024.2.0.dist-info}/RECORD +145 -121
- {nabu-2024.1.10.dist-info → nabu-2024.2.0.dist-info}/WHEEL +1 -1
- 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.10.dist-info → nabu-2024.2.0.dist-info}/LICENSE +0 -0
- {nabu-2024.1.10.dist-info → nabu-2024.2.0.dist-info}/entry_points.txt +0 -0
- {nabu-2024.1.10.dist-info → nabu-2024.2.0.dist-info}/top_level.txt +0 -0
@@ -3,14 +3,52 @@ import pytest
|
|
3
3
|
|
4
4
|
from nabu.stitching.overlap import compute_image_minimum_divergence, compute_image_higher_signal, check_overlaps
|
5
5
|
from nabu.testutils import get_data
|
6
|
+
from nabu.stitching.overlap import ImageStichOverlapKernel, OverlapStitchingStrategy
|
7
|
+
from nabu.stitching.stitcher_2D import stitch_raw_frames
|
8
|
+
from silx.image.phantomgenerator import PhantomGenerator
|
9
|
+
|
10
|
+
|
11
|
+
strategies_to_test_weights = (
|
12
|
+
OverlapStitchingStrategy.CLOSEST,
|
13
|
+
OverlapStitchingStrategy.COSINUS_WEIGHTS,
|
14
|
+
OverlapStitchingStrategy.LINEAR_WEIGHTS,
|
15
|
+
OverlapStitchingStrategy.MEAN,
|
16
|
+
)
|
17
|
+
|
18
|
+
|
19
|
+
@pytest.mark.parametrize("strategy", strategies_to_test_weights)
|
20
|
+
@pytest.mark.parametrize("stitching_axis", (0, 1))
|
21
|
+
def test_overlap_stitcher(strategy, stitching_axis):
|
22
|
+
frame_width = 128
|
23
|
+
frame_height = frame_width
|
24
|
+
frame_1 = PhantomGenerator.get2DPhantomSheppLogan(n=frame_width)
|
25
|
+
stitcher = ImageStichOverlapKernel(
|
26
|
+
stitching_strategy=strategy,
|
27
|
+
overlap_size=frame_height,
|
28
|
+
frame_unstitched_axis_size=128,
|
29
|
+
stitching_axis=stitching_axis,
|
30
|
+
)
|
31
|
+
stitched_frame = stitcher.stitch(frame_1, frame_1)[0]
|
32
|
+
assert stitched_frame.shape == (frame_height, frame_width)
|
33
|
+
# check result is close to the expected one
|
34
|
+
numpy.testing.assert_allclose(frame_1, stitched_frame, atol=10e-10)
|
35
|
+
|
36
|
+
# check sum of weights ~ 1.0
|
37
|
+
numpy.testing.assert_allclose(
|
38
|
+
stitcher.weights_img_1 + stitcher.weights_img_2,
|
39
|
+
numpy.ones_like(stitcher.weights_img_1),
|
40
|
+
)
|
6
41
|
|
7
42
|
|
8
|
-
|
43
|
+
@pytest.mark.parametrize("stitching_axis", (0, 1))
|
44
|
+
def test_compute_image_minimum_divergence(stitching_axis):
|
9
45
|
"""make sure the compute_image_minimum_divergence function is processing"""
|
10
46
|
raw_data_1 = get_data("brain_phantom.npz")["data"]
|
11
47
|
raw_data_2 = numpy.random.rand(*raw_data_1.shape) * 255.0
|
12
48
|
|
13
|
-
stitching = compute_image_minimum_divergence(
|
49
|
+
stitching = compute_image_minimum_divergence(
|
50
|
+
raw_data_1, raw_data_2, high_frequency_threshold=2, stitching_axis=stitching_axis
|
51
|
+
)
|
14
52
|
assert stitching.shape == raw_data_1.shape
|
15
53
|
|
16
54
|
|
@@ -43,7 +81,7 @@ def test_check_overlaps():
|
|
43
81
|
numpy.ones(10),
|
44
82
|
numpy.ones(20),
|
45
83
|
),
|
46
|
-
positions=((10,), (0,)),
|
84
|
+
positions=((10, 0, 0), (0, 0, 0)),
|
47
85
|
axis=0,
|
48
86
|
raise_error=True,
|
49
87
|
)
|
@@ -55,7 +93,7 @@ def test_check_overlaps():
|
|
55
93
|
numpy.ones(10),
|
56
94
|
numpy.ones(20),
|
57
95
|
),
|
58
|
-
positions=((0,), (100,)),
|
96
|
+
positions=((0, 0, 0), (100, 0, 0)),
|
59
97
|
axis=0,
|
60
98
|
raise_error=True,
|
61
99
|
)
|
@@ -67,7 +105,7 @@ def test_check_overlaps():
|
|
67
105
|
numpy.ones(20),
|
68
106
|
numpy.ones(10),
|
69
107
|
),
|
70
|
-
positions=((8,), (5,)),
|
108
|
+
positions=((8, 0, 0), (5, 0, 0)),
|
71
109
|
axis=0,
|
72
110
|
raise_error=True,
|
73
111
|
)
|
@@ -79,7 +117,7 @@ def test_check_overlaps():
|
|
79
117
|
numpy.ones(20),
|
80
118
|
numpy.ones(10),
|
81
119
|
),
|
82
|
-
positions=((20,), (10,), (0,)),
|
120
|
+
positions=((20, 0, 0), (10, 0, 0), (0, 0, 0)),
|
83
121
|
axis=0,
|
84
122
|
raise_error=True,
|
85
123
|
)
|
@@ -92,7 +130,111 @@ def test_check_overlaps():
|
|
92
130
|
numpy.ones(10),
|
93
131
|
numpy.ones(10),
|
94
132
|
),
|
95
|
-
positions=((20,), (15,), (11,)),
|
133
|
+
positions=((20, 0, 0), (15, 0, 0), (11, 0, 0)),
|
96
134
|
axis=0,
|
97
135
|
raise_error=True,
|
98
136
|
)
|
137
|
+
|
138
|
+
|
139
|
+
@pytest.mark.parametrize("dtype", (numpy.float16, numpy.float32))
|
140
|
+
def test_stitch_vertically_raw_frames(dtype):
|
141
|
+
"""
|
142
|
+
ensure a stitching with 3 frames and different overlap can be done
|
143
|
+
"""
|
144
|
+
ref_frame_width = 256
|
145
|
+
frame_ref = PhantomGenerator.get2DPhantomSheppLogan(n=ref_frame_width).astype(dtype)
|
146
|
+
|
147
|
+
# split the frame into several part
|
148
|
+
frame_1 = frame_ref[0:100]
|
149
|
+
frame_2 = frame_ref[80:164]
|
150
|
+
frame_3 = frame_ref[154:]
|
151
|
+
|
152
|
+
kernel_1 = ImageStichOverlapKernel(frame_unstitched_axis_size=ref_frame_width, overlap_size=20, stitching_axis=0)
|
153
|
+
kernel_2 = ImageStichOverlapKernel(frame_unstitched_axis_size=ref_frame_width, overlap_size=10, stitching_axis=0)
|
154
|
+
|
155
|
+
stitched = stitch_raw_frames(
|
156
|
+
frames=(frame_1, frame_2, frame_3),
|
157
|
+
output_dtype=dtype,
|
158
|
+
overlap_kernels=(kernel_1, kernel_2),
|
159
|
+
raw_frames_compositions=None,
|
160
|
+
overlap_frames_compositions=None,
|
161
|
+
key_lines=(
|
162
|
+
(
|
163
|
+
90, # frame_1 height - kernel_1 height / 2.0
|
164
|
+
10, # kernel_1 height / 2.0
|
165
|
+
),
|
166
|
+
(
|
167
|
+
79, # frame_2 height - kernel_2 height / 2.0 ou 102-20 ?
|
168
|
+
5, # kernel_2 height / 2.0
|
169
|
+
),
|
170
|
+
),
|
171
|
+
)
|
172
|
+
|
173
|
+
assert stitched.shape == frame_ref.shape
|
174
|
+
numpy.testing.assert_array_almost_equal(frame_ref, stitched)
|
175
|
+
|
176
|
+
|
177
|
+
def test_stitch_vertically_raw_frames_2():
|
178
|
+
"""
|
179
|
+
ensure a stitching with 3 frames and different overlap can be done
|
180
|
+
"""
|
181
|
+
ref_frame_width = 256
|
182
|
+
frame_ref = PhantomGenerator.get2DPhantomSheppLogan(n=ref_frame_width).astype(numpy.float32)
|
183
|
+
|
184
|
+
# split the frame into several part
|
185
|
+
frame_1 = frame_ref.copy()
|
186
|
+
frame_2 = frame_ref.copy()
|
187
|
+
frame_3 = frame_ref.copy()
|
188
|
+
|
189
|
+
kernel_1 = ImageStichOverlapKernel(frame_unstitched_axis_size=ref_frame_width, overlap_size=10, stitching_axis=0)
|
190
|
+
kernel_2 = ImageStichOverlapKernel(frame_unstitched_axis_size=ref_frame_width, overlap_size=10, stitching_axis=0)
|
191
|
+
|
192
|
+
stitched = stitch_raw_frames(
|
193
|
+
frames=(frame_1, frame_2, frame_3),
|
194
|
+
output_dtype=numpy.float32,
|
195
|
+
overlap_kernels=(kernel_1, kernel_2),
|
196
|
+
raw_frames_compositions=None,
|
197
|
+
overlap_frames_compositions=None,
|
198
|
+
key_lines=((20, 20), (105, 105)),
|
199
|
+
)
|
200
|
+
|
201
|
+
assert stitched.shape == frame_ref.shape
|
202
|
+
numpy.testing.assert_array_almost_equal(frame_ref, stitched)
|
203
|
+
|
204
|
+
|
205
|
+
@pytest.mark.parametrize("dtype", (numpy.float16, numpy.float32))
|
206
|
+
def test_stitch_horizontally_raw_frames(dtype):
|
207
|
+
"""
|
208
|
+
ensure a stitching with 3 frames and different overlap can be done along axis 1
|
209
|
+
"""
|
210
|
+
ref_frame_width = 256
|
211
|
+
frame_ref = PhantomGenerator.get2DPhantomSheppLogan(n=ref_frame_width).astype(dtype)
|
212
|
+
|
213
|
+
# split the frame into several part
|
214
|
+
frame_1 = frame_ref[:, 0:100]
|
215
|
+
frame_2 = frame_ref[:, 80:164]
|
216
|
+
frame_3 = frame_ref[:, 154:]
|
217
|
+
|
218
|
+
kernel_1 = ImageStichOverlapKernel(frame_unstitched_axis_size=ref_frame_width, overlap_size=20, stitching_axis=1)
|
219
|
+
kernel_2 = ImageStichOverlapKernel(frame_unstitched_axis_size=ref_frame_width, overlap_size=10, stitching_axis=1)
|
220
|
+
|
221
|
+
stitched = stitch_raw_frames(
|
222
|
+
frames=(frame_1, frame_2, frame_3),
|
223
|
+
output_dtype=dtype,
|
224
|
+
overlap_kernels=(kernel_1, kernel_2),
|
225
|
+
raw_frames_compositions=None,
|
226
|
+
overlap_frames_compositions=None,
|
227
|
+
key_lines=(
|
228
|
+
(
|
229
|
+
90, # frame_1 height - kernel_1 height / 2.0
|
230
|
+
10, # kernel_1 height / 2.0
|
231
|
+
),
|
232
|
+
(
|
233
|
+
79, # frame_2 height - kernel_2 height / 2.0 ou 102-20 ?
|
234
|
+
5, # kernel_2 height / 2.0
|
235
|
+
),
|
236
|
+
),
|
237
|
+
)
|
238
|
+
|
239
|
+
assert stitched.shape == frame_ref.shape
|
240
|
+
numpy.testing.assert_array_almost_equal(frame_ref, stitched)
|
@@ -0,0 +1,132 @@
|
|
1
|
+
import os
|
2
|
+
import pytest
|
3
|
+
import numpy
|
4
|
+
from tqdm import tqdm
|
5
|
+
|
6
|
+
from nabu.stitching.y_stitching import y_stitching
|
7
|
+
from nabu.stitching.config import PreProcessedYStitchingConfiguration
|
8
|
+
from nxtomo.application.nxtomo import NXtomo
|
9
|
+
from nxtomo.nxobject.nxdetector import ImageKey
|
10
|
+
from tomoscan.esrf.scan.nxtomoscan import NXtomoScan
|
11
|
+
|
12
|
+
|
13
|
+
def build_nxtomos(output_dir, flip_lr, flip_ud) -> tuple:
|
14
|
+
r"""
|
15
|
+
build two nxtomos in output_dir and return the list of NXtomos ready to be stitched
|
16
|
+
/\
|
17
|
+
| ______________ ______________
|
18
|
+
| |~ ~~| |~ |
|
19
|
+
| |~ nxtomo 1 ~~| |~ nxtomo 0 |
|
20
|
+
Z | |~ frame ~~| |~ frame |
|
21
|
+
|______________| |______________|
|
22
|
+
<-----------------------------------------------
|
23
|
+
90 40 0
|
24
|
+
y (in acquisition space)
|
25
|
+
* ~: represent the overlap area
|
26
|
+
"""
|
27
|
+
dark_data = numpy.array([0] * 64 * 120, dtype=numpy.float32).reshape((64, 120))
|
28
|
+
flat_data = numpy.array([1] * 64 * 120, dtype=numpy.float32).reshape((64, 120))
|
29
|
+
normalized_data = numpy.linspace(128, 1024, num=64 * 120, dtype=numpy.float32).reshape((64, 120))
|
30
|
+
if flip_lr:
|
31
|
+
dark_data = numpy.fliplr(dark_data)
|
32
|
+
flat_data = numpy.fliplr(flat_data)
|
33
|
+
normalized_data = numpy.fliplr(normalized_data)
|
34
|
+
if flip_ud:
|
35
|
+
dark_data = numpy.flipud(dark_data)
|
36
|
+
flat_data = numpy.flipud(flat_data)
|
37
|
+
normalized_data = numpy.flipud(normalized_data)
|
38
|
+
|
39
|
+
raw_data = (normalized_data + dark_data) * (flat_data + dark_data)
|
40
|
+
|
41
|
+
# create raw data
|
42
|
+
scans = []
|
43
|
+
slices = (slice(0, 80), slice(60, -1))
|
44
|
+
frame_y_positions = (40, 90)
|
45
|
+
for i_nxtomo, (my_slice, frame_y_position) in enumerate(zip(slices, frame_y_positions)):
|
46
|
+
my_raw_data = raw_data[:, my_slice]
|
47
|
+
assert my_raw_data.ndim == 2
|
48
|
+
my_dark_data = dark_data[:, my_slice]
|
49
|
+
assert my_dark_data.ndim == 2
|
50
|
+
my_flat_data = flat_data[:, my_slice]
|
51
|
+
assert my_flat_data.ndim == 2
|
52
|
+
|
53
|
+
n_projs = 3
|
54
|
+
nx_tomo = NXtomo()
|
55
|
+
nx_tomo.sample.x_translation = [0] * (n_projs + 2)
|
56
|
+
nx_tomo.sample.y_translation = [frame_y_position] * (n_projs + 2)
|
57
|
+
nx_tomo.sample.z_translation = [0] * (n_projs + 2)
|
58
|
+
nx_tomo.sample.rotation_angle = numpy.linspace(0, 180, num=(n_projs + 2), endpoint=False)
|
59
|
+
nx_tomo.instrument.detector.image_key_control = (
|
60
|
+
ImageKey.DARK_FIELD,
|
61
|
+
ImageKey.FLAT_FIELD,
|
62
|
+
ImageKey.PROJECTION,
|
63
|
+
ImageKey.PROJECTION,
|
64
|
+
ImageKey.PROJECTION,
|
65
|
+
)
|
66
|
+
nx_tomo.instrument.detector.x_pixel_size = 1.0
|
67
|
+
nx_tomo.instrument.detector.y_pixel_size = 1.0
|
68
|
+
nx_tomo.instrument.detector.distance = 2.3
|
69
|
+
nx_tomo.energy = 19.2
|
70
|
+
nx_tomo.instrument.detector.data = numpy.stack(
|
71
|
+
(
|
72
|
+
my_dark_data,
|
73
|
+
my_flat_data,
|
74
|
+
my_raw_data,
|
75
|
+
my_raw_data,
|
76
|
+
my_raw_data,
|
77
|
+
)
|
78
|
+
)
|
79
|
+
|
80
|
+
file_path = os.path.join(output_dir, f"nxtomo_{i_nxtomo}.nx")
|
81
|
+
entry = f"entry000{i_nxtomo}"
|
82
|
+
nx_tomo.save(file_path=file_path, data_path=entry)
|
83
|
+
scans.append(NXtomoScan(scan=file_path, entry=entry))
|
84
|
+
return scans, frame_y_positions, normalized_data
|
85
|
+
|
86
|
+
|
87
|
+
@pytest.mark.parametrize("flip_lr", (True, False))
|
88
|
+
@pytest.mark.parametrize("flip_ud", (True, False))
|
89
|
+
@pytest.mark.parametrize("progress", (None, "with_tqdm"))
|
90
|
+
def test_preprocessing_stitching(tmp_path, flip_lr, flip_ud, progress):
|
91
|
+
if progress == "with_tqdm":
|
92
|
+
progress = tqdm(total=100)
|
93
|
+
|
94
|
+
nxtomo_dir = tmp_path / "nxtomos"
|
95
|
+
nxtomo_dir.mkdir()
|
96
|
+
output_dir = tmp_path / "output"
|
97
|
+
output_dir.mkdir()
|
98
|
+
|
99
|
+
output_file_path = os.path.join(output_dir, "nxtomo.nxs")
|
100
|
+
|
101
|
+
nxtomos, _, normalized_data = build_nxtomos(
|
102
|
+
output_dir=nxtomo_dir,
|
103
|
+
flip_lr=flip_lr,
|
104
|
+
flip_ud=flip_ud,
|
105
|
+
)
|
106
|
+
|
107
|
+
configuration = PreProcessedYStitchingConfiguration(
|
108
|
+
input_scans=nxtomos,
|
109
|
+
axis_0_pos_px=None,
|
110
|
+
axis_1_pos_px=None,
|
111
|
+
axis_2_pos_px=None,
|
112
|
+
output_file_path=output_file_path,
|
113
|
+
output_data_path="stitched_volume",
|
114
|
+
)
|
115
|
+
|
116
|
+
output_identifier = y_stitching(
|
117
|
+
configuration=configuration,
|
118
|
+
progress=progress,
|
119
|
+
)
|
120
|
+
created_nx_tomo = NXtomo().load(
|
121
|
+
file_path=output_identifier.file_path,
|
122
|
+
data_path=output_identifier.data_path,
|
123
|
+
detector_data_as="as_numpy_array",
|
124
|
+
)
|
125
|
+
assert created_nx_tomo.instrument.detector.data.shape == (
|
126
|
+
3,
|
127
|
+
64,
|
128
|
+
120,
|
129
|
+
) # 3 == number of projections, dark and flat will not be exported when doing the stitching
|
130
|
+
# TODO: improve me: the relative tolerance is pretty high. This doesn't comes from the algorithm on itself
|
131
|
+
# but more on the numerical calculation and the flat field normalization
|
132
|
+
numpy.testing.assert_allclose(normalized_data, created_nx_tomo.instrument.detector.data[0], rtol=0.06)
|