sigima 0.0.1.dev0__py3-none-any.whl → 1.0.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.
- sigima/__init__.py +142 -2
- sigima/client/__init__.py +105 -0
- sigima/client/base.py +780 -0
- sigima/client/remote.py +469 -0
- sigima/client/stub.py +814 -0
- sigima/client/utils.py +90 -0
- sigima/config.py +444 -0
- sigima/data/logo/Sigima.svg +135 -0
- sigima/data/tests/annotations.json +798 -0
- sigima/data/tests/curve_fitting/exponential_fit.txt +511 -0
- sigima/data/tests/curve_fitting/gaussian_fit.txt +100 -0
- sigima/data/tests/curve_fitting/piecewiseexponential_fit.txt +1022 -0
- sigima/data/tests/curve_fitting/polynomial_fit.txt +100 -0
- sigima/data/tests/curve_fitting/twohalfgaussian_fit.txt +1000 -0
- sigima/data/tests/curve_formats/bandwidth.txt +201 -0
- sigima/data/tests/curve_formats/boxcar.npy +0 -0
- sigima/data/tests/curve_formats/datetime.txt +1001 -0
- sigima/data/tests/curve_formats/dynamic_parameters.txt +4000 -0
- sigima/data/tests/curve_formats/fw1e2.txt +301 -0
- sigima/data/tests/curve_formats/fwhm.txt +319 -0
- sigima/data/tests/curve_formats/multiple_curves.csv +29 -0
- sigima/data/tests/curve_formats/noised_saw.mat +0 -0
- sigima/data/tests/curve_formats/oscilloscope.csv +111 -0
- sigima/data/tests/curve_formats/other/other2/recursive2.txt +5 -0
- sigima/data/tests/curve_formats/other/recursive1.txt +5 -0
- sigima/data/tests/curve_formats/paracetamol.npy +0 -0
- sigima/data/tests/curve_formats/paracetamol.txt +1010 -0
- sigima/data/tests/curve_formats/paracetamol_dx_dy.csv +1000 -0
- sigima/data/tests/curve_formats/paracetamol_dy.csv +1001 -0
- sigima/data/tests/curve_formats/pulse1.npy +0 -0
- sigima/data/tests/curve_formats/pulse2.npy +0 -0
- sigima/data/tests/curve_formats/simple.txt +5 -0
- sigima/data/tests/curve_formats/spectrum.mca +2139 -0
- sigima/data/tests/curve_formats/square2.npy +0 -0
- sigima/data/tests/curve_formats/step.npy +0 -0
- sigima/data/tests/fabry-perot1.jpg +0 -0
- sigima/data/tests/fabry-perot2.jpg +0 -0
- sigima/data/tests/flower.npy +0 -0
- sigima/data/tests/image_formats/NF 180338201.scor-data +11003 -0
- sigima/data/tests/image_formats/binary_image.npy +0 -0
- sigima/data/tests/image_formats/binary_image.png +0 -0
- sigima/data/tests/image_formats/centroid_test.npy +0 -0
- sigima/data/tests/image_formats/coordinated_text/complex_image.txt +10011 -0
- sigima/data/tests/image_formats/coordinated_text/complex_ref_image.txt +10010 -0
- sigima/data/tests/image_formats/coordinated_text/image.txt +15 -0
- sigima/data/tests/image_formats/coordinated_text/image2.txt +14 -0
- sigima/data/tests/image_formats/coordinated_text/image_no_unit_no_label.txt +14 -0
- sigima/data/tests/image_formats/coordinated_text/image_with_nan.txt +15 -0
- sigima/data/tests/image_formats/coordinated_text/image_with_unit.txt +14 -0
- sigima/data/tests/image_formats/fiber.csv +480 -0
- sigima/data/tests/image_formats/fiber.jpg +0 -0
- sigima/data/tests/image_formats/fiber.png +0 -0
- sigima/data/tests/image_formats/fiber.txt +480 -0
- sigima/data/tests/image_formats/gaussian_spot_with_noise.npy +0 -0
- sigima/data/tests/image_formats/mr-brain.dcm +0 -0
- sigima/data/tests/image_formats/noised_gaussian.mat +0 -0
- sigima/data/tests/image_formats/sif_reader/nd_lum_image_no_glue.sif +0 -0
- sigima/data/tests/image_formats/sif_reader/raman1.sif +0 -0
- sigima/data/tests/image_formats/tiling.txt +10 -0
- sigima/data/tests/image_formats/uint16.tiff +0 -0
- sigima/data/tests/image_formats/uint8.tiff +0 -0
- sigima/data/tests/laser_beam/TEM00_z_13.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_18.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_23.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_30.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_35.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_40.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_45.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_50.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_55.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_60.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_65.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_70.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_75.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_80.jpg +0 -0
- sigima/enums.py +195 -0
- sigima/io/__init__.py +123 -0
- sigima/io/base.py +311 -0
- sigima/io/common/__init__.py +5 -0
- sigima/io/common/basename.py +164 -0
- sigima/io/common/converters.py +189 -0
- sigima/io/common/objmeta.py +181 -0
- sigima/io/common/textreader.py +58 -0
- sigima/io/convenience.py +157 -0
- sigima/io/enums.py +17 -0
- sigima/io/ftlab.py +395 -0
- sigima/io/image/__init__.py +9 -0
- sigima/io/image/base.py +177 -0
- sigima/io/image/formats.py +1016 -0
- sigima/io/image/funcs.py +414 -0
- sigima/io/signal/__init__.py +9 -0
- sigima/io/signal/base.py +129 -0
- sigima/io/signal/formats.py +290 -0
- sigima/io/signal/funcs.py +723 -0
- sigima/objects/__init__.py +260 -0
- sigima/objects/base.py +937 -0
- sigima/objects/image/__init__.py +88 -0
- sigima/objects/image/creation.py +556 -0
- sigima/objects/image/object.py +524 -0
- sigima/objects/image/roi.py +904 -0
- sigima/objects/scalar/__init__.py +57 -0
- sigima/objects/scalar/common.py +215 -0
- sigima/objects/scalar/geometry.py +502 -0
- sigima/objects/scalar/table.py +784 -0
- sigima/objects/shape.py +290 -0
- sigima/objects/signal/__init__.py +133 -0
- sigima/objects/signal/constants.py +27 -0
- sigima/objects/signal/creation.py +1428 -0
- sigima/objects/signal/object.py +444 -0
- sigima/objects/signal/roi.py +274 -0
- sigima/params.py +405 -0
- sigima/proc/__init__.py +96 -0
- sigima/proc/base.py +381 -0
- sigima/proc/decorator.py +330 -0
- sigima/proc/image/__init__.py +513 -0
- sigima/proc/image/arithmetic.py +335 -0
- sigima/proc/image/base.py +260 -0
- sigima/proc/image/detection.py +519 -0
- sigima/proc/image/edges.py +329 -0
- sigima/proc/image/exposure.py +406 -0
- sigima/proc/image/extraction.py +458 -0
- sigima/proc/image/filtering.py +219 -0
- sigima/proc/image/fourier.py +147 -0
- sigima/proc/image/geometry.py +661 -0
- sigima/proc/image/mathops.py +340 -0
- sigima/proc/image/measurement.py +195 -0
- sigima/proc/image/morphology.py +155 -0
- sigima/proc/image/noise.py +107 -0
- sigima/proc/image/preprocessing.py +182 -0
- sigima/proc/image/restoration.py +235 -0
- sigima/proc/image/threshold.py +217 -0
- sigima/proc/image/transformations.py +393 -0
- sigima/proc/signal/__init__.py +376 -0
- sigima/proc/signal/analysis.py +206 -0
- sigima/proc/signal/arithmetic.py +551 -0
- sigima/proc/signal/base.py +262 -0
- sigima/proc/signal/extraction.py +60 -0
- sigima/proc/signal/features.py +310 -0
- sigima/proc/signal/filtering.py +484 -0
- sigima/proc/signal/fitting.py +276 -0
- sigima/proc/signal/fourier.py +259 -0
- sigima/proc/signal/mathops.py +420 -0
- sigima/proc/signal/processing.py +580 -0
- sigima/proc/signal/stability.py +175 -0
- sigima/proc/title_formatting.py +227 -0
- sigima/proc/validation.py +272 -0
- sigima/tests/__init__.py +7 -0
- sigima/tests/common/__init__.py +0 -0
- sigima/tests/common/arithmeticparam_unit_test.py +26 -0
- sigima/tests/common/basename_unit_test.py +126 -0
- sigima/tests/common/client_unit_test.py +412 -0
- sigima/tests/common/converters_unit_test.py +77 -0
- sigima/tests/common/decorator_unit_test.py +176 -0
- sigima/tests/common/examples_unit_test.py +104 -0
- sigima/tests/common/kernel_normalization_unit_test.py +242 -0
- sigima/tests/common/roi_basic_unit_test.py +73 -0
- sigima/tests/common/roi_geometry_unit_test.py +171 -0
- sigima/tests/common/scalar_builder_unit_test.py +142 -0
- sigima/tests/common/scalar_unit_test.py +991 -0
- sigima/tests/common/shape_unit_test.py +183 -0
- sigima/tests/common/stat_unit_test.py +138 -0
- sigima/tests/common/title_formatting_unit_test.py +338 -0
- sigima/tests/common/tools_coordinates_unit_test.py +60 -0
- sigima/tests/common/transformations_unit_test.py +178 -0
- sigima/tests/common/validation_unit_test.py +205 -0
- sigima/tests/conftest.py +129 -0
- sigima/tests/data.py +998 -0
- sigima/tests/env.py +280 -0
- sigima/tests/guiutils.py +163 -0
- sigima/tests/helpers.py +532 -0
- sigima/tests/image/__init__.py +28 -0
- sigima/tests/image/binning_unit_test.py +128 -0
- sigima/tests/image/blob_detection_unit_test.py +312 -0
- sigima/tests/image/centroid_unit_test.py +170 -0
- sigima/tests/image/check_2d_array_unit_test.py +63 -0
- sigima/tests/image/contour_unit_test.py +172 -0
- sigima/tests/image/convolution_unit_test.py +178 -0
- sigima/tests/image/datatype_unit_test.py +67 -0
- sigima/tests/image/edges_unit_test.py +155 -0
- sigima/tests/image/enclosingcircle_unit_test.py +88 -0
- sigima/tests/image/exposure_unit_test.py +223 -0
- sigima/tests/image/fft2d_unit_test.py +189 -0
- sigima/tests/image/filtering_unit_test.py +166 -0
- sigima/tests/image/geometry_unit_test.py +654 -0
- sigima/tests/image/hough_circle_unit_test.py +147 -0
- sigima/tests/image/imageobj_unit_test.py +737 -0
- sigima/tests/image/morphology_unit_test.py +71 -0
- sigima/tests/image/noise_unit_test.py +57 -0
- sigima/tests/image/offset_correction_unit_test.py +72 -0
- sigima/tests/image/operation_unit_test.py +518 -0
- sigima/tests/image/peak2d_limits_unit_test.py +41 -0
- sigima/tests/image/peak2d_unit_test.py +133 -0
- sigima/tests/image/profile_unit_test.py +159 -0
- sigima/tests/image/projections_unit_test.py +121 -0
- sigima/tests/image/restoration_unit_test.py +141 -0
- sigima/tests/image/roi2dparam_unit_test.py +53 -0
- sigima/tests/image/roi_advanced_unit_test.py +588 -0
- sigima/tests/image/roi_grid_unit_test.py +279 -0
- sigima/tests/image/spectrum2d_unit_test.py +40 -0
- sigima/tests/image/threshold_unit_test.py +91 -0
- sigima/tests/io/__init__.py +0 -0
- sigima/tests/io/addnewformat_unit_test.py +125 -0
- sigima/tests/io/convenience_funcs_unit_test.py +470 -0
- sigima/tests/io/coordinated_text_format_unit_test.py +495 -0
- sigima/tests/io/datetime_csv_unit_test.py +198 -0
- sigima/tests/io/imageio_formats_test.py +41 -0
- sigima/tests/io/ioregistry_unit_test.py +69 -0
- sigima/tests/io/objmeta_unit_test.py +87 -0
- sigima/tests/io/readobj_unit_test.py +130 -0
- sigima/tests/io/readwriteobj_unit_test.py +67 -0
- sigima/tests/signal/__init__.py +0 -0
- sigima/tests/signal/analysis_unit_test.py +135 -0
- sigima/tests/signal/check_1d_arrays_unit_test.py +169 -0
- sigima/tests/signal/convolution_unit_test.py +404 -0
- sigima/tests/signal/datetime_unit_test.py +176 -0
- sigima/tests/signal/fft1d_unit_test.py +303 -0
- sigima/tests/signal/filters_unit_test.py +403 -0
- sigima/tests/signal/fitting_unit_test.py +929 -0
- sigima/tests/signal/fwhm_unit_test.py +111 -0
- sigima/tests/signal/noise_unit_test.py +128 -0
- sigima/tests/signal/offset_correction_unit_test.py +34 -0
- sigima/tests/signal/operation_unit_test.py +489 -0
- sigima/tests/signal/peakdetection_unit_test.py +145 -0
- sigima/tests/signal/processing_unit_test.py +657 -0
- sigima/tests/signal/pulse/__init__.py +112 -0
- sigima/tests/signal/pulse/crossing_times_unit_test.py +123 -0
- sigima/tests/signal/pulse/plateau_detection_unit_test.py +102 -0
- sigima/tests/signal/pulse/pulse_unit_test.py +1824 -0
- sigima/tests/signal/roi_advanced_unit_test.py +392 -0
- sigima/tests/signal/signalobj_unit_test.py +603 -0
- sigima/tests/signal/stability_unit_test.py +431 -0
- sigima/tests/signal/uncertainty_unit_test.py +611 -0
- sigima/tests/vistools.py +1030 -0
- sigima/tools/__init__.py +59 -0
- sigima/tools/checks.py +290 -0
- sigima/tools/coordinates.py +308 -0
- sigima/tools/datatypes.py +26 -0
- sigima/tools/image/__init__.py +97 -0
- sigima/tools/image/detection.py +451 -0
- sigima/tools/image/exposure.py +77 -0
- sigima/tools/image/extraction.py +48 -0
- sigima/tools/image/fourier.py +260 -0
- sigima/tools/image/geometry.py +190 -0
- sigima/tools/image/preprocessing.py +165 -0
- sigima/tools/signal/__init__.py +86 -0
- sigima/tools/signal/dynamic.py +254 -0
- sigima/tools/signal/features.py +135 -0
- sigima/tools/signal/filtering.py +171 -0
- sigima/tools/signal/fitting.py +1171 -0
- sigima/tools/signal/fourier.py +466 -0
- sigima/tools/signal/interpolation.py +70 -0
- sigima/tools/signal/peakdetection.py +126 -0
- sigima/tools/signal/pulse.py +1626 -0
- sigima/tools/signal/scaling.py +50 -0
- sigima/tools/signal/stability.py +258 -0
- sigima/tools/signal/windowing.py +90 -0
- sigima/worker.py +79 -0
- sigima-1.0.0.dist-info/METADATA +233 -0
- sigima-1.0.0.dist-info/RECORD +262 -0
- {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/licenses/LICENSE +29 -29
- sigima-0.0.1.dev0.dist-info/METADATA +0 -60
- sigima-0.0.1.dev0.dist-info/RECORD +0 -6
- {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/WHEEL +0 -0
- {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/top_level.txt +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
1,0000000e+000 2,0000000e+000 3,0000000e+000 4,0000000e+000 5,0000000e+000 6,0000000e+000 7,0000000e+000 8,0000000e+000 9,0000000e+000 1,0000000e+001
|
|
2
|
+
2,0000000e+000 4,0000000e+000 6,0000000e+000 8,0000000e+000 1,0000000e+001 1,2000000e+001 1,4000000e+001 1,6000000e+001 1,8000000e+001 2,0000000e+001
|
|
3
|
+
3,0000000e+000 6,0000000e+000 9,0000000e+000 1,2000000e+001 1,5000000e+001 1,8000000e+001 2,1000000e+001 2,4000000e+001 2,7000000e+001 3,0000000e+001
|
|
4
|
+
4,0000000e+000 8,0000000e+000 1,2000000e+001 1,6000000e+001 2,0000000e+001 2,4000000e+001 2,8000000e+001 3,2000000e+001 3,6000000e+001 4,0000000e+001
|
|
5
|
+
5,0000000e+000 1,0000000e+001 1,5000000e+001 2,0000000e+001 2,5000000e+001 3,0000000e+001 3,5000000e+001 4,0000000e+001 4,5000000e+001 5,0000000e+001
|
|
6
|
+
6,0000000e+000 1,2000000e+001 1,8000000e+001 2,4000000e+001 3,0000000e+001 3,6000000e+001 4,2000000e+001 4,8000000e+001 5,4000000e+001 6,0000000e+001
|
|
7
|
+
7,0000000e+000 1,4000000e+001 2,1000000e+001 2,8000000e+001 3,5000000e+001 4,2000000e+001 4,9000000e+001 5,6000000e+001 6,3000000e+001 7,0000000e+001
|
|
8
|
+
8,0000000e+000 1,6000000e+001 2,4000000e+001 3,2000000e+001 4,0000000e+001 4,8000000e+001 5,6000000e+001 6,4000000e+001 7,2000000e+001 8,0000000e+001
|
|
9
|
+
9,0000000e+000 1,8000000e+001 2,7000000e+001 3,6000000e+001 4,5000000e+001 5,4000000e+001 6,3000000e+001 7,2000000e+001 8,1000000e+001 9,0000000e+001
|
|
10
|
+
1,0000000e+001 2,0000000e+001 3,0000000e+001 4,0000000e+001 5,0000000e+001 6,0000000e+001 7,0000000e+001 8,0000000e+001 9,0000000e+001 1,0000000e+002
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
sigima/enums.py
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""Common enum definitions for Sigima processing."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import guidata.dataset as gds
|
|
8
|
+
|
|
9
|
+
from sigima.config import _
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AngleUnit(gds.LabeledEnum):
|
|
13
|
+
"""Angle units."""
|
|
14
|
+
|
|
15
|
+
RADIAN = "rad"
|
|
16
|
+
DEGREE = "°"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class BinningOperation(gds.LabeledEnum):
|
|
20
|
+
"""Binning operations for image processing."""
|
|
21
|
+
|
|
22
|
+
SUM = "sum"
|
|
23
|
+
AVERAGE = "average"
|
|
24
|
+
MEDIAN = "median"
|
|
25
|
+
MIN = "min"
|
|
26
|
+
MAX = "max"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ContourShape(gds.LabeledEnum):
|
|
30
|
+
"""Contour shapes for image processing."""
|
|
31
|
+
|
|
32
|
+
ELLIPSE = "ellipse", _("Ellipse")
|
|
33
|
+
CIRCLE = "circle", _("Circle")
|
|
34
|
+
POLYGON = "polygon", _("Polygon")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class BorderMode(gds.LabeledEnum):
|
|
38
|
+
"""Border modes for filtering and image processing."""
|
|
39
|
+
|
|
40
|
+
CONSTANT = "constant"
|
|
41
|
+
NEAREST = "nearest"
|
|
42
|
+
REFLECT = "reflect"
|
|
43
|
+
WRAP = "wrap"
|
|
44
|
+
MIRROR = "mirror"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class MathOperator(gds.LabeledEnum):
|
|
48
|
+
"""Mathematical operators for data operations."""
|
|
49
|
+
|
|
50
|
+
ADD = "+"
|
|
51
|
+
SUBTRACT = "-"
|
|
52
|
+
MULTIPLY = "×"
|
|
53
|
+
DIVIDE = "/"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class FilterMode(gds.LabeledEnum):
|
|
57
|
+
"""Filter modes for signal and image processing."""
|
|
58
|
+
|
|
59
|
+
REFLECT = "reflect"
|
|
60
|
+
CONSTANT = "constant"
|
|
61
|
+
NEAREST = "nearest"
|
|
62
|
+
MIRROR = "mirror"
|
|
63
|
+
WRAP = "wrap"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class WaveletMode(gds.LabeledEnum):
|
|
67
|
+
"""Wavelet transform modes."""
|
|
68
|
+
|
|
69
|
+
CONSTANT = "constant"
|
|
70
|
+
EDGE = "edge"
|
|
71
|
+
SYMMETRIC = "symmetric"
|
|
72
|
+
REFLECT = "reflect"
|
|
73
|
+
WRAP = "wrap"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class ThresholdMethod(gds.LabeledEnum):
|
|
77
|
+
"""Thresholding methods for wavelet denoising."""
|
|
78
|
+
|
|
79
|
+
SOFT = "soft"
|
|
80
|
+
HARD = "hard"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class ShrinkageMethod(gds.LabeledEnum):
|
|
84
|
+
"""Shrinkage methods for wavelet denoising."""
|
|
85
|
+
|
|
86
|
+
BAYES_SHRINK = "BayesShrink"
|
|
87
|
+
VISU_SHRINK = "VisuShrink"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class PadLocation1D(gds.LabeledEnum):
|
|
91
|
+
"""Padding location for 1D signal processing."""
|
|
92
|
+
|
|
93
|
+
APPEND = "append"
|
|
94
|
+
PREPEND = "prepend"
|
|
95
|
+
BOTH = "both"
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class PadLocation2D(gds.LabeledEnum):
|
|
99
|
+
"""Padding location for 2D image processing."""
|
|
100
|
+
|
|
101
|
+
BOTTOM_RIGHT = "bottom-right", _("Bottom-right")
|
|
102
|
+
AROUND = "around", _("Around")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class PowerUnit(gds.LabeledEnum):
|
|
106
|
+
"""Power spectral density units."""
|
|
107
|
+
|
|
108
|
+
DBC = "dBc"
|
|
109
|
+
DBFS = "dBFS"
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class WindowingMethod(gds.LabeledEnum):
|
|
113
|
+
"""Windowing methods enumeration."""
|
|
114
|
+
|
|
115
|
+
BARTHANN = "barthann", "Barthann"
|
|
116
|
+
BARTLETT = "bartlett", "Bartlett"
|
|
117
|
+
BLACKMAN = "blackman", "Blackman"
|
|
118
|
+
BLACKMAN_HARRIS = "blackman_harris", "Blackman-Harris"
|
|
119
|
+
BOHMAN = "bohman", "Bohman"
|
|
120
|
+
BOXCAR = "boxcar", "Boxcar"
|
|
121
|
+
COSINE = "cosine", _("Cosine")
|
|
122
|
+
EXPONENTIAL = "exponential", _("Exponential")
|
|
123
|
+
FLAT_TOP = "flat_top", _("Flat Top")
|
|
124
|
+
GAUSSIAN = "gaussian", _("Gaussian")
|
|
125
|
+
HAMMING = "hamming", "Hamming"
|
|
126
|
+
HANN = "hann", "Hann"
|
|
127
|
+
KAISER = "kaiser", "Kaiser"
|
|
128
|
+
LANCZOS = "lanczos", "Lanczos"
|
|
129
|
+
NUTTALL = "nuttall", "Nuttall"
|
|
130
|
+
PARZEN = "parzen", "Parzen"
|
|
131
|
+
TAYLOR = "taylor", "Taylor"
|
|
132
|
+
TUKEY = "tukey", "Tukey"
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class Interpolation1DMethod(gds.LabeledEnum):
|
|
136
|
+
"""Methods for 1D interpolation and resampling."""
|
|
137
|
+
|
|
138
|
+
LINEAR = "linear", _("Linear")
|
|
139
|
+
SPLINE = "spline", _("Spline")
|
|
140
|
+
QUADRATIC = "quadratic", _("Quadratic")
|
|
141
|
+
CUBIC = "cubic", _("Cubic")
|
|
142
|
+
BARYCENTRIC = "barycentric", _("Barycentric")
|
|
143
|
+
PCHIP = "pchip", _("PCHIP")
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class Interpolation2DMethod(gds.LabeledEnum):
|
|
147
|
+
"""Methods for 2D interpolation and resampling."""
|
|
148
|
+
|
|
149
|
+
NEAREST = "nearest", _("Nearest")
|
|
150
|
+
LINEAR = "linear", _("Linear")
|
|
151
|
+
CUBIC = "cubic", _("Cubic")
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class NormalizationMethod(gds.LabeledEnum):
|
|
155
|
+
"""Normalization methods for signal processing."""
|
|
156
|
+
|
|
157
|
+
MAXIMUM = "maximum", _("Maximum")
|
|
158
|
+
AMPLITUDE = "amplitude", _("Amplitude")
|
|
159
|
+
AREA = "area", _("Area")
|
|
160
|
+
ENERGY = "energy", _("Energy")
|
|
161
|
+
RMS = "rms", _("RMS")
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class FilterType(gds.LabeledEnum):
|
|
165
|
+
"""Filter types"""
|
|
166
|
+
|
|
167
|
+
LOWPASS = "lowpass", "lowpass"
|
|
168
|
+
HIGHPASS = "highpass", "highpass"
|
|
169
|
+
BANDPASS = "bandpass", "bandpass"
|
|
170
|
+
BANDSTOP = "bandstop", "bandstop"
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class FrequencyFilterMethod(gds.LabeledEnum):
|
|
174
|
+
"""Frequency filter methods for signal processing."""
|
|
175
|
+
|
|
176
|
+
BESSEL = "bessel", "Bessel"
|
|
177
|
+
BRICKWALL = "brickwall", _("Brickwall")
|
|
178
|
+
BUTTERWORTH = "butterworth", "Butterworth"
|
|
179
|
+
CHEBYSHEV1 = "chebyshev1", "Chebyshev I"
|
|
180
|
+
CHEBYSHEV2 = "chebyshev2", "Chebyshev II"
|
|
181
|
+
ELLIPTIC = "elliptic", _("Elliptic")
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class SignalShape(gds.LabeledEnum):
|
|
185
|
+
"""Signal shapes."""
|
|
186
|
+
|
|
187
|
+
STEP = "step"
|
|
188
|
+
SQUARE = "square"
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class SignalsToImageOrientation(gds.LabeledEnum):
|
|
192
|
+
"""Orientation for combining signals into an image."""
|
|
193
|
+
|
|
194
|
+
ROWS = "rows", _("As rows")
|
|
195
|
+
COLUMNS = "columns", _("As columns")
|
sigima/io/__init__.py
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
I/O (:mod:`sigima.io`)
|
|
5
|
+
-----------------------
|
|
6
|
+
|
|
7
|
+
This package provides input/output functionality for reading and writing
|
|
8
|
+
signals and images in various formats. It includes a registry for managing
|
|
9
|
+
the available formats and their associated read/write functions.
|
|
10
|
+
|
|
11
|
+
General purpose I/O functions
|
|
12
|
+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
13
|
+
|
|
14
|
+
This package provides functions to read and write signals and images, allowing users
|
|
15
|
+
to easily handle different file formats without needing to know the specifics
|
|
16
|
+
of each format.
|
|
17
|
+
|
|
18
|
+
It includes the following main functions:
|
|
19
|
+
|
|
20
|
+
- :py:func:`read_signals`: Read a list of signals from a file.
|
|
21
|
+
- :py:func:`read_signal`: Read a single signal from a file.
|
|
22
|
+
- :py:func:`write_signal`: Write a single signal to a file.
|
|
23
|
+
- :py:func:`read_images`: Read a list of images from a file.
|
|
24
|
+
- :py:func:`read_image`: Read a single image from a file.
|
|
25
|
+
- :py:func:`write_image`: Write a single image to a file.
|
|
26
|
+
|
|
27
|
+
Supported formats
|
|
28
|
+
^^^^^^^^^^^^^^^^^
|
|
29
|
+
|
|
30
|
+
.. autodata:: SIGNAL_FORMAT_INFO
|
|
31
|
+
|
|
32
|
+
.. autodata:: IMAGE_FORMAT_INFO
|
|
33
|
+
|
|
34
|
+
Adding new formats
|
|
35
|
+
^^^^^^^^^^^^^^^^^^
|
|
36
|
+
|
|
37
|
+
To add new formats, you can create a new class that inherits from
|
|
38
|
+
:py:class:`sigima.io.image.base.ImageFormatBase` or
|
|
39
|
+
:py:class:`sigima.io.signal.base.SignalFormatBase` and implement the required methods.
|
|
40
|
+
|
|
41
|
+
.. note::
|
|
42
|
+
|
|
43
|
+
Thanks to the plugin system, you can add new formats simply by defining a new class
|
|
44
|
+
in a separate module, and it will be automatically discovered and registered, as
|
|
45
|
+
long as it is imported in your application or library.
|
|
46
|
+
|
|
47
|
+
Example of a new image format plugin:
|
|
48
|
+
|
|
49
|
+
.. code-block:: python
|
|
50
|
+
|
|
51
|
+
from sigima.io.image.base import ImageFormatBase
|
|
52
|
+
from sigima.io.base import FormatInfo
|
|
53
|
+
|
|
54
|
+
class MyImageFormat(ImageFormatBase):
|
|
55
|
+
\"\"\"Object representing MyImageFormat image file type\"\"\"
|
|
56
|
+
|
|
57
|
+
FORMAT_INFO = FormatInfo(
|
|
58
|
+
name="MyImageFormat",
|
|
59
|
+
extensions="*.myimg",
|
|
60
|
+
readable=True,
|
|
61
|
+
writeable=False,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@staticmethod
|
|
65
|
+
def read_data(filename: str) -> np.ndarray:
|
|
66
|
+
\"\"\"Read data and return it
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
filename (str): path to MyImageFormat file
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
np.ndarray: image data
|
|
73
|
+
\"\"\"
|
|
74
|
+
# Implement reading logic here
|
|
75
|
+
pass
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
from __future__ import annotations
|
|
79
|
+
|
|
80
|
+
from sigima.io.common.objmeta import (
|
|
81
|
+
read_metadata,
|
|
82
|
+
read_roi,
|
|
83
|
+
read_roi_grid,
|
|
84
|
+
write_metadata,
|
|
85
|
+
write_roi,
|
|
86
|
+
write_roi_grid,
|
|
87
|
+
)
|
|
88
|
+
from sigima.io.convenience import (
|
|
89
|
+
read_image,
|
|
90
|
+
read_images,
|
|
91
|
+
read_signal,
|
|
92
|
+
read_signals,
|
|
93
|
+
write_image,
|
|
94
|
+
write_images,
|
|
95
|
+
write_signal,
|
|
96
|
+
write_signals,
|
|
97
|
+
)
|
|
98
|
+
from sigima.io.image.base import ImageIORegistry
|
|
99
|
+
from sigima.io.signal.base import SignalIORegistry
|
|
100
|
+
|
|
101
|
+
__all__ = [
|
|
102
|
+
"IMAGE_FORMAT_INFO",
|
|
103
|
+
"SIGNAL_FORMAT_INFO",
|
|
104
|
+
"ImageIORegistry",
|
|
105
|
+
"SignalIORegistry",
|
|
106
|
+
"read_image",
|
|
107
|
+
"read_images",
|
|
108
|
+
"read_metadata",
|
|
109
|
+
"read_roi",
|
|
110
|
+
"read_roi_grid",
|
|
111
|
+
"read_signal",
|
|
112
|
+
"read_signals",
|
|
113
|
+
"write_image",
|
|
114
|
+
"write_images",
|
|
115
|
+
"write_metadata",
|
|
116
|
+
"write_roi",
|
|
117
|
+
"write_roi_grid",
|
|
118
|
+
"write_signal",
|
|
119
|
+
"write_signals",
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
SIGNAL_FORMAT_INFO = SignalIORegistry.get_format_info(mode="rst")
|
|
123
|
+
IMAGE_FORMAT_INFO = ImageIORegistry.get_format_info(mode="rst")
|
sigima/io/base.py
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Sigima Common tools for signal and image io support
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# pylint: disable=invalid-name # Allows short reference names like x, y, ...
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import dataclasses
|
|
12
|
+
import enum
|
|
13
|
+
import os
|
|
14
|
+
import os.path as osp
|
|
15
|
+
import re
|
|
16
|
+
from typing import Generic, Literal, Sequence
|
|
17
|
+
|
|
18
|
+
from sigima.config import _
|
|
19
|
+
from sigima.objects.base import BaseObj, TypeObj
|
|
20
|
+
from sigima.worker import CallbackWorkerProtocol
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class IOAction(enum.Enum):
|
|
24
|
+
"""I/O action type"""
|
|
25
|
+
|
|
26
|
+
LOAD = enum.auto()
|
|
27
|
+
SAVE = enum.auto()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclasses.dataclass
|
|
31
|
+
class FormatInfo:
|
|
32
|
+
"""Format info"""
|
|
33
|
+
|
|
34
|
+
name: str = None # e.g. "Foobar camera image files"
|
|
35
|
+
extensions: str = None # e.g. "*.foobar *.fb"
|
|
36
|
+
readable: bool = False # True if format can be read
|
|
37
|
+
writeable: bool = False # True if format can be written
|
|
38
|
+
requires: list[str] = None # e.g. ["foobar"] if format requires foobar package
|
|
39
|
+
|
|
40
|
+
def __str__(self) -> str:
|
|
41
|
+
"""Return string representation of format info"""
|
|
42
|
+
return f"""{self.name}:
|
|
43
|
+
Extensions: {self.extensions}
|
|
44
|
+
Readable: {"Yes" if self.readable else "No"}
|
|
45
|
+
Writeable: {"Yes" if self.writeable else "No"}
|
|
46
|
+
Requires: {", ".join(self.requires) if self.requires else "None"}"""
|
|
47
|
+
|
|
48
|
+
def to_rst_table_row(self) -> str:
|
|
49
|
+
"""Return reStructuredText table row for format info
|
|
50
|
+
(table `.. list-table::` format, with 5 columns)"""
|
|
51
|
+
return f""" * - {self.name}
|
|
52
|
+
- {self.extensions}
|
|
53
|
+
- {"•" if self.readable else ""}
|
|
54
|
+
- {"•" if self.writeable else ""}
|
|
55
|
+
- {", ".join(self.requires) if self.requires else "-"}"""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class FormatBase(Generic[TypeObj]):
|
|
59
|
+
"""Object representing a data file io"""
|
|
60
|
+
|
|
61
|
+
FORMAT_INFO: FormatInfo = None
|
|
62
|
+
|
|
63
|
+
def __init__(self):
|
|
64
|
+
self.info = self.FORMAT_INFO
|
|
65
|
+
if self.info is None:
|
|
66
|
+
raise ValueError(f"Format info not set for {self.__class__.__name__}")
|
|
67
|
+
if self.info.name is None:
|
|
68
|
+
raise ValueError(f"Format name not set for {self.__class__.__name__}")
|
|
69
|
+
if self.info.extensions is None:
|
|
70
|
+
raise ValueError(f"Format extensions not set for {self.__class__.__name__}")
|
|
71
|
+
if not self.info.readable and not self.info.writeable:
|
|
72
|
+
raise ValueError(f"Format {self.info.name} is not readable nor writeable")
|
|
73
|
+
self.extlist = get_file_extensions(self.info.extensions)
|
|
74
|
+
if not self.extlist:
|
|
75
|
+
raise ValueError(f"Invalid format extensions for {self.__class__.__name__}")
|
|
76
|
+
if self.info.requires:
|
|
77
|
+
for package in self.info.requires:
|
|
78
|
+
try:
|
|
79
|
+
__import__(package)
|
|
80
|
+
except ImportError as exc:
|
|
81
|
+
raise ImportError(
|
|
82
|
+
f"Format {self.info.name} requires {package} package"
|
|
83
|
+
) from exc
|
|
84
|
+
|
|
85
|
+
def get_filter(self, action: IOAction) -> str | None:
|
|
86
|
+
"""Return file filter for Qt file dialog
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
action: I/O action type
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
File filter string
|
|
93
|
+
"""
|
|
94
|
+
assert action in (IOAction.LOAD, IOAction.SAVE)
|
|
95
|
+
if action == IOAction.LOAD and not self.info.readable:
|
|
96
|
+
return None
|
|
97
|
+
if action == IOAction.SAVE and not self.info.writeable:
|
|
98
|
+
return None
|
|
99
|
+
return f"{self.info.name} ({self.info.extensions})"
|
|
100
|
+
|
|
101
|
+
def read(
|
|
102
|
+
self, filename: str, worker: CallbackWorkerProtocol | None = None
|
|
103
|
+
) -> Sequence[TypeObj]:
|
|
104
|
+
"""Read list of native objects (signal or image) from file.
|
|
105
|
+
For single object, return a list with one object.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
filename: file name
|
|
109
|
+
worker: Callback worker object
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
NotImplementedError: if format is not supported
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
List of native objects (signal or image)
|
|
116
|
+
"""
|
|
117
|
+
raise NotImplementedError(f"Reading from {self.info.name} is not supported")
|
|
118
|
+
|
|
119
|
+
def write(self, filename: str, obj: BaseObj) -> None:
|
|
120
|
+
"""Write data to file
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
filename: file name
|
|
124
|
+
obj: native object (signal or image)
|
|
125
|
+
|
|
126
|
+
Raises:
|
|
127
|
+
NotImplementedError: if format is not supported
|
|
128
|
+
"""
|
|
129
|
+
raise NotImplementedError(f"Writing to {self.info.name} is not supported")
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# pylint: disable=bad-mcs-classmethod-argument
|
|
133
|
+
class BaseIORegistry(Generic[TypeObj], type):
|
|
134
|
+
"""Metaclass for registering I/O handler classes"""
|
|
135
|
+
|
|
136
|
+
REGISTRY_INFO: str = "" # Registry info, override in subclasses
|
|
137
|
+
|
|
138
|
+
_io_format_instances: list[FormatBase] = []
|
|
139
|
+
|
|
140
|
+
def __init__(cls, name, bases, attrs):
|
|
141
|
+
super().__init__(name, bases, attrs)
|
|
142
|
+
if not name.endswith("FormatBase"):
|
|
143
|
+
try:
|
|
144
|
+
# pylint: disable=no-value-for-parameter
|
|
145
|
+
cls._io_format_instances.append(cls())
|
|
146
|
+
except ImportError:
|
|
147
|
+
# This format is not supported
|
|
148
|
+
pass
|
|
149
|
+
|
|
150
|
+
@classmethod
|
|
151
|
+
def get_formats(cls) -> list[FormatBase]:
|
|
152
|
+
"""Return I/O format handlers
|
|
153
|
+
|
|
154
|
+
Returns:
|
|
155
|
+
List of I/O format handlers
|
|
156
|
+
"""
|
|
157
|
+
return cls._io_format_instances
|
|
158
|
+
|
|
159
|
+
@classmethod
|
|
160
|
+
def get_format_info(cls, mode: Literal["rst", "text"] = "rst") -> str:
|
|
161
|
+
"""Return I/O format info
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
mode: Output format, either 'rst' (reStructuredText) or 'text'
|
|
165
|
+
|
|
166
|
+
Returns:
|
|
167
|
+
Text description for all I/O formats
|
|
168
|
+
"""
|
|
169
|
+
if mode == "rst":
|
|
170
|
+
txt = f"{cls.REGISTRY_INFO}:\n\n.. list-table::\n :header-rows: 1\n\n"
|
|
171
|
+
txt += " * - Name\n - Extensions\n "
|
|
172
|
+
txt += "- Readable\n - Writeable\n - Requires\n"
|
|
173
|
+
txt += "\n".join([fmt.info.to_rst_table_row() for fmt in cls.get_formats()])
|
|
174
|
+
else:
|
|
175
|
+
txt = f"{cls.REGISTRY_INFO}:{os.linesep}"
|
|
176
|
+
indent = " " * 4
|
|
177
|
+
finfo = "\n".join([str(fmt.info) for fmt in cls.get_formats()])
|
|
178
|
+
txt += "\n".join([indent + line for line in finfo.splitlines()])
|
|
179
|
+
return txt
|
|
180
|
+
|
|
181
|
+
@classmethod
|
|
182
|
+
def __get_all_supported_filter(cls, action: IOAction) -> str:
|
|
183
|
+
"""Return all supported file filter for Qt file dialog
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
action: I/O action type
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
File filter
|
|
190
|
+
"""
|
|
191
|
+
extlist = [] # file extension list
|
|
192
|
+
for fmt in cls.get_formats():
|
|
193
|
+
fmt: FormatBase
|
|
194
|
+
if not fmt.info.readable and action == IOAction.LOAD:
|
|
195
|
+
continue
|
|
196
|
+
if not fmt.info.writeable and action == IOAction.SAVE:
|
|
197
|
+
continue
|
|
198
|
+
extlist.extend(fmt.extlist)
|
|
199
|
+
allsupported = _("All supported files")
|
|
200
|
+
return f"{allsupported} ({'*.' + ' *.'.join(extlist)})"
|
|
201
|
+
|
|
202
|
+
@classmethod
|
|
203
|
+
def get_filters(cls, action: IOAction) -> str:
|
|
204
|
+
"""Return file filters for Qt file dialog
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
action: I/O action type
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
File filters
|
|
211
|
+
"""
|
|
212
|
+
flist = [] # file filter list
|
|
213
|
+
flist.append(cls.__get_all_supported_filter(action))
|
|
214
|
+
for fmt in cls.get_formats():
|
|
215
|
+
fmt: FormatBase
|
|
216
|
+
flt = fmt.get_filter(action)
|
|
217
|
+
if flt is not None:
|
|
218
|
+
flist.append(flt)
|
|
219
|
+
return "\n".join(flist)
|
|
220
|
+
|
|
221
|
+
@classmethod
|
|
222
|
+
def get_read_filters(cls) -> str:
|
|
223
|
+
"""Return file filters for Qt open file dialog
|
|
224
|
+
|
|
225
|
+
Returns:
|
|
226
|
+
File filters
|
|
227
|
+
"""
|
|
228
|
+
return cls.get_filters(IOAction.LOAD)
|
|
229
|
+
|
|
230
|
+
@classmethod
|
|
231
|
+
def get_write_filters(cls) -> str:
|
|
232
|
+
"""Return file filters for Qt save file dialog
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
File filters
|
|
236
|
+
"""
|
|
237
|
+
return cls.get_filters(IOAction.SAVE)
|
|
238
|
+
|
|
239
|
+
@classmethod
|
|
240
|
+
def get_format(cls, filename: str, action: IOAction) -> FormatBase:
|
|
241
|
+
"""Return format handler for filename
|
|
242
|
+
|
|
243
|
+
Args:
|
|
244
|
+
filename: file name
|
|
245
|
+
action: I/O action type
|
|
246
|
+
|
|
247
|
+
Raises:
|
|
248
|
+
NotImplementedError: if file data type is not supported
|
|
249
|
+
|
|
250
|
+
Returns:
|
|
251
|
+
Format handler
|
|
252
|
+
"""
|
|
253
|
+
for fmt in cls.get_formats():
|
|
254
|
+
fmt: FormatBase
|
|
255
|
+
if osp.splitext(filename)[1][1:].lower() in fmt.extlist:
|
|
256
|
+
if not fmt.info.readable and action == IOAction.LOAD:
|
|
257
|
+
continue
|
|
258
|
+
if not fmt.info.writeable and action == IOAction.SAVE:
|
|
259
|
+
continue
|
|
260
|
+
return fmt
|
|
261
|
+
raise NotImplementedError(
|
|
262
|
+
f"{filename} is not supported for {action.name.lower()}"
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
@classmethod
|
|
266
|
+
def read(
|
|
267
|
+
cls, filename: str, worker: CallbackWorkerProtocol | None = None
|
|
268
|
+
) -> Sequence[TypeObj]:
|
|
269
|
+
"""Read data from file, return native object (signal or image) list.
|
|
270
|
+
For single object, return a list with one object.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
filename: file name
|
|
274
|
+
worker: Callback worker object
|
|
275
|
+
|
|
276
|
+
Raises:
|
|
277
|
+
NotImplementedError: if file data type is not supported
|
|
278
|
+
|
|
279
|
+
Returns:
|
|
280
|
+
List of native objects (signal or image)
|
|
281
|
+
"""
|
|
282
|
+
fmt = cls.get_format(filename, IOAction.LOAD)
|
|
283
|
+
return fmt.read(filename, worker)
|
|
284
|
+
|
|
285
|
+
@classmethod
|
|
286
|
+
def write(cls, filename: str, obj: BaseObj) -> None:
|
|
287
|
+
"""Write data to file from native object (signal or image).
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
filename: file name
|
|
291
|
+
obj: native object (signal or image)
|
|
292
|
+
|
|
293
|
+
Raises:
|
|
294
|
+
NotImplementedError: if file data type is not supported
|
|
295
|
+
"""
|
|
296
|
+
fmt = cls.get_format(filename, IOAction.SAVE)
|
|
297
|
+
fmt.write(filename, obj)
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
def get_file_extensions(string: str) -> list[str]:
|
|
301
|
+
"""Return a sorted list of unique file extensions contained in `string`.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
string: String containing file extensions.
|
|
305
|
+
|
|
306
|
+
Returns:
|
|
307
|
+
List of file extensions.
|
|
308
|
+
"""
|
|
309
|
+
pattern = r"\S+\.[\w-]+"
|
|
310
|
+
matches = re.findall(pattern, string)
|
|
311
|
+
return sorted({match.split(".")[-1].lower() for match in matches})
|