tomwer 1.3.0.dev2__py3-none-any.whl → 1.3.0rc10__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.
- orangecontrib/tomwer/widgets/__init__.py +11 -12
- orangecontrib/tomwer/widgets/control/DataListenerOW.py +6 -6
- orangecontrib/tomwer/widgets/control/DataValidatorOW.py +6 -6
- orangecontrib/tomwer/widgets/control/NXTomomillMixIn.py +3 -3
- orangecontrib/tomwer/widgets/control/NXTomomillOW.py +10 -8
- orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +6 -6
- orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +1 -1
- orangecontrib/tomwer/widgets/icat/RawDataScreenshotCreatorOW.py +98 -98
- orangecontrib/tomwer/widgets/icat/SaveToGalleryAndPublishOW.py +129 -129
- orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +13 -12
- orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +11 -9
- orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +11 -9
- orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +12 -15
- orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +9 -9
- orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -1
- orangecontrib/tomwer/widgets/visualization/SinogramViewerOW.py +0 -1
- tomwer/__main__.py +0 -10
- tomwer/app/canvas_launcher/config.py +3 -3
- tomwer/app/canvas_launcher/environ.py +1 -0
- tomwer/app/intensitynormalization.py +12 -11
- tomwer/app/nabuapp.py +0 -11
- tomwer/app/zstitching.py +11 -1
- tomwer/core/process/control/datalistener/datalistener.py +15 -10
- tomwer/core/process/control/nxtomomill.py +1 -1
- tomwer/core/process/control/scantransfer.py +8 -32
- tomwer/core/process/edit/darkflatpatch.py +8 -9
- tomwer/core/process/edit/imagekeyeditor.py +20 -22
- tomwer/core/process/icat/screenshots.py +1 -0
- tomwer/core/process/reconstruction/axis/axis.py +263 -59
- tomwer/core/process/reconstruction/axis/mode.py +161 -50
- tomwer/core/process/reconstruction/axis/params.py +23 -20
- tomwer/core/process/reconstruction/darkref/darkrefs.py +12 -13
- tomwer/core/process/reconstruction/nabu/castvolume.py +3 -3
- tomwer/core/process/reconstruction/nabu/nabucommon.py +43 -19
- tomwer/core/process/reconstruction/nabu/nabuscores.py +34 -7
- tomwer/core/process/reconstruction/nabu/nabuslices.py +81 -26
- tomwer/core/process/reconstruction/nabu/nabuvolume.py +31 -26
- tomwer/core/process/reconstruction/nabu/plane.py +9 -0
- tomwer/core/process/reconstruction/nabu/utils.py +32 -9
- tomwer/core/process/reconstruction/saaxis/saaxis.py +4 -1
- tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +9 -1
- tomwer/core/process/reconstruction/scores/params.py +3 -3
- tomwer/core/process/reconstruction/test/test_darkref_copy.py +4 -4
- tomwer/core/process/stitching/nabustitcher.py +11 -10
- tomwer/core/process/task.py +33 -27
- tomwer/core/process/test/test_axis.py +7 -6
- tomwer/core/process/test/test_data_transfer.py +3 -3
- tomwer/core/process/test/test_nabu.py +10 -2
- tomwer/core/process/test/test_normalization.py +2 -2
- tomwer/core/scan/blissscan.py +3 -3
- tomwer/core/scan/edfscan.py +9 -9
- tomwer/core/scan/nxtomoscan.py +11 -11
- tomwer/core/scan/scanbase.py +31 -24
- tomwer/core/scan/test/test_future_scan.py +1 -1
- tomwer/core/scan/test/test_h5.py +4 -4
- tomwer/core/scan/test/test_process_registration.py +2 -2
- tomwer/core/scan/test/test_scan.py +1 -75
- tomwer/core/settings.py +3 -3
- tomwer/core/test/test_utils.py +2 -2
- tomwer/core/volume/edfvolume.py +6 -6
- tomwer/core/volume/hdf5volume.py +6 -6
- tomwer/core/volume/jp2kvolume.py +6 -6
- tomwer/core/volume/rawvolume.py +6 -6
- tomwer/core/volume/tiffvolume.py +12 -12
- tomwer/gui/cluster/slurm.py +14 -9
- tomwer/gui/cluster/supervisor.py +12 -0
- tomwer/gui/cluster/test/test_cluster.py +1 -2
- tomwer/gui/cluster/test/test_supervisor.py +1 -1
- tomwer/gui/control/datalist.py +5 -0
- tomwer/gui/control/datawatcher/controlwidget.py +2 -4
- tomwer/gui/control/reducedarkflatselector.py +8 -8
- tomwer/gui/control/test/test_single_tomo_obj.py +1 -1
- tomwer/gui/edit/dkrfpatch.py +4 -4
- tomwer/gui/edit/nxtomowarmer.py +2 -2
- tomwer/gui/edit/test/test_dkrf_patch.py +6 -6
- tomwer/gui/imagefromfile.py +2 -2
- tomwer/gui/qfolderdialog.py +5 -0
- tomwer/gui/reconstruction/axis/CompareImages.py +94 -168
- tomwer/gui/reconstruction/axis/radioaxis.py +58 -182
- tomwer/gui/reconstruction/darkref/darkrefwidget.py +2 -1
- tomwer/gui/reconstruction/nabu/castvolume.py +8 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +54 -21
- tomwer/gui/reconstruction/normalization/intensity.py +3 -25
- tomwer/gui/reconstruction/saaxis/corrangeselector.py +1 -1
- tomwer/gui/reconstruction/saaxis/saaxis.py +1 -11
- tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +0 -10
- tomwer/gui/reconstruction/scores/scoreplot.py +1 -6
- tomwer/gui/reconstruction/test/test_axis.py +18 -4
- tomwer/gui/reconstruction/test/test_nabu.py +3 -0
- tomwer/gui/stitching/stitching.py +2 -2
- tomwer/gui/stitching/stitching_preview.py +7 -53
- tomwer/gui/stitching/stitching_raw.py +3 -3
- tomwer/gui/utils/inputwidget.py +12 -2
- tomwer/gui/utils/lineselector/lineselector.py +1 -1
- tomwer/gui/visualization/dataviewer.py +47 -17
- tomwer/gui/visualization/sinogramviewer.py +19 -26
- tomwer/gui/visualization/test/test_volumeviewer.py +64 -66
- tomwer/gui/visualization/volumeviewer.py +105 -105
- tomwer/io/utils/h5pyutils.py +7 -3
- tomwer/io/utils/utils.py +3 -3
- tomwer/resources/gui/icons/parameters.svg +1 -1
- tomwer/resources/gui/illustrations/no_rot.svg +1 -1
- tomwer/synctools/stacks/edit/darkflatpatch.py +17 -12
- tomwer/tests/test_scripts.py +0 -3
- tomwer/third_part/WaitingOverlay.py +110 -0
- tomwer/third_part/__init__.py +0 -0
- tomwer/version.py +2 -2
- {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/METADATA +32 -31
- {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/RECORD +115 -153
- {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/WHEEL +1 -1
- orangecontrib/tomwer/widgets/reconstruction/TofuOW.py +0 -197
- orangecontrib/tomwer/widgets/reconstruction/icons/XY_lamino.svg +0 -168
- orangecontrib/tomwer/widgets/reconstruction/icons/XZ_lamino.svg +0 -275
- orangecontrib/tomwer/widgets/reconstruction/icons/YZ_lamino.svg +0 -182
- tomwer/app/lamino.py +0 -143
- tomwer/core/process/reconstruction/lamino/__init__.py +0 -1
- tomwer/core/process/reconstruction/lamino/tofu.py +0 -1000
- tomwer/core/process/test/test_lamino.py +0 -76
- tomwer/core/test/test_lamino.py +0 -92
- tomwer/gui/reconstruction/lamino/__init__.py +0 -31
- tomwer/gui/reconstruction/lamino/tofu/TofuOptionLoader.py +0 -107
- tomwer/gui/reconstruction/lamino/tofu/__init__.py +0 -1
- tomwer/gui/reconstruction/lamino/tofu/misc.py +0 -148
- tomwer/gui/reconstruction/lamino/tofu/projections.py +0 -896
- tomwer/gui/reconstruction/lamino/tofu/settings.py +0 -75
- tomwer/gui/reconstruction/lamino/tofu/tofu.py +0 -432
- tomwer/gui/reconstruction/lamino/tofu/tofuexpert.py +0 -567
- tomwer/gui/reconstruction/lamino/tofu/tofuoutput.py +0 -757
- tomwer/gui/reconstruction/test/test_lamino.py +0 -194
- tomwer/resources/gui/icons/lamino_parameters.svg +0 -70
- tomwer/resources/gui/illustrations/lamino_angle.png +0 -0
- tomwer/resources/gui/illustrations/lamino_angle.svg +0 -509
- tomwer/resources/gui/illustrations/lamino_beta_angle.png +0 -0
- tomwer/resources/gui/illustrations/lamino_beta_angle.svg +0 -97
- tomwer/resources/gui/illustrations/lamino_theta_angle.png +0 -0
- tomwer/resources/gui/illustrations/lamino_theta_angle.svg +0 -368
- tomwer/resources/gui/illustrations/manual_slice.png +0 -0
- tomwer/resources/gui/illustrations/manual_slice.svg +0 -221
- tomwer/resources/gui/illustrations/psi_angle.png +0 -0
- tomwer/resources/gui/illustrations/psi_angle.svg +0 -479
- tomwer/resources/gui/illustrations/rotation_center.png +0 -0
- tomwer/resources/gui/illustrations/rotation_center.svg +0 -276
- tomwer/resources/gui/illustrations/slice_stack.png +0 -0
- tomwer/resources/gui/illustrations/slice_stack.svg +0 -266
- tomwer/resources/gui/illustrations/xy_slice.png +0 -0
- tomwer/resources/gui/illustrations/xy_slice.svg +0 -269
- tomwer/resources/gui/illustrations/xz_slice.png +0 -0
- tomwer/resources/gui/illustrations/xz_slice.svg +0 -270
- tomwer/resources/gui/illustrations/yz_slice.png +0 -0
- tomwer/resources/gui/illustrations/yz_slice.svg +0 -270
- tomwer/synctools/stacks/reconstruction/lamino.py +0 -233
- /tomwer-1.3.0.dev2-py3.11-nspkg.pth → /tomwer-1.3.0rc10-py3.11-nspkg.pth +0 -0
- {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/LICENSE +0 -0
- {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/entry_points.txt +0 -0
- {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/namespace_packages.txt +0 -0
- {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/top_level.txt +0 -0
@@ -38,8 +38,9 @@ from nabu.estimation.cor import (
|
|
38
38
|
CenterOfRotationAdaptiveSearch,
|
39
39
|
CenterOfRotationGrowingWindow,
|
40
40
|
CenterOfRotationSlidingWindow,
|
41
|
+
CenterOfRotationOctaveAccurate,
|
41
42
|
)
|
42
|
-
from nabu.pipeline.estimators import SinoCORFinder
|
43
|
+
from nabu.pipeline.estimators import SinoCORFinder, CORFinder
|
43
44
|
from nabu.resources.nxflatfield import update_dataset_info_flats_darks
|
44
45
|
from processview.core.manager import DatasetState, ProcessManager
|
45
46
|
from processview.core.superviseprocess import SuperviseProcess
|
@@ -75,7 +76,7 @@ else:
|
|
75
76
|
has_composite_cor_finder = True
|
76
77
|
from silx.io.url import DataUrl
|
77
78
|
from silx.io.utils import h5py_read_dataset
|
78
|
-
from tomoscan.io import HDF5File
|
79
|
+
from tomoscan.io import HDF5File, get_swmr_mode
|
79
80
|
|
80
81
|
_logger = logging.getLogger(__name__)
|
81
82
|
if not has_composite_cor_finder:
|
@@ -173,6 +174,50 @@ def compute_cor_nabu_growing_window(
|
|
173
174
|
return res
|
174
175
|
|
175
176
|
|
177
|
+
def compute_cor_nabu_growing_window_radios(
|
178
|
+
scan: TomwerScanBase,
|
179
|
+
):
|
180
|
+
"""
|
181
|
+
Call nabu.preproc.alignement.CenterOfRotationGrowingWindow.find_shift
|
182
|
+
|
183
|
+
:param TomwerScanBase scan:
|
184
|
+
|
185
|
+
:return:
|
186
|
+
"""
|
187
|
+
has_darks = scan.reduced_darks is not None and len(scan.reduced_darks) > 0
|
188
|
+
has_flats = scan.reduced_flats is not None and len(scan.reduced_flats) > 0
|
189
|
+
|
190
|
+
projection_angles = scan.get_proj_angle_url()
|
191
|
+
projection_angles_i = {
|
192
|
+
value.path(): key for key, value in projection_angles.items()
|
193
|
+
}
|
194
|
+
url_radio_1, url_radio_2 = AxisTask.get_inputs_urls(scan=scan)
|
195
|
+
angle_radio_1 = float(projection_angles_i[url_radio_1.url.path()])
|
196
|
+
angle_radio_2 = float(projection_angles_i[url_radio_2.url.path()])
|
197
|
+
radio_angles = tuple(numpy.radians((angle_radio_1, angle_radio_2)))
|
198
|
+
|
199
|
+
corfinder = CORFinder(
|
200
|
+
dataset_info=adapt_tomwer_scan_to_nabu(scan),
|
201
|
+
method="growing-window",
|
202
|
+
do_flatfield=has_darks and has_flats,
|
203
|
+
cor_options=scan.axis_params.get_nabu_cor_options_as_dict(),
|
204
|
+
radio_angles=radio_angles,
|
205
|
+
logger=_logger,
|
206
|
+
)
|
207
|
+
res = corfinder.find_cor() # Returns absolute cor
|
208
|
+
if isinstance(res, numpy.ndarray):
|
209
|
+
if len(res) == 1:
|
210
|
+
res = res[0]
|
211
|
+
else:
|
212
|
+
raise ValueError(
|
213
|
+
"nabu rsult is expected to be a scalar, numpy array found. Please upgrade nabu this issue is expected to be solved"
|
214
|
+
)
|
215
|
+
|
216
|
+
return _absolute_pos_to_relative_with_warning(
|
217
|
+
absolute_pos=res, det_width=scan.dim_1
|
218
|
+
)
|
219
|
+
|
220
|
+
|
176
221
|
def compute_cor_nabu_growing_window_sinogram(
|
177
222
|
scan: TomwerScanBase,
|
178
223
|
):
|
@@ -188,7 +233,7 @@ def compute_cor_nabu_growing_window_sinogram(
|
|
188
233
|
|
189
234
|
corfinder = SinoCORFinder(
|
190
235
|
dataset_info=adapt_tomwer_scan_to_nabu(scan),
|
191
|
-
method="growing-window",
|
236
|
+
method="sino-growing-window",
|
192
237
|
slice_idx=scan.axis_params.sinogram_line or "middle",
|
193
238
|
subsampling=scan.axis_params.sinogram_subsampling,
|
194
239
|
do_flatfield=has_darks and has_flats,
|
@@ -321,13 +366,7 @@ def compute_scan_cor_nabu_growing_window(scan):
|
|
321
366
|
if scan.axis_params.use_sinogram:
|
322
367
|
return compute_cor_nabu_growing_window_sinogram(scan=scan)
|
323
368
|
else:
|
324
|
-
return
|
325
|
-
radio_1=radio_1.copy(),
|
326
|
-
radio_2=radio_2.copy(),
|
327
|
-
side=scan.axis_params.side,
|
328
|
-
padding_mode=scan.axis_params.padding_mode,
|
329
|
-
flip_frame_2_lr=scan.axis_params.flip_lr,
|
330
|
-
)
|
369
|
+
return compute_cor_nabu_growing_window_radios(scan=scan)
|
331
370
|
|
332
371
|
|
333
372
|
def compute_cor_nabu_sliding_window(
|
@@ -363,17 +402,45 @@ def compute_cor_nabu_sliding_window(
|
|
363
402
|
padding_mode=padding_mode,
|
364
403
|
median_filt_shape=None,
|
365
404
|
)
|
366
|
-
# now fixed but on some version nabu could return a numpy array instead of float
|
367
|
-
if isinstance(res, numpy.ndarray):
|
368
|
-
if len(res) == 1:
|
369
|
-
res = res[0]
|
370
|
-
else:
|
371
|
-
raise ValueError(
|
372
|
-
"nabu result is expected to be a scalar, numpy array found. Please upgrade nabu this issue is expected to be solved"
|
373
|
-
)
|
374
405
|
return res
|
375
406
|
|
376
407
|
|
408
|
+
def compute_cor_nabu_sliding_window_radios(
|
409
|
+
scan,
|
410
|
+
):
|
411
|
+
"""
|
412
|
+
Call nabu.preproc.alignement.CenterOfRotationGrowingWindow.find_shift
|
413
|
+
|
414
|
+
:param TomwerScanBase scan:
|
415
|
+
|
416
|
+
:return:
|
417
|
+
"""
|
418
|
+
has_darks = scan.reduced_darks is not None and len(scan.reduced_darks) > 0
|
419
|
+
has_flats = scan.reduced_flats is not None and len(scan.reduced_flats) > 0
|
420
|
+
|
421
|
+
projection_angles = scan.get_proj_angle_url()
|
422
|
+
projection_angles_i = {
|
423
|
+
value.path(): key for key, value in projection_angles.items()
|
424
|
+
}
|
425
|
+
url_radio_1, url_radio_2 = AxisTask.get_inputs_urls(scan=scan)
|
426
|
+
angle_radio_1 = float(projection_angles_i[url_radio_1.url.path()])
|
427
|
+
angle_radio_2 = float(projection_angles_i[url_radio_2.url.path()])
|
428
|
+
radio_angles = tuple(numpy.radians((angle_radio_1, angle_radio_2)))
|
429
|
+
|
430
|
+
corfinder = CORFinder(
|
431
|
+
dataset_info=adapt_tomwer_scan_to_nabu(scan),
|
432
|
+
method="sliding-window",
|
433
|
+
do_flatfield=has_darks and has_flats,
|
434
|
+
cor_options=scan.axis_params.get_nabu_cor_options_as_dict(),
|
435
|
+
radio_angles=radio_angles,
|
436
|
+
logger=_logger,
|
437
|
+
)
|
438
|
+
res = corfinder.find_cor() # Returns absolute cor.
|
439
|
+
return _absolute_pos_to_relative_with_warning(
|
440
|
+
absolute_pos=res, det_width=scan.dim_1
|
441
|
+
)
|
442
|
+
|
443
|
+
|
377
444
|
def compute_cor_nabu_sliding_window_sinogram(
|
378
445
|
scan,
|
379
446
|
):
|
@@ -389,7 +456,7 @@ def compute_cor_nabu_sliding_window_sinogram(
|
|
389
456
|
|
390
457
|
corfinder = SinoCORFinder(
|
391
458
|
dataset_info=adapt_tomwer_scan_to_nabu(scan),
|
392
|
-
method="sliding-window",
|
459
|
+
method="sino-sliding-window",
|
393
460
|
slice_idx=scan.axis_params.sinogram_line or "middle",
|
394
461
|
subsampling=scan.axis_params.sinogram_subsampling,
|
395
462
|
do_flatfield=has_darks and has_flats,
|
@@ -397,14 +464,6 @@ def compute_cor_nabu_sliding_window_sinogram(
|
|
397
464
|
logger=_logger,
|
398
465
|
)
|
399
466
|
res = corfinder.find_cor()
|
400
|
-
# now fixed but on some version nabu could return a numpy array instead of float
|
401
|
-
if isinstance(res, numpy.ndarray):
|
402
|
-
if len(res) == 1:
|
403
|
-
res = res[0]
|
404
|
-
else:
|
405
|
-
raise ValueError(
|
406
|
-
"nabu result is expected to be a scalar, numpy array found. Please upgrade nabu this issue is expected to be solved"
|
407
|
-
)
|
408
467
|
return _absolute_pos_to_relative_with_warning(
|
409
468
|
absolute_pos=res, det_width=scan.dim_1
|
410
469
|
)
|
@@ -437,13 +496,129 @@ def compute_scan_cor_nabu_sliding_window(scan):
|
|
437
496
|
if scan.axis_params.use_sinogram:
|
438
497
|
return compute_cor_nabu_sliding_window_sinogram(scan=scan)
|
439
498
|
else:
|
440
|
-
return
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
499
|
+
return compute_cor_nabu_sliding_window_radios(scan=scan)
|
500
|
+
|
501
|
+
|
502
|
+
def compute_scan_fourier_angles(scan):
|
503
|
+
"""
|
504
|
+
run 'scan_fourier_angles' algorithm for the requested scan
|
505
|
+
"""
|
506
|
+
has_darks = scan.reduced_darks is not None and len(scan.reduced_darks) > 0
|
507
|
+
has_flats = scan.reduced_flats is not None and len(scan.reduced_flats) > 0
|
508
|
+
|
509
|
+
corfinder = SinoCORFinder(
|
510
|
+
dataset_info=adapt_tomwer_scan_to_nabu(scan),
|
511
|
+
method="fourier-angles",
|
512
|
+
slice_idx=scan.axis_params.sinogram_line or "middle",
|
513
|
+
subsampling=scan.axis_params.sinogram_subsampling,
|
514
|
+
do_flatfield=has_darks and has_flats,
|
515
|
+
cor_options=scan.axis_params.get_nabu_cor_options_as_dict(),
|
516
|
+
logger=_logger,
|
517
|
+
)
|
518
|
+
res = corfinder.find_cor()
|
519
|
+
return _absolute_pos_to_relative_with_warning(
|
520
|
+
absolute_pos=res, det_width=scan.dim_1
|
521
|
+
)
|
522
|
+
|
523
|
+
|
524
|
+
def compute_scan_octave_accurate_radios(
|
525
|
+
scan,
|
526
|
+
):
|
527
|
+
"""
|
528
|
+
Call nabu.preproc.alignement.CenterOfRotationGrowingWindow.find_shift
|
529
|
+
|
530
|
+
:param TomwerScanBase scan:
|
531
|
+
|
532
|
+
:return:
|
533
|
+
"""
|
534
|
+
has_darks = scan.reduced_darks is not None and len(scan.reduced_darks) > 0
|
535
|
+
has_flats = scan.reduced_flats is not None and len(scan.reduced_flats) > 0
|
536
|
+
|
537
|
+
has_darks = scan.reduced_darks is not None and len(scan.reduced_darks) > 0
|
538
|
+
has_flats = scan.reduced_flats is not None and len(scan.reduced_flats) > 0
|
539
|
+
|
540
|
+
projection_angles = scan.get_proj_angle_url()
|
541
|
+
projection_angles_i = {
|
542
|
+
value.path(): key for key, value in projection_angles.items()
|
543
|
+
}
|
544
|
+
url_radio_1, url_radio_2 = AxisTask.get_inputs_urls(scan=scan)
|
545
|
+
angle_radio_1 = float(projection_angles_i[url_radio_1.url.path()])
|
546
|
+
angle_radio_2 = float(projection_angles_i[url_radio_2.url.path()])
|
547
|
+
radio_angles = tuple(numpy.radians((angle_radio_1, angle_radio_2)))
|
548
|
+
|
549
|
+
corfinder = CORFinder(
|
550
|
+
dataset_info=adapt_tomwer_scan_to_nabu(scan),
|
551
|
+
method="octave-accurate",
|
552
|
+
do_flatfield=has_darks and has_flats,
|
553
|
+
cor_options=scan.axis_params.get_nabu_cor_options_as_dict(),
|
554
|
+
radio_angles=radio_angles,
|
555
|
+
logger=_logger,
|
556
|
+
)
|
557
|
+
res = corfinder.find_cor()
|
558
|
+
return _absolute_pos_to_relative_with_warning(
|
559
|
+
absolute_pos=res, det_width=scan.dim_1
|
560
|
+
)
|
561
|
+
|
562
|
+
|
563
|
+
def compute_scan_octave_accurate(scan):
|
564
|
+
"""
|
565
|
+
Compute center of rotation from `octave-accurate` algorithm
|
566
|
+
scan
|
567
|
+
:param scan:
|
568
|
+
:return:
|
569
|
+
"""
|
570
|
+
cor_options = scan.axis_params.get_nabu_cor_options_as_dict()
|
571
|
+
radio_1, radio_2 = AxisTask.get_inputs(scan=scan)
|
572
|
+
extra_options = {}
|
573
|
+
for key in "low_pass", "high_pass":
|
574
|
+
if key in cor_options:
|
575
|
+
extra_options[key] = float(cor_options[key])
|
576
|
+
|
577
|
+
corfinder = CenterOfRotationOctaveAccurate(cor_options=cor_options)
|
578
|
+
res = corfinder.find_shift(
|
579
|
+
img_1=radio_1,
|
580
|
+
img_2=numpy.fliplr(radio_2) if scan.axis_params.flip_lr else radio_2,
|
581
|
+
side=scan.axis_params.side,
|
582
|
+
padding_mode=scan.axis_params.padding_mode,
|
583
|
+
**extra_options,
|
584
|
+
)
|
585
|
+
return res
|
586
|
+
|
587
|
+
|
588
|
+
def compute_cor_nabu_centered_radios(
|
589
|
+
scan,
|
590
|
+
):
|
591
|
+
"""
|
592
|
+
Call nabu.preproc.alignement.CenterOfRotationGrowingWindow.find_shift
|
593
|
+
|
594
|
+
:param TomwerScanBase scan:
|
595
|
+
|
596
|
+
:return:
|
597
|
+
"""
|
598
|
+
has_darks = scan.reduced_darks is not None and len(scan.reduced_darks) > 0
|
599
|
+
has_flats = scan.reduced_flats is not None and len(scan.reduced_flats) > 0
|
600
|
+
|
601
|
+
projection_angles = scan.get_proj_angle_url()
|
602
|
+
projection_angles_i = {
|
603
|
+
value.path(): key for key, value in projection_angles.items()
|
604
|
+
}
|
605
|
+
url_radio_1, url_radio_2 = AxisTask.get_inputs_urls(scan=scan)
|
606
|
+
angle_radio_1 = float(projection_angles_i[url_radio_1.url.path()])
|
607
|
+
angle_radio_2 = float(projection_angles_i[url_radio_2.url.path()])
|
608
|
+
radio_angles = tuple(numpy.radians((angle_radio_1, angle_radio_2)))
|
609
|
+
|
610
|
+
corfinder = CORFinder(
|
611
|
+
dataset_info=adapt_tomwer_scan_to_nabu(scan),
|
612
|
+
method="centered",
|
613
|
+
do_flatfield=has_darks and has_flats,
|
614
|
+
cor_options=scan.axis_params.get_nabu_cor_options_as_dict(),
|
615
|
+
radio_angles=radio_angles,
|
616
|
+
logger=_logger,
|
617
|
+
)
|
618
|
+
res = corfinder.find_cor()
|
619
|
+
return _absolute_pos_to_relative_with_warning(
|
620
|
+
absolute_pos=res, det_width=scan.dim_1
|
621
|
+
)
|
447
622
|
|
448
623
|
|
449
624
|
def compute_cor_nabu_centered(
|
@@ -452,6 +627,7 @@ def compute_cor_nabu_centered(
|
|
452
627
|
padding_mode,
|
453
628
|
flip_frame_2_lr=True,
|
454
629
|
horz_fft_width=False,
|
630
|
+
vert_fft_width=False,
|
455
631
|
):
|
456
632
|
"""
|
457
633
|
Call nabu.preproc.alignement.CenterOfRotation.find_shift
|
@@ -468,7 +644,9 @@ def compute_cor_nabu_centered(
|
|
468
644
|
|
469
645
|
:return:
|
470
646
|
"""
|
471
|
-
nabu_class = CenterOfRotation(
|
647
|
+
nabu_class = CenterOfRotation(
|
648
|
+
horz_fft_width=horz_fft_width, vert_fft_width=vert_fft_width
|
649
|
+
)
|
472
650
|
return nabu_class.find_shift(
|
473
651
|
img_1=radio_1,
|
474
652
|
img_2=numpy.fliplr(radio_2) if flip_frame_2_lr else radio_2,
|
@@ -497,12 +675,7 @@ def compute_scan_cor_nabu_centered(scan):
|
|
497
675
|
"mode %s" % scan.axis_params.padding_mode
|
498
676
|
)
|
499
677
|
|
500
|
-
return
|
501
|
-
radio_1=radio_1.copy(),
|
502
|
-
radio_2=radio_2.copy(),
|
503
|
-
padding_mode=scan.axis_params.padding_mode,
|
504
|
-
flip_frame_2_lr=scan.axis_params.flip_lr,
|
505
|
-
)
|
678
|
+
return compute_cor_nabu_centered_radios(scan)
|
506
679
|
|
507
680
|
|
508
681
|
def compute_cor_nabu_global(
|
@@ -532,6 +705,42 @@ def compute_cor_nabu_global(
|
|
532
705
|
)
|
533
706
|
|
534
707
|
|
708
|
+
def compute_cor_nabu_global_radios(
|
709
|
+
scan: TomwerScanBase,
|
710
|
+
):
|
711
|
+
"""
|
712
|
+
Call nabu.preproc.alignement.CenterOfRotationGrowingWindow.find_shift
|
713
|
+
|
714
|
+
:param TomwerScanBase scan:
|
715
|
+
|
716
|
+
:return:
|
717
|
+
"""
|
718
|
+
has_darks = scan.reduced_darks is not None and len(scan.reduced_darks) > 0
|
719
|
+
has_flats = scan.reduced_flats is not None and len(scan.reduced_flats) > 0
|
720
|
+
|
721
|
+
projection_angles = scan.get_proj_angle_url()
|
722
|
+
projection_angles_i = {
|
723
|
+
value.path(): key for key, value in projection_angles.items()
|
724
|
+
}
|
725
|
+
url_radio_1, url_radio_2 = AxisTask.get_inputs_urls(scan=scan)
|
726
|
+
angle_radio_1 = float(projection_angles_i[url_radio_1.url.path()])
|
727
|
+
angle_radio_2 = float(projection_angles_i[url_radio_2.url.path()])
|
728
|
+
radio_angles = tuple(numpy.radians((angle_radio_1, angle_radio_2)))
|
729
|
+
|
730
|
+
corfinder = CORFinder(
|
731
|
+
dataset_info=adapt_tomwer_scan_to_nabu(scan),
|
732
|
+
method="global",
|
733
|
+
do_flatfield=has_darks and has_flats,
|
734
|
+
cor_options=scan.axis_params.get_nabu_cor_options_as_dict(),
|
735
|
+
radio_angles=radio_angles,
|
736
|
+
logger=_logger,
|
737
|
+
)
|
738
|
+
res = corfinder.find_cor()
|
739
|
+
return _absolute_pos_to_relative_with_warning(
|
740
|
+
absolute_pos=res, det_width=scan.dim_1
|
741
|
+
)
|
742
|
+
|
743
|
+
|
535
744
|
def compute_scan_cor_nabu_global(scan):
|
536
745
|
"""
|
537
746
|
Call to nabu.preproc.alignment.CenterOfRotation from the scan axis_params
|
@@ -550,13 +759,7 @@ def compute_scan_cor_nabu_global(scan):
|
|
550
759
|
"compute scan axis from nabu CenterOfRotation with padding "
|
551
760
|
"mode %s" % scan.axis_params.padding_mode
|
552
761
|
)
|
553
|
-
|
554
|
-
return compute_cor_nabu_global(
|
555
|
-
radio_1=radio_1.copy(),
|
556
|
-
radio_2=radio_2.copy(),
|
557
|
-
padding_mode=scan.axis_params.padding_mode,
|
558
|
-
flip_frame_2_lr=scan.axis_params.flip_lr,
|
559
|
-
)
|
762
|
+
return compute_cor_nabu_global_radios(scan)
|
560
763
|
|
561
764
|
|
562
765
|
def get_stdmax_column(x: numpy.ndarray) -> float:
|
@@ -604,6 +807,8 @@ class AxisTask(
|
|
604
807
|
AxisMode.sino_coarse_to_fine: compute_scan_sino_coarse_to_fine,
|
605
808
|
AxisMode.composite_coarse_to_fine: compute_scan_composite_coarse_to_fine,
|
606
809
|
AxisMode.near: compute_scan_composite_coarse_to_fine,
|
810
|
+
AxisMode.sino_fourier_angles: compute_scan_fourier_angles,
|
811
|
+
AxisMode.octave_accurate_radios: compute_scan_octave_accurate,
|
607
812
|
}
|
608
813
|
|
609
814
|
def __init__(
|
@@ -731,15 +936,14 @@ class AxisTask(
|
|
731
936
|
entry = "entry"
|
732
937
|
if isinstance(scan, NXtomoScan):
|
733
938
|
entry = scan.entry
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
)
|
939
|
+
self.register_process(
|
940
|
+
process_file=scan.process_file,
|
941
|
+
entry=entry,
|
942
|
+
results={"center_of_rotation": cor if cor is not None else "-"},
|
943
|
+
configuration=self._axis_params.to_dict(),
|
944
|
+
process_index=scan.pop_process_index(),
|
945
|
+
overwrite=True,
|
946
|
+
)
|
743
947
|
|
744
948
|
try:
|
745
949
|
extra = {
|
@@ -960,7 +1164,7 @@ class AxisTask(
|
|
960
1164
|
:return:
|
961
1165
|
"""
|
962
1166
|
if entry is None:
|
963
|
-
with HDF5File(process_file, "r", swmr=
|
1167
|
+
with HDF5File(process_file, "r", swmr=get_swmr_mode()) as h5f:
|
964
1168
|
entries = AxisTask._get_process_nodes(root_node=h5f, process=AxisTask)
|
965
1169
|
if len(entries) == 0:
|
966
1170
|
_logger.info("unable to find a Axis process in %s" % process_file)
|
@@ -971,7 +1175,7 @@ class AxisTask(
|
|
971
1175
|
entry = list(entries.keys())[0]
|
972
1176
|
_logger.info("take %s as default entry" % entry)
|
973
1177
|
|
974
|
-
with HDF5File(process_file, "r", swmr=
|
1178
|
+
with HDF5File(process_file, "r", swmr=get_swmr_mode()) as h5f:
|
975
1179
|
axis_nodes = AxisTask._get_process_nodes(
|
976
1180
|
root_node=h5f[entry], process=AxisTask
|
977
1181
|
)
|
@@ -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__ = "15/10/2019"
|
29
|
-
|
30
|
-
|
31
1
|
import logging
|
32
2
|
|
33
3
|
from silx.utils.enum import Enum as _Enum
|
@@ -35,6 +5,55 @@ from silx.utils.enum import Enum as _Enum
|
|
35
5
|
_logger = logging.getLogger(__name__)
|
36
6
|
|
37
7
|
|
8
|
+
class AxisModeMetadata:
|
9
|
+
"""
|
10
|
+
Util class to store metadata regarding processing of a mode.
|
11
|
+
|
12
|
+
Ease processing and display
|
13
|
+
Maybe this function should be part of nabu ?
|
14
|
+
"""
|
15
|
+
|
16
|
+
def __init__(
|
17
|
+
self,
|
18
|
+
lockable,
|
19
|
+
tooltip="",
|
20
|
+
computing_constrains=(),
|
21
|
+
allows_padding=False,
|
22
|
+
valid_inputs=(),
|
23
|
+
valid_sides=(),
|
24
|
+
) -> None:
|
25
|
+
self._lockable = lockable
|
26
|
+
self._tooltip = tooltip
|
27
|
+
self._computing_constrains = computing_constrains
|
28
|
+
self._allows_padding = allows_padding
|
29
|
+
self._valid_inputs = valid_inputs
|
30
|
+
self._valid_sides = valid_sides
|
31
|
+
|
32
|
+
@property
|
33
|
+
def is_lockable(self) -> bool:
|
34
|
+
return self._lockable
|
35
|
+
|
36
|
+
@property
|
37
|
+
def tooltip(self) -> str:
|
38
|
+
return self._tooltip
|
39
|
+
|
40
|
+
@property
|
41
|
+
def computing_constrains(self) -> tuple:
|
42
|
+
return self._computing_constrains
|
43
|
+
|
44
|
+
@property
|
45
|
+
def allows_padding(self) -> bool:
|
46
|
+
return self._allows_padding
|
47
|
+
|
48
|
+
@property
|
49
|
+
def valid_inputs(self) -> tuple:
|
50
|
+
return self._valid_inputs
|
51
|
+
|
52
|
+
@property
|
53
|
+
def valid_sides(self) -> tuple:
|
54
|
+
return self._valid_sides
|
55
|
+
|
56
|
+
|
38
57
|
class _InputType(_Enum):
|
39
58
|
SINOGRAM = "sinogram"
|
40
59
|
RADIOS_X2 = "2 radios"
|
@@ -55,6 +74,8 @@ class AxisMode(_Enum):
|
|
55
74
|
sliding_window_radios = "radios-sliding-window"
|
56
75
|
sino_coarse_to_fine = "sino-coarse-to-fine"
|
57
76
|
composite_coarse_to_fine = "composite-coarse-to-fine"
|
77
|
+
sino_fourier_angles = "sino-fourier-angles"
|
78
|
+
octave_accurate_radios = "radios-octave-accurate"
|
58
79
|
read = "read"
|
59
80
|
# alias to composite_coarse_to_fine with near mode
|
60
81
|
near = "near"
|
@@ -76,24 +97,114 @@ class AxisMode(_Enum):
|
|
76
97
|
return super().from_value(value=value)
|
77
98
|
|
78
99
|
|
79
|
-
|
80
|
-
|
81
|
-
AxisMode.
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
AxisMode.
|
98
|
-
|
100
|
+
AXIS_MODE_METADATAS = {
|
101
|
+
# manual
|
102
|
+
AxisMode.manual: AxisModeMetadata(
|
103
|
+
lockable=False,
|
104
|
+
tooltip="Enter or find manually the COR value",
|
105
|
+
computing_constrains=(),
|
106
|
+
allows_padding=False,
|
107
|
+
valid_inputs=(_InputType.RADIOS_X2,),
|
108
|
+
),
|
109
|
+
# read
|
110
|
+
AxisMode.read: AxisModeMetadata(
|
111
|
+
lockable=False,
|
112
|
+
tooltip="Read COR value from a file",
|
113
|
+
computing_constrains=(),
|
114
|
+
allows_padding=False,
|
115
|
+
valid_inputs=None,
|
116
|
+
),
|
117
|
+
# radio algorithm
|
118
|
+
AxisMode.centered: AxisModeMetadata(
|
119
|
+
lockable=True,
|
120
|
+
tooltip="Dedicated to fullfield. Previously named 'accurate'",
|
121
|
+
computing_constrains=(),
|
122
|
+
allows_padding=True,
|
123
|
+
valid_inputs=(_InputType.RADIOS_X2,),
|
124
|
+
),
|
125
|
+
AxisMode.global_: AxisModeMetadata(
|
126
|
+
lockable=True,
|
127
|
+
tooltip="Algorithm which can work for both half acquisition and standard ('full field') acquisition",
|
128
|
+
computing_constrains=(),
|
129
|
+
allows_padding=True,
|
130
|
+
valid_inputs=(_InputType.RADIOS_X2,),
|
131
|
+
),
|
132
|
+
AxisMode.growing_window_radios: AxisModeMetadata(
|
133
|
+
lockable=True,
|
134
|
+
tooltip="A auto-Cor method",
|
135
|
+
computing_constrains=(),
|
136
|
+
allows_padding=True,
|
137
|
+
valid_inputs=(_InputType.RADIOS_X2,),
|
138
|
+
valid_sides=("left", "right", "center", "all"),
|
139
|
+
),
|
140
|
+
AxisMode.sliding_window_radios: AxisModeMetadata(
|
141
|
+
lockable=True,
|
142
|
+
tooltip="A method for estimating semi-automatically the CoR position. You have to provide a hint on where the CoR is (left, center, right).",
|
143
|
+
computing_constrains=(),
|
144
|
+
allows_padding=True,
|
145
|
+
valid_inputs=(_InputType.RADIOS_X2,),
|
146
|
+
valid_sides=("left", "right", "center", "near"),
|
147
|
+
),
|
148
|
+
AxisMode.octave_accurate_radios: AxisModeMetadata(
|
149
|
+
lockable=True,
|
150
|
+
tooltip="Same method as the 'accurate' octave code",
|
151
|
+
computing_constrains=(),
|
152
|
+
allows_padding=True,
|
153
|
+
valid_inputs=(_InputType.RADIOS_X2,),
|
154
|
+
valid_sides=("center",),
|
155
|
+
),
|
156
|
+
# sinogram algorithm
|
157
|
+
AxisMode.growing_window_sinogram: AxisModeMetadata(
|
158
|
+
lockable=True,
|
159
|
+
tooltip="A auto-Cor method",
|
160
|
+
computing_constrains=(),
|
161
|
+
allows_padding=True,
|
162
|
+
valid_inputs=(_InputType.SINOGRAM,),
|
163
|
+
valid_sides=("left", "right", "center", "all"),
|
164
|
+
),
|
165
|
+
AxisMode.sliding_window_sinogram: AxisModeMetadata(
|
166
|
+
lockable=True,
|
167
|
+
tooltip="A method for estimating semi-automatically the CoR position. You have to provide a hint on where the CoR is (left, center, right).",
|
168
|
+
computing_constrains=(),
|
169
|
+
allows_padding=True,
|
170
|
+
valid_inputs=(_InputType.SINOGRAM,),
|
171
|
+
valid_sides=("left", "right", "center", "near"),
|
172
|
+
),
|
173
|
+
AxisMode.sino_coarse_to_fine: AxisModeMetadata(
|
174
|
+
lockable=True,
|
175
|
+
tooltip="Estimate CoR from sinogram. Only works for 360 degrees scans.",
|
176
|
+
computing_constrains=(_Constrain.FULL_TURN,),
|
177
|
+
allows_padding=True,
|
178
|
+
valid_inputs=(_InputType.SINOGRAM,),
|
179
|
+
),
|
180
|
+
AxisMode.sino_fourier_angles: AxisModeMetadata(
|
181
|
+
lockable=True,
|
182
|
+
tooltip="",
|
183
|
+
computing_constrains=(_Constrain.FULL_TURN,),
|
184
|
+
allows_padding=True,
|
185
|
+
valid_inputs=(_InputType.SINOGRAM,),
|
186
|
+
valid_sides=(
|
187
|
+
"left",
|
188
|
+
"right",
|
189
|
+
"center",
|
190
|
+
"near",
|
191
|
+
),
|
192
|
+
),
|
193
|
+
# coarse-to-fine algorithm
|
194
|
+
AxisMode.composite_coarse_to_fine: AxisModeMetadata(
|
195
|
+
lockable=True,
|
196
|
+
tooltip="A auto-Cor method",
|
197
|
+
computing_constrains=(_Constrain.FULL_TURN,),
|
198
|
+
allows_padding=True,
|
199
|
+
valid_inputs=(_InputType.COMPOSITE,),
|
200
|
+
valid_sides=("left", "right", "center", "near"),
|
201
|
+
),
|
202
|
+
AxisMode.near: AxisModeMetadata(
|
203
|
+
lockable=True,
|
204
|
+
tooltip="Alias to composite_coarse_to_fine",
|
205
|
+
computing_constrains=(_Constrain.FULL_TURN,),
|
206
|
+
allows_padding=True,
|
207
|
+
valid_inputs=(_InputType.COMPOSITE,),
|
208
|
+
valid_sides=("left", "right", "center", "near"),
|
209
|
+
),
|
99
210
|
}
|