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.
Files changed (151) hide show
  1. nabu/__init__.py +1 -1
  2. nabu/app/bootstrap.py +2 -3
  3. nabu/app/cast_volume.py +4 -2
  4. nabu/app/cli_configs.py +5 -0
  5. nabu/app/composite_cor.py +1 -1
  6. nabu/app/create_distortion_map_from_poly.py +5 -6
  7. nabu/app/diag_to_pix.py +7 -19
  8. nabu/app/diag_to_rot.py +14 -29
  9. nabu/app/double_flatfield.py +32 -44
  10. nabu/app/parse_reconstruction_log.py +3 -0
  11. nabu/app/reconstruct.py +53 -15
  12. nabu/app/reconstruct_helical.py +2 -2
  13. nabu/app/stitching.py +27 -13
  14. nabu/app/tests/test_reduce_dark_flat.py +4 -1
  15. nabu/cuda/kernel.py +11 -2
  16. nabu/cuda/processing.py +2 -2
  17. nabu/cuda/src/cone.cu +77 -0
  18. nabu/cuda/src/hierarchical_backproj.cu +271 -0
  19. nabu/cuda/utils.py +0 -6
  20. nabu/estimation/alignment.py +5 -19
  21. nabu/estimation/cor.py +173 -599
  22. nabu/estimation/cor_sino.py +356 -26
  23. nabu/estimation/focus.py +63 -11
  24. nabu/estimation/tests/test_cor.py +124 -58
  25. nabu/estimation/tests/test_focus.py +6 -6
  26. nabu/estimation/tilt.py +2 -1
  27. nabu/estimation/utils.py +5 -33
  28. nabu/io/__init__.py +1 -1
  29. nabu/io/cast_volume.py +1 -1
  30. nabu/io/reader.py +416 -21
  31. nabu/io/tests/test_readers.py +422 -0
  32. nabu/io/tests/test_writers.py +1 -102
  33. nabu/io/writer.py +4 -433
  34. nabu/opencl/kernel.py +14 -3
  35. nabu/opencl/processing.py +8 -0
  36. nabu/pipeline/config_validators.py +5 -2
  37. nabu/pipeline/datadump.py +12 -5
  38. nabu/pipeline/estimators.py +162 -188
  39. nabu/pipeline/fullfield/chunked.py +168 -92
  40. nabu/pipeline/fullfield/chunked_cuda.py +7 -3
  41. nabu/pipeline/fullfield/computations.py +2 -7
  42. nabu/pipeline/fullfield/dataset_validator.py +0 -4
  43. nabu/pipeline/fullfield/nabu_config.py +37 -13
  44. nabu/pipeline/fullfield/processconfig.py +22 -13
  45. nabu/pipeline/fullfield/reconstruction.py +13 -9
  46. nabu/pipeline/helical/helical_chunked_regridded.py +1 -1
  47. nabu/pipeline/helical/helical_chunked_regridded_cuda.py +1 -0
  48. nabu/pipeline/helical/helical_reconstruction.py +1 -1
  49. nabu/pipeline/params.py +21 -1
  50. nabu/pipeline/processconfig.py +1 -12
  51. nabu/pipeline/reader.py +146 -0
  52. nabu/pipeline/tests/test_estimators.py +44 -72
  53. nabu/pipeline/utils.py +4 -2
  54. nabu/pipeline/writer.py +10 -2
  55. nabu/preproc/ccd_cuda.py +1 -1
  56. nabu/preproc/ctf.py +14 -7
  57. nabu/preproc/ctf_cuda.py +2 -3
  58. nabu/preproc/double_flatfield.py +5 -12
  59. nabu/preproc/double_flatfield_cuda.py +2 -2
  60. nabu/preproc/flatfield.py +5 -1
  61. nabu/preproc/flatfield_cuda.py +5 -1
  62. nabu/preproc/phase.py +24 -73
  63. nabu/preproc/phase_cuda.py +5 -8
  64. nabu/preproc/tests/test_ctf.py +11 -7
  65. nabu/preproc/tests/test_flatfield.py +67 -122
  66. nabu/preproc/tests/test_paganin.py +54 -30
  67. nabu/processing/azim.py +206 -0
  68. nabu/processing/convolution_cuda.py +1 -1
  69. nabu/processing/fft_cuda.py +15 -17
  70. nabu/processing/histogram.py +2 -0
  71. nabu/processing/histogram_cuda.py +2 -1
  72. nabu/processing/kernel_base.py +3 -0
  73. nabu/processing/muladd_cuda.py +1 -0
  74. nabu/processing/padding_opencl.py +1 -1
  75. nabu/processing/roll_opencl.py +1 -0
  76. nabu/processing/rotation_cuda.py +2 -2
  77. nabu/processing/tests/test_fft.py +17 -10
  78. nabu/processing/unsharp_cuda.py +1 -1
  79. nabu/reconstruction/cone.py +104 -40
  80. nabu/reconstruction/fbp.py +3 -0
  81. nabu/reconstruction/fbp_base.py +7 -2
  82. nabu/reconstruction/filtering.py +20 -7
  83. nabu/reconstruction/filtering_cuda.py +7 -1
  84. nabu/reconstruction/hbp.py +424 -0
  85. nabu/reconstruction/mlem.py +99 -0
  86. nabu/reconstruction/reconstructor.py +2 -0
  87. nabu/reconstruction/rings_cuda.py +19 -19
  88. nabu/reconstruction/sinogram_cuda.py +1 -0
  89. nabu/reconstruction/sinogram_opencl.py +3 -1
  90. nabu/reconstruction/tests/test_cone.py +10 -5
  91. nabu/reconstruction/tests/test_deringer.py +7 -6
  92. nabu/reconstruction/tests/test_fbp.py +124 -10
  93. nabu/reconstruction/tests/test_filtering.py +13 -11
  94. nabu/reconstruction/tests/test_halftomo.py +30 -4
  95. nabu/reconstruction/tests/test_mlem.py +91 -0
  96. nabu/reconstruction/tests/test_reconstructor.py +8 -3
  97. nabu/resources/dataset_analyzer.py +142 -92
  98. nabu/resources/gpu.py +1 -0
  99. nabu/resources/nxflatfield.py +134 -125
  100. nabu/resources/templates/id16a_fluo.conf +42 -0
  101. nabu/resources/tests/test_extract.py +10 -0
  102. nabu/resources/tests/test_nxflatfield.py +2 -2
  103. nabu/stitching/alignment.py +80 -24
  104. nabu/stitching/config.py +105 -68
  105. nabu/stitching/definitions.py +1 -0
  106. nabu/stitching/frame_composition.py +68 -60
  107. nabu/stitching/overlap.py +91 -51
  108. nabu/stitching/single_axis_stitching.py +32 -0
  109. nabu/stitching/slurm_utils.py +6 -6
  110. nabu/stitching/stitcher/__init__.py +0 -0
  111. nabu/stitching/stitcher/base.py +124 -0
  112. nabu/stitching/stitcher/dumper/__init__.py +3 -0
  113. nabu/stitching/stitcher/dumper/base.py +94 -0
  114. nabu/stitching/stitcher/dumper/postprocessing.py +356 -0
  115. nabu/stitching/stitcher/dumper/preprocessing.py +60 -0
  116. nabu/stitching/stitcher/post_processing.py +555 -0
  117. nabu/stitching/stitcher/pre_processing.py +1068 -0
  118. nabu/stitching/stitcher/single_axis.py +484 -0
  119. nabu/stitching/stitcher/stitcher.py +0 -0
  120. nabu/stitching/stitcher/y_stitcher.py +13 -0
  121. nabu/stitching/stitcher/z_stitcher.py +45 -0
  122. nabu/stitching/stitcher_2D.py +278 -0
  123. nabu/stitching/tests/test_config.py +12 -37
  124. nabu/stitching/tests/test_frame_composition.py +33 -59
  125. nabu/stitching/tests/test_overlap.py +149 -7
  126. nabu/stitching/tests/test_utils.py +1 -1
  127. nabu/stitching/tests/test_y_preprocessing_stitching.py +132 -0
  128. nabu/stitching/tests/{test_z_stitching.py → test_z_postprocessing_stitching.py} +167 -561
  129. nabu/stitching/tests/test_z_preprocessing_stitching.py +431 -0
  130. nabu/stitching/utils/__init__.py +1 -0
  131. nabu/stitching/utils/post_processing.py +281 -0
  132. nabu/stitching/utils/tests/test_post-processing.py +21 -0
  133. nabu/stitching/{utils.py → utils/utils.py} +79 -52
  134. nabu/stitching/y_stitching.py +27 -0
  135. nabu/stitching/z_stitching.py +32 -2263
  136. nabu/testutils.py +1 -152
  137. nabu/thirdparty/tomocupy_remove_stripe.py +43 -9
  138. nabu/utils.py +158 -61
  139. {nabu-2024.1.9.dist-info → nabu-2024.2.0.dist-info}/METADATA +10 -3
  140. {nabu-2024.1.9.dist-info → nabu-2024.2.0.dist-info}/RECORD +144 -121
  141. nabu/io/tiffwriter_zmm.py +0 -99
  142. nabu/pipeline/fallback_utils.py +0 -149
  143. nabu/pipeline/helical/tests/test_accumulator.py +0 -158
  144. nabu/pipeline/helical/tests/test_pipeline_elements_full.py +0 -355
  145. nabu/pipeline/helical/tests/test_strategy.py +0 -61
  146. nabu/pipeline/helical/utils.py +0 -51
  147. nabu/pipeline/tests/test_chunk_reader.py +0 -74
  148. {nabu-2024.1.9.dist-info → nabu-2024.2.0.dist-info}/LICENSE +0 -0
  149. {nabu-2024.1.9.dist-info → nabu-2024.2.0.dist-info}/WHEEL +0 -0
  150. {nabu-2024.1.9.dist-info → nabu-2024.2.0.dist-info}/entry_points.txt +0 -0
  151. {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.PostProcessedZStitchingConfiguration,
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.PreProcessedZStitchingConfiguration,
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.PostProcessedZStitchingConfiguration,
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.PreProcessedZStitchingConfiguration,
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.Z_PRE_PROC_SECTION: {
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.PreProcessedZStitchingConfiguration.get_description_dict(), dict)
197
+ assert isinstance(stiching_config.PreProcessedSingleAxisStitchingConfiguration.get_description_dict(), dict)
223
198
  assert isinstance(
224
- stiching_config.PostProcessedZStitchingConfiguration.get_description_dict(),
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 ZFrameComposition
2
+ from nabu.stitching.frame_composition import FrameComposition
33
3
  import numpy
34
4
 
35
- from nabu.stitching.overlap import OverlapStitchingStrategy, ZStichOverlapKernel
5
+ from nabu.stitching.overlap import OverlapStitchingStrategy, ImageStichOverlapKernel
36
6
 
37
7
 
38
8
  def test_frame_composition():
39
9
  """
40
- Test _ZFrameComposition
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
- ZStichOverlapKernel(
52
- frame_width=1,
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
- ZStichOverlapKernel(
57
- frame_width=1,
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 = ZFrameComposition.compute_raw_frame_compositions(
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, ZFrameComposition)
44
+ assert isinstance(raw_composition, FrameComposition)
73
45
 
74
- assert raw_composition.local_start_y == (0, 12, 9)
75
- assert raw_composition.local_end_y == (88, 89, 205)
76
- assert raw_composition.global_start_y == (0, 92, 177)
77
- assert raw_composition.global_end_y == (88, 169, 373)
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 = ZFrameComposition.compute_stitch_frame_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
- ZFrameComposition.pprint_z_stitching(raw_composition, stitch_composition)
68
+ FrameComposition.pprint_composition(raw_composition, stitch_composition)
97
69
 
98
- assert stitch_composition.local_start_y == (0, 0)
99
- assert stitch_composition.local_end_y == (4, 8)
100
- assert stitch_composition.global_start_y == (88, 169)
101
- assert stitch_composition.global_end_y == (92, 177)
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
- ZStichOverlapKernel(
134
- frame_width=1,
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
- ZStichOverlapKernel(
139
- frame_width=1,
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 = ZFrameComposition.compute_raw_frame_compositions(
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.global_start_y == configuration.get("raw_global_start")
170
- assert raw_composition.global_end_y == configuration.get("raw_global_end")
171
- assert raw_composition.local_start_y == configuration.get("raw_local_start")
172
- assert raw_composition.local_end_y == configuration.get("raw_local_end")
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.global_end_y[-1] - raw_composition.global_start_y[0]),
150
+ (raw_composition.global_end[-1] - raw_composition.global_start[0]),
177
151
  1,
178
152
  )
179
153
  )