tomwer 1.4.0__py3-none-any.whl → 1.4.0rc0__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/tutorials/test_cor.ows +3 -3
- orangecontrib/tomwer/widgets/reconstruction/AxisOW.py +14 -6
- orangecontrib/tomwer/widgets/reconstruction/NabuVolumeOW.py +2 -4
- tomwer/app/axis.py +3 -0
- tomwer/app/multipag.py +3 -11
- tomwer/core/process/reconstruction/axis/axis.py +736 -27
- tomwer/core/process/reconstruction/axis/mode.py +24 -86
- tomwer/core/process/reconstruction/axis/params.py +138 -127
- tomwer/core/process/reconstruction/nabu/nabuscores.py +22 -19
- tomwer/core/process/reconstruction/nabu/nabuslices.py +1 -5
- tomwer/core/process/reconstruction/saaxis/saaxis.py +4 -4
- tomwer/core/process/reconstruction/sadeltabeta/sadeltabeta.py +4 -4
- tomwer/core/process/reconstruction/tests/test_axis.py +1 -1
- tomwer/core/process/reconstruction/tests/test_utils.py +4 -4
- tomwer/core/process/reconstruction/utils/cor.py +4 -8
- tomwer/core/process/tests/test_axis.py +231 -0
- tomwer/core/process/tests/test_nabu.py +3 -1
- tomwer/core/scan/nxtomoscan.py +0 -2
- tomwer/core/scan/scanbase.py +4 -4
- tomwer/core/scan/tests/test_process_registration.py +18 -0
- tomwer/gui/reconstruction/axis/AxisMainWindow.py +9 -20
- tomwer/gui/reconstruction/axis/AxisOptionsWidget.py +79 -239
- tomwer/gui/reconstruction/axis/AxisSettingsWidget.py +17 -38
- tomwer/gui/reconstruction/axis/AxisWidget.py +8 -16
- tomwer/gui/reconstruction/axis/CalculationWidget.py +200 -44
- tomwer/gui/reconstruction/axis/ControlWidget.py +2 -10
- tomwer/gui/reconstruction/axis/InputWidget.py +155 -11
- tomwer/gui/reconstruction/saaxis/corrangeselector.py +10 -19
- tomwer/gui/reconstruction/scores/scoreplot.py +2 -5
- tomwer/gui/reconstruction/tests/test_nabu.py +0 -8
- tomwer/gui/stitching/config/axisparams.py +0 -2
- tomwer/gui/stitching/z_stitching/fineestimation.py +1 -1
- tomwer/gui/tests/test_axis_gui.py +15 -31
- tomwer/synctools/stacks/reconstruction/axis.py +23 -5
- tomwer/synctools/stacks/reconstruction/dkrefcopy.py +1 -1
- tomwer/synctools/stacks/reconstruction/nabu.py +2 -2
- tomwer/synctools/stacks/reconstruction/normalization.py +1 -1
- tomwer/synctools/stacks/reconstruction/saaxis.py +1 -1
- tomwer/synctools/stacks/reconstruction/sadeltabeta.py +1 -1
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_axis.py +16 -0
- tomwer/tests/test_ewoks/test_single_node_execution.py +1 -1
- tomwer/tests/test_ewoks/test_workflows.py +1 -1
- tomwer/version.py +1 -1
- {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/METADATA +3 -3
- {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/RECORD +49 -52
- tomwer/core/process/reconstruction/axis/side.py +0 -8
- tomwer/gui/fonts.py +0 -5
- tomwer/gui/reconstruction/axis/EstimatedCORWidget.py +0 -394
- tomwer/gui/reconstruction/axis/EstimatedCorComboBox.py +0 -118
- {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/LICENSE +0 -0
- {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/WHEEL +0 -0
- {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/entry_points.txt +0 -0
- {tomwer-1.4.0.dist-info → tomwer-1.4.0rc0.dist-info}/top_level.txt +0 -0
@@ -5,11 +5,10 @@ from collections import namedtuple
|
|
5
5
|
|
6
6
|
import numpy
|
7
7
|
from silx.io.url import DataUrl
|
8
|
+
from silx.utils.deprecation import deprecated
|
8
9
|
from silx.utils.enum import Enum as _Enum
|
9
10
|
from tomoscan.esrf.scan.utils import get_data
|
10
11
|
|
11
|
-
from tomwer.core.process.reconstruction.utils.cor import relative_pos_to_absolute
|
12
|
-
from tomwer.core.process.reconstruction.axis.side import Side
|
13
12
|
from tomwer.core.scan.scanbase import TomwerScanBase
|
14
13
|
|
15
14
|
from .anglemode import CorAngleMode
|
@@ -78,14 +77,13 @@ class AxisResource(object):
|
|
78
77
|
"""Paganin configuration for axis calculation. To simplify we have only one
|
79
78
|
static configuration for now. Otherwise complicate stuff"""
|
80
79
|
|
81
|
-
def __init__(self, url
|
80
|
+
def __init__(self, url):
|
82
81
|
assert url is None or isinstance(url, DataUrl)
|
83
82
|
assert url is None or url.is_valid()
|
84
83
|
self.__url = url
|
85
84
|
self.__raw_data = None
|
86
85
|
self.__norme_data = None
|
87
86
|
self.__norm_paganin = None
|
88
|
-
self.__angle = angle
|
89
87
|
|
90
88
|
def __str__(self):
|
91
89
|
return f"{type(self)}, url: {self.__url.path() if self.__url else None}"
|
@@ -118,10 +116,6 @@ class AxisResource(object):
|
|
118
116
|
def normalized_data(self, data):
|
119
117
|
self.__norme_data = data
|
120
118
|
|
121
|
-
@property
|
122
|
-
def angle(self) -> float | None:
|
123
|
-
return self.__angle
|
124
|
-
|
125
119
|
def normalize_data(self, scan, log_):
|
126
120
|
"""Normalize data for axis calculation"""
|
127
121
|
if not isinstance(scan, TomwerScanBase):
|
@@ -188,7 +182,7 @@ class AxisResource(object):
|
|
188
182
|
|
189
183
|
class AxisRP:
|
190
184
|
"""
|
191
|
-
Configuration class for a tomwer :class:`
|
185
|
+
Configuration class for a tomwer :class:`AxisProcess`
|
192
186
|
|
193
187
|
note: every modification on the parameters will process a call fo changed
|
194
188
|
except `axis_url_1` and `axis_url_2` which will produce a call to the
|
@@ -212,12 +206,11 @@ class AxisRP:
|
|
212
206
|
"FINE_STEP_X",
|
213
207
|
"SCALE_IMG2_TO_IMG1",
|
214
208
|
"NEAR_POSITION",
|
215
|
-
"MOTOR_OFFSET",
|
216
|
-
"X_ROTATION_AXIS_PIXEL_POSITION",
|
217
209
|
"SINOGRAM_SUBSAMPLING",
|
218
210
|
"PADDING_MODE",
|
219
211
|
"FLIP_LR",
|
220
212
|
"COMPOSITE_OPTS",
|
213
|
+
"SIDE",
|
221
214
|
"COR_OPTIONS",
|
222
215
|
)
|
223
216
|
|
@@ -232,18 +225,17 @@ class AxisRP:
|
|
232
225
|
None is not processing"""
|
233
226
|
self.__angle_mode = CorAngleMode.use_0_180
|
234
227
|
"""Angle to use for radios"""
|
235
|
-
self.__x_rotation_axis_pixel_position = None
|
236
|
-
"""rotation axis position obtained from motor"""
|
237
|
-
self.__x_rotation_axis_pos_px_offset = 0.0
|
238
|
-
"""motor offset to be used to compute the 'estimated_cor' from 'x_rotation_axis_pixel_position'"""
|
239
228
|
self.__estimated_cor = 0.0
|
240
|
-
"""
|
229
|
+
"""Position to use for near calculation"""
|
241
230
|
self.__axis_url_1 = AxisResource(url=None)
|
242
231
|
"""first data url to use for axis cor calculation"""
|
243
232
|
self.__axis_url_2 = AxisResource(url=None)
|
244
233
|
"""second data url to use for axis cor calculation"""
|
245
234
|
self.__calculation_input_type = AxisCalculationInput.transmission
|
246
235
|
"""Type of input (emission, absorption, with or without paganin)"""
|
236
|
+
self.__use_sinogram = False
|
237
|
+
"""Do we want to use the sinogram of the radios for computing center
|
238
|
+
of rotation"""
|
247
239
|
self.__sinogram_line = "middle"
|
248
240
|
"""Line of the radios to use for getting the sinogram"""
|
249
241
|
self.__sinogram_subsampling = 10
|
@@ -252,14 +244,17 @@ class AxisRP:
|
|
252
244
|
self.__look_at_stdmax = False
|
253
245
|
"""do the near search at X position which as the max Y column standard
|
254
246
|
deviation"""
|
255
|
-
self.
|
247
|
+
self.__near_wx = 5
|
256
248
|
"""do the near search in an X window of size +-near_wx"""
|
257
|
-
self.
|
249
|
+
self.__fine_stepx = 0.1
|
258
250
|
"""shift step x for fine shifting image"""
|
259
251
|
self.__scale_img2_to_img1 = False
|
260
252
|
"""do image scaling"""
|
261
253
|
self.__padding_mode = None
|
262
254
|
self.__frame_width = None
|
255
|
+
self.__side = "right"
|
256
|
+
"""side of the cor. Requested by nabu cor algorithms growing-window
|
257
|
+
and sliding-window"""
|
263
258
|
self.__flip_lr = True
|
264
259
|
self.__composite_options = {
|
265
260
|
"theta": DEFAULT_CMP_THETA,
|
@@ -279,7 +274,37 @@ class AxisRP:
|
|
279
274
|
|
280
275
|
@mode.setter
|
281
276
|
def mode(self, mode):
|
282
|
-
|
277
|
+
if isinstance(mode, str):
|
278
|
+
try:
|
279
|
+
name = mode
|
280
|
+
if name in ("global_", "global"):
|
281
|
+
name = AxisMode.global_.name
|
282
|
+
elif name == "accurate":
|
283
|
+
_logger.info(
|
284
|
+
f"convert axis mode {name} to {AxisMode.centered.name} (renamed)"
|
285
|
+
)
|
286
|
+
name = AxisMode.centered.name
|
287
|
+
elif name == "growing-window":
|
288
|
+
_logger.warning(
|
289
|
+
f"growing-window mode has been removed. Replace it by {AxisMode.growing_window_radios.value}"
|
290
|
+
)
|
291
|
+
name = AxisMode.growing_window_radios.name
|
292
|
+
elif name == "sliding-window":
|
293
|
+
_logger.warning(
|
294
|
+
f"sliding-window mode has been removed. Replace it by {AxisMode.sliding_window_radios.value}"
|
295
|
+
)
|
296
|
+
name = AxisMode.sliding_window_radios.name
|
297
|
+
try:
|
298
|
+
_mode = getattr(AxisMode, name)
|
299
|
+
except Exception:
|
300
|
+
_mode = AxisMode.from_value(name)
|
301
|
+
except Exception:
|
302
|
+
raise ValueError(f"Fail to create axis mode from {mode}")
|
303
|
+
else:
|
304
|
+
if not isinstance(mode, AxisMode):
|
305
|
+
raise TypeError(f"mode is expected to be an instance of {AxisMode}")
|
306
|
+
_mode = mode
|
307
|
+
self.__mode = _mode
|
283
308
|
self.changed()
|
284
309
|
|
285
310
|
@property
|
@@ -321,7 +346,7 @@ class AxisRP:
|
|
321
346
|
def set_relative_value(self, value):
|
322
347
|
if not isinstance(value, (int, float, str, type(None))):
|
323
348
|
raise TypeError(
|
324
|
-
f"value is expected to be an instance of {int}
|
349
|
+
f"value is expected to be an instance of {int} {float}, {str} or {None}. {type(value)} provided"
|
325
350
|
)
|
326
351
|
if value is None:
|
327
352
|
changed = self.__relative_value is not None
|
@@ -336,46 +361,32 @@ class AxisRP:
|
|
336
361
|
else:
|
337
362
|
self.__relative_value = float(value)
|
338
363
|
if self.frame_width is not None:
|
339
|
-
self.__absolute_value =
|
340
|
-
|
364
|
+
self.__absolute_value = (
|
365
|
+
self.__relative_value + (self.frame_width - 1) / 2.0
|
341
366
|
)
|
342
367
|
self.changed()
|
343
368
|
|
344
369
|
@property
|
345
|
-
def estimated_cor(self)
|
370
|
+
def estimated_cor(self):
|
346
371
|
return self.__estimated_cor
|
347
372
|
|
348
373
|
@estimated_cor.setter
|
349
|
-
def estimated_cor(self, value
|
350
|
-
try:
|
351
|
-
value = Side.from_value(value)
|
352
|
-
except ValueError:
|
353
|
-
pass
|
374
|
+
def estimated_cor(self, value):
|
354
375
|
if self.__estimated_cor != value:
|
355
376
|
self.__estimated_cor = value
|
356
377
|
self.changed()
|
357
378
|
|
358
379
|
@property
|
359
|
-
def
|
360
|
-
return self.
|
361
|
-
|
362
|
-
@
|
363
|
-
def
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
@property
|
370
|
-
def x_rotation_axis_pixel_position(self) -> float | None:
|
371
|
-
return self.__x_rotation_axis_pixel_position
|
372
|
-
|
373
|
-
@x_rotation_axis_pixel_position.setter
|
374
|
-
def x_rotation_axis_pixel_position(self, value: float | None):
|
375
|
-
assert isinstance(
|
376
|
-
value, (float, type(None))
|
377
|
-
), f"x_rotation_axis_pixel_position should be None or a float. Got{type(value)}"
|
378
|
-
self.__x_rotation_axis_pixel_position = value
|
380
|
+
def side(self):
|
381
|
+
return self.__side
|
382
|
+
|
383
|
+
@side.setter
|
384
|
+
def side(self, side):
|
385
|
+
if side not in ("all", "left", "right", "center", "near"):
|
386
|
+
raise ValueError(f"side '{side}' is not managed")
|
387
|
+
if self.__side != side:
|
388
|
+
self.__side = side
|
389
|
+
self.changed()
|
379
390
|
|
380
391
|
@property
|
381
392
|
def axis_url_1(self):
|
@@ -459,6 +470,16 @@ class AxisRP:
|
|
459
470
|
self.__calculation_input_type = type_
|
460
471
|
self.changed()
|
461
472
|
|
473
|
+
@property
|
474
|
+
def use_sinogram(self):
|
475
|
+
return self.__use_sinogram
|
476
|
+
|
477
|
+
@use_sinogram.setter
|
478
|
+
def use_sinogram(self, sinogram):
|
479
|
+
if self.__use_sinogram != sinogram:
|
480
|
+
self.__use_sinogram = sinogram
|
481
|
+
self.changed()
|
482
|
+
|
462
483
|
@property
|
463
484
|
def sinogram_line(self):
|
464
485
|
return self.__sinogram_line
|
@@ -499,24 +520,23 @@ class AxisRP:
|
|
499
520
|
self.__look_at_stdmax = stdmax
|
500
521
|
|
501
522
|
@property
|
502
|
-
def
|
503
|
-
return self.
|
523
|
+
def near_wx(self):
|
524
|
+
return self.__near_wx
|
504
525
|
|
505
|
-
@
|
506
|
-
def
|
507
|
-
if self.
|
508
|
-
self.
|
526
|
+
@near_wx.setter
|
527
|
+
def near_wx(self, width):
|
528
|
+
if self.__near_wx != width:
|
529
|
+
self.__near_wx = width
|
509
530
|
self.changed()
|
510
531
|
|
511
532
|
@property
|
512
|
-
def
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
self.__composite_fine_step = step_size
|
533
|
+
def fine_step_x(self):
|
534
|
+
return self.__fine_stepx
|
535
|
+
|
536
|
+
@fine_step_x.setter
|
537
|
+
def fine_step_x(self, step_size):
|
538
|
+
if self.__fine_stepx != step_size:
|
539
|
+
self.__fine_stepx = step_size
|
520
540
|
self.changed()
|
521
541
|
|
522
542
|
@property
|
@@ -573,7 +593,7 @@ class AxisRP:
|
|
573
593
|
"near_pos",
|
574
594
|
"near_width",
|
575
595
|
):
|
576
|
-
raise KeyError(f"{key} is not
|
596
|
+
raise KeyError(f"{key} is not recogized")
|
577
597
|
self.__composite_options = opts
|
578
598
|
|
579
599
|
@property
|
@@ -587,7 +607,7 @@ class AxisRP:
|
|
587
607
|
self.changed()
|
588
608
|
|
589
609
|
def changed(self):
|
590
|
-
"""callback to overwrite when the
|
610
|
+
"""callback to overwrite when the paramter value changed"""
|
591
611
|
pass
|
592
612
|
|
593
613
|
def n_url(self):
|
@@ -620,27 +640,21 @@ class AxisRP:
|
|
620
640
|
"POSITION_VALUE": self.relative_cor_value,
|
621
641
|
"CALC_INPUT_TYPE": self.calculation_input_type.to_dict(),
|
622
642
|
"ANGLE_MODE": self.angle_mode.value,
|
623
|
-
"
|
624
|
-
|
625
|
-
),
|
643
|
+
"USE_SINOGRAM": self.use_sinogram,
|
644
|
+
"SINOGRAM_LINE": self.sinogram_line if self.use_sinogram else "",
|
626
645
|
"SINOGRAM_SUBSAMPLING": self.sinogram_subsampling,
|
627
646
|
"AXIS_URL_1": axis_urls_1,
|
628
647
|
"AXIS_URL_2": axis_urls_2,
|
629
648
|
"LOOK_AT_STDMAX": self.look_at_stdmax,
|
630
|
-
"NEAR_WX": self.
|
631
|
-
"FINE_STEP_X": self.
|
649
|
+
"NEAR_WX": self.near_wx,
|
650
|
+
"FINE_STEP_X": self.fine_step_x,
|
632
651
|
"SCALE_IMG2_TO_IMG1": self.scale_img2_to_img1,
|
633
|
-
"NEAR_POSITION":
|
634
|
-
self.estimated_cor.value
|
635
|
-
if isinstance(self.estimated_cor, Side)
|
636
|
-
else self.estimated_cor
|
637
|
-
),
|
652
|
+
"NEAR_POSITION": self.estimated_cor,
|
638
653
|
"PADDING_MODE": self.padding_mode,
|
639
654
|
"FLIP_LR": self.flip_lr,
|
640
655
|
"COMPOSITE_OPTS": self.composite_options,
|
656
|
+
"SIDE": self.side,
|
641
657
|
"COR_OPTIONS": self.extra_cor_options,
|
642
|
-
"MOTOR_OFFSET": self.x_rotation_axis_pos_px_offset,
|
643
|
-
"X_ROTATION_AXIS_PIXEL_POSITION": self.x_rotation_axis_pixel_position,
|
644
658
|
}
|
645
659
|
return _dict
|
646
660
|
|
@@ -665,6 +679,8 @@ class AxisRP:
|
|
665
679
|
self.calculation_input_type = AxisCalculationInput.from_value(
|
666
680
|
_dict["CALC_INPUT_TYPE"]
|
667
681
|
)
|
682
|
+
if "USE_SINOGRAM" in _dict:
|
683
|
+
self.use_sinogram = _dict["USE_SINOGRAM"]
|
668
684
|
if "ANGLE_MODE" in _dict:
|
669
685
|
self.angle_mode = CorAngleMode.from_value(_dict["ANGLE_MODE"])
|
670
686
|
if "SINOGRAM_LINE" in _dict:
|
@@ -676,13 +692,13 @@ class AxisRP:
|
|
676
692
|
if "LOOK_AT_STDMAX" in _dict:
|
677
693
|
self.look_at_stdmax = _dict["LOOK_AT_STDMAX"]
|
678
694
|
if "NEAR_WX" in _dict:
|
679
|
-
self.
|
695
|
+
self.near_wx = _dict["NEAR_WX"]
|
680
696
|
if "FINE_STEP_X" in _dict:
|
681
|
-
self.
|
697
|
+
self.fine_step_x = _dict["FINE_STEP_X"]
|
682
698
|
if "SCALE_IMG2_TO_IMG1" in _dict:
|
683
699
|
self.scale_img2_to_img1 = _dict["SCALE_IMG2_TO_IMG1"]
|
684
700
|
if "NEAR_POSITION" in _dict:
|
685
|
-
self.estimated_cor = _dict["NEAR_POSITION"]
|
701
|
+
self.estimated_cor = float(_dict["NEAR_POSITION"])
|
686
702
|
if "SINOGRAM_SUBSAMPLING" in _dict:
|
687
703
|
self.sinogram_subsampling = _dict["SINOGRAM_SUBSAMPLING"]
|
688
704
|
if "PADDING_MODE" in _dict:
|
@@ -691,6 +707,8 @@ class AxisRP:
|
|
691
707
|
self.flip_lr = bool(_dict["FLIP_LR"])
|
692
708
|
if "COMPOSITE_OPTS" in _dict:
|
693
709
|
self.composite_options = _dict["COMPOSITE_OPTS"]
|
710
|
+
if "SIDE" in _dict:
|
711
|
+
self.side = _dict["SIDE"]
|
694
712
|
self.extra_cor_options = _dict.get("COR_OPTIONS", "")
|
695
713
|
|
696
714
|
def copy(self, axis_params, copy_axis_url=True, copy_flip_lr=True):
|
@@ -699,17 +717,17 @@ class AxisRP:
|
|
699
717
|
self.frame_width = axis_params.frame_width
|
700
718
|
self.set_relative_value(axis_params.relative_cor_value)
|
701
719
|
self.calculation_input_type = axis_params.calculation_input_type
|
720
|
+
self.use_sinogram = axis_params.use_sinogram
|
702
721
|
self.angle_mode = axis_params.angle_mode
|
703
722
|
self.sinogram_line = axis_params.sinogram_line
|
704
723
|
self.sinogram_subsampling = axis_params.sinogram_subsampling
|
705
724
|
self.look_at_stdmax = axis_params.look_at_stdmax
|
706
|
-
self.
|
707
|
-
self.
|
725
|
+
self.near_wx = axis_params.near_wx
|
726
|
+
self.fine_step_x = axis_params.fine_step_x
|
708
727
|
self.scale_img2_to_img1 = axis_params.scale_img2_to_img1
|
709
728
|
self.estimated_cor = axis_params.estimated_cor
|
710
|
-
self.x_rotation_axis_pixel_position = axis_params.x_rotation_axis_pixel_position
|
711
|
-
self.x_rotation_axis_pos_px_offset = axis_params.x_rotation_axis_pos_px_offset
|
712
729
|
self.padding_mode = axis_params.padding_mode
|
730
|
+
self.side = axis_params.side
|
713
731
|
self.composite_options = axis_params.composite_options
|
714
732
|
self.extra_cor_options = axis_params.extra_cor_options
|
715
733
|
if copy_axis_url:
|
@@ -736,63 +754,56 @@ class AxisRP:
|
|
736
754
|
AxisMode.sliding_window_radios,
|
737
755
|
AxisMode.sliding_window_sinogram,
|
738
756
|
):
|
739
|
-
extra_info = f"side: {self.
|
757
|
+
extra_info = f"side: {self.side}, use sinogram: {self.use_sinogram}"
|
740
758
|
results = ", ".join((results, extra_info))
|
741
759
|
return results
|
742
760
|
|
743
761
|
def get_nabu_cor_options_as_dict(self) -> str:
|
744
762
|
options = {}
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
"near_width", DEFAULT_CMP_NEAR_WIDTH
|
757
|
-
)
|
758
|
-
options["theta_interval"] = self.composite_options.get(
|
759
|
-
"theta_interval", DEFAULT_CMP_THETA
|
760
|
-
)
|
761
|
-
options["oversampling"] = self.composite_options.get(
|
762
|
-
"oversampling", DEFAULT_CMP_OVERSAMPLING
|
763
|
-
)
|
764
|
-
options["n_subsampling_y"] = self.composite_options.get(
|
765
|
-
"n_subsampling_y", DEFAULT_CMP_N_SUBSAMPLING_Y
|
766
|
-
)
|
767
|
-
options["take_log"] = self.composite_options.get(
|
768
|
-
"take_log", DEFAULT_CMP_TAKE_LOG
|
769
|
-
)
|
763
|
+
if self.mode is AxisMode.near:
|
764
|
+
self.side = "near"
|
765
|
+
request_side = len(AXIS_MODE_METADATAS[self.mode].valid_sides) > 0
|
766
|
+
if request_side:
|
767
|
+
|
768
|
+
if self.side == "near":
|
769
|
+
options["side"] = self.composite_options.get(
|
770
|
+
"near_pos", self.estimated_cor
|
771
|
+
)
|
772
|
+
else:
|
773
|
+
options["side"] = self.side
|
770
774
|
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
options["radio_angles"] = (
|
775
|
-
numpy.deg2rad(self.axis_url_1.angle or 0.0),
|
776
|
-
numpy.deg2rad(self.axis_url_2.angle or 180.0),
|
777
|
-
)
|
778
|
-
if self.mode.requires_sinogram_index:
|
779
|
-
options["slice_idx"] = self.sinogram_line
|
775
|
+
if self.side == "near":
|
776
|
+
near_width = self.composite_options.get("near_width", 20.0)
|
777
|
+
options["near_width"] = near_width
|
780
778
|
|
781
779
|
# append "extra_cor_options" to already handled cor options
|
782
|
-
# expected values: low_pass, high_pass
|
783
780
|
extra_cor_options = self.extra_cor_options.replace(" ", "")
|
784
781
|
|
785
782
|
if extra_cor_options != "":
|
786
783
|
for opt in self.extra_cor_options.replace(" ", "").split(";"):
|
787
784
|
if len(opt.split("=")) == 2:
|
788
785
|
key, value = opt.split("=")
|
789
|
-
|
790
|
-
value = float(value)
|
791
|
-
options[key] = value
|
792
|
-
else:
|
793
|
-
_logger.warning(
|
794
|
-
f"key {key} is not recognized by nabu. Ignore it."
|
795
|
-
)
|
786
|
+
options[key] = value
|
796
787
|
else:
|
797
|
-
_logger.info(f"ignore option {opt}. Invalid
|
788
|
+
_logger.info(f"ignore option {opt}. Invalid synthax")
|
798
789
|
return options
|
790
|
+
|
791
|
+
@deprecated(replacement="get_nabu_cor_options_as_str", since_version="1.1")
|
792
|
+
def get_nabu_cor_options(self) -> str:
|
793
|
+
return self.get_nabu_cor_options_as_str()
|
794
|
+
|
795
|
+
def get_nabu_cor_options_as_str(self) -> str:
|
796
|
+
"""return cor option for nabu"""
|
797
|
+
|
798
|
+
def cast_key_value(key, value):
|
799
|
+
if key in ("side",):
|
800
|
+
return f"{key}='{value}'"
|
801
|
+
else:
|
802
|
+
return f"{key}={value}"
|
803
|
+
|
804
|
+
return " ; ".join(
|
805
|
+
[
|
806
|
+
cast_key_value(key, value)
|
807
|
+
for key, value in self.get_nabu_cor_options_as_dict().items()
|
808
|
+
]
|
809
|
+
)
|
@@ -42,10 +42,6 @@ from tomwer.core.process.reconstruction.nabu.utils import (
|
|
42
42
|
slice_index_to_int,
|
43
43
|
get_nabu_multicor_file_prefix,
|
44
44
|
)
|
45
|
-
from tomwer.core.process.reconstruction.utils.cor import (
|
46
|
-
relative_pos_to_absolute,
|
47
|
-
absolute_pos_to_relative,
|
48
|
-
)
|
49
45
|
from tomwer.core.process.reconstruction.nabu.target import Target
|
50
46
|
from tomwer.core.scan.scanbase import TomwerScanBase
|
51
47
|
from tomwer.core.utils.slurm import get_slurm_script_name, is_slurm_available
|
@@ -287,7 +283,7 @@ class _Reconstructor(_NabuBaseReconstructor):
|
|
287
283
|
)
|
288
284
|
|
289
285
|
results = {}
|
290
|
-
if self.advancement
|
286
|
+
if self.advancement:
|
291
287
|
self.advancement.total = len(self.nabu_configs)
|
292
288
|
for var_value, config in self.nabu_configs.items():
|
293
289
|
if self._cancelled:
|
@@ -312,7 +308,7 @@ class _Reconstructor(_NabuBaseReconstructor):
|
|
312
308
|
process_name=self.process_name,
|
313
309
|
)
|
314
310
|
# specific treatment for cor: rename output files
|
315
|
-
if self.advancement
|
311
|
+
if self.advancement:
|
316
312
|
self.advancement.update()
|
317
313
|
return results
|
318
314
|
|
@@ -499,6 +495,22 @@ class _ReconstructorMultiCor(_NabuBaseReconstructor):
|
|
499
495
|
else:
|
500
496
|
raise ValueError(f"{self.target} is not recognized as a valid target")
|
501
497
|
|
498
|
+
@staticmethod
|
499
|
+
def convert_cor_from_rel_to_abs(scan, cor):
|
500
|
+
if scan.dim_1 is not None:
|
501
|
+
return cor + (scan.dim_1 - 1) / 2.0
|
502
|
+
else:
|
503
|
+
_logger.warning("enable to get image half width. Set it to 1024")
|
504
|
+
return cor + 1024
|
505
|
+
|
506
|
+
@staticmethod
|
507
|
+
def convert_cor_from_abs_to_rel(scan, cor):
|
508
|
+
if scan.dim_1 is not None:
|
509
|
+
return cor - (scan.dim_1 - 1) / 2.0
|
510
|
+
else:
|
511
|
+
_logger.warning("enable to get image half width. Set it to 1024")
|
512
|
+
return cor - 1024
|
513
|
+
|
502
514
|
def _run_nabu_multicor_locally(
|
503
515
|
self,
|
504
516
|
conf_file: str,
|
@@ -518,10 +530,7 @@ class _ReconstructorMultiCor(_NabuBaseReconstructor):
|
|
518
530
|
slice_index = slice_index_to_int(self.slice_index, scan=self.scan)
|
519
531
|
|
520
532
|
cor_in_nabu_ref = tuple(
|
521
|
-
[
|
522
|
-
relative_pos_to_absolute(relative_pos=cor, det_width=self.scan.dim_1)
|
523
|
-
for cor in self.cors
|
524
|
-
]
|
533
|
+
[self.convert_cor_from_rel_to_abs(self.scan, cor) for cor in self.cors]
|
525
534
|
)
|
526
535
|
cor_in_nabu_ref = ",".join([str(cor) for cor in cor_in_nabu_ref])
|
527
536
|
command = " ".join(
|
@@ -558,15 +567,12 @@ class _ReconstructorMultiCor(_NabuBaseReconstructor):
|
|
558
567
|
scan=self.scan,
|
559
568
|
file_format=file_format,
|
560
569
|
cors=[
|
561
|
-
|
562
|
-
for cor in self.cors
|
570
|
+
self.convert_cor_from_rel_to_abs(self.scan, cor) for cor in self.cors
|
563
571
|
],
|
564
572
|
)
|
565
573
|
# convert back from abs ref to rel ref
|
566
574
|
recons_vol_identifiers = {
|
567
|
-
|
568
|
-
absolute_pos=cor, det_width=self.scan.dim_1
|
569
|
-
): identifiers
|
575
|
+
self.convert_cor_from_abs_to_rel(self.scan, cor): identifiers
|
570
576
|
for cor, identifiers in recons_vol_identifiers.items()
|
571
577
|
}
|
572
578
|
return ResultsLocalRun(
|
@@ -616,10 +622,7 @@ class _ReconstructorMultiCor(_NabuBaseReconstructor):
|
|
616
622
|
|
617
623
|
slice_index = slice_index_to_int(self.slice_index, scan=self.scan)
|
618
624
|
cor_in_nabu_ref = tuple(
|
619
|
-
[
|
620
|
-
relative_pos_to_absolute(relative_pos=cor, det_width=self.scan.dim_1)
|
621
|
-
for cor in self.cors
|
622
|
-
]
|
625
|
+
[self.convert_cor_from_rel_to_abs(self.scan, cor) for cor in self.cors]
|
623
626
|
)
|
624
627
|
cor_in_nabu_ref = ",".join([str(cor) for cor in cor_in_nabu_ref])
|
625
628
|
|
@@ -16,7 +16,6 @@ from tomwer.core.utils.scanutils import data_identifier_to_scan
|
|
16
16
|
from tomwer.core.utils.slurm import is_slurm_available
|
17
17
|
from tomwer.core.process.reconstruction.nabu.plane import NabuPlane
|
18
18
|
from tomwer.core.process.reconstruction.nabu.utils import slice_index_to_int
|
19
|
-
from tomwer.core.process.reconstruction.utils.cor import relative_pos_to_absolute
|
20
19
|
from tomwer.core.volume.volumefactory import VolumeFactory
|
21
20
|
from tomwer.core.process.reconstruction.output import (
|
22
21
|
PROCESS_FOLDER_RECONSTRUCTED_SLICES,
|
@@ -132,10 +131,7 @@ def run_slices_reconstruction(
|
|
132
131
|
if scan.axis_params is not None and scan.axis_params.relative_cor_value is not None:
|
133
132
|
if "reconstruction" in config:
|
134
133
|
# move the cor value to the nabu reference
|
135
|
-
cor_nabu_ref =
|
136
|
-
relative_pos=scan.axis_params.relative_cor_value,
|
137
|
-
det_width=scan.dim_1,
|
138
|
-
)
|
134
|
+
cor_nabu_ref = scan.axis_params.relative_cor_value + (scan.dim_1 - 1) / 2.0
|
139
135
|
config["reconstruction"]["rotation_axis_position"] = str(cor_nabu_ref)
|
140
136
|
_logger.info(f"set nabu reconstruction parameters to {scan}")
|
141
137
|
|
@@ -31,7 +31,6 @@ from tomwer.core.process.reconstruction.scores import (
|
|
31
31
|
get_disk_mask_radius,
|
32
32
|
)
|
33
33
|
from tomwer.core.process.reconstruction.scores.params import ScoreMethod
|
34
|
-
from tomwer.core.process.reconstruction.utils.cor import relative_pos_to_absolute
|
35
34
|
from tomwer.core.process.task import Task
|
36
35
|
from tomwer.core.scan.nxtomoscan import NXtomoScan
|
37
36
|
from tomwer.core.scan.scanbase import TomwerScanBase
|
@@ -54,6 +53,7 @@ from tomwer.core.process.reconstruction.nabu.utils import (
|
|
54
53
|
get_multi_cor_recons_volume_identifiers,
|
55
54
|
get_nabu_multicor_file_prefix,
|
56
55
|
)
|
56
|
+
from tomwer.core.process.reconstruction.nabu.nabuscores import _ReconstructorMultiCor
|
57
57
|
|
58
58
|
from .params import SAAxisParams
|
59
59
|
|
@@ -316,9 +316,9 @@ class SAAxisTask(
|
|
316
316
|
continue
|
317
317
|
|
318
318
|
for cor in cors:
|
319
|
-
cor_nabu_ref =
|
320
|
-
|
321
|
-
|
319
|
+
cor_nabu_ref = _ReconstructorMultiCor.convert_cor_from_rel_to_abs(
|
320
|
+
scan=scan,
|
321
|
+
cor=cor,
|
322
322
|
)
|
323
323
|
volume_identifiers = get_multi_cor_recons_volume_identifiers(
|
324
324
|
scan=scan,
|
@@ -28,7 +28,6 @@ from tomwer.core.process.reconstruction.nabu.nabucommon import (
|
|
28
28
|
ResultsWithStd,
|
29
29
|
)
|
30
30
|
from tomwer.core.process.reconstruction.nabu.nabuslices import SingleSliceRunner
|
31
|
-
from tomwer.core.process.reconstruction.utils.cor import relative_pos_to_absolute
|
32
31
|
from tomwer.core.process.reconstruction.scores import (
|
33
32
|
ComputedScore,
|
34
33
|
ScoreMethod,
|
@@ -361,14 +360,15 @@ class SADeltaBetaTask(
|
|
361
360
|
|
362
361
|
def _config_preprocessing(self, scan, config, delta_beta_s, output_dir) -> dict:
|
363
362
|
config.get("phase", {}).pop("beam_shape", None)
|
363
|
+
# if scan contains some center of position copy it to nabu
|
364
364
|
if (
|
365
365
|
scan.axis_params is not None
|
366
366
|
and scan.axis_params.relative_cor_value is not None
|
367
367
|
):
|
368
368
|
if "reconstruction" in config:
|
369
|
-
|
370
|
-
|
371
|
-
|
369
|
+
# move the cor value to the nabu reference
|
370
|
+
cor_nabu_ref = (
|
371
|
+
scan.axis_params.relative_cor_value + (scan.dim_1 - 1) / 2.0
|
372
372
|
)
|
373
373
|
config["reconstruction"]["rotation_axis_position"] = str(cor_nabu_ref)
|
374
374
|
|
@@ -42,5 +42,5 @@ def test_read_x_rotation_axis_pixel_position(nxtomo_scan_360): # noqa F811
|
|
42
42
|
|
43
43
|
nxtomo_scan_360.clear_caches()
|
44
44
|
task.run()
|
45
|
-
assert nxtomo_scan_360.axis_params.absolute_cor_value == 22.
|
45
|
+
assert nxtomo_scan_360.axis_params.absolute_cor_value == 22.0
|
46
46
|
assert nxtomo_scan_360.axis_params.relative_cor_value == 12.5
|
@@ -10,11 +10,11 @@ def test_cor_conversion():
|
|
10
10
|
"""
|
11
11
|
test absolute_pos_to_relative and relative_pos_to_absolute functions
|
12
12
|
"""
|
13
|
-
assert relative_pos_to_absolute(relative_pos=0.0, det_width=100) ==
|
14
|
-
assert relative_pos_to_absolute(relative_pos=0.0, det_width=101) == 50.
|
13
|
+
assert relative_pos_to_absolute(relative_pos=0.0, det_width=100) == 49.5
|
14
|
+
assert relative_pos_to_absolute(relative_pos=0.0, det_width=101) == 50.0
|
15
15
|
|
16
|
-
assert absolute_pos_to_relative(absolute_pos=20, det_width=500) == -
|
17
|
-
assert absolute_pos_to_relative(absolute_pos=300, det_width=500) == 50.
|
16
|
+
assert absolute_pos_to_relative(absolute_pos=20, det_width=500) == -229.5
|
17
|
+
assert absolute_pos_to_relative(absolute_pos=300, det_width=500) == 50.5
|
18
18
|
|
19
19
|
for det_width in (10, 20, 30, 50):
|
20
20
|
for relative_cor_pos in (0, -2.3, -4.5):
|