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.
Files changed (156) hide show
  1. orangecontrib/tomwer/widgets/__init__.py +11 -12
  2. orangecontrib/tomwer/widgets/control/DataListenerOW.py +6 -6
  3. orangecontrib/tomwer/widgets/control/DataValidatorOW.py +6 -6
  4. orangecontrib/tomwer/widgets/control/NXTomomillMixIn.py +3 -3
  5. orangecontrib/tomwer/widgets/control/NXTomomillOW.py +10 -8
  6. orangecontrib/tomwer/widgets/control/SingleTomoObjOW.py +6 -6
  7. orangecontrib/tomwer/widgets/debugtools/DatasetGeneratorOW.py +1 -1
  8. orangecontrib/tomwer/widgets/icat/RawDataScreenshotCreatorOW.py +98 -98
  9. orangecontrib/tomwer/widgets/icat/SaveToGalleryAndPublishOW.py +129 -129
  10. orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +13 -12
  11. orangecontrib/tomwer/widgets/reconstruction/SAAxisOW.py +11 -9
  12. orangecontrib/tomwer/widgets/reconstruction/SADeltaBetaOW.py +11 -9
  13. orangecontrib/tomwer/widgets/reconstruction/SinoNormOW.py +12 -15
  14. orangecontrib/tomwer/widgets/visualization/DataViewerOW.py +9 -9
  15. orangecontrib/tomwer/widgets/visualization/DiffViewerOW.py +1 -1
  16. orangecontrib/tomwer/widgets/visualization/SinogramViewerOW.py +0 -1
  17. tomwer/__main__.py +0 -10
  18. tomwer/app/canvas_launcher/config.py +3 -3
  19. tomwer/app/canvas_launcher/environ.py +1 -0
  20. tomwer/app/intensitynormalization.py +12 -11
  21. tomwer/app/nabuapp.py +0 -11
  22. tomwer/app/zstitching.py +11 -1
  23. tomwer/core/process/control/datalistener/datalistener.py +15 -10
  24. tomwer/core/process/control/nxtomomill.py +1 -1
  25. tomwer/core/process/control/scantransfer.py +8 -32
  26. tomwer/core/process/edit/darkflatpatch.py +8 -9
  27. tomwer/core/process/edit/imagekeyeditor.py +20 -22
  28. tomwer/core/process/icat/screenshots.py +1 -0
  29. tomwer/core/process/reconstruction/axis/axis.py +263 -59
  30. tomwer/core/process/reconstruction/axis/mode.py +161 -50
  31. tomwer/core/process/reconstruction/axis/params.py +23 -20
  32. tomwer/core/process/reconstruction/darkref/darkrefs.py +12 -13
  33. tomwer/core/process/reconstruction/nabu/castvolume.py +3 -3
  34. tomwer/core/process/reconstruction/nabu/nabucommon.py +43 -19
  35. tomwer/core/process/reconstruction/nabu/nabuscores.py +34 -7
  36. tomwer/core/process/reconstruction/nabu/nabuslices.py +81 -26
  37. tomwer/core/process/reconstruction/nabu/nabuvolume.py +31 -26
  38. tomwer/core/process/reconstruction/nabu/plane.py +9 -0
  39. tomwer/core/process/reconstruction/nabu/utils.py +32 -9
  40. tomwer/core/process/reconstruction/saaxis/saaxis.py +4 -1
  41. tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +9 -1
  42. tomwer/core/process/reconstruction/scores/params.py +3 -3
  43. tomwer/core/process/reconstruction/test/test_darkref_copy.py +4 -4
  44. tomwer/core/process/stitching/nabustitcher.py +11 -10
  45. tomwer/core/process/task.py +33 -27
  46. tomwer/core/process/test/test_axis.py +7 -6
  47. tomwer/core/process/test/test_data_transfer.py +3 -3
  48. tomwer/core/process/test/test_nabu.py +10 -2
  49. tomwer/core/process/test/test_normalization.py +2 -2
  50. tomwer/core/scan/blissscan.py +3 -3
  51. tomwer/core/scan/edfscan.py +9 -9
  52. tomwer/core/scan/nxtomoscan.py +11 -11
  53. tomwer/core/scan/scanbase.py +31 -24
  54. tomwer/core/scan/test/test_future_scan.py +1 -1
  55. tomwer/core/scan/test/test_h5.py +4 -4
  56. tomwer/core/scan/test/test_process_registration.py +2 -2
  57. tomwer/core/scan/test/test_scan.py +1 -75
  58. tomwer/core/settings.py +3 -3
  59. tomwer/core/test/test_utils.py +2 -2
  60. tomwer/core/volume/edfvolume.py +6 -6
  61. tomwer/core/volume/hdf5volume.py +6 -6
  62. tomwer/core/volume/jp2kvolume.py +6 -6
  63. tomwer/core/volume/rawvolume.py +6 -6
  64. tomwer/core/volume/tiffvolume.py +12 -12
  65. tomwer/gui/cluster/slurm.py +14 -9
  66. tomwer/gui/cluster/supervisor.py +12 -0
  67. tomwer/gui/cluster/test/test_cluster.py +1 -2
  68. tomwer/gui/cluster/test/test_supervisor.py +1 -1
  69. tomwer/gui/control/datalist.py +5 -0
  70. tomwer/gui/control/datawatcher/controlwidget.py +2 -4
  71. tomwer/gui/control/reducedarkflatselector.py +8 -8
  72. tomwer/gui/control/test/test_single_tomo_obj.py +1 -1
  73. tomwer/gui/edit/dkrfpatch.py +4 -4
  74. tomwer/gui/edit/nxtomowarmer.py +2 -2
  75. tomwer/gui/edit/test/test_dkrf_patch.py +6 -6
  76. tomwer/gui/imagefromfile.py +2 -2
  77. tomwer/gui/qfolderdialog.py +5 -0
  78. tomwer/gui/reconstruction/axis/CompareImages.py +94 -168
  79. tomwer/gui/reconstruction/axis/radioaxis.py +58 -182
  80. tomwer/gui/reconstruction/darkref/darkrefwidget.py +2 -1
  81. tomwer/gui/reconstruction/nabu/castvolume.py +8 -1
  82. tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +54 -21
  83. tomwer/gui/reconstruction/normalization/intensity.py +3 -25
  84. tomwer/gui/reconstruction/saaxis/corrangeselector.py +1 -1
  85. tomwer/gui/reconstruction/saaxis/saaxis.py +1 -11
  86. tomwer/gui/reconstruction/sadeltabeta/saadeltabeta.py +0 -10
  87. tomwer/gui/reconstruction/scores/scoreplot.py +1 -6
  88. tomwer/gui/reconstruction/test/test_axis.py +18 -4
  89. tomwer/gui/reconstruction/test/test_nabu.py +3 -0
  90. tomwer/gui/stitching/stitching.py +2 -2
  91. tomwer/gui/stitching/stitching_preview.py +7 -53
  92. tomwer/gui/stitching/stitching_raw.py +3 -3
  93. tomwer/gui/utils/inputwidget.py +12 -2
  94. tomwer/gui/utils/lineselector/lineselector.py +1 -1
  95. tomwer/gui/visualization/dataviewer.py +47 -17
  96. tomwer/gui/visualization/sinogramviewer.py +19 -26
  97. tomwer/gui/visualization/test/test_volumeviewer.py +64 -66
  98. tomwer/gui/visualization/volumeviewer.py +105 -105
  99. tomwer/io/utils/h5pyutils.py +7 -3
  100. tomwer/io/utils/utils.py +3 -3
  101. tomwer/resources/gui/icons/parameters.svg +1 -1
  102. tomwer/resources/gui/illustrations/no_rot.svg +1 -1
  103. tomwer/synctools/stacks/edit/darkflatpatch.py +17 -12
  104. tomwer/tests/test_scripts.py +0 -3
  105. tomwer/third_part/WaitingOverlay.py +110 -0
  106. tomwer/third_part/__init__.py +0 -0
  107. tomwer/version.py +2 -2
  108. {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/METADATA +32 -31
  109. {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/RECORD +115 -153
  110. {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/WHEEL +1 -1
  111. orangecontrib/tomwer/widgets/reconstruction/TofuOW.py +0 -197
  112. orangecontrib/tomwer/widgets/reconstruction/icons/XY_lamino.svg +0 -168
  113. orangecontrib/tomwer/widgets/reconstruction/icons/XZ_lamino.svg +0 -275
  114. orangecontrib/tomwer/widgets/reconstruction/icons/YZ_lamino.svg +0 -182
  115. tomwer/app/lamino.py +0 -143
  116. tomwer/core/process/reconstruction/lamino/__init__.py +0 -1
  117. tomwer/core/process/reconstruction/lamino/tofu.py +0 -1000
  118. tomwer/core/process/test/test_lamino.py +0 -76
  119. tomwer/core/test/test_lamino.py +0 -92
  120. tomwer/gui/reconstruction/lamino/__init__.py +0 -31
  121. tomwer/gui/reconstruction/lamino/tofu/TofuOptionLoader.py +0 -107
  122. tomwer/gui/reconstruction/lamino/tofu/__init__.py +0 -1
  123. tomwer/gui/reconstruction/lamino/tofu/misc.py +0 -148
  124. tomwer/gui/reconstruction/lamino/tofu/projections.py +0 -896
  125. tomwer/gui/reconstruction/lamino/tofu/settings.py +0 -75
  126. tomwer/gui/reconstruction/lamino/tofu/tofu.py +0 -432
  127. tomwer/gui/reconstruction/lamino/tofu/tofuexpert.py +0 -567
  128. tomwer/gui/reconstruction/lamino/tofu/tofuoutput.py +0 -757
  129. tomwer/gui/reconstruction/test/test_lamino.py +0 -194
  130. tomwer/resources/gui/icons/lamino_parameters.svg +0 -70
  131. tomwer/resources/gui/illustrations/lamino_angle.png +0 -0
  132. tomwer/resources/gui/illustrations/lamino_angle.svg +0 -509
  133. tomwer/resources/gui/illustrations/lamino_beta_angle.png +0 -0
  134. tomwer/resources/gui/illustrations/lamino_beta_angle.svg +0 -97
  135. tomwer/resources/gui/illustrations/lamino_theta_angle.png +0 -0
  136. tomwer/resources/gui/illustrations/lamino_theta_angle.svg +0 -368
  137. tomwer/resources/gui/illustrations/manual_slice.png +0 -0
  138. tomwer/resources/gui/illustrations/manual_slice.svg +0 -221
  139. tomwer/resources/gui/illustrations/psi_angle.png +0 -0
  140. tomwer/resources/gui/illustrations/psi_angle.svg +0 -479
  141. tomwer/resources/gui/illustrations/rotation_center.png +0 -0
  142. tomwer/resources/gui/illustrations/rotation_center.svg +0 -276
  143. tomwer/resources/gui/illustrations/slice_stack.png +0 -0
  144. tomwer/resources/gui/illustrations/slice_stack.svg +0 -266
  145. tomwer/resources/gui/illustrations/xy_slice.png +0 -0
  146. tomwer/resources/gui/illustrations/xy_slice.svg +0 -269
  147. tomwer/resources/gui/illustrations/xz_slice.png +0 -0
  148. tomwer/resources/gui/illustrations/xz_slice.svg +0 -270
  149. tomwer/resources/gui/illustrations/yz_slice.png +0 -0
  150. tomwer/resources/gui/illustrations/yz_slice.svg +0 -270
  151. tomwer/synctools/stacks/reconstruction/lamino.py +0 -233
  152. /tomwer-1.3.0.dev2-py3.11-nspkg.pth → /tomwer-1.3.0rc10-py3.11-nspkg.pth +0 -0
  153. {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/LICENSE +0 -0
  154. {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/entry_points.txt +0 -0
  155. {tomwer-1.3.0.dev2.dist-info → tomwer-1.3.0rc10.dist-info}/namespace_packages.txt +0 -0
  156. {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 compute_cor_nabu_growing_window(
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 compute_cor_nabu_sliding_window(
441
- radio_1=radio_1.copy(),
442
- radio_2=radio_2.copy(),
443
- side=scan.axis_params.side,
444
- padding_mode=scan.axis_params.padding_mode,
445
- flip_frame_2_lr=scan.axis_params.flip_lr,
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(horz_fft_width=horz_fft_width)
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 compute_cor_nabu_centered(
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
- with scan.acquire_process_file_lock():
735
- self.register_process(
736
- process_file=scan.process_file,
737
- entry=entry,
738
- results={"center_of_rotation": cor if cor is not None else "-"},
739
- configuration=self._axis_params.to_dict(),
740
- process_index=scan.pop_process_index(),
741
- overwrite=True,
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=True) as h5f:
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=True) as h5f:
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
- _VALID_INPUTS = {
80
- AxisMode.centered: (_InputType.RADIOS_X2,),
81
- AxisMode.global_: (_InputType.RADIOS_X2,),
82
- AxisMode.manual: (_InputType.RADIOS_X2,),
83
- AxisMode.growing_window_radios: (_InputType.RADIOS_X2,),
84
- AxisMode.sliding_window_radios: (_InputType.RADIOS_X2,),
85
- AxisMode.sliding_window_sinogram: (_InputType.SINOGRAM,),
86
- AxisMode.growing_window_sinogram: (_InputType.SINOGRAM,),
87
- AxisMode.sino_coarse_to_fine: (_InputType.SINOGRAM,),
88
- AxisMode.composite_coarse_to_fine: (
89
- _InputType.COMPOSITE,
90
- ), # in fact it is more an n radio constrain
91
- AxisMode.read: None,
92
- AxisMode.near: (_InputType.COMPOSITE,), # in fact it is more an n radio constrain
93
- }
94
-
95
- _AXIS_MODE_CONSTRAIN = {
96
- AxisMode.sino_coarse_to_fine: (_Constrain.FULL_TURN,),
97
- AxisMode.composite_coarse_to_fine: (_Constrain.FULL_TURN,),
98
- AxisMode.near: (_Constrain.FULL_TURN,),
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
  }