darfix 4.2.0__py3-none-any.whl → 4.3.0__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.
- darfix/core/data_selection.py +11 -2
- darfix/core/dataset.py +72 -157
- darfix/core/grainplot.py +44 -56
- darfix/core/{imageStack.py → image_stack.py} +9 -15
- darfix/core/moment_types.py +6 -0
- darfix/core/{noiseremoval.py → noise_removal.py} +25 -24
- darfix/core/noise_removal_type.py +14 -0
- darfix/core/positioners.py +6 -0
- darfix/core/rocking_curves.py +6 -3
- darfix/core/rocking_curves_map.py +1 -1
- darfix/core/{shiftcorrection.py → shift_correction.py} +1 -2
- darfix/core/state_of_operation.py +7 -46
- darfix/core/utils.py +0 -39
- darfix/dtypes.py +1 -9
- darfix/gui/{binningWidget.py → binning_widget.py} +2 -29
- darfix/gui/{blindSourceSeparationWidget.py → blind_source_separation_widget.py} +4 -16
- darfix/gui/{chooseDimensions.py → choose_dimensions.py} +1 -1
- darfix/gui/concatenate_scans.py +4 -4
- darfix/gui/data_selection/{hdf5_data_selection_widgets.py → hdf5_dataset_selection_widget.py} +3 -56
- darfix/gui/data_selection/line_edits.py +54 -8
- darfix/gui/data_selection/scan_selection_widgets.py +24 -11
- darfix/gui/data_selection/utils.py +11 -0
- darfix/gui/data_selection/{WorkingDirSelectionWidget.py → working_dir_selection_widget.py} +15 -14
- darfix/gui/{dimensionsWidget.py → dimensions_widget.py} +1 -1
- darfix/gui/{displayComponentsWidget.py → display_components_widget.py} +1 -1
- darfix/gui/{filterByDimension.py → filter_by_dimension.py} +1 -1
- darfix/gui/{grainplot/dimensionRangeSlider2D.py → grain_plot/dimension_range_slider_2d.py} +2 -2
- darfix/gui/{grainplot/grainPlotWidget.py → grain_plot/grain_plot_widget.py} +1 -1
- darfix/gui/{grainplot/mosaicityWidget.py → grain_plot/mosaicity_widget.py} +21 -23
- darfix/gui/{magnificationWidget.py → magnification_widget.py} +1 -1
- darfix/gui/{noiseremoval → noise_removal}/noise_removal_widget.py +12 -16
- darfix/gui/{noiseremoval → noise_removal}/operation_list_widget.py +2 -2
- darfix/gui/{noiseremoval → noise_removal}/parameters_widget.py +6 -6
- darfix/gui/{PCAWidget.py → pca_widget.py} +2 -4
- darfix/gui/{projectionWidget.py → projection_widget.py} +1 -1
- darfix/gui/rocking_curves/{rockingCurvesPlot.py → rocking_curves_plot.py} +13 -13
- darfix/gui/rocking_curves/{rockingCurvesWidget.py → rocking_curves_widget.py} +10 -18
- darfix/gui/{roiSelectionWidget.py → roi_selection_widget.py} +9 -101
- darfix/gui/{shiftcorrection/shiftCorrectionWidget.py → shift_correction/shift_correction_widget.py} +4 -7
- darfix/gui/utils/data_path_completer.py +7 -7
- darfix/gui/utils/data_path_selection.py +4 -4
- darfix/gui/utils/{rangeSlider.py → range_slider.py} +1 -1
- darfix/gui/{weakBeamWidget.py → weak_beam_widget.py} +13 -28
- darfix/gui/{zSumWidget.py → zsum_widget.py} +1 -2
- darfix/main.py +19 -3
- darfix/processing/rocking_curves.py +12 -13
- darfix/tasks/binning.py +6 -17
- darfix/tasks/blind_source_separation.py +121 -0
- darfix/tasks/blindsourceseparation.py +8 -131
- darfix/tasks/copy.py +0 -2
- darfix/tasks/data_partition.py +39 -0
- darfix/tasks/datapartition.py +8 -50
- darfix/tasks/dimension_definition.py +197 -0
- darfix/tasks/dimensiondefinition.py +8 -197
- darfix/tasks/grain_plot.py +93 -0
- darfix/tasks/grainplot.py +8 -103
- darfix/tasks/hdf5_data_selection.py +5 -11
- darfix/tasks/hdf5_scans_concatenation.py +4 -4
- darfix/tasks/noise_removal.py +88 -0
- darfix/tasks/noiseremoval.py +8 -86
- darfix/tasks/pca.py +1 -3
- darfix/tasks/projection.py +1 -6
- darfix/tasks/rocking_curves.py +10 -5
- darfix/tasks/roi.py +0 -2
- darfix/tasks/shift_correction.py +45 -0
- darfix/tasks/shiftcorrection.py +8 -43
- darfix/tasks/transformation.py +0 -2
- darfix/tasks/weak_beam.py +71 -0
- darfix/tasks/weakbeam.py +8 -67
- darfix/tasks/zsum.py +1 -1
- darfix/tests/conftest.py +1 -1
- darfix/tests/gui/test_data_path_completer.py +4 -4
- darfix/tests/gui/test_dimension_range_slider_2d.py +2 -2
- darfix/tests/gui/test_range_slider_with_spinboxes.py +1 -1
- darfix/tests/orange/test_ewoks.py +13 -9
- darfix/tests/orange/widgets/test_hdf5_data_selection.py +93 -0
- darfix/tests/tasks/test_data_copy.py +0 -2
- darfix/tests/tasks/{test_dimensiondefinition.py → test_dimension_definition.py} +1 -1
- darfix/tests/tasks/test_weak_beam.py +9 -0
- darfix/tests/test_components_matching.py +2 -2
- darfix/tests/test_dataset.py +2 -28
- darfix/tests/test_dimension.py +1 -1
- darfix/tests/test_generate_grain_maps_nxdict.py +4 -5
- darfix/tests/test_image_operations.py +4 -4
- darfix/tests/test_image_registration.py +17 -17
- darfix/tests/test_image_stack.py +2 -13
- darfix/tests/test_mask.py +1 -1
- darfix/tests/test_moments.py +2 -2
- darfix/tests/test_rocking_curves.py +1 -3
- darfix/tests/test_shift.py +7 -7
- darfix/tests/test_workflow.py +4 -4
- darfix/tests/test_zsum.py +3 -6
- {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/METADATA +5 -3
- {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/RECORD +141 -135
- orangecontrib/darfix/widgets/__init__.py +10 -1
- orangecontrib/darfix/widgets/binning.py +3 -3
- orangecontrib/darfix/widgets/blindsourceseparation.py +4 -6
- orangecontrib/darfix/widgets/concatenateHDF5.py +1 -1
- orangecontrib/darfix/widgets/datacopy.py +1 -1
- orangecontrib/darfix/widgets/datapartition.py +7 -102
- orangecontrib/darfix/widgets/{datasetWidgetBase.py → dataset_widget_base.py} +17 -5
- orangecontrib/darfix/widgets/dimensions.py +6 -6
- orangecontrib/darfix/widgets/grainplot.py +3 -3
- orangecontrib/darfix/widgets/hdf5dataselection.py +34 -14
- orangecontrib/darfix/widgets/metadata.py +2 -2
- orangecontrib/darfix/widgets/noiseremoval.py +4 -4
- orangecontrib/darfix/widgets/{operationWidgetBase.py → operation_widget_base.py} +2 -2
- orangecontrib/darfix/widgets/pca.py +2 -2
- orangecontrib/darfix/widgets/projection.py +2 -2
- orangecontrib/darfix/widgets/rockingcurves.py +5 -2
- orangecontrib/darfix/widgets/roiselection.py +24 -106
- orangecontrib/darfix/widgets/rsmhistogram.py +2 -2
- orangecontrib/darfix/widgets/shiftcorrection.py +3 -3
- orangecontrib/darfix/widgets/transformation.py +4 -4
- orangecontrib/darfix/widgets/weakbeam.py +20 -103
- orangecontrib/darfix/widgets/zsum.py +3 -5
- darfix/gui/dataPartitionWidget.py +0 -167
- darfix/gui/data_selection/DataSelectionBase.py +0 -59
- darfix/tests/tasks/test_datapartition.py +0 -52
- /darfix/core/{componentsMatching.py → components_matching.py} +0 -0
- /darfix/core/{datapathfinder.py → data_path_finder.py} +0 -0
- /darfix/core/{imageRegistration.py → image_registration.py} +0 -0
- /darfix/gui/{grainplot → grain_plot}/__init__.py +0 -0
- /darfix/gui/{grainplot → grain_plot}/_oridist_toolbar_buttons.py +0 -0
- /darfix/gui/{grainplot → grain_plot}/flashlight.py +0 -0
- /darfix/gui/{grainplot → grain_plot}/flashlight_mode_action.py +0 -0
- /darfix/gui/{grainplot → grain_plot}/oridist_toolbar.py +0 -0
- /darfix/gui/{grainplot → grain_plot}/utils.py +0 -0
- /darfix/gui/{metadataWidget.py → metadata_widget.py} +0 -0
- /darfix/gui/{operationProcess.py → parallel/operation_process.py} +0 -0
- /darfix/gui/{operationThread.py → parallel/operation_thread.py} +0 -0
- /darfix/gui/rocking_curves/{fitComboBox.py → fit_combobox.py} +0 -0
- /darfix/gui/{roiLimitsToolbar.py → roi_limits_toolbar.py} +0 -0
- /darfix/gui/{rsmHistogramWidget.py → rsm_histogram_widget.py} +0 -0
- /darfix/gui/{rsmWidget.py → rsm_widget.py} +0 -0
- /darfix/gui/{shiftcorrection → shift_correction}/__init__.py +0 -0
- /darfix/gui/{shiftcorrection/shiftInput.py → shift_correction/shift_input.py} +0 -0
- /darfix/gui/utils/{standardButtonBox.py → standard_buttonbox.py} +0 -0
- /darfix/processing/{imageOperations.py → image_operations.py} +0 -0
- /darfix/tests/{test_datapathfinder.py → test_data_path_finder.py} +0 -0
- {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/WHEEL +0 -0
- {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/entry_points.txt +0 -0
- {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/licenses/LICENSE +0 -0
- {darfix-4.2.0.dist-info → darfix-4.3.0.dist-info}/top_level.txt +0 -0
darfix/core/grainplot.py
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import warnings
|
|
3
4
|
from dataclasses import dataclass
|
|
4
5
|
from enum import Enum
|
|
5
6
|
from typing import Any
|
|
6
|
-
from typing import Dict
|
|
7
7
|
from typing import Tuple
|
|
8
8
|
|
|
9
|
+
import colorstamps
|
|
9
10
|
import numpy
|
|
10
|
-
from matplotlib.colors import hsv_to_rgb
|
|
11
11
|
from silx.math.medianfilter import medfilt2d
|
|
12
12
|
|
|
13
13
|
from darfix.core.dimension import AcquisitionDims
|
|
@@ -16,19 +16,16 @@ from darfix.io.utils import create_nxdata_dict
|
|
|
16
16
|
|
|
17
17
|
from ..dtypes import AxisType
|
|
18
18
|
from ..dtypes import Dataset
|
|
19
|
+
from .moment_types import MomentsPerDimension
|
|
19
20
|
from .moment_types import MomentType
|
|
20
|
-
from .utils import compute_hsv
|
|
21
21
|
|
|
22
22
|
DimensionRange = Tuple[float, float]
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
DimensionMoments = Dict[MomentType, numpy.ndarray]
|
|
26
|
-
|
|
27
|
-
|
|
28
25
|
@dataclass
|
|
29
26
|
class GrainPlotMaps:
|
|
30
27
|
dims: AcquisitionDims
|
|
31
|
-
moments_dims:
|
|
28
|
+
moments_dims: MomentsPerDimension
|
|
32
29
|
zsum: numpy.ndarray
|
|
33
30
|
transformation: numpy.ndarray
|
|
34
31
|
title: str
|
|
@@ -50,7 +47,7 @@ class GrainPlotMaps:
|
|
|
50
47
|
)
|
|
51
48
|
|
|
52
49
|
|
|
53
|
-
class
|
|
50
|
+
class GrainPlotData:
|
|
54
51
|
KEY_IMAGE_SIZE = 1000
|
|
55
52
|
|
|
56
53
|
def __init__(
|
|
@@ -61,27 +58,30 @@ class OrientationDistData:
|
|
|
61
58
|
x_dimension_range: DimensionRange,
|
|
62
59
|
y_dimension_range: DimensionRange,
|
|
63
60
|
zsum: numpy.ndarray | None = None,
|
|
61
|
+
colormap_name: str = "hsv",
|
|
62
|
+
sat: int = 40,
|
|
64
63
|
) -> None:
|
|
65
64
|
"""
|
|
66
65
|
Store data for orientation distribution RGB layer (the HSV colormap) and data (Histogram 2D)
|
|
67
66
|
|
|
68
67
|
:param zsum: Precomputed dataset.zsum() used as the weight of the histogram 2D . If None dataset.zsum() is called.
|
|
68
|
+
|
|
69
|
+
:param colormap_name: See https://colorstamps.readthedocs.io/en/latest/index.html#quick-reference
|
|
70
|
+
|
|
71
|
+
:param sat: See https://colorstamps.readthedocs.io/en/latest/stamps.html#colorstamps.stamps.get_cmap
|
|
69
72
|
"""
|
|
70
73
|
|
|
71
74
|
if len(grain_plot_maps.moments_dims) == 0:
|
|
72
75
|
raise ValueError("Moments should be computed before.")
|
|
73
76
|
|
|
74
|
-
com_x = grain_plot_maps.moments_dims[x_dimension][MomentType.COM]
|
|
75
|
-
com_y = grain_plot_maps.moments_dims[y_dimension][MomentType.COM]
|
|
77
|
+
com_x = grain_plot_maps.moments_dims[x_dimension][MomentType.COM]
|
|
78
|
+
com_y = grain_plot_maps.moments_dims[y_dimension][MomentType.COM]
|
|
76
79
|
|
|
77
80
|
self.x_range = x_dimension_range
|
|
78
81
|
self.y_range = y_dimension_range
|
|
79
82
|
|
|
80
83
|
if zsum is None:
|
|
81
84
|
zsum = grain_plot_maps.zsum
|
|
82
|
-
zsum = zsum.ravel()
|
|
83
|
-
else:
|
|
84
|
-
zsum = zsum.ravel()
|
|
85
85
|
|
|
86
86
|
# automatic bins
|
|
87
87
|
# In darfix<=3.x orientation distribution shape was the size of the dimension
|
|
@@ -92,16 +92,11 @@ class OrientationDistData:
|
|
|
92
92
|
self.x_label = grain_plot_maps.dims.get(x_dimension).name
|
|
93
93
|
self.y_label = grain_plot_maps.dims.get(y_dimension).name
|
|
94
94
|
|
|
95
|
-
x_data = numpy.linspace(-1, 1, self.KEY_IMAGE_SIZE)
|
|
96
|
-
y_data = numpy.linspace(-1, 1, self.KEY_IMAGE_SIZE)
|
|
97
|
-
x_mesh, y_mesh = numpy.meshgrid(x_data, y_data)
|
|
98
|
-
self.rgb_key = hsv_to_rgb(compute_hsv(x_mesh, y_mesh))
|
|
99
|
-
|
|
100
95
|
# Histogram in 2D
|
|
101
96
|
histogram, _, _ = numpy.histogram2d(
|
|
102
|
-
com_y,
|
|
103
|
-
com_x, # note: y first is in purpose : see numpy.histogram2d documentation
|
|
104
|
-
weights=zsum, # We need to take into account pixel intensity
|
|
97
|
+
com_y.ravel(),
|
|
98
|
+
com_x.ravel(), # note: y first is in purpose : see numpy.histogram2d documentation
|
|
99
|
+
weights=zsum.ravel(), # We need to take into account pixel intensity
|
|
105
100
|
bins=[self.y_bins, self.x_bins],
|
|
106
101
|
range=[self.y_range, self.x_range],
|
|
107
102
|
)
|
|
@@ -109,6 +104,28 @@ class OrientationDistData:
|
|
|
109
104
|
"""Orientation distribution data as an histogram 2D of the center of mass in two dimensions"""
|
|
110
105
|
self.smooth_data = medfilt2d(numpy.ascontiguousarray(self.data))
|
|
111
106
|
""" `self.data` filtered with a median filter 2D"""
|
|
107
|
+
with warnings.catch_warnings():
|
|
108
|
+
warnings.simplefilter("ignore", RuntimeWarning) # Ignore nan values warning
|
|
109
|
+
self.mosaicity, stamp = colorstamps.apply_stamp(
|
|
110
|
+
com_y,
|
|
111
|
+
com_x,
|
|
112
|
+
colormap_name,
|
|
113
|
+
vmin_0=self.y_range[0],
|
|
114
|
+
vmax_0=self.y_range[1],
|
|
115
|
+
vmin_1=self.x_range[0],
|
|
116
|
+
vmax_1=self.x_range[1],
|
|
117
|
+
sat=sat,
|
|
118
|
+
clip="none",
|
|
119
|
+
l=self.KEY_IMAGE_SIZE,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Display pixel with null intensity as black
|
|
123
|
+
self.mosaicity[zsum == 0] = 0, 0, 0
|
|
124
|
+
|
|
125
|
+
# Display out of range pixel as grey
|
|
126
|
+
self.mosaicity[numpy.isnan(self.mosaicity)] = 0.2
|
|
127
|
+
|
|
128
|
+
self.rgb_key = stamp.cmap
|
|
112
129
|
|
|
113
130
|
def x_data_values(self) -> numpy.ndarray:
|
|
114
131
|
return numpy.linspace(
|
|
@@ -194,34 +211,6 @@ def get_axes(transformation: Transformation | None) -> tuple[
|
|
|
194
211
|
return axes, axes_names, axes_long_names
|
|
195
212
|
|
|
196
213
|
|
|
197
|
-
def compute_normalized_component(
|
|
198
|
-
component: numpy.ndarray, dimension_range: DimensionRange
|
|
199
|
-
):
|
|
200
|
-
|
|
201
|
-
min_component = dimension_range[0]
|
|
202
|
-
max_component = dimension_range[1]
|
|
203
|
-
|
|
204
|
-
return 2 * (component - min_component) / (max_component - min_component) - 1
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
def compute_mosaicity(
|
|
208
|
-
moments: dict[int, numpy.ndarray],
|
|
209
|
-
x_dimension: int,
|
|
210
|
-
y_dimension: int,
|
|
211
|
-
x_dimension_range: DimensionRange,
|
|
212
|
-
y_dimension_range: DimensionRange,
|
|
213
|
-
):
|
|
214
|
-
norm_center_of_mass_x = compute_normalized_component(
|
|
215
|
-
moments[x_dimension][MomentType.COM],
|
|
216
|
-
dimension_range=x_dimension_range,
|
|
217
|
-
)
|
|
218
|
-
norm_center_of_mass_y = compute_normalized_component(
|
|
219
|
-
moments[y_dimension][MomentType.COM],
|
|
220
|
-
dimension_range=y_dimension_range,
|
|
221
|
-
)
|
|
222
|
-
return hsv_to_rgb(compute_hsv(norm_center_of_mass_x, norm_center_of_mass_y))
|
|
223
|
-
|
|
224
|
-
|
|
225
214
|
def create_moment_nxdata_groups(
|
|
226
215
|
parent: dict[str, Any],
|
|
227
216
|
moment_data: numpy.ndarray,
|
|
@@ -243,8 +232,7 @@ def create_moment_nxdata_groups(
|
|
|
243
232
|
|
|
244
233
|
def generate_grain_maps_nxdict(
|
|
245
234
|
grainPlotMaps: GrainPlotMaps,
|
|
246
|
-
|
|
247
|
-
orientation_dist_image: OrientationDistData | None,
|
|
235
|
+
orientation_dist_image: GrainPlotData | None,
|
|
248
236
|
) -> dict:
|
|
249
237
|
moments = grainPlotMaps.moments_dims
|
|
250
238
|
axes, axes_names, axes_long_names = get_axes(grainPlotMaps.transformation)
|
|
@@ -255,9 +243,10 @@ def generate_grain_maps_nxdict(
|
|
|
255
243
|
"@default": "entry",
|
|
256
244
|
}
|
|
257
245
|
|
|
258
|
-
if
|
|
246
|
+
if orientation_dist_image is not None:
|
|
247
|
+
|
|
259
248
|
nx["entry"][MultiDimMomentType.MOSAICITY.value] = create_nxdata_dict(
|
|
260
|
-
mosaicity,
|
|
249
|
+
orientation_dist_image.mosaicity,
|
|
261
250
|
MultiDimMomentType.MOSAICITY.value,
|
|
262
251
|
axes,
|
|
263
252
|
axes_names,
|
|
@@ -265,10 +254,7 @@ def generate_grain_maps_nxdict(
|
|
|
265
254
|
rgba=True,
|
|
266
255
|
)
|
|
267
256
|
nx["entry"]["@default"] = MultiDimMomentType.MOSAICITY.value
|
|
268
|
-
else:
|
|
269
|
-
nx["entry"]["@default"] = MomentType.COM.value
|
|
270
257
|
|
|
271
|
-
if orientation_dist_image is not None:
|
|
272
258
|
nx["entry"][MultiDimMomentType.ORIENTATION_DIST.value] = {
|
|
273
259
|
"key": create_nxdata_dict(
|
|
274
260
|
orientation_dist_image.rgb_key,
|
|
@@ -291,6 +277,8 @@ def generate_grain_maps_nxdict(
|
|
|
291
277
|
),
|
|
292
278
|
"@default": "data",
|
|
293
279
|
}
|
|
280
|
+
else:
|
|
281
|
+
nx["entry"]["@default"] = MomentType.COM.value
|
|
294
282
|
|
|
295
283
|
if grainPlotMaps.dims.ndim <= 1:
|
|
296
284
|
create_moment_nxdata_groups(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import warnings
|
|
3
4
|
from typing import NamedTuple
|
|
4
5
|
from typing import Sequence
|
|
5
6
|
|
|
@@ -75,17 +76,11 @@ class ImageStack:
|
|
|
75
76
|
def data(self) -> numpy.ndarray:
|
|
76
77
|
return self._data
|
|
77
78
|
|
|
78
|
-
def as_array3d(self
|
|
79
|
-
|
|
80
|
-
indices = Ellipsis
|
|
81
|
-
return self._data.reshape((self.nframes,) + self.frame_shape)[indices]
|
|
79
|
+
def as_array3d(self) -> numpy.ndarray:
|
|
80
|
+
return self._data.reshape((-1,) + self.frame_shape)
|
|
82
81
|
|
|
83
|
-
def as_array2d(self
|
|
84
|
-
|
|
85
|
-
indices = Ellipsis
|
|
86
|
-
return self._data.reshape((self.nframes, self.data.size // self.nframes))[
|
|
87
|
-
indices
|
|
88
|
-
]
|
|
82
|
+
def as_array2d(self) -> numpy.ndarray:
|
|
83
|
+
return self._data.reshape((self.nframes, -1))
|
|
89
84
|
|
|
90
85
|
def filter_indices(
|
|
91
86
|
self,
|
|
@@ -95,6 +90,8 @@ class ImageStack:
|
|
|
95
90
|
"""
|
|
96
91
|
:return selected_indices: a list of indices filtered by input `indices` and optionally filtered with one fixed dimension `fixed_dimension`. If inputs are None return the full range of indices.
|
|
97
92
|
"""
|
|
93
|
+
warnings.warn("`filter_indices` method is deprecated", DeprecationWarning)
|
|
94
|
+
|
|
98
95
|
if fixed_dimension is not None and not isinstance(
|
|
99
96
|
fixed_dimension, FixedDimension
|
|
100
97
|
):
|
|
@@ -122,7 +119,6 @@ class ImageStack:
|
|
|
122
119
|
|
|
123
120
|
def get_filtered_data(
|
|
124
121
|
self,
|
|
125
|
-
indices: numpy.ndarray | None = None,
|
|
126
122
|
fixed_dimension: FixedDimension | None = None,
|
|
127
123
|
):
|
|
128
124
|
"""
|
|
@@ -131,8 +127,6 @@ class ImageStack:
|
|
|
131
127
|
:warning: if `fixed_dimension` is not None, this method duplicate the fitered part of the dataset.
|
|
132
128
|
"""
|
|
133
129
|
if fixed_dimension is None:
|
|
134
|
-
return self.as_array3d(
|
|
130
|
+
return self.as_array3d()
|
|
135
131
|
|
|
136
|
-
return self.as_array3d()[
|
|
137
|
-
self.filter_indices(indices=indices, fixed_dimension=fixed_dimension)
|
|
138
|
-
]
|
|
132
|
+
return self.as_array3d()[self.filter_indices(fixed_dimension=fixed_dimension)]
|
darfix/core/moment_types.py
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from enum import Enum
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
import numpy
|
|
4
7
|
|
|
5
8
|
|
|
6
9
|
class MomentType(Enum):
|
|
@@ -8,3 +11,6 @@ class MomentType(Enum):
|
|
|
8
11
|
FWHM = "FWHM"
|
|
9
12
|
SKEWNESS = "Skewness"
|
|
10
13
|
KURTOSIS = "Kurtosis"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
MomentsPerDimension = Dict[int, Dict[MomentType, numpy.ndarray]]
|
|
@@ -13,34 +13,33 @@ from tqdm import tqdm
|
|
|
13
13
|
from darfix.core.utils import OperationAborted
|
|
14
14
|
|
|
15
15
|
from ..dtypes import Dataset
|
|
16
|
-
from ..processing import
|
|
17
|
-
from .
|
|
16
|
+
from ..processing import image_operations
|
|
17
|
+
from .noise_removal_type import NoiseRemovalType
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
class BackgroundType(_Enum):
|
|
21
21
|
DATA = "Data"
|
|
22
|
-
UNUSED_DATA = "Unused data (after partition)"
|
|
23
22
|
DARK_DATA = "Dark data"
|
|
24
23
|
|
|
25
24
|
|
|
26
25
|
class NoiseRemovalOperation(TypedDict):
|
|
27
|
-
type:
|
|
26
|
+
type: NoiseRemovalType
|
|
28
27
|
parameters: dict[str, Any]
|
|
29
28
|
|
|
30
29
|
|
|
31
30
|
def operation_to_str(op: NoiseRemovalOperation) -> str:
|
|
32
31
|
result = None
|
|
33
32
|
op_type = op["type"]
|
|
34
|
-
if op_type is
|
|
33
|
+
if op_type is NoiseRemovalType.BS:
|
|
35
34
|
result = f"Background subtraction {op['parameters']}"
|
|
36
35
|
|
|
37
|
-
elif op_type is
|
|
36
|
+
elif op_type is NoiseRemovalType.HP:
|
|
38
37
|
result = f"Hot pixel removal: {op['parameters']}"
|
|
39
38
|
|
|
40
|
-
elif op_type is
|
|
39
|
+
elif op_type is NoiseRemovalType.THRESHOLD:
|
|
41
40
|
result = f"Threshold removal: {op['parameters']}"
|
|
42
41
|
|
|
43
|
-
elif op_type is
|
|
42
|
+
elif op_type is NoiseRemovalType.MASK:
|
|
44
43
|
result = "Mask removal"
|
|
45
44
|
else:
|
|
46
45
|
raise ValueError(f"Unknown operation type {op_type}")
|
|
@@ -48,7 +47,11 @@ def operation_to_str(op: NoiseRemovalOperation) -> str:
|
|
|
48
47
|
|
|
49
48
|
|
|
50
49
|
def clean_operation_dict(op: NoiseRemovalOperation) -> dict:
|
|
51
|
-
"""Just keep `type` and `parameters` in the saved dict"""
|
|
50
|
+
"""Just keep `type` and `parameters` in the saved dict. Transform numpy array into list."""
|
|
51
|
+
parameters = op["parameters"]
|
|
52
|
+
for key, value in parameters.items():
|
|
53
|
+
if isinstance(value, numpy.ndarray):
|
|
54
|
+
parameters[key] = value.tolist()
|
|
52
55
|
return {
|
|
53
56
|
"type": op["type"],
|
|
54
57
|
"parameters": op["parameters"],
|
|
@@ -58,29 +61,29 @@ def clean_operation_dict(op: NoiseRemovalOperation) -> dict:
|
|
|
58
61
|
def apply_noise_removal_operation(
|
|
59
62
|
image: numpy.ndarray, operation: NoiseRemovalOperation
|
|
60
63
|
) -> None:
|
|
61
|
-
if operation["type"] is
|
|
64
|
+
if operation["type"] is NoiseRemovalType.BS:
|
|
62
65
|
apply_background_substraction(image, operation["background"])
|
|
63
66
|
|
|
64
|
-
if operation["type"] is
|
|
67
|
+
if operation["type"] is NoiseRemovalType.HP:
|
|
65
68
|
apply_hot_pixel_removal(image, **operation["parameters"])
|
|
66
69
|
|
|
67
|
-
if operation["type"] is
|
|
70
|
+
if operation["type"] is NoiseRemovalType.THRESHOLD:
|
|
68
71
|
apply_threshold_removal(image, **operation["parameters"])
|
|
69
72
|
|
|
70
|
-
if operation["type"] is
|
|
73
|
+
if operation["type"] is NoiseRemovalType.MASK:
|
|
71
74
|
apply_mask_removal(image, **operation["parameters"])
|
|
72
75
|
|
|
73
76
|
|
|
74
77
|
def add_background_data_into_operation(
|
|
75
78
|
dataset: Dataset,
|
|
76
79
|
operation: NoiseRemovalOperation,
|
|
77
|
-
) ->
|
|
78
|
-
"""Compute a background image and
|
|
80
|
+
) -> None:
|
|
81
|
+
"""Compute a background image and add it into `operation["background"]`"""
|
|
79
82
|
|
|
80
|
-
if operation["type"] is not
|
|
83
|
+
if operation["type"] is not NoiseRemovalType.BS:
|
|
81
84
|
raise ValueError("Operation type should be `Operation.BS`")
|
|
82
85
|
|
|
83
|
-
method = operation["parameters"].get("method",
|
|
86
|
+
method = operation["parameters"].get("method", image_operations.Method.MEDIAN)
|
|
84
87
|
|
|
85
88
|
background_type = BackgroundType(
|
|
86
89
|
operation["parameters"].get("background_type", BackgroundType.DATA.value)
|
|
@@ -88,8 +91,6 @@ def add_background_data_into_operation(
|
|
|
88
91
|
|
|
89
92
|
if background_type is BackgroundType.DARK_DATA:
|
|
90
93
|
bg = dataset.bg_dataset.as_array3d()
|
|
91
|
-
elif background_type is BackgroundType.UNUSED_DATA:
|
|
92
|
-
bg = dataset.dataset.as_array3d(dataset.bg_indices)
|
|
93
94
|
elif background_type is BackgroundType.DATA:
|
|
94
95
|
bg = dataset.dataset.as_array3d()
|
|
95
96
|
else:
|
|
@@ -97,13 +98,13 @@ def add_background_data_into_operation(
|
|
|
97
98
|
f"Background type {background_type!r} not implemented yet."
|
|
98
99
|
)
|
|
99
100
|
|
|
100
|
-
operation["background"] =
|
|
101
|
+
operation["background"] = image_operations.compute_background(bg, method)
|
|
101
102
|
|
|
102
103
|
|
|
103
104
|
def apply_background_substraction(
|
|
104
105
|
image: numpy.ndarray, background: numpy.ndarray
|
|
105
106
|
) -> None:
|
|
106
|
-
|
|
107
|
+
image_operations.background_subtraction(image, background)
|
|
107
108
|
|
|
108
109
|
|
|
109
110
|
def apply_hot_pixel_removal(
|
|
@@ -112,19 +113,19 @@ def apply_hot_pixel_removal(
|
|
|
112
113
|
if kernel_size is None:
|
|
113
114
|
kernel_size = 3
|
|
114
115
|
|
|
115
|
-
|
|
116
|
+
image_operations.hot_pixel_removal(image, ksize=kernel_size)
|
|
116
117
|
|
|
117
118
|
|
|
118
119
|
def apply_threshold_removal(
|
|
119
120
|
image: numpy.ndarray, bottom: int | None = None, top: int | None = None
|
|
120
121
|
) -> None:
|
|
121
|
-
|
|
122
|
+
image_operations.threshold_removal(image, bottom=bottom, top=top)
|
|
122
123
|
|
|
123
124
|
|
|
124
125
|
def apply_mask_removal(image: numpy.ndarray, mask: numpy.ndarray | None) -> None:
|
|
125
126
|
if mask is None:
|
|
126
127
|
return
|
|
127
|
-
|
|
128
|
+
image_operations.mask_removal(image, numpy.asarray(mask, dtype=bool))
|
|
128
129
|
|
|
129
130
|
|
|
130
131
|
def apply_noise_removal_operations(
|
darfix/core/positioners.py
CHANGED
|
@@ -38,6 +38,12 @@ class Positioners:
|
|
|
38
38
|
else:
|
|
39
39
|
self.load()
|
|
40
40
|
|
|
41
|
+
def filter_by_indices(self, indices: numpy.ndarray) -> Positioners:
|
|
42
|
+
new_positioners = Positioners(self._url, dict(**self._data))
|
|
43
|
+
for positioner_name, positioner_data in self._data.items():
|
|
44
|
+
new_positioners._data[positioner_name] = positioner_data[indices]
|
|
45
|
+
return new_positioners
|
|
46
|
+
|
|
41
47
|
def all(self):
|
|
42
48
|
"""
|
|
43
49
|
Merge constants and data in the same dict
|
darfix/core/rocking_curves.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from threading import Event
|
|
3
4
|
from typing import Sequence
|
|
4
5
|
|
|
5
6
|
import numpy
|
|
@@ -48,6 +49,7 @@ def fit_rocking_curve_parallel(
|
|
|
48
49
|
motor_values: Sequence[numpy.ndarray] | numpy.ndarray,
|
|
49
50
|
thresh: float | None,
|
|
50
51
|
method: FitMethod | None,
|
|
52
|
+
abort_event: Event = Event(),
|
|
51
53
|
) -> tuple[numpy.ndarray, numpy.ndarray]:
|
|
52
54
|
"""
|
|
53
55
|
Fit the rocking curves using multiprocessing.
|
|
@@ -95,6 +97,8 @@ def fit_rocking_curve_parallel(
|
|
|
95
97
|
i = idx % data.shape[2]
|
|
96
98
|
output_data[:, j, i] = y_gauss
|
|
97
99
|
maps[:, j, i] = maps_ji
|
|
100
|
+
if abort_event.is_set():
|
|
101
|
+
break
|
|
98
102
|
|
|
99
103
|
return output_data, maps
|
|
100
104
|
|
|
@@ -155,13 +159,12 @@ def generate_rocking_curves_nxdict(
|
|
|
155
159
|
def compute_residuals(
|
|
156
160
|
target_dataset, # ImageDataset. Cannot type due to circular import
|
|
157
161
|
original_dataset, # ImageDataset. Cannot type due to circular import
|
|
158
|
-
indices: numpy.ndarray | None,
|
|
159
162
|
):
|
|
160
163
|
return numpy.sqrt(
|
|
161
164
|
(
|
|
162
165
|
numpy.subtract(
|
|
163
|
-
target_dataset.as_array3d(
|
|
164
|
-
original_dataset.as_array3d(
|
|
166
|
+
target_dataset.as_array3d(),
|
|
167
|
+
original_dataset.as_array3d(),
|
|
165
168
|
)
|
|
166
169
|
** 2
|
|
167
170
|
).sum(axis=(0))
|
|
@@ -1,48 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
import warnings
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
from enum import IntEnum
|
|
5
|
-
from typing import Optional
|
|
3
|
+
from darfix.core.noise_removal_type import NoiseRemovalType
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
class
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
PARTITION = 0
|
|
14
|
-
BS = 1
|
|
15
|
-
HP = 2
|
|
16
|
-
THRESHOLD = 3
|
|
17
|
-
SHIFT = 4
|
|
18
|
-
ROI = 5
|
|
19
|
-
MOMENTS = 6
|
|
20
|
-
FIT = 7
|
|
21
|
-
BINNING = 8
|
|
22
|
-
MASK = 9
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class StateOfOperations:
|
|
26
|
-
def __init__(self):
|
|
27
|
-
self._is_running = [False] * len(Operation)
|
|
28
|
-
|
|
29
|
-
def _start(self, operation: Optional[Operation]) -> None:
|
|
30
|
-
if operation is None:
|
|
31
|
-
return
|
|
32
|
-
self._is_running[operation] = True
|
|
33
|
-
|
|
34
|
-
def stop(self, operation: Optional[Operation]) -> None:
|
|
35
|
-
if operation is None:
|
|
36
|
-
return
|
|
37
|
-
self._is_running[operation] = False
|
|
38
|
-
|
|
39
|
-
@contextmanager
|
|
40
|
-
def run_context(self, operation: Optional[Operation]):
|
|
41
|
-
self._start(operation)
|
|
42
|
-
try:
|
|
43
|
-
yield
|
|
44
|
-
finally:
|
|
45
|
-
self.stop(operation)
|
|
46
|
-
|
|
47
|
-
def is_running(self, operation: Operation) -> bool:
|
|
48
|
-
return self._is_running[operation]
|
|
5
|
+
warnings.warn(
|
|
6
|
+
"Use of `Operation` class is deprecated and is only kept for backward compatibility with .ows file from Darfix < 4.3.",
|
|
7
|
+
DeprecationWarning,
|
|
8
|
+
)
|
|
9
|
+
Operation = NoiseRemovalType
|
darfix/core/utils.py
CHANGED
|
@@ -29,42 +29,3 @@ class TooManyDimensionsForRockingCurvesError(ValueError):
|
|
|
29
29
|
super().__init__(
|
|
30
30
|
"Unsupported number of dimensions. Rocking curves only support 1D, 2D or 3D datasets."
|
|
31
31
|
)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def wrapTo2pi(x):
|
|
35
|
-
"""
|
|
36
|
-
Python implementation of Matlab method `wrapTo2pi`.
|
|
37
|
-
Wraps angles in x, in radians, to the interval [0, 2*pi] such that 0 maps
|
|
38
|
-
to 0 and 2*pi maps to 2*pi. In general, positive multiples of 2*pi map to
|
|
39
|
-
2*pi and negative multiples of 2*pi map to 0.
|
|
40
|
-
"""
|
|
41
|
-
xwrap = numpy.remainder(x - numpy.pi, TWO_PI)
|
|
42
|
-
mask = numpy.abs(xwrap) > numpy.pi
|
|
43
|
-
xwrap[mask] -= TWO_PI * numpy.sign(xwrap[mask])
|
|
44
|
-
return xwrap + numpy.pi
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def compute_hsv(x_data: numpy.ndarray, y_data: numpy.ndarray):
|
|
48
|
-
data = numpy.arctan2(-y_data, -x_data)
|
|
49
|
-
|
|
50
|
-
hue = wrapTo2pi(data) / TWO_PI
|
|
51
|
-
saturation = numpy.sqrt(numpy.power(x_data, 2) + numpy.power(y_data, 2)) / SQRT_2
|
|
52
|
-
value = numpy.ones_like(x_data)
|
|
53
|
-
|
|
54
|
-
# Display NaN values as black
|
|
55
|
-
value[numpy.isnan(data)] = 0
|
|
56
|
-
hue[numpy.isnan(data)] = 0
|
|
57
|
-
saturation[numpy.isnan(data)] = 0
|
|
58
|
-
|
|
59
|
-
# Display out of range as grey
|
|
60
|
-
value[saturation > 1.0] = 0.2
|
|
61
|
-
saturation[saturation > 1.0] = 1.0
|
|
62
|
-
|
|
63
|
-
return numpy.stack(
|
|
64
|
-
(
|
|
65
|
-
hue,
|
|
66
|
-
saturation,
|
|
67
|
-
value,
|
|
68
|
-
),
|
|
69
|
-
axis=2,
|
|
70
|
-
)
|
darfix/dtypes.py
CHANGED
|
@@ -7,8 +7,6 @@ from typing import Optional
|
|
|
7
7
|
from typing import Tuple
|
|
8
8
|
from typing import Union
|
|
9
9
|
|
|
10
|
-
import numpy
|
|
11
|
-
|
|
12
10
|
from darfix.core.dataset import ImageDataset
|
|
13
11
|
|
|
14
12
|
AxisAndValueIndices = Tuple[List[int], List[int]]
|
|
@@ -20,20 +18,14 @@ class Dataset:
|
|
|
20
18
|
def __init__(
|
|
21
19
|
self,
|
|
22
20
|
dataset: ImageDataset,
|
|
23
|
-
indices: Optional[numpy.ndarray] = None,
|
|
24
|
-
bg_indices: Optional[numpy.ndarray] = None,
|
|
25
21
|
bg_dataset: Optional[ImageDataset] = None,
|
|
26
22
|
):
|
|
27
|
-
"""Darfix dataset
|
|
23
|
+
"""Darfix dataset and background
|
|
28
24
|
|
|
29
25
|
:param dataset: Darfix dataset object that holds the image stack
|
|
30
|
-
:param indices: Image stack indices to be taking into account. Usually set by the 'partition data' task. Defaults to None.
|
|
31
|
-
:param bg_indices: Dark image stack indices to be taking into account. Usually set by the 'partition data' task. Defaults to None.
|
|
32
26
|
:param bg_dataset: Darfix dataset object that holds the dark image stack. Defaults to None.
|
|
33
27
|
"""
|
|
34
28
|
self.dataset = dataset
|
|
35
|
-
self.indices = indices
|
|
36
|
-
self.bg_indices = bg_indices
|
|
37
29
|
self.bg_dataset = bg_dataset
|
|
38
30
|
|
|
39
31
|
|