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.
Files changed (264) hide show
  1. sigima/__init__.py +142 -2
  2. sigima/client/__init__.py +105 -0
  3. sigima/client/base.py +780 -0
  4. sigima/client/remote.py +469 -0
  5. sigima/client/stub.py +814 -0
  6. sigima/client/utils.py +90 -0
  7. sigima/config.py +444 -0
  8. sigima/data/logo/Sigima.svg +135 -0
  9. sigima/data/tests/annotations.json +798 -0
  10. sigima/data/tests/curve_fitting/exponential_fit.txt +511 -0
  11. sigima/data/tests/curve_fitting/gaussian_fit.txt +100 -0
  12. sigima/data/tests/curve_fitting/piecewiseexponential_fit.txt +1022 -0
  13. sigima/data/tests/curve_fitting/polynomial_fit.txt +100 -0
  14. sigima/data/tests/curve_fitting/twohalfgaussian_fit.txt +1000 -0
  15. sigima/data/tests/curve_formats/bandwidth.txt +201 -0
  16. sigima/data/tests/curve_formats/boxcar.npy +0 -0
  17. sigima/data/tests/curve_formats/datetime.txt +1001 -0
  18. sigima/data/tests/curve_formats/dynamic_parameters.txt +4000 -0
  19. sigima/data/tests/curve_formats/fw1e2.txt +301 -0
  20. sigima/data/tests/curve_formats/fwhm.txt +319 -0
  21. sigima/data/tests/curve_formats/multiple_curves.csv +29 -0
  22. sigima/data/tests/curve_formats/noised_saw.mat +0 -0
  23. sigima/data/tests/curve_formats/oscilloscope.csv +111 -0
  24. sigima/data/tests/curve_formats/other/other2/recursive2.txt +5 -0
  25. sigima/data/tests/curve_formats/other/recursive1.txt +5 -0
  26. sigima/data/tests/curve_formats/paracetamol.npy +0 -0
  27. sigima/data/tests/curve_formats/paracetamol.txt +1010 -0
  28. sigima/data/tests/curve_formats/paracetamol_dx_dy.csv +1000 -0
  29. sigima/data/tests/curve_formats/paracetamol_dy.csv +1001 -0
  30. sigima/data/tests/curve_formats/pulse1.npy +0 -0
  31. sigima/data/tests/curve_formats/pulse2.npy +0 -0
  32. sigima/data/tests/curve_formats/simple.txt +5 -0
  33. sigima/data/tests/curve_formats/spectrum.mca +2139 -0
  34. sigima/data/tests/curve_formats/square2.npy +0 -0
  35. sigima/data/tests/curve_formats/step.npy +0 -0
  36. sigima/data/tests/fabry-perot1.jpg +0 -0
  37. sigima/data/tests/fabry-perot2.jpg +0 -0
  38. sigima/data/tests/flower.npy +0 -0
  39. sigima/data/tests/image_formats/NF 180338201.scor-data +11003 -0
  40. sigima/data/tests/image_formats/binary_image.npy +0 -0
  41. sigima/data/tests/image_formats/binary_image.png +0 -0
  42. sigima/data/tests/image_formats/centroid_test.npy +0 -0
  43. sigima/data/tests/image_formats/coordinated_text/complex_image.txt +10011 -0
  44. sigima/data/tests/image_formats/coordinated_text/complex_ref_image.txt +10010 -0
  45. sigima/data/tests/image_formats/coordinated_text/image.txt +15 -0
  46. sigima/data/tests/image_formats/coordinated_text/image2.txt +14 -0
  47. sigima/data/tests/image_formats/coordinated_text/image_no_unit_no_label.txt +14 -0
  48. sigima/data/tests/image_formats/coordinated_text/image_with_nan.txt +15 -0
  49. sigima/data/tests/image_formats/coordinated_text/image_with_unit.txt +14 -0
  50. sigima/data/tests/image_formats/fiber.csv +480 -0
  51. sigima/data/tests/image_formats/fiber.jpg +0 -0
  52. sigima/data/tests/image_formats/fiber.png +0 -0
  53. sigima/data/tests/image_formats/fiber.txt +480 -0
  54. sigima/data/tests/image_formats/gaussian_spot_with_noise.npy +0 -0
  55. sigima/data/tests/image_formats/mr-brain.dcm +0 -0
  56. sigima/data/tests/image_formats/noised_gaussian.mat +0 -0
  57. sigima/data/tests/image_formats/sif_reader/nd_lum_image_no_glue.sif +0 -0
  58. sigima/data/tests/image_formats/sif_reader/raman1.sif +0 -0
  59. sigima/data/tests/image_formats/tiling.txt +10 -0
  60. sigima/data/tests/image_formats/uint16.tiff +0 -0
  61. sigima/data/tests/image_formats/uint8.tiff +0 -0
  62. sigima/data/tests/laser_beam/TEM00_z_13.jpg +0 -0
  63. sigima/data/tests/laser_beam/TEM00_z_18.jpg +0 -0
  64. sigima/data/tests/laser_beam/TEM00_z_23.jpg +0 -0
  65. sigima/data/tests/laser_beam/TEM00_z_30.jpg +0 -0
  66. sigima/data/tests/laser_beam/TEM00_z_35.jpg +0 -0
  67. sigima/data/tests/laser_beam/TEM00_z_40.jpg +0 -0
  68. sigima/data/tests/laser_beam/TEM00_z_45.jpg +0 -0
  69. sigima/data/tests/laser_beam/TEM00_z_50.jpg +0 -0
  70. sigima/data/tests/laser_beam/TEM00_z_55.jpg +0 -0
  71. sigima/data/tests/laser_beam/TEM00_z_60.jpg +0 -0
  72. sigima/data/tests/laser_beam/TEM00_z_65.jpg +0 -0
  73. sigima/data/tests/laser_beam/TEM00_z_70.jpg +0 -0
  74. sigima/data/tests/laser_beam/TEM00_z_75.jpg +0 -0
  75. sigima/data/tests/laser_beam/TEM00_z_80.jpg +0 -0
  76. sigima/enums.py +195 -0
  77. sigima/io/__init__.py +123 -0
  78. sigima/io/base.py +311 -0
  79. sigima/io/common/__init__.py +5 -0
  80. sigima/io/common/basename.py +164 -0
  81. sigima/io/common/converters.py +189 -0
  82. sigima/io/common/objmeta.py +181 -0
  83. sigima/io/common/textreader.py +58 -0
  84. sigima/io/convenience.py +157 -0
  85. sigima/io/enums.py +17 -0
  86. sigima/io/ftlab.py +395 -0
  87. sigima/io/image/__init__.py +9 -0
  88. sigima/io/image/base.py +177 -0
  89. sigima/io/image/formats.py +1016 -0
  90. sigima/io/image/funcs.py +414 -0
  91. sigima/io/signal/__init__.py +9 -0
  92. sigima/io/signal/base.py +129 -0
  93. sigima/io/signal/formats.py +290 -0
  94. sigima/io/signal/funcs.py +723 -0
  95. sigima/objects/__init__.py +260 -0
  96. sigima/objects/base.py +937 -0
  97. sigima/objects/image/__init__.py +88 -0
  98. sigima/objects/image/creation.py +556 -0
  99. sigima/objects/image/object.py +524 -0
  100. sigima/objects/image/roi.py +904 -0
  101. sigima/objects/scalar/__init__.py +57 -0
  102. sigima/objects/scalar/common.py +215 -0
  103. sigima/objects/scalar/geometry.py +502 -0
  104. sigima/objects/scalar/table.py +784 -0
  105. sigima/objects/shape.py +290 -0
  106. sigima/objects/signal/__init__.py +133 -0
  107. sigima/objects/signal/constants.py +27 -0
  108. sigima/objects/signal/creation.py +1428 -0
  109. sigima/objects/signal/object.py +444 -0
  110. sigima/objects/signal/roi.py +274 -0
  111. sigima/params.py +405 -0
  112. sigima/proc/__init__.py +96 -0
  113. sigima/proc/base.py +381 -0
  114. sigima/proc/decorator.py +330 -0
  115. sigima/proc/image/__init__.py +513 -0
  116. sigima/proc/image/arithmetic.py +335 -0
  117. sigima/proc/image/base.py +260 -0
  118. sigima/proc/image/detection.py +519 -0
  119. sigima/proc/image/edges.py +329 -0
  120. sigima/proc/image/exposure.py +406 -0
  121. sigima/proc/image/extraction.py +458 -0
  122. sigima/proc/image/filtering.py +219 -0
  123. sigima/proc/image/fourier.py +147 -0
  124. sigima/proc/image/geometry.py +661 -0
  125. sigima/proc/image/mathops.py +340 -0
  126. sigima/proc/image/measurement.py +195 -0
  127. sigima/proc/image/morphology.py +155 -0
  128. sigima/proc/image/noise.py +107 -0
  129. sigima/proc/image/preprocessing.py +182 -0
  130. sigima/proc/image/restoration.py +235 -0
  131. sigima/proc/image/threshold.py +217 -0
  132. sigima/proc/image/transformations.py +393 -0
  133. sigima/proc/signal/__init__.py +376 -0
  134. sigima/proc/signal/analysis.py +206 -0
  135. sigima/proc/signal/arithmetic.py +551 -0
  136. sigima/proc/signal/base.py +262 -0
  137. sigima/proc/signal/extraction.py +60 -0
  138. sigima/proc/signal/features.py +310 -0
  139. sigima/proc/signal/filtering.py +484 -0
  140. sigima/proc/signal/fitting.py +276 -0
  141. sigima/proc/signal/fourier.py +259 -0
  142. sigima/proc/signal/mathops.py +420 -0
  143. sigima/proc/signal/processing.py +580 -0
  144. sigima/proc/signal/stability.py +175 -0
  145. sigima/proc/title_formatting.py +227 -0
  146. sigima/proc/validation.py +272 -0
  147. sigima/tests/__init__.py +7 -0
  148. sigima/tests/common/__init__.py +0 -0
  149. sigima/tests/common/arithmeticparam_unit_test.py +26 -0
  150. sigima/tests/common/basename_unit_test.py +126 -0
  151. sigima/tests/common/client_unit_test.py +412 -0
  152. sigima/tests/common/converters_unit_test.py +77 -0
  153. sigima/tests/common/decorator_unit_test.py +176 -0
  154. sigima/tests/common/examples_unit_test.py +104 -0
  155. sigima/tests/common/kernel_normalization_unit_test.py +242 -0
  156. sigima/tests/common/roi_basic_unit_test.py +73 -0
  157. sigima/tests/common/roi_geometry_unit_test.py +171 -0
  158. sigima/tests/common/scalar_builder_unit_test.py +142 -0
  159. sigima/tests/common/scalar_unit_test.py +991 -0
  160. sigima/tests/common/shape_unit_test.py +183 -0
  161. sigima/tests/common/stat_unit_test.py +138 -0
  162. sigima/tests/common/title_formatting_unit_test.py +338 -0
  163. sigima/tests/common/tools_coordinates_unit_test.py +60 -0
  164. sigima/tests/common/transformations_unit_test.py +178 -0
  165. sigima/tests/common/validation_unit_test.py +205 -0
  166. sigima/tests/conftest.py +129 -0
  167. sigima/tests/data.py +998 -0
  168. sigima/tests/env.py +280 -0
  169. sigima/tests/guiutils.py +163 -0
  170. sigima/tests/helpers.py +532 -0
  171. sigima/tests/image/__init__.py +28 -0
  172. sigima/tests/image/binning_unit_test.py +128 -0
  173. sigima/tests/image/blob_detection_unit_test.py +312 -0
  174. sigima/tests/image/centroid_unit_test.py +170 -0
  175. sigima/tests/image/check_2d_array_unit_test.py +63 -0
  176. sigima/tests/image/contour_unit_test.py +172 -0
  177. sigima/tests/image/convolution_unit_test.py +178 -0
  178. sigima/tests/image/datatype_unit_test.py +67 -0
  179. sigima/tests/image/edges_unit_test.py +155 -0
  180. sigima/tests/image/enclosingcircle_unit_test.py +88 -0
  181. sigima/tests/image/exposure_unit_test.py +223 -0
  182. sigima/tests/image/fft2d_unit_test.py +189 -0
  183. sigima/tests/image/filtering_unit_test.py +166 -0
  184. sigima/tests/image/geometry_unit_test.py +654 -0
  185. sigima/tests/image/hough_circle_unit_test.py +147 -0
  186. sigima/tests/image/imageobj_unit_test.py +737 -0
  187. sigima/tests/image/morphology_unit_test.py +71 -0
  188. sigima/tests/image/noise_unit_test.py +57 -0
  189. sigima/tests/image/offset_correction_unit_test.py +72 -0
  190. sigima/tests/image/operation_unit_test.py +518 -0
  191. sigima/tests/image/peak2d_limits_unit_test.py +41 -0
  192. sigima/tests/image/peak2d_unit_test.py +133 -0
  193. sigima/tests/image/profile_unit_test.py +159 -0
  194. sigima/tests/image/projections_unit_test.py +121 -0
  195. sigima/tests/image/restoration_unit_test.py +141 -0
  196. sigima/tests/image/roi2dparam_unit_test.py +53 -0
  197. sigima/tests/image/roi_advanced_unit_test.py +588 -0
  198. sigima/tests/image/roi_grid_unit_test.py +279 -0
  199. sigima/tests/image/spectrum2d_unit_test.py +40 -0
  200. sigima/tests/image/threshold_unit_test.py +91 -0
  201. sigima/tests/io/__init__.py +0 -0
  202. sigima/tests/io/addnewformat_unit_test.py +125 -0
  203. sigima/tests/io/convenience_funcs_unit_test.py +470 -0
  204. sigima/tests/io/coordinated_text_format_unit_test.py +495 -0
  205. sigima/tests/io/datetime_csv_unit_test.py +198 -0
  206. sigima/tests/io/imageio_formats_test.py +41 -0
  207. sigima/tests/io/ioregistry_unit_test.py +69 -0
  208. sigima/tests/io/objmeta_unit_test.py +87 -0
  209. sigima/tests/io/readobj_unit_test.py +130 -0
  210. sigima/tests/io/readwriteobj_unit_test.py +67 -0
  211. sigima/tests/signal/__init__.py +0 -0
  212. sigima/tests/signal/analysis_unit_test.py +135 -0
  213. sigima/tests/signal/check_1d_arrays_unit_test.py +169 -0
  214. sigima/tests/signal/convolution_unit_test.py +404 -0
  215. sigima/tests/signal/datetime_unit_test.py +176 -0
  216. sigima/tests/signal/fft1d_unit_test.py +303 -0
  217. sigima/tests/signal/filters_unit_test.py +403 -0
  218. sigima/tests/signal/fitting_unit_test.py +929 -0
  219. sigima/tests/signal/fwhm_unit_test.py +111 -0
  220. sigima/tests/signal/noise_unit_test.py +128 -0
  221. sigima/tests/signal/offset_correction_unit_test.py +34 -0
  222. sigima/tests/signal/operation_unit_test.py +489 -0
  223. sigima/tests/signal/peakdetection_unit_test.py +145 -0
  224. sigima/tests/signal/processing_unit_test.py +657 -0
  225. sigima/tests/signal/pulse/__init__.py +112 -0
  226. sigima/tests/signal/pulse/crossing_times_unit_test.py +123 -0
  227. sigima/tests/signal/pulse/plateau_detection_unit_test.py +102 -0
  228. sigima/tests/signal/pulse/pulse_unit_test.py +1824 -0
  229. sigima/tests/signal/roi_advanced_unit_test.py +392 -0
  230. sigima/tests/signal/signalobj_unit_test.py +603 -0
  231. sigima/tests/signal/stability_unit_test.py +431 -0
  232. sigima/tests/signal/uncertainty_unit_test.py +611 -0
  233. sigima/tests/vistools.py +1030 -0
  234. sigima/tools/__init__.py +59 -0
  235. sigima/tools/checks.py +290 -0
  236. sigima/tools/coordinates.py +308 -0
  237. sigima/tools/datatypes.py +26 -0
  238. sigima/tools/image/__init__.py +97 -0
  239. sigima/tools/image/detection.py +451 -0
  240. sigima/tools/image/exposure.py +77 -0
  241. sigima/tools/image/extraction.py +48 -0
  242. sigima/tools/image/fourier.py +260 -0
  243. sigima/tools/image/geometry.py +190 -0
  244. sigima/tools/image/preprocessing.py +165 -0
  245. sigima/tools/signal/__init__.py +86 -0
  246. sigima/tools/signal/dynamic.py +254 -0
  247. sigima/tools/signal/features.py +135 -0
  248. sigima/tools/signal/filtering.py +171 -0
  249. sigima/tools/signal/fitting.py +1171 -0
  250. sigima/tools/signal/fourier.py +466 -0
  251. sigima/tools/signal/interpolation.py +70 -0
  252. sigima/tools/signal/peakdetection.py +126 -0
  253. sigima/tools/signal/pulse.py +1626 -0
  254. sigima/tools/signal/scaling.py +50 -0
  255. sigima/tools/signal/stability.py +258 -0
  256. sigima/tools/signal/windowing.py +90 -0
  257. sigima/worker.py +79 -0
  258. sigima-1.0.0.dist-info/METADATA +233 -0
  259. sigima-1.0.0.dist-info/RECORD +262 -0
  260. {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/licenses/LICENSE +29 -29
  261. sigima-0.0.1.dev0.dist-info/METADATA +0 -60
  262. sigima-0.0.1.dev0.dist-info/RECORD +0 -6
  263. {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/WHEEL +0 -0
  264. {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/top_level.txt +0 -0
@@ -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
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})