tomwer 1.4.19__py3-none-any.whl → 1.5.2rc0__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/simple_volume_local_reconstruction.ows +11 -8
- orangecontrib/tomwer/tutorials/simple_volume_to_slurm_reconstruction.ows +12 -9
- orangecontrib/tomwer/widgets/control/DataDiscoveryOW.py +1 -1
- orangecontrib/tomwer/widgets/control/NXTomomillMixIn.py +21 -10
- tomwer/app/axis.py +1 -1
- tomwer/app/reducedarkflat.py +2 -2
- tomwer/core/process/control/datalistener/rpcserver.py +2 -8
- tomwer/core/process/drac/binning.py +2 -2
- tomwer/core/process/drac/output.py +1 -1
- tomwer/core/process/edit/imagekeyeditor.py +4 -6
- tomwer/core/process/edit/nxtomoeditor.py +58 -20
- tomwer/core/process/output.py +6 -5
- tomwer/core/process/reconstruction/axis/anglemode.py +2 -2
- tomwer/core/process/reconstruction/axis/axis.py +1 -0
- tomwer/core/process/reconstruction/axis/mode.py +2 -2
- tomwer/core/process/reconstruction/axis/params.py +4 -4
- tomwer/core/process/reconstruction/axis/projectiontype.py +1 -1
- tomwer/core/process/reconstruction/axis/side.py +1 -1
- tomwer/core/process/reconstruction/darkref/darkrefs.py +2 -2
- tomwer/core/process/reconstruction/darkref/darkrefscopy.py +1 -1
- tomwer/core/process/reconstruction/darkref/params.py +2 -3
- tomwer/core/process/reconstruction/nabu/castvolume.py +4 -1
- tomwer/core/process/reconstruction/nabu/helical.py +3 -1
- tomwer/core/process/reconstruction/nabu/nabucommon.py +2 -2
- tomwer/core/process/reconstruction/nabu/nabuscores.py +1 -1
- tomwer/core/process/reconstruction/nabu/nabuslices.py +4 -4
- tomwer/core/process/reconstruction/nabu/plane.py +2 -2
- tomwer/core/process/reconstruction/nabu/target.py +1 -1
- tomwer/core/process/reconstruction/nabu/test/test_castvolume.py +2 -0
- tomwer/core/process/reconstruction/nabu/utils.py +15 -14
- tomwer/core/process/reconstruction/normalization/normalization.py +1 -1
- tomwer/core/process/reconstruction/normalization/params.py +4 -4
- tomwer/core/process/reconstruction/output.py +2 -2
- tomwer/core/process/reconstruction/saaxis/params.py +3 -3
- tomwer/core/process/reconstruction/saaxis/saaxis.py +1 -1
- tomwer/core/process/reconstruction/scores/params.py +2 -2
- tomwer/core/process/reconstruction/scores/scores.py +3 -3
- tomwer/core/process/reconstruction/tests/test_axis.py +1 -1
- tomwer/core/process/stitching/metadataholder.py +5 -5
- tomwer/core/process/stitching/nabustitcher.py +1 -4
- tomwer/core/process/tests/test_normalization.py +2 -1
- tomwer/core/scan/edfscan.py +3 -3
- tomwer/core/scan/nxtomoscan.py +3 -3
- tomwer/core/scan/scanbase.py +3 -3
- tomwer/core/scan/scantype.py +1 -1
- tomwer/core/settings.py +1 -1
- tomwer/core/tomwer_object.py +1 -1
- tomwer/core/utils/nxtomoutils.py +2 -2
- tomwer/core/utils/spec.py +6 -3
- tomwer/gui/cluster/slurm.py +3 -3
- tomwer/gui/configuration/level.py +1 -1
- tomwer/gui/control/actions.py +1 -1
- tomwer/gui/control/datadiscovery.py +1 -1
- tomwer/gui/control/datalist.py +1 -1
- tomwer/gui/control/reducedarkflatselector.py +4 -4
- tomwer/gui/control/series/seriescreator.py +5 -5
- tomwer/gui/control/tomoobjdisplaymode.py +1 -1
- tomwer/gui/dataportal/gallery.py +6 -6
- tomwer/gui/edit/imagekeyeditor.py +7 -9
- tomwer/gui/edit/nxtomoeditor.py +420 -112
- tomwer/gui/edit/tests/test_nx_editor.py +155 -83
- tomwer/gui/reconstruction/axis/CalculationWidget.py +1 -1
- tomwer/gui/reconstruction/axis/EstimatedCORWidget.py +12 -8
- tomwer/gui/reconstruction/axis/EstimatedCorComboBox.py +2 -2
- tomwer/gui/reconstruction/axis/InputWidget.py +3 -3
- tomwer/gui/reconstruction/darkref/darkrefwidget.py +2 -2
- tomwer/gui/reconstruction/nabu/castvolume.py +16 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/base.py +2 -4
- tomwer/gui/reconstruction/nabu/nabuconfig/ctf.py +6 -6
- tomwer/gui/reconstruction/nabu/nabuconfig/nabuconfig.py +1 -1
- tomwer/gui/reconstruction/nabu/nabuconfig/phase.py +5 -5
- tomwer/gui/reconstruction/nabu/nabuconfig/preprocessing.py +2 -4
- tomwer/gui/reconstruction/nabu/nabuconfig/reconstruction.py +78 -52
- tomwer/gui/reconstruction/nabu/nabuflow.py +3 -13
- tomwer/gui/reconstruction/nabu/slices.py +11 -11
- tomwer/gui/reconstruction/nabu/test/test_cast_volume.py +19 -0
- tomwer/gui/reconstruction/nabu/volume.py +1 -1
- tomwer/gui/reconstruction/normalization/intensity.py +8 -12
- tomwer/gui/reconstruction/saaxis/corrangeselector.py +2 -2
- tomwer/gui/reconstruction/saaxis/dimensionwidget.py +71 -67
- tomwer/gui/reconstruction/sacommon.py +1 -1
- tomwer/gui/reconstruction/scores/scoreplot.py +18 -10
- tomwer/gui/reconstruction/tests/test_saaxis.py +18 -16
- tomwer/gui/stitching/SingleAxisStitchingWidget.py +8 -8
- tomwer/gui/stitching/StitchingOptionsWidget.py +1 -1
- tomwer/gui/stitching/alignment.py +8 -8
- tomwer/gui/stitching/config/axisparams.py +2 -2
- tomwer/gui/stitching/config/output.py +1 -1
- tomwer/gui/stitching/config/positionoveraxis.py +1 -1
- tomwer/gui/stitching/config/stitchingstrategies.py +4 -6
- tomwer/gui/stitching/config/tomoobjdetails.py +21 -13
- tomwer/gui/stitching/normalization.py +6 -6
- tomwer/gui/stitching/tests/test_ZStitchingWindow.py +8 -1
- tomwer/gui/stitching/tests/test_preview.py +10 -7
- tomwer/gui/stitching/tests/utils.py +27 -18
- tomwer/gui/stitching/z_stitching/fineestimation.py +7 -9
- tomwer/gui/stitching/z_stitching/tests/test_raw_estimation.py +18 -7
- tomwer/gui/stitching/z_stitching/tests/test_stitching_window.py +7 -2
- tomwer/gui/utils/buttons.py +53 -35
- tomwer/gui/utils/flow.py +2 -2
- tomwer/gui/utils/loadingmode.py +1 -1
- tomwer/gui/utils/unitsystem.py +44 -33
- tomwer/gui/utils/vignettes.py +1 -1
- tomwer/gui/visualization/dataviewer.py +7 -7
- tomwer/gui/visualization/diffviewer/diffviewer.py +4 -4
- tomwer/gui/visualization/diffviewer/shiftwidget.py +4 -6
- tomwer/gui/visualization/reconstructionparameters.py +35 -23
- tomwer/gui/visualization/scanoverview.py +28 -11
- tomwer/gui/visualization/test/test_nx_tomo_metadata_viewer.py +25 -13
- tomwer/gui/visualization/test/test_reconstruction_parameters.py +2 -2
- tomwer/model/dataset.py +0 -0
- tomwer/synctools/utils/scanstages.py +3 -3
- tomwer/tasks/reconstruction/cleardarkflat.py +42 -0
- tomwer/tests/app/test_stitching.py +1 -1
- tomwer/tests/orangecontrib/tomwer/widgets/edit/tests/test_nxtomo_editor.py +32 -20
- tomwer/tests/orangecontrib/tomwer/widgets/reconstruction/tests/test_nabu_widget.py +1 -1
- tomwer/version.py +3 -3
- {tomwer-1.4.19.dist-info → tomwer-1.5.2rc0.dist-info}/METADATA +8 -8
- {tomwer-1.4.19.dist-info → tomwer-1.5.2rc0.dist-info}/RECORD +123 -121
- {tomwer-1.4.19.dist-info → tomwer-1.5.2rc0.dist-info}/WHEEL +1 -1
- {tomwer-1.4.19.dist-info → tomwer-1.5.2rc0.dist-info}/entry_points.txt +0 -0
- {tomwer-1.4.19.dist-info → tomwer-1.5.2rc0.dist-info}/licenses/LICENSE +0 -0
- {tomwer-1.4.19.dist-info → tomwer-1.5.2rc0.dist-info}/top_level.txt +0 -0
@@ -1,5 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import pint
|
3
4
|
from nabu.stitching.config import StitchingType
|
4
5
|
from silx.gui import qt
|
5
6
|
from silx.gui.utils import blockSignals
|
@@ -11,6 +12,8 @@ from tomwer.gui.utils.qt_utils import block_signals
|
|
11
12
|
from tomwer.gui.stitching.metadataholder import QStitchingMetadata
|
12
13
|
from tomwer.gui.utils.unitsystem import MetricEntry, PixelEntry
|
13
14
|
|
15
|
+
_ureg = pint.get_application_registry()
|
16
|
+
|
14
17
|
|
15
18
|
class _AxisPositionGroup(qt.QGroupBox):
|
16
19
|
sigUpdate = qt.Signal()
|
@@ -26,13 +29,18 @@ class _AxisPositionGroup(qt.QGroupBox):
|
|
26
29
|
|
27
30
|
# pixel size
|
28
31
|
self._pixelSizeRaw = MetricEntry(
|
29
|
-
value="unknown",
|
32
|
+
value="unknown",
|
33
|
+
name="pixel size",
|
34
|
+
parent=self,
|
35
|
+
default_unit=_ureg.millimeter,
|
30
36
|
)
|
31
37
|
self._pixelSizeRaw.setReadOnly(True)
|
32
38
|
self.layout().addWidget(self._pixelSizeRaw, 0, 0, 1, 2)
|
33
39
|
self._overridePixelSizeCB = qt.QCheckBox("overwrite", self)
|
34
40
|
self.layout().addWidget(self._overridePixelSizeCB, 0, 2, 1, 1)
|
35
|
-
self._pixelSizeOverride = MetricEntry(
|
41
|
+
self._pixelSizeOverride = MetricEntry(
|
42
|
+
name="", parent=self, default_unit=_ureg.millimeter
|
43
|
+
)
|
36
44
|
self.layout().addWidget(self._pixelSizeOverride, 0, 3, 1, 2)
|
37
45
|
|
38
46
|
# raw position (in meter or millimeter)
|
@@ -40,14 +48,14 @@ class _AxisPositionGroup(qt.QGroupBox):
|
|
40
48
|
value="unknown",
|
41
49
|
name=f"axis {axis} position (metric unit)",
|
42
50
|
parent=self,
|
43
|
-
default_unit=
|
51
|
+
default_unit=_ureg.millimeter,
|
44
52
|
)
|
45
53
|
self._rawPositionMetric.setReadOnly(True)
|
46
54
|
self.layout().addWidget(self._rawPositionMetric, 1, 0, 1, 2)
|
47
55
|
self._overrideMetricPositionCB = qt.QCheckBox("overwrite", self)
|
48
56
|
self.layout().addWidget(self._overrideMetricPositionCB, 1, 2, 1, 1)
|
49
57
|
self._metricPositionOverride = MetricEntry(
|
50
|
-
name="", parent=self, default_unit=
|
58
|
+
name="", parent=self, default_unit=_ureg.millimeter
|
51
59
|
)
|
52
60
|
self.layout().addWidget(self._metricPositionOverride, 1, 3, 1, 2)
|
53
61
|
|
@@ -110,9 +118,10 @@ class _AxisPositionGroup(qt.QGroupBox):
|
|
110
118
|
self._stitching_metadata.setPixelOrVoxelSize(
|
111
119
|
value=self.getOverrridePixelSize(), axis=self.axis
|
112
120
|
)
|
113
|
-
self.
|
114
|
-
|
115
|
-
|
121
|
+
metric_quantity = self.getOverrrideMetricPosition()
|
122
|
+
if isinstance(metric_quantity, pint.Quantity):
|
123
|
+
metric_quantity = metric_quantity.to_base_units().magnitude
|
124
|
+
self._stitching_metadata.setMetricPos(metric_quantity, axis=self.axis)
|
116
125
|
self._stitching_metadata.setPxPos(
|
117
126
|
self.getOverrridePxPosition(), axis=self.axis
|
118
127
|
)
|
@@ -133,7 +142,6 @@ class _AxisPositionGroup(qt.QGroupBox):
|
|
133
142
|
position_m = self.get_final_metric_position()
|
134
143
|
if position_m is None:
|
135
144
|
return None
|
136
|
-
|
137
145
|
position_px = int(position_m / pixel_size_m)
|
138
146
|
self._rawPxPosition.setValue(position_px)
|
139
147
|
|
@@ -189,9 +197,9 @@ class _AxisPositionGroup(qt.QGroupBox):
|
|
189
197
|
with blockSignals(*self._editingWidgets):
|
190
198
|
# handle pixel size
|
191
199
|
if self.axis == 0:
|
192
|
-
pixel_size = tomo_obj.
|
200
|
+
pixel_size = tomo_obj.sample_y_pixel_size
|
193
201
|
else:
|
194
|
-
pixel_size = tomo_obj.
|
202
|
+
pixel_size = tomo_obj.sample_x_pixel_size
|
195
203
|
if pixel_size is not None:
|
196
204
|
self.setRawPixelSize(pixel_size)
|
197
205
|
override_pixel_size = stitching_metadata._pixel_or_voxel_size[self.axis]
|
@@ -257,7 +265,7 @@ class _AxisPositionGroup(qt.QGroupBox):
|
|
257
265
|
self._overridePxPosition.setValue(position_px)
|
258
266
|
self._overridePxPosition.valueChanged.emit()
|
259
267
|
|
260
|
-
def getOverrrideMetricPosition(self):
|
268
|
+
def getOverrrideMetricPosition(self) -> pint.Quantity:
|
261
269
|
if self._overrideMetricPositionCB.isChecked():
|
262
270
|
return self._metricPositionOverride.getValue()
|
263
271
|
else:
|
@@ -274,7 +282,7 @@ class _AxisPositionGroup(qt.QGroupBox):
|
|
274
282
|
def getRawMetricPosition(self):
|
275
283
|
return self._rawPositionMetric.getValue()
|
276
284
|
|
277
|
-
def setRawMetricPosition(self, position_m, displayed_unit=
|
285
|
+
def setRawMetricPosition(self, position_m, displayed_unit=_ureg.millimeter):
|
278
286
|
self._rawPositionMetric.setValue(
|
279
287
|
value_m=position_m, displayed_unit=displayed_unit
|
280
288
|
)
|
@@ -351,7 +359,7 @@ class TomoObjectPositionInfos(qt.QWidget):
|
|
351
359
|
self._axis_2_pos.setStitchingMetadata(metadata)
|
352
360
|
|
353
361
|
def updateStitchingType(self, stitching_type: StitchingType):
|
354
|
-
stitching_type = StitchingType
|
362
|
+
stitching_type = StitchingType(stitching_type)
|
355
363
|
if stitching_type is StitchingType.Z_POSTPROC:
|
356
364
|
pixel_or_voxel_label = "voxel size"
|
357
365
|
elif stitching_type is StitchingType.Z_PREPROC:
|
@@ -23,13 +23,13 @@ class NormalizationBySampleGroupBox(qt.QGroupBox):
|
|
23
23
|
|
24
24
|
# method
|
25
25
|
self._methodCB = qt.QComboBox(self)
|
26
|
-
self._methodCB.addItems(_SampleNormalizationMethod
|
26
|
+
self._methodCB.addItems([item.value for item in _SampleNormalizationMethod])
|
27
27
|
self._methodCB.setCurrentText(_SampleNormalizationMethod.MEDIAN.value)
|
28
28
|
self.layout().addRow("method", self._methodCB)
|
29
29
|
|
30
30
|
# side
|
31
31
|
self._sideCB = qt.QComboBox(self)
|
32
|
-
self._sideCB.addItems(_SampleSide
|
32
|
+
self._sideCB.addItems([item.value for item in _SampleSide])
|
33
33
|
self._sideCB.setCurrentText(_SampleSide.LEFT.value)
|
34
34
|
self.layout().addRow("sampling side", self._sideCB)
|
35
35
|
|
@@ -57,17 +57,17 @@ class NormalizationBySampleGroupBox(qt.QGroupBox):
|
|
57
57
|
self.sigConfigChanged.emit()
|
58
58
|
|
59
59
|
def getMethod(self) -> _SampleNormalizationMethod:
|
60
|
-
return _SampleNormalizationMethod
|
60
|
+
return _SampleNormalizationMethod(self._methodCB.currentText())
|
61
61
|
|
62
62
|
def setMethod(self, method: _SampleNormalizationMethod | str):
|
63
|
-
method = _SampleNormalizationMethod
|
63
|
+
method = _SampleNormalizationMethod(method)
|
64
64
|
self._methodCB.setCurrentText(method.value)
|
65
65
|
|
66
66
|
def getSide(self) -> _SampleSide:
|
67
|
-
return _SampleSide
|
67
|
+
return _SampleSide(self._sideCB.currentText())
|
68
68
|
|
69
69
|
def setSide(self, side: _SampleSide):
|
70
|
-
side = _SampleSide
|
70
|
+
side = _SampleSide(side)
|
71
71
|
self._sideCB.setCurrentText(side.value)
|
72
72
|
|
73
73
|
def getMargin(self) -> int:
|
@@ -1,4 +1,8 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
|
1
4
|
import os
|
5
|
+
import pint
|
2
6
|
import tempfile
|
3
7
|
|
4
8
|
from tomoscan.series import Series
|
@@ -8,6 +12,9 @@ from tomwer.gui.stitching.tests.utils import create_scans_z_series
|
|
8
12
|
from tomwer.tests.conftest import qtapp # noqa F401
|
9
13
|
|
10
14
|
|
15
|
+
_ureg = pint.get_application_registry()
|
16
|
+
|
17
|
+
|
11
18
|
def test_ZStitchingWindow(
|
12
19
|
qtapp, # noqa F811
|
13
20
|
tmp_path,
|
@@ -34,7 +41,7 @@ def test_ZStitchingWindow(
|
|
34
41
|
z_positions_m=axis_0_positions,
|
35
42
|
x_positions_m=axis_2_positions,
|
36
43
|
shifts=((0.0, 0.0), (-90.0, 0.0), (-180.0, 0.0)),
|
37
|
-
|
44
|
+
sample_pixel_size=pixel_size,
|
38
45
|
raw_frame_width=280,
|
39
46
|
final_frame_width=100,
|
40
47
|
)
|
@@ -1,5 +1,7 @@
|
|
1
|
-
import
|
1
|
+
from __future__ import annotations
|
2
2
|
|
3
|
+
import os
|
4
|
+
import pint
|
3
5
|
import numpy
|
4
6
|
import pytest
|
5
7
|
from nabu.stitching.config import PreProcessedZStitchingConfiguration
|
@@ -11,13 +13,15 @@ from silx.image.phantomgenerator import PhantomGenerator
|
|
11
13
|
from tomwer.gui.stitching.stitching_preview import PreviewStitchingPlot
|
12
14
|
from tomwer.gui.stitching.tests.utils import create_scans_z_series
|
13
15
|
|
16
|
+
_ureg = pint.get_application_registry()
|
17
|
+
|
14
18
|
|
15
19
|
@pytest.mark.parametrize("flip_lr", (True, False))
|
16
20
|
@pytest.mark.parametrize("flip_ud", (True, False))
|
17
21
|
def test_preview(tmp_path, flip_lr, flip_ud, qtapp): # noqa F401
|
18
22
|
axis_0_positions = (90, 0.0, -90.0)
|
19
23
|
axis_2_positions = (0.0, 0.0, 0.0)
|
20
|
-
|
24
|
+
sample_pixel_size = 1.0
|
21
25
|
|
22
26
|
output_file_path = os.path.join(str(tmp_path), "output", "stitched.nx")
|
23
27
|
input_dir = os.path.join(tmp_path, "input")
|
@@ -27,7 +31,7 @@ def test_preview(tmp_path, flip_lr, flip_ud, qtapp): # noqa F401
|
|
27
31
|
z_positions_m=axis_0_positions,
|
28
32
|
x_positions_m=axis_2_positions,
|
29
33
|
shifts=((0.0, 0.0), (-90.0, 0.0), (-180.0, 0.0)),
|
30
|
-
|
34
|
+
sample_pixel_size=sample_pixel_size,
|
31
35
|
raw_frame_width=280,
|
32
36
|
final_frame_width=100,
|
33
37
|
flip_lr=flip_lr,
|
@@ -38,16 +42,15 @@ def test_preview(tmp_path, flip_lr, flip_ud, qtapp): # noqa F401
|
|
38
42
|
output_data_path="entry_stitched",
|
39
43
|
overwrite_results=True,
|
40
44
|
slurm_config=None,
|
41
|
-
axis_0_pos_mm=numpy.array(axis_0_positions)
|
42
|
-
axis_2_pos_mm=numpy.array(axis_2_positions)
|
45
|
+
axis_0_pos_mm=numpy.array(axis_0_positions) * 1000,
|
46
|
+
axis_2_pos_mm=numpy.array(axis_2_positions) * 1000,
|
43
47
|
axis_0_pos_px=None,
|
44
48
|
axis_1_pos_px=None,
|
45
49
|
axis_2_pos_px=None,
|
46
50
|
input_scans=scans,
|
47
|
-
pixel_size=
|
51
|
+
pixel_size=sample_pixel_size,
|
48
52
|
)
|
49
53
|
widget = PreviewStitchingPlot(axis=0)
|
50
|
-
|
51
54
|
widget._backGroundAction.toggle()
|
52
55
|
|
53
56
|
stitcher = PreProcessZStitcher(configuration=stitching_config)
|
@@ -1,4 +1,7 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import os
|
4
|
+
import pint
|
2
5
|
|
3
6
|
import numpy
|
4
7
|
from nxtomo.application.nxtomo import NXtomo
|
@@ -9,15 +12,17 @@ from nxtomo.nxobject.nxdetector import ImageKey
|
|
9
12
|
from tomwer.core.scan.nxtomoscan import NXtomoScan
|
10
13
|
from nxtomo.utils.transformation import DetYFlipTransformation, DetZFlipTransformation
|
11
14
|
|
15
|
+
_ureg = pint.get_application_registry()
|
16
|
+
|
12
17
|
|
13
18
|
def create_scans_z_series(
|
14
19
|
output_dir,
|
15
|
-
z_positions_m,
|
16
|
-
x_positions_m=None,
|
17
|
-
|
18
|
-
n_proj=20,
|
19
|
-
raw_frame_width=100,
|
20
|
-
final_frame_width=100,
|
20
|
+
z_positions_m: tuple[float | None] | None,
|
21
|
+
x_positions_m: tuple[float | None] | None = None,
|
22
|
+
sample_pixel_size: float | tuple[float, float] = 10.0e6,
|
23
|
+
n_proj: int = 20,
|
24
|
+
raw_frame_width: int = 100,
|
25
|
+
final_frame_width: int = 100,
|
21
26
|
shifts=None,
|
22
27
|
z_rois=None,
|
23
28
|
flip_lr: bool = False,
|
@@ -44,22 +49,26 @@ def create_scans_z_series(
|
|
44
49
|
):
|
45
50
|
nx_tomo = NXtomo()
|
46
51
|
if z_pos is not None:
|
47
|
-
nx_tomo.sample.z_translation = [z_pos] * n_proj
|
52
|
+
nx_tomo.sample.z_translation = ([z_pos] * n_proj) * _ureg.meter
|
48
53
|
if x_pos is not None:
|
49
|
-
nx_tomo.sample.x_translation = [x_pos] * n_proj
|
50
|
-
nx_tomo.sample.rotation_angle =
|
51
|
-
0, 180, num=n_proj, endpoint=False
|
54
|
+
nx_tomo.sample.x_translation = ([x_pos] * n_proj) * _ureg.meter
|
55
|
+
nx_tomo.sample.rotation_angle = (
|
56
|
+
numpy.linspace(0, 180, num=n_proj, endpoint=False) * _ureg.degree
|
52
57
|
)
|
53
58
|
nx_tomo.instrument.detector.image_key_control = [ImageKey.PROJECTION] * n_proj
|
54
|
-
|
55
|
-
|
56
|
-
|
59
|
+
# sample pixel size
|
60
|
+
if sample_pixel_size is not None:
|
61
|
+
if isinstance(sample_pixel_size, (tuple, list)):
|
62
|
+
sample_y_pix_size, sample_x_pix_size = sample_pixel_size
|
57
63
|
else:
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
64
|
+
sample_y_pix_size, sample_x_pix_size = (
|
65
|
+
sample_pixel_size,
|
66
|
+
sample_pixel_size,
|
67
|
+
)
|
68
|
+
nx_tomo.sample.x_pixel_size = sample_x_pix_size * _ureg.meter
|
69
|
+
nx_tomo.sample.y_pixel_size = sample_y_pix_size * _ureg.meter
|
70
|
+
nx_tomo.instrument.detector.distance = 2.3 * _ureg.meter
|
71
|
+
nx_tomo.energy = 19.2 * _ureg.keV
|
63
72
|
nx_tomo.instrument.detector.transformations.add_transformation(
|
64
73
|
DetYFlipTransformation(flip=flip_ud)
|
65
74
|
)
|
@@ -25,8 +25,8 @@ class Axis_N_Params(qt.QGroupBox):
|
|
25
25
|
|
26
26
|
# img registration method
|
27
27
|
self._imageRegMethodCB = qt.QComboBox(self)
|
28
|
-
for method in _NabuShiftAlgorithm
|
29
|
-
self._imageRegMethodCB.addItem(method)
|
28
|
+
for method in _NabuShiftAlgorithm:
|
29
|
+
self._imageRegMethodCB.addItem(method.value)
|
30
30
|
self._imageRegMethodCB.setToolTip(
|
31
31
|
"method to use in order to affine positions provided by the user"
|
32
32
|
)
|
@@ -36,12 +36,10 @@ class Axis_N_Params(qt.QGroupBox):
|
|
36
36
|
self._imageRegMethodCB.setCurrentText(_NabuShiftAlgorithm.NONE.value)
|
37
37
|
|
38
38
|
def getCurrentMethod(self):
|
39
|
-
return _NabuShiftAlgorithm
|
39
|
+
return _NabuShiftAlgorithm(self._imageRegMethodCB.currentText())
|
40
40
|
|
41
41
|
def setCurrentMethod(self, method):
|
42
|
-
self._imageRegMethodCB.setCurrentText(
|
43
|
-
_NabuShiftAlgorithm.from_value(method).value
|
44
|
-
)
|
42
|
+
self._imageRegMethodCB.setCurrentText(_NabuShiftAlgorithm(method).value)
|
45
43
|
|
46
44
|
def getOptsLine(self) -> str:
|
47
45
|
current_method = self.getCurrentMethod()
|
@@ -86,8 +84,8 @@ class AutoRefineWidget(qt.QWidget):
|
|
86
84
|
|
87
85
|
# stitching strategy
|
88
86
|
self._stitchingStrategyCG = qt.QComboBox(parent=self)
|
89
|
-
for strategy in OverlapStitchingStrategy
|
90
|
-
self._stitchingStrategyCG.addItem(strategy)
|
87
|
+
for strategy in OverlapStitchingStrategy:
|
88
|
+
self._stitchingStrategyCG.addItem(strategy.value)
|
91
89
|
self._globalOpts.layout().addRow(
|
92
90
|
"stitching strategy", self._stitchingStrategyCG
|
93
91
|
)
|
@@ -135,7 +133,7 @@ class AutoRefineWidget(qt.QWidget):
|
|
135
133
|
raise NotImplementedError
|
136
134
|
|
137
135
|
def updateStitchingType(self, mode: StitchingType):
|
138
|
-
mode = StitchingType
|
136
|
+
mode = StitchingType(mode)
|
139
137
|
self._preProcGroup.setVisible(mode is StitchingType.Z_PREPROC)
|
140
138
|
self._postProcGroup.setVisible(mode is StitchingType.Z_POSTPROC)
|
141
139
|
|
@@ -1,6 +1,10 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import os
|
2
4
|
import shutil
|
3
5
|
import tempfile
|
6
|
+
import pint
|
7
|
+
import numpy
|
4
8
|
|
5
9
|
from silx.gui import qt
|
6
10
|
from silx.gui.utils.testutils import TestCaseQt
|
@@ -11,6 +15,8 @@ from tomwer.gui.stitching.tests.utils import create_scans_z_series
|
|
11
15
|
from tomwer.gui.stitching.config.tomoobjdetails import TomoObjectPositionInfos
|
12
16
|
from tomwer.gui.stitching.axisorderedlist import AxisOrderedTomoObjsModel
|
13
17
|
|
18
|
+
_ureg = pint.get_application_registry()
|
19
|
+
|
14
20
|
|
15
21
|
class TestTomoObjectPositionInfos(TestCaseQt):
|
16
22
|
"""
|
@@ -26,14 +32,19 @@ class TestTomoObjectPositionInfos(TestCaseQt):
|
|
26
32
|
self._tmp_path,
|
27
33
|
z_positions_m=(0.200, 0.205, 0.210),
|
28
34
|
x_positions_m=(0.0, 0.0, None),
|
29
|
-
|
35
|
+
sample_pixel_size=(self._y_pixel_size, self._x_pixel_size),
|
30
36
|
raw_frame_width=100,
|
31
37
|
)
|
32
38
|
self.scan_0_metadata = QStitchingMetadata(tomo_obj=self.scans[0])
|
33
|
-
|
39
|
+
numpy.testing.assert_almost_equal(
|
40
|
+
self.scan_0_metadata.get_raw_position_m(axis=0), 0.20
|
41
|
+
)
|
42
|
+
|
34
43
|
assert self.scan_0_metadata.get_raw_position_m(axis=2) == 0.0
|
35
44
|
self.scan_2_metadata = QStitchingMetadata(tomo_obj=self.scans[2])
|
36
|
-
|
45
|
+
numpy.testing.assert_almost_equal(
|
46
|
+
self.scan_2_metadata.get_raw_position_m(axis=0), 0.21
|
47
|
+
)
|
37
48
|
self._widget = TomoObjectPositionInfos()
|
38
49
|
|
39
50
|
def tearDown(self):
|
@@ -59,7 +70,7 @@ class TestTomoObjectPositionInfos(TestCaseQt):
|
|
59
70
|
# test editing some parameters from the GUI. Make sure GUI is updated as the underlying metadata object
|
60
71
|
self._widget._axis_0_pos._overrideMetricPositionCB.setChecked(True)
|
61
72
|
self._widget._axis_0_pos.setRawMetricPosition(
|
62
|
-
position_m=0.4, displayed_unit=
|
73
|
+
position_m=0.4, displayed_unit=_ureg.nanometer
|
63
74
|
)
|
64
75
|
while self.qapp.hasPendingEvents():
|
65
76
|
self.qapp.processEvents()
|
@@ -85,19 +96,19 @@ class TestAxisOrderedTomoObjsModel(TestCaseQt):
|
|
85
96
|
self.scans_with_pos_and_pixel_size = create_scans_z_series(
|
86
97
|
os.path.join(self._tmp_path, "case1"),
|
87
98
|
z_positions_m=(0.200, 0.205, 0.210),
|
88
|
-
|
99
|
+
sample_pixel_size=0.001,
|
89
100
|
raw_frame_width=100,
|
90
101
|
)
|
91
102
|
self.scans_with_pixel_size = create_scans_z_series(
|
92
103
|
os.path.join(self._tmp_path, "case2"),
|
93
104
|
z_positions_m=(None, None, None),
|
94
|
-
|
105
|
+
sample_pixel_size=0.001,
|
95
106
|
raw_frame_width=100,
|
96
107
|
)
|
97
108
|
self.scans_without_metadata = create_scans_z_series(
|
98
109
|
os.path.join(self._tmp_path, "case3"),
|
99
110
|
z_positions_m=(None, None, None),
|
100
|
-
|
111
|
+
sample_pixel_size=None,
|
101
112
|
raw_frame_width=100,
|
102
113
|
)
|
103
114
|
self._widget = qt.QTableView()
|
@@ -1,6 +1,9 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import os
|
2
4
|
import shutil
|
3
5
|
import tempfile
|
6
|
+
import pint
|
4
7
|
|
5
8
|
from silx.gui import qt
|
6
9
|
from silx.gui.utils.testutils import TestCaseQt
|
@@ -9,6 +12,9 @@ from tomwer.gui.stitching.tests.utils import create_scans_z_series
|
|
9
12
|
from tomwer.gui.stitching.StitchingWindow import ZStitchingWindow
|
10
13
|
|
11
14
|
|
15
|
+
_ureg = pint.get_application_registry()
|
16
|
+
|
17
|
+
|
12
18
|
class TestZStichingWindow(TestCaseQt):
|
13
19
|
"""
|
14
20
|
Test high level z stitching definition
|
@@ -20,7 +26,7 @@ class TestZStichingWindow(TestCaseQt):
|
|
20
26
|
self.scans = create_scans_z_series(
|
21
27
|
os.path.join(self._tmp_path, "case1"),
|
22
28
|
z_positions_m=(0.200, 0.205, 0.210),
|
23
|
-
|
29
|
+
sample_pixel_size=0.001,
|
24
30
|
raw_frame_width=100,
|
25
31
|
)
|
26
32
|
|
@@ -45,7 +51,6 @@ class TestZStichingWindow(TestCaseQt):
|
|
45
51
|
self._widget.show()
|
46
52
|
# fill the widget with scans
|
47
53
|
|
48
|
-
scan_0, scan_1, scan_2 = self.scans
|
49
54
|
for scan in self.scans:
|
50
55
|
self._widget.addTomoObj(scan)
|
51
56
|
# note: add the sigChanged to the z ordered list 'update z' slot
|
tomwer/gui/utils/buttons.py
CHANGED
@@ -4,6 +4,7 @@ Button of general usage.
|
|
4
4
|
|
5
5
|
from __future__ import annotations
|
6
6
|
|
7
|
+
import pint
|
7
8
|
import numpy
|
8
9
|
import logging
|
9
10
|
from silx.gui import qt
|
@@ -12,11 +13,11 @@ from silx.gui.plot.items.roi import LineROI
|
|
12
13
|
from silx.gui.plot.PlotToolButtons import PlotToolButton
|
13
14
|
|
14
15
|
from tomwer.gui import icons
|
15
|
-
from pyunitsystem.metricsystem import MetricSystem
|
16
|
-
|
17
16
|
|
18
17
|
_logger = logging.getLogger(__file__)
|
19
18
|
|
19
|
+
_ureg = pint.get_application_registry()
|
20
|
+
|
20
21
|
|
21
22
|
class PadlockButton(qt.QPushButton):
|
22
23
|
"""Simple button to define a button with PadLock icons"""
|
@@ -87,40 +88,11 @@ class TabBrowsersButtons(qt.QWidget):
|
|
87
88
|
class TapeMeasureToolButton(PlotToolButton):
|
88
89
|
"""Button to active measurement between two point of the plot"""
|
89
90
|
|
90
|
-
class TapeMeasureROI(LineROI):
|
91
|
-
def __init__(self, parent=None, pixel_size_m=None):
|
92
|
-
super().__init__(parent)
|
93
|
-
self._pixel_size_m = None
|
94
|
-
self.setPixelSize(pixel_size_m)
|
95
|
-
|
96
|
-
def setEndPoints(self, startPoint, endPoint):
|
97
|
-
distance_px = numpy.linalg.norm(endPoint - startPoint)
|
98
|
-
super().setEndPoints(startPoint=startPoint, endPoint=endPoint)
|
99
|
-
if self._pixel_size_m is None:
|
100
|
-
self._updateText(f"{distance_px :.1f}px")
|
101
|
-
else:
|
102
|
-
distance_m = distance_px * self._pixel_size_m
|
103
|
-
value, unit = MetricSystem.cast_metric_to_best_unit(distance_m)
|
104
|
-
self._updateText(f"{distance_px :.1f}px ({value:.2f}{unit})")
|
105
|
-
|
106
|
-
def setPixelSize(self, pixel_size_m: tuple | float | None):
|
107
|
-
if isinstance(pixel_size_m, (tuple, list)):
|
108
|
-
assert (
|
109
|
-
len(pixel_size_m) == 2
|
110
|
-
), "expects at most two pixel size values (x and y values)"
|
111
|
-
if not numpy.isclose(pixel_size_m[0], pixel_size_m[1]):
|
112
|
-
value, unit = MetricSystem.cast_metric_to_best_unit(pixel_size_m[0])
|
113
|
-
_logger.warning(
|
114
|
-
f"TapeMeasure is only handling square pixels for now. Will consider the pixel is {value:.2f}{unit}x{value:.2f}{unit}"
|
115
|
-
)
|
116
|
-
pixel_size_m = pixel_size_m[0]
|
117
|
-
self._pixel_size_m = pixel_size_m
|
118
|
-
|
119
91
|
def __init__(self, parent=None, plot=None, pixel_size_mm=None):
|
120
92
|
super().__init__(parent=parent, plot=plot)
|
121
93
|
self._roiManager = None
|
122
94
|
self._lastRoiCreated = None
|
123
|
-
self.
|
95
|
+
self._pixel_size_m = pixel_size_mm
|
124
96
|
self.setIcon(icons.getQIcon("ruler"))
|
125
97
|
self.setToolTip("measure distance between two pixels")
|
126
98
|
self.toggled.connect(self._callback)
|
@@ -130,7 +102,7 @@ class TapeMeasureToolButton(PlotToolButton):
|
|
130
102
|
return super().setPlot(plot)
|
131
103
|
|
132
104
|
def setPixelSize(self, pixel_size_m: tuple | float | None):
|
133
|
-
self.
|
105
|
+
self._pixel_size_m = pixel_size_m
|
134
106
|
|
135
107
|
def _callback(self, toggled):
|
136
108
|
if not self._roiManager:
|
@@ -179,8 +151,54 @@ class TapeMeasureToolButton(PlotToolButton):
|
|
179
151
|
def _registerCurrentROI(self, currentRoi):
|
180
152
|
if self._lastRoiCreated is None:
|
181
153
|
self._lastRoiCreated = currentRoi
|
182
|
-
self._lastRoiCreated.setPixelSize(self.
|
154
|
+
self._lastRoiCreated.setPixelSize(self._pixel_size_m)
|
183
155
|
elif currentRoi != self._lastRoiCreated and self._roiManager is not None:
|
184
156
|
self._roiManager.removeRoi(self._lastRoiCreated)
|
185
157
|
self._lastRoiCreated = currentRoi
|
186
|
-
self._lastRoiCreated.setPixelSize(self.
|
158
|
+
self._lastRoiCreated.setPixelSize(self._pixel_size_m)
|
159
|
+
|
160
|
+
|
161
|
+
class TapeMeasureROI(LineROI):
|
162
|
+
"""ROI dedicated to tape measure"""
|
163
|
+
|
164
|
+
def __init__(self, parent=None, pixel_size_m=None):
|
165
|
+
super().__init__(parent)
|
166
|
+
self._pixel_size_m = None
|
167
|
+
self.setPixelSize(pixel_size_m)
|
168
|
+
|
169
|
+
def setEndPoints(self, startPoint, endPoint):
|
170
|
+
distance_px = numpy.linalg.norm(endPoint - startPoint)
|
171
|
+
super().setEndPoints(startPoint=startPoint, endPoint=endPoint)
|
172
|
+
if self._pixel_size_m is None:
|
173
|
+
self._updateText(f"{distance_px :.1f}px")
|
174
|
+
else:
|
175
|
+
distance_m = distance_px * self._pixel_size_m
|
176
|
+
value = self.cast_metric_to_best_unit(distance_m)
|
177
|
+
self._updateText(f"{distance_px :.1f}px ({value:~})")
|
178
|
+
|
179
|
+
def setPixelSize(self, pixel_size_m: tuple | float | None):
|
180
|
+
if isinstance(pixel_size_m, (tuple, list)):
|
181
|
+
assert (
|
182
|
+
len(pixel_size_m) == 2
|
183
|
+
), "expects at most two pixel size values (x and y values)"
|
184
|
+
if not numpy.isclose(pixel_size_m[0], pixel_size_m[1]):
|
185
|
+
value = self.cast_metric_to_best_unit(pixel_size_m[0])
|
186
|
+
_logger.warning(
|
187
|
+
f"TapeMeasure is only handling square pixels for now. Will consider the pixel is {value:~}{value:~}"
|
188
|
+
)
|
189
|
+
pixel_size_m = pixel_size_m[0]
|
190
|
+
self._pixel_size_m = pixel_size_m
|
191
|
+
|
192
|
+
@staticmethod
|
193
|
+
def cast_metric_to_best_unit(value: pint.Quantity) -> pint.Quantity:
|
194
|
+
value = value.to_base_units()
|
195
|
+
if value < (1.0 * _ureg.micrometer):
|
196
|
+
return value.to(_ureg.nanometer)
|
197
|
+
elif value < (0.1 * _ureg.millimeter): # prefer mm to um
|
198
|
+
return value.to(_ureg.micrometer)
|
199
|
+
elif value < (1.0 * _ureg.centimeter):
|
200
|
+
return value.to(_ureg.millimeter)
|
201
|
+
elif value < (1.0 * _ureg.meter):
|
202
|
+
return value.to(_ureg.centimeter)
|
203
|
+
else:
|
204
|
+
return value.to(_ureg.meter)
|
tomwer/gui/utils/flow.py
CHANGED
@@ -4,7 +4,7 @@ import functools
|
|
4
4
|
from typing import Iterable
|
5
5
|
|
6
6
|
from silx.gui import qt
|
7
|
-
from
|
7
|
+
from enum import Enum as _Enum
|
8
8
|
|
9
9
|
from tomwer.gui import icons
|
10
10
|
from tomwer.utils import docstring
|
@@ -178,7 +178,7 @@ class FlowCanvas(qt.QWidget):
|
|
178
178
|
self, parent, direction: str | FlowDirection, show_lock_state=True
|
179
179
|
) -> None:
|
180
180
|
qt.QWidget.__init__(self, parent=parent)
|
181
|
-
self._direction = FlowDirection
|
181
|
+
self._direction = FlowDirection(direction)
|
182
182
|
if self._direction is FlowDirection.HORIZONTAL:
|
183
183
|
layout = qt.QHBoxLayout()
|
184
184
|
elif self._direction is FlowDirection.VERTICAL:
|