nabu 2024.2.0rc2__py3-none-any.whl → 2024.2.0rc4__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.
- doc/doc_config.py +32 -0
- nabu/__init__.py +1 -1
- nabu/estimation/cor.py +1 -1
- nabu/pipeline/estimators.py +3 -3
- nabu/pipeline/fullfield/chunked.py +6 -2
- nabu/pipeline/writer.py +7 -0
- nabu/reconstruction/astra.py +244 -0
- nabu/resources/dataset_analyzer.py +11 -11
- {nabu-2024.2.0rc2.dist-info → nabu-2024.2.0rc4.dist-info}/METADATA +2 -2
- {nabu-2024.2.0rc2.dist-info → nabu-2024.2.0rc4.dist-info}/RECORD +14 -14
- {nabu-2024.2.0rc2.dist-info → nabu-2024.2.0rc4.dist-info}/WHEEL +1 -1
- nabu/app/tests/__init__.py +0 -0
- nabu/resources/tests/test_extract.py +0 -10
- {nabu-2024.2.0rc2.dist-info → nabu-2024.2.0rc4.dist-info}/LICENSE +0 -0
- {nabu-2024.2.0rc2.dist-info → nabu-2024.2.0rc4.dist-info}/entry_points.txt +0 -0
- {nabu-2024.2.0rc2.dist-info → nabu-2024.2.0rc4.dist-info}/top_level.txt +0 -0
doc/doc_config.py
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
from nabu.resources.nabu_config import nabu_config
|
4
|
+
|
5
|
+
|
6
|
+
def generate(file_):
|
7
|
+
def write(content):
|
8
|
+
print(content, file=file_)
|
9
|
+
for section, values in nabu_config.items():
|
10
|
+
if section == "about":
|
11
|
+
continue
|
12
|
+
write("## %s\n" % section)
|
13
|
+
for key, val in values.items():
|
14
|
+
if val["type"] == "unsupported":
|
15
|
+
continue
|
16
|
+
write(val["help"] + "\n")
|
17
|
+
write(
|
18
|
+
"```ini\n%s = %s\n```"
|
19
|
+
% (key, val["default"])
|
20
|
+
)
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
if __name__ == "__main__":
|
25
|
+
|
26
|
+
import sys, os
|
27
|
+
print(os.path.abspath(__file__))
|
28
|
+
exit(0)
|
29
|
+
|
30
|
+
fname = "/tmp/test.md"
|
31
|
+
with open(fname, "w") as f:
|
32
|
+
generate(f)
|
nabu/__init__.py
CHANGED
nabu/estimation/cor.py
CHANGED
@@ -239,7 +239,7 @@ class CenterOfRotationSlidingWindow(CenterOfRotation):
|
|
239
239
|
win_2_start = img_width // 2 - window_shift
|
240
240
|
else:
|
241
241
|
abs_pos = int(side + img_width // 2)
|
242
|
-
window_fraction = 0.
|
242
|
+
window_fraction = 0.1 # Hard-coded ?
|
243
243
|
|
244
244
|
window_width = round(window_fraction * img_width)
|
245
245
|
window_shift = window_width // 2
|
nabu/pipeline/estimators.py
CHANGED
@@ -243,13 +243,13 @@ class CORFinder(CORFinderBase):
|
|
243
243
|
# All find_shift() methods in self.search_methods have the same API with "img_1" and "img_2"
|
244
244
|
cor_exec_kwargs = update_func_kwargs(self.cor_finder.find_shift, self.cor_options)
|
245
245
|
cor_exec_kwargs["return_relative_to_middle"] = False
|
246
|
-
# FIXME
|
246
|
+
# ----- FIXME -----
|
247
247
|
# 'self.cor_options' can contain 'side="from_file"', and we should not modify it directly
|
248
248
|
# because it's entered by the user.
|
249
249
|
# Either make a copy of self.cor_options, or change the inspect() mechanism
|
250
|
-
if cor_exec_kwargs
|
250
|
+
if cor_exec_kwargs.get("side", None) == "from_file":
|
251
251
|
cor_exec_kwargs["side"] = self._lookup_side or "center"
|
252
|
-
#
|
252
|
+
# ------
|
253
253
|
if self._lookup_side is not None:
|
254
254
|
cor_exec_kwargs["side"] = self._lookup_side
|
255
255
|
self.logger.debug("%s.find_shift(%s)" % (self.cor_finder.__class__.__name__, str(cor_exec_kwargs)))
|
@@ -668,7 +668,10 @@ class ChunkedPipeline:
|
|
668
668
|
"jpeg2000_compression_ratio": options["jpeg2000_compression_ratio"],
|
669
669
|
"float_clip_values": options["float_clip_values"],
|
670
670
|
"tiff_single_file": options.get("tiff_single_file", False),
|
671
|
-
"single_output_file_initialized": getattr(
|
671
|
+
"single_output_file_initialized": getattr(
|
672
|
+
self.process_config, "single_output_file_initialized", False
|
673
|
+
), # COMPAT.
|
674
|
+
"writer_initialized": getattr(self.process_config, "_writer_initialized", False),
|
672
675
|
"raw_vol_metadata": {"voxelSize": self.dataset_info.pixel_size}, # legacy...
|
673
676
|
}
|
674
677
|
writer_extra_options.update(extra_options)
|
@@ -853,7 +856,8 @@ class ChunkedPipeline:
|
|
853
856
|
self.writer.write_data(data)
|
854
857
|
self.logger.info("Wrote %s" % self.writer.fname)
|
855
858
|
self._write_histogram()
|
856
|
-
self.process_config.single_output_file_initialized = True
|
859
|
+
self.process_config.single_output_file_initialized = True # COMPAT.
|
860
|
+
self.process_config._writer_initialized = True
|
857
861
|
|
858
862
|
def _write_histogram(self):
|
859
863
|
if "histogram" not in self.processing_steps:
|
nabu/pipeline/writer.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
from os import path
|
2
2
|
from tomoscan.esrf import TIFFVolume, MultiTIFFVolume, EDFVolume, JP2KVolume
|
3
|
+
from tomoscan.esrf.volume.singleframebase import VolumeSingleFrameBase
|
3
4
|
from ..utils import check_supported, get_num_threads
|
4
5
|
from ..resources.logger import LoggerOrPrint
|
5
6
|
from ..io.writer import NXProcessWriter, HSTVolVolume, NXVolVolume
|
@@ -113,6 +114,7 @@ class WriterManager:
|
|
113
114
|
return vol_writer.data_url.file_path()
|
114
115
|
|
115
116
|
def _init_writer(self):
|
117
|
+
self._writer_was_already_initialized = self.extra_options.get("writer_initialized", False)
|
116
118
|
if self.file_format in ["tiff", "edf", "jp2", "hdf5"]:
|
117
119
|
writer_kwargs = {
|
118
120
|
"folder": self.output_dir,
|
@@ -143,6 +145,11 @@ class WriterManager:
|
|
143
145
|
self._h5_entry = self.metadata.get("entry", "entry")
|
144
146
|
self.writer = self._writer_classes[self.file_format](**writer_kwargs)
|
145
147
|
self.fname = self.get_fname(self.writer)
|
148
|
+
# In certain cases, tomoscan needs to remove any previous existing volume filess
|
149
|
+
# and avoid calling 'clean_output_data' when writing downstream (for chunk processing)
|
150
|
+
if isinstance(self.writer, VolumeSingleFrameBase):
|
151
|
+
self.writer.skip_existing_data_files_removal = self._writer_was_already_initialized
|
152
|
+
# ---
|
146
153
|
if path.exists(self.fname):
|
147
154
|
err = "File already exists: %s" % self.fname
|
148
155
|
if self.overwrite:
|
@@ -0,0 +1,244 @@
|
|
1
|
+
try:
|
2
|
+
import astra
|
3
|
+
|
4
|
+
__have_astra__ = True
|
5
|
+
except ImportError:
|
6
|
+
__have_astra__ = False
|
7
|
+
astra = None
|
8
|
+
|
9
|
+
|
10
|
+
class AstraReconstructor:
|
11
|
+
"""
|
12
|
+
Base class for reconstructors based on the Astra toolbox
|
13
|
+
"""
|
14
|
+
|
15
|
+
default_extra_options = {
|
16
|
+
"axis_correction": None,
|
17
|
+
"clip_outer_circle": False,
|
18
|
+
"scale_factor": None,
|
19
|
+
"filter_cutoff": 1.0,
|
20
|
+
"outer_circle_value": 0.0,
|
21
|
+
}
|
22
|
+
|
23
|
+
def __init__(
|
24
|
+
self,
|
25
|
+
sinos_shape,
|
26
|
+
angles=None,
|
27
|
+
volume_shape=None,
|
28
|
+
rot_center=None,
|
29
|
+
pixel_size=None,
|
30
|
+
padding_mode="zeros",
|
31
|
+
filter_name=None,
|
32
|
+
slice_roi=None,
|
33
|
+
cuda_options=None,
|
34
|
+
extra_options=None,
|
35
|
+
):
|
36
|
+
self._configure_extra_options(extra_options)
|
37
|
+
self._init_cuda(cuda_options)
|
38
|
+
self._set_sino_shape(sinos_shape)
|
39
|
+
self._orig_prog_geom = None
|
40
|
+
self._init_geometry(
|
41
|
+
source_origin_dist,
|
42
|
+
origin_detector_dist,
|
43
|
+
pixel_size,
|
44
|
+
angles,
|
45
|
+
volume_shape,
|
46
|
+
rot_center,
|
47
|
+
relative_z_position,
|
48
|
+
slice_roi,
|
49
|
+
)
|
50
|
+
self._init_fdk(padding_mode, filter_name)
|
51
|
+
self._alg_id = None
|
52
|
+
self._vol_id = None
|
53
|
+
self._proj_id = None
|
54
|
+
|
55
|
+
def _configure_extra_options(self, extra_options):
|
56
|
+
self.extra_options = self.default_extra_options.copy()
|
57
|
+
self.extra_options.update(extra_options or {})
|
58
|
+
|
59
|
+
def _init_cuda(self, cuda_options):
|
60
|
+
cuda_options = cuda_options or {}
|
61
|
+
self.cuda = CudaProcessing(**cuda_options)
|
62
|
+
|
63
|
+
def _set_sino_shape(self, sinos_shape):
|
64
|
+
if len(sinos_shape) != 3:
|
65
|
+
raise ValueError("Expected a 3D shape")
|
66
|
+
self.sinos_shape = sinos_shape
|
67
|
+
self.n_sinos, self.n_angles, self.prj_width = sinos_shape
|
68
|
+
|
69
|
+
def _set_pixel_size(self, pixel_size):
|
70
|
+
if pixel_size is None:
|
71
|
+
det_spacing_y = det_spacing_x = 1
|
72
|
+
elif np.iterable(pixel_size):
|
73
|
+
det_spacing_y, det_spacing_x = pixel_size
|
74
|
+
else:
|
75
|
+
# assuming scalar
|
76
|
+
det_spacing_y = det_spacing_x = pixel_size
|
77
|
+
self._det_spacing_y = det_spacing_y
|
78
|
+
self._det_spacing_x = det_spacing_x
|
79
|
+
|
80
|
+
def _set_slice_roi(self, slice_roi):
|
81
|
+
self.slice_roi = slice_roi
|
82
|
+
self._vol_geom_n_x = self.n_x
|
83
|
+
self._vol_geom_n_y = self.n_y
|
84
|
+
self._crop_data = True
|
85
|
+
if slice_roi is None:
|
86
|
+
return
|
87
|
+
start_x, end_x, start_y, end_y = slice_roi
|
88
|
+
if roi_is_centered(self.volume_shape[1:], (slice(start_y, end_y), slice(start_x, end_x))):
|
89
|
+
# Astra can only reconstruct subregion centered around the origin
|
90
|
+
self._vol_geom_n_x = self.n_x - start_x * 2
|
91
|
+
self._vol_geom_n_y = self.n_y - start_y * 2
|
92
|
+
else:
|
93
|
+
raise NotImplementedError(
|
94
|
+
"Astra supports only slice_roi centered around origin (got slice_roi=%s with n_x=%d, n_y=%d)"
|
95
|
+
% (str(slice_roi), self.n_x, self.n_y)
|
96
|
+
)
|
97
|
+
|
98
|
+
def _init_geometry(
|
99
|
+
self,
|
100
|
+
source_origin_dist,
|
101
|
+
origin_detector_dist,
|
102
|
+
pixel_size,
|
103
|
+
angles,
|
104
|
+
volume_shape,
|
105
|
+
rot_center,
|
106
|
+
relative_z_position,
|
107
|
+
slice_roi,
|
108
|
+
):
|
109
|
+
if angles is None:
|
110
|
+
self.angles = np.linspace(0, 2 * np.pi, self.n_angles, endpoint=True)
|
111
|
+
else:
|
112
|
+
self.angles = angles
|
113
|
+
if volume_shape is None:
|
114
|
+
volume_shape = (self.sinos_shape[0], self.sinos_shape[2], self.sinos_shape[2])
|
115
|
+
self.volume_shape = volume_shape
|
116
|
+
self.n_z, self.n_y, self.n_x = self.volume_shape
|
117
|
+
self.source_origin_dist = source_origin_dist
|
118
|
+
self.origin_detector_dist = origin_detector_dist
|
119
|
+
self.magnification = 1 + origin_detector_dist / source_origin_dist
|
120
|
+
self._set_slice_roi(slice_roi)
|
121
|
+
self.vol_geom = astra.create_vol_geom(self._vol_geom_n_y, self._vol_geom_n_x, self.n_z)
|
122
|
+
self.vol_shape = astra.geom_size(self.vol_geom)
|
123
|
+
self._cor_shift = 0.0
|
124
|
+
self.rot_center = rot_center
|
125
|
+
if rot_center is not None:
|
126
|
+
self._cor_shift = (self.sinos_shape[-1] - 1) / 2.0 - rot_center
|
127
|
+
self._set_pixel_size(pixel_size)
|
128
|
+
self._axis_corrections = self.extra_options.get("axis_correction", None)
|
129
|
+
self._create_astra_proj_geometry(relative_z_position)
|
130
|
+
|
131
|
+
def _create_astra_proj_geometry(self, relative_z_position):
|
132
|
+
# This object has to be re-created each time, because once the modifications below are done,
|
133
|
+
# it is no more a "cone" geometry but a "cone_vec" geometry, and cannot be updated subsequently
|
134
|
+
# (see astra/functions.py:271)
|
135
|
+
self.proj_geom = astra.create_proj_geom(
|
136
|
+
"cone",
|
137
|
+
self._det_spacing_x,
|
138
|
+
self._det_spacing_y,
|
139
|
+
self.n_sinos,
|
140
|
+
self.prj_width,
|
141
|
+
self.angles,
|
142
|
+
self.source_origin_dist,
|
143
|
+
self.origin_detector_dist,
|
144
|
+
)
|
145
|
+
self.relative_z_position = relative_z_position or 0.0
|
146
|
+
# This will turn the geometry of type "cone" into a geometry of type "cone_vec"
|
147
|
+
if self._orig_prog_geom is None:
|
148
|
+
self._orig_prog_geom = self.proj_geom
|
149
|
+
self.proj_geom = astra.geom_postalignment(self.proj_geom, (self._cor_shift, 0))
|
150
|
+
# (src, detector_center, u, v) = (srcX, srcY, srcZ, dX, dY, dZ, uX, uY, uZ, vX, vY, vZ)
|
151
|
+
vecs = self.proj_geom["Vectors"]
|
152
|
+
|
153
|
+
# To adapt the center of rotation:
|
154
|
+
# dX = cor_shift * cos(theta) - origin_detector_dist * sin(theta)
|
155
|
+
# dY = origin_detector_dist * cos(theta) + cor_shift * sin(theta)
|
156
|
+
if self._axis_corrections is not None:
|
157
|
+
# should we check that dX and dY match the above formulas ?
|
158
|
+
cor_shifts = self._cor_shift + self._axis_corrections
|
159
|
+
vecs[:, 3] = cor_shifts * np.cos(self.angles) - self.origin_detector_dist * np.sin(self.angles)
|
160
|
+
vecs[:, 4] = self.origin_detector_dist * np.cos(self.angles) + cor_shifts * np.sin(self.angles)
|
161
|
+
|
162
|
+
# To adapt the z position:
|
163
|
+
# Component 2 of vecs is the z coordinate of the source, component 5 is the z component of the detector position
|
164
|
+
# We need to re-create the same inclination of the cone beam, thus we need to keep the inclination of the two z positions.
|
165
|
+
# The detector is centered on the rotation axis, thus moving it up or down, just moves it out of the reconstruction volume.
|
166
|
+
# We can bring back the detector in the correct volume position, by applying a rigid translation of both the detector and the source.
|
167
|
+
# The translation is exactly the amount that brought the detector up or down, but in the opposite direction.
|
168
|
+
vecs[:, 2] = -self.relative_z_position
|
169
|
+
|
170
|
+
def _set_output(self, volume):
|
171
|
+
if volume is not None:
|
172
|
+
expected_shape = self.vol_shape # if not (self._crop_data) else self._output_cropped_shape
|
173
|
+
self.cuda.check_array(volume, expected_shape)
|
174
|
+
self.cuda.set_array("output", volume)
|
175
|
+
if volume is None:
|
176
|
+
self.cuda.allocate_array("output", self.vol_shape)
|
177
|
+
d_volume = self.cuda.get_array("output")
|
178
|
+
z, y, x = d_volume.shape
|
179
|
+
self._vol_link = astra.data3d.GPULink(d_volume.ptr, x, y, z, d_volume.strides[-2])
|
180
|
+
self._vol_id = astra.data3d.link("-vol", self.vol_geom, self._vol_link)
|
181
|
+
|
182
|
+
def _set_input(self, sinos):
|
183
|
+
self.cuda.check_array(sinos, self.sinos_shape)
|
184
|
+
self.cuda.set_array("sinos", sinos) # self.cuda.sinos is now a GPU array
|
185
|
+
# TODO don't create new link/proj_id if ptr is the same ?
|
186
|
+
# But it seems Astra modifies the input sinogram while doing FDK, so this might be not relevant
|
187
|
+
d_sinos = self.cuda.get_array("sinos")
|
188
|
+
|
189
|
+
# self._proj_data_link = astra.data3d.GPULink(d_sinos.ptr, self.prj_width, self.n_angles, self.n_z, sinos.strides[-2])
|
190
|
+
self._proj_data_link = astra.data3d.GPULink(
|
191
|
+
d_sinos.ptr, self.prj_width, self.n_angles, self.n_sinos, d_sinos.strides[-2]
|
192
|
+
)
|
193
|
+
self._proj_id = astra.data3d.link("-sino", self.proj_geom, self._proj_data_link)
|
194
|
+
|
195
|
+
def _preprocess_data(self):
|
196
|
+
d_sinos = self.cuda.sinos
|
197
|
+
for i in range(d_sinos.shape[0]):
|
198
|
+
self.sino_filter.filter_sino(d_sinos[i], output=d_sinos[i])
|
199
|
+
|
200
|
+
def _update_reconstruction(self):
|
201
|
+
cfg = astra.astra_dict("BP3D_CUDA")
|
202
|
+
cfg["ReconstructionDataId"] = self._vol_id
|
203
|
+
cfg["ProjectionDataId"] = self._proj_id
|
204
|
+
if self._alg_id is not None:
|
205
|
+
astra.algorithm.delete(self._alg_id)
|
206
|
+
self._alg_id = astra.algorithm.create(cfg)
|
207
|
+
|
208
|
+
def reconstruct(self, sinos, output=None, relative_z_position=None):
|
209
|
+
"""
|
210
|
+
sinos: numpy.ndarray or pycuda.gpuarray
|
211
|
+
Sinograms, with shape (n_sinograms, n_angles, width)
|
212
|
+
output: pycuda.gpuarray, optional
|
213
|
+
Output array. If not provided, a new numpy array is returned
|
214
|
+
relative_z_position: int, optional
|
215
|
+
Position of the central slice of the slab, with respect to the full stack of slices.
|
216
|
+
By default it is set to zero, meaning that the current slab is assumed in the middle of the stack
|
217
|
+
"""
|
218
|
+
self._create_astra_proj_geometry(relative_z_position)
|
219
|
+
self._set_input(sinos)
|
220
|
+
self._set_output(output)
|
221
|
+
self._preprocess_data()
|
222
|
+
self._update_reconstruction()
|
223
|
+
astra.algorithm.run(self._alg_id)
|
224
|
+
#
|
225
|
+
# NB: Could also be done with
|
226
|
+
# from astra.experimental import direct_BP3D
|
227
|
+
# projector_id = astra.create_projector("cuda3d", self.proj_geom, self.vol_geom, options=None)
|
228
|
+
# direct_BP3D(projector_id, self._vol_link, self._proj_data_link)
|
229
|
+
#
|
230
|
+
result = self.cuda.get_array("output")
|
231
|
+
if output is None:
|
232
|
+
result = result.get()
|
233
|
+
if self.extra_options.get("scale_factor", None) is not None:
|
234
|
+
result *= np.float32(self.extra_options["scale_factor"]) # in-place for pycuda
|
235
|
+
self.cuda.recover_arrays_references(["sinos", "output"])
|
236
|
+
return result
|
237
|
+
|
238
|
+
def __del__(self):
|
239
|
+
if getattr(self, "_alg_id", None) is not None:
|
240
|
+
astra.algorithm.delete(self._alg_id)
|
241
|
+
if getattr(self, "_vol_id", None) is not None:
|
242
|
+
astra.data3d.delete(self._vol_id)
|
243
|
+
if getattr(self, "_proj_id", None) is not None:
|
244
|
+
astra.data3d.delete(self._proj_id)
|
@@ -52,7 +52,7 @@ class DatasetAnalyzer:
|
|
52
52
|
"output_dir": None,
|
53
53
|
"exclude_projections": None,
|
54
54
|
"hdf5_entry": None,
|
55
|
-
"nx_version": 1.0,
|
55
|
+
# "nx_version": 1.0,
|
56
56
|
}
|
57
57
|
# --
|
58
58
|
advanced_options.update(extra_options)
|
@@ -302,7 +302,7 @@ class EDFDatasetAnalyzer(DatasetAnalyzer):
|
|
302
302
|
return np.deg2rad(self.dataset_scanner.rotation_angle())
|
303
303
|
|
304
304
|
def get_reduced_flats(self, **reader_kwargs):
|
305
|
-
if self.
|
305
|
+
if self.raw_flats in [None, {}]:
|
306
306
|
raise FileNotFoundError("No reduced flat ('refHST') found in %s" % self.location)
|
307
307
|
# A few notes:
|
308
308
|
# (1) In principle we could do the reduction (mean/median) from raw frames (ref_xxxx_yyyy)
|
@@ -311,15 +311,15 @@ class EDFDatasetAnalyzer(DatasetAnalyzer):
|
|
311
311
|
# (eg. subsampling, binning, distortion correction...)
|
312
312
|
# (3) The following spawns one reader instance per file, which is not elegant,
|
313
313
|
# but in principle there are typically 1-2 reduced flats in a scan
|
314
|
-
readers = {k: EDFStackReader([self.
|
315
|
-
return {k: readers[k].load_data()[0] for k in self.
|
314
|
+
readers = {k: EDFStackReader([self.raw_flats[k].file_path()], **reader_kwargs) for k in self.raw_flats.keys()}
|
315
|
+
return {k: readers[k].load_data()[0] for k in self.raw_flats.keys()}
|
316
316
|
|
317
317
|
def get_reduced_darks(self, **reader_kwargs):
|
318
318
|
# See notes in get_reduced_flats() above
|
319
|
-
if self.
|
319
|
+
if self.raw_darks in [None, {}]:
|
320
320
|
raise FileNotFoundError("No reduced dark ('darkend.edf' or 'dark.edf') found in %s" % self.location)
|
321
|
-
readers = {k: EDFStackReader([self.
|
322
|
-
return {k: readers[k].load_data()[0] for k in self.
|
321
|
+
readers = {k: EDFStackReader([self.raw_darks[k].file_path()], **reader_kwargs) for k in self.raw_darks.keys()}
|
322
|
+
return {k: readers[k].load_data()[0] for k in self.raw_darks.keys()}
|
323
323
|
|
324
324
|
@property
|
325
325
|
def files(self):
|
@@ -365,10 +365,10 @@ class HDF5DatasetAnalyzer(DatasetAnalyzer):
|
|
365
365
|
def _get_dataset_hdf5_url(self):
|
366
366
|
if len(self.projections) > 0:
|
367
367
|
frames_to_take = self.projections
|
368
|
-
elif len(self.
|
369
|
-
frames_to_take = self.
|
370
|
-
elif len(self.
|
371
|
-
frames_to_take = self.
|
368
|
+
elif len(self.raw_flats) > 0:
|
369
|
+
frames_to_take = self.raw_flats
|
370
|
+
elif len(self.raw_darks) > 0:
|
371
|
+
frames_to_take = self.raw_darks
|
372
372
|
else:
|
373
373
|
raise ValueError("No projections, no flats and no darks ?!")
|
374
374
|
first_proj_idx = sorted(frames_to_take.keys())[0]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: nabu
|
3
|
-
Version: 2024.2.
|
3
|
+
Version: 2024.2.0rc4
|
4
4
|
Summary: Nabu - Tomography software
|
5
5
|
Author-email: Pierre Paleo <pierre.paleo@esrf.fr>, Henri Payno <henri.payno@esrf.fr>, Alessandro Mirone <mirone@esrf.fr>, Jérôme Lesaint <jerome.lesaint@esrf.fr>
|
6
6
|
Maintainer-email: Pierre Paleo <pierre.paleo@esrf.fr>
|
@@ -53,7 +53,7 @@ Requires-Dist: numpy <2,>1.9.0
|
|
53
53
|
Requires-Dist: scipy
|
54
54
|
Requires-Dist: h5py >=3.0
|
55
55
|
Requires-Dist: silx >=0.15.0
|
56
|
-
Requires-Dist: tomoscan >=2.1.
|
56
|
+
Requires-Dist: tomoscan >=2.1.0
|
57
57
|
Requires-Dist: psutil
|
58
58
|
Requires-Dist: pytest
|
59
59
|
Requires-Dist: tifffile
|
@@ -1,7 +1,8 @@
|
|
1
1
|
doc/conf.py,sha256=3xtCarCHrXPr50GbeRDuH-o3Jzojw7mpr7vpGfZPLAE,3787
|
2
2
|
doc/create_conf_doc.py,sha256=IVOdP70KvbW9WS_UQu3Iyd0YfS60E2fJ5IDtQ_s4cDw,1143
|
3
|
+
doc/doc_config.py,sha256=anqeOVjqE2e7eVzg7yuh9dvIneTkrA5doGl1cVBqT7Q,730
|
3
4
|
doc/get_mathjax.py,sha256=VIvKRCdDuF2VoY8JD3mSey9XX13AZMmwTJBHdt1tUs4,1012
|
4
|
-
nabu/__init__.py,sha256=
|
5
|
+
nabu/__init__.py,sha256=NEQPS4U8T5nfg0_kumGk9YWMlO5RkFqOihedIBF9z_A,274
|
5
6
|
nabu/tests.py,sha256=cew9OY2uTyncHI_HM32W8CP6B1GTGKaOW65XtMEqs7o,1417
|
6
7
|
nabu/testutils.py,sha256=VkSL9tbY0XEH49Z5OjDFFhzkSxrCv4UIuvSVFgegSUY,7632
|
7
8
|
nabu/utils.py,sha256=V1B_sD54XGNKn5pORa2yNCATyswOzybey3sv8BuIYWY,26355
|
@@ -31,7 +32,6 @@ nabu/app/shrink_dataset.py,sha256=P9dorO0Q-gPAWgSHyZi3XQp4jkMTJacDYzNvJY4oh98,35
|
|
31
32
|
nabu/app/stitching.py,sha256=T5nQVp7D6jNg86vMi8BCQANJJsKstvwItJWZDs05t64,4194
|
32
33
|
nabu/app/utils.py,sha256=XUBRWDmth4i3BZHd27rfarFAUP7OEcsMeVmDJ6T4EXA,1178
|
33
34
|
nabu/app/validator.py,sha256=IR-DcUV5h1Fc5CChBfBIaglrGpfKNICX7tGirAroMiw,3368
|
34
|
-
nabu/app/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
35
35
|
nabu/app/tests/test_reduce_dark_flat.py,sha256=qD52JL6fgJh7UEeGLssmsmGkqPTL8YTu29Hj1Nk9Bjg,2725
|
36
36
|
nabu/cuda/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
37
|
nabu/cuda/convolution.py,sha256=n8KsJ7IZdPOs_K5QZC6qblnOvIKYwxtdt03oNa0GiMU,241
|
@@ -64,7 +64,7 @@ nabu/cuda/src/transpose.cu,sha256=Enim7vLxTCFZbK3BmYdQ6ZatA_FLp6601VOSl8iGFjg,47
|
|
64
64
|
nabu/cuda/tests/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
65
65
|
nabu/estimation/__init__.py,sha256=HWE3ivArjlJx4FjFh2Q73VmpIyzod80KTmXvFo1AP1s,379
|
66
66
|
nabu/estimation/alignment.py,sha256=DWe4PBLsAOt95m_UEinVXUhXyYDmV0NOHW-oHpVEjVk,21185
|
67
|
-
nabu/estimation/cor.py,sha256=
|
67
|
+
nabu/estimation/cor.py,sha256=HcE0xw0ECSkx_kG30taw964rWZwh6lfgg8m9wnKdXik,50415
|
68
68
|
nabu/estimation/cor_sino.py,sha256=Wh0t8Ak6h8kf3rn5azD1XqD4e0Xa90oZUy90n9Ory8c,19116
|
69
69
|
nabu/estimation/distortion.py,sha256=DEXizQpgHBXmrhbQ0kuEchicxmiDgmU2qrh8bCgSezg,4701
|
70
70
|
nabu/estimation/focus.py,sha256=I2B5ODmGToE0-Y-B_6v1zJv7XcWdkXPZzrs2uYpiPlc,18029
|
@@ -131,14 +131,14 @@ nabu/pipeline/config_validators.py,sha256=ocAKB26iRjm5qs1Ay4B_rgGcg8aZjAP34XpEZR
|
|
131
131
|
nabu/pipeline/datadump.py,sha256=lK36YlsVSeE4fdkD7cgVCl4RKn-Wa9KYgOw4DNtH8Ow,6982
|
132
132
|
nabu/pipeline/dataset_validator.py,sha256=etQw9NC_YGsdWCgjsn8aJ3WfvcRuJlLVZlWoqhvvo-8,9263
|
133
133
|
nabu/pipeline/detector_distortion_provider.py,sha256=ru1AxbcuO-FA8FYooPBWgp1lzdSDUtzFUC1A_sS8jME,920
|
134
|
-
nabu/pipeline/estimators.py,sha256=
|
134
|
+
nabu/pipeline/estimators.py,sha256=AZXDmz7hngbVEfytpcu3E2QkOG4IqtXjQN8uUMBJTa0,40298
|
135
135
|
nabu/pipeline/params.py,sha256=EoovjCUTUXmj5HQ3qE0RhP7XD3cndaiT21TdvjTIhE8,3746
|
136
136
|
nabu/pipeline/processconfig.py,sha256=3xx2Lc8uEzPAqSMwUncr4RCiCtKn2c7wnXXbPSn8GNo,7719
|
137
137
|
nabu/pipeline/reader.py,sha256=wkxPHYOi_C8dHNc7kddB8AMtFuW7GjsP_tm6SJeHlEY,4792
|
138
138
|
nabu/pipeline/utils.py,sha256=0O1GLyYLQ8oA2ErI_T3BIfEVjP48dl-u_gl91eX7pjU,3543
|
139
|
-
nabu/pipeline/writer.py,sha256=
|
139
|
+
nabu/pipeline/writer.py,sha256=MG_R1oU8Ff9NdKRHiBkLMz0CmvEXY47zBUE-DpjXElQ,8172
|
140
140
|
nabu/pipeline/fullfield/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
141
|
-
nabu/pipeline/fullfield/chunked.py,sha256=
|
141
|
+
nabu/pipeline/fullfield/chunked.py,sha256=_LauzrZSMO0y6E1g_zYFweK8wb07u1p2JulrVDRnA04,40549
|
142
142
|
nabu/pipeline/fullfield/chunked_cuda.py,sha256=Jdkk6ZIt3S6UZYbupHtSj2vrj3krWMcqRHHprfblDfk,5848
|
143
143
|
nabu/pipeline/fullfield/computations.py,sha256=AEp3qvwyY-l8-GzjH1E6kmcmU6OgDp6sB-mltq0Jnxg,9970
|
144
144
|
nabu/pipeline/fullfield/dataset_validator.py,sha256=Iy6oOnXnBldDcg0ifm_zzrzMQ6YdkR_hkHFySZgxbno,2943
|
@@ -221,6 +221,7 @@ nabu/processing/tests/test_rotation.py,sha256=vedRXV9RePJywBKoyBkGANP1dhZCjphbYO
|
|
221
221
|
nabu/processing/tests/test_transpose.py,sha256=hTG17wTaB5Wv6twbW3ZFhBv6BYfqJY7DTQPoO0-KdkM,2760
|
222
222
|
nabu/processing/tests/test_unsharp.py,sha256=R3ovbwDDp3ccy2A8t6CcUVELXRWkED5EnQdN2FQOfQM,4391
|
223
223
|
nabu/reconstruction/__init__.py,sha256=EmKVvx_-FJvzJngG4ielIC7FhMCpI1Waaflg_lF44tk,163
|
224
|
+
nabu/reconstruction/astra.py,sha256=qTAkUe6UGN5CRqS9ie-nDsvZTYrXBIjUl0JzPKQjkMg,10431
|
224
225
|
nabu/reconstruction/cone.py,sha256=WObFcHvv7NkaZhUoC_xTlvl95f38AjsAJkePSOzngVk,18870
|
225
226
|
nabu/reconstruction/fbp.py,sha256=uwEniGdEOn1atc9mTAHEDeF1y-ZqneifCKVr-ieHZss,5015
|
226
227
|
nabu/reconstruction/fbp_base.py,sha256=DwZCilPXgGMRPV8_XfkWiaXUzWFM8rNBa8IyMdy5nno,17092
|
@@ -250,7 +251,7 @@ nabu/reconstruction/tests/test_reconstructor.py,sha256=3p2Wk_OqgZqkNOkhK_NJWlHkO
|
|
250
251
|
nabu/reconstruction/tests/test_sino_normalization.py,sha256=fGv5Dlidxgm8ZC70Nk6oqVgpY2jzOW9NJaGlo44IJOo,3692
|
251
252
|
nabu/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
252
253
|
nabu/resources/cor.py,sha256=-mcrTbj3G7o4PP5E_gIRo2j6_-ADmMkkOc_0CyQv84c,170
|
253
|
-
nabu/resources/dataset_analyzer.py,sha256=
|
254
|
+
nabu/resources/dataset_analyzer.py,sha256=e3AqYR9ORW9Q03mGYCiC66nXld-X0LPnx9E8X3zFIGU,18568
|
254
255
|
nabu/resources/gpu.py,sha256=GgpMb5umRQAUsEDEAefb4wSA5qm4JSMhkWmCEpW3X9g,5702
|
255
256
|
nabu/resources/logger.py,sha256=-lOzhN_sU4R3BIfC69aMj2O8S_ocsvXsmwkhWlcxVEc,3758
|
256
257
|
nabu/resources/nxflatfield.py,sha256=XlhLYj1TmSQ4s36W48kn0lNTvqXlFCuZxKHfTveltow,9225
|
@@ -263,7 +264,6 @@ nabu/resources/templates/id16_holo.conf,sha256=sDd_rEJGZjOGVAsGub5sT2arfXDnc_sxy
|
|
263
264
|
nabu/resources/templates/id16a_fluo.conf,sha256=Nz1etzO2fSwksi7CThWJ5T1kZEdyBe8rMO7puNJ93Hc,542
|
264
265
|
nabu/resources/templates/id19_pag.conf,sha256=u4fFPEBprzOW9_5_ChkIgowQcYpLhjmA8Gwm5XgC4Jc,384
|
265
266
|
nabu/resources/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
266
|
-
nabu/resources/tests/test_extract.py,sha256=pDFvgwPNH4n-UjhJibRH2vTkjDWYF2wSImUtfNq1ITo,220
|
267
267
|
nabu/resources/tests/test_nxflatfield.py,sha256=XRGbYwqJv0NYAVQnAB224TwTZP_W2Bs3-yu0zQnDzEM,4179
|
268
268
|
nabu/resources/tests/test_units.py,sha256=F2jFTck-1UwYET1MwTtX6ntzYUosfwOJkugSencGgz8,2155
|
269
269
|
nabu/stitching/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -311,9 +311,9 @@ nabu/thirdparty/pore3d_deringer_munch.py,sha256=o4bisnFc-wMjuohWBT8wgWmfNehPQGtC
|
|
311
311
|
nabu/thirdparty/tomocupy_remove_stripe.py,sha256=Khe4zFf0kRzu65Yxnvq58gt1ljOztqJGdMDhVAiM7lM,24363
|
312
312
|
nabu/thirdparty/tomopy_phase.py,sha256=hK4oPpkogLOhv23XzzEXQY2u3r8fJvASY_bINVs6ERE,8634
|
313
313
|
nabu/thirdparty/tomwer_load_flats_darks.py,sha256=ZNoVAinUb_wGYbfvs_4BVnWsjsQmNxSvCh1bWhR2WWg,5611
|
314
|
-
nabu-2024.2.
|
315
|
-
nabu-2024.2.
|
316
|
-
nabu-2024.2.
|
317
|
-
nabu-2024.2.
|
318
|
-
nabu-2024.2.
|
319
|
-
nabu-2024.2.
|
314
|
+
nabu-2024.2.0rc4.dist-info/LICENSE,sha256=1eAIPSnEsnSFNUODnLtNtQTs76exG3ZxJ1DJR6zoUBA,1066
|
315
|
+
nabu-2024.2.0rc4.dist-info/METADATA,sha256=X82wyEoBnquYyUlKh6UBebcpBLAS9ieXX7EETWAe068,5541
|
316
|
+
nabu-2024.2.0rc4.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
317
|
+
nabu-2024.2.0rc4.dist-info/entry_points.txt,sha256=cJKGkBeykVL7uK3E4R0RLRqMXifTL2qdO573syPAvJc,1288
|
318
|
+
nabu-2024.2.0rc4.dist-info/top_level.txt,sha256=fsm_N3eXLRZk2QXF9OSKPNDPFXOz8FAQjHh5avT3dok,9
|
319
|
+
nabu-2024.2.0rc4.dist-info/RECORD,,
|
nabu/app/tests/__init__.py
DELETED
File without changes
|
File without changes
|
File without changes
|
File without changes
|