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,340 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Mathematical Operations Module
5
+ ------------------------------
6
+
7
+ This module implements mathematical operations on images, such as inversion,
8
+ absolute value, real/imaginary part extraction, type casting, and exponentiation.
9
+
10
+ Main features include:
11
+
12
+ - Pixel-wise mathematical transformations (e.g., log, exp, abs, real, imag, log10)
13
+ - Type casting and other value-level operations
14
+
15
+ These functions enable flexible manipulation of image data at the value level.
16
+ """
17
+
18
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
19
+
20
+ # Note:
21
+ # ----
22
+ # - All `guidata.dataset.DataSet` parameter classes must also be imported
23
+ # in the `sigima.params` module.
24
+ # - All functions decorated by `computation_function` must be imported in the upper
25
+ # level `sigima.proc.image` module.
26
+
27
+ from __future__ import annotations
28
+
29
+ import warnings
30
+
31
+ import guidata.dataset as gds
32
+ import numpy as np
33
+
34
+ import sigima.tools.image
35
+ from sigima.config import _
36
+ from sigima.config import options as sigima_options
37
+ from sigima.enums import AngleUnit
38
+ from sigima.objects.image import ImageObj
39
+ from sigima.proc.base import AngleUnitParam, PhaseParam, dst_1_to_1, dst_2_to_1
40
+ from sigima.proc.decorator import computation_function
41
+ from sigima.proc.image.base import Wrap1to1Func, restore_data_outside_roi
42
+ from sigima.tools import coordinates
43
+ from sigima.tools.datatypes import clip_astype
44
+
45
+ # NOTE: Only parameter classes DEFINED in this module should be included in __all__.
46
+ # Parameter classes imported from other modules (like sigima.proc.base) should NOT
47
+ # be re-exported to avoid Sphinx cross-reference conflicts. The sigima.params module
48
+ # serves as the central API point that imports and re-exports all parameter classes.
49
+ __all__ = [
50
+ "DataTypeIParam",
51
+ "Log10ZPlusNParam",
52
+ "absolute",
53
+ "absolute",
54
+ "astype",
55
+ "complex_from_magnitude_phase",
56
+ "complex_from_real_imag",
57
+ "convolution",
58
+ "deconvolution",
59
+ "exp",
60
+ "exp",
61
+ "imag",
62
+ "imag",
63
+ "inverse",
64
+ "inverse",
65
+ "log10",
66
+ "log10",
67
+ "log10_z_plus_n",
68
+ "phase",
69
+ "real",
70
+ "real",
71
+ ]
72
+
73
+
74
+ @computation_function()
75
+ def inverse(src: ImageObj) -> ImageObj:
76
+ """Compute the inverse of an image and return the new result image object
77
+
78
+ Args:
79
+ src: input image object
80
+
81
+ Returns:
82
+ Result image object 1 / **src** (new object)
83
+ """
84
+ dst = dst_1_to_1(src, "inverse")
85
+ with warnings.catch_warnings():
86
+ warnings.simplefilter("ignore", category=RuntimeWarning)
87
+ dst.data = np.reciprocal(src.data, dtype=float)
88
+ dst.data[np.isinf(dst.data)] = np.nan
89
+ restore_data_outside_roi(dst, src)
90
+ return dst
91
+
92
+
93
+ @computation_function()
94
+ def absolute(src: ImageObj) -> ImageObj:
95
+ """Compute absolute value with :py:data:`numpy.absolute`
96
+
97
+ Args:
98
+ src: input image object
99
+
100
+ Returns:
101
+ Output image object
102
+ """
103
+ return Wrap1to1Func(np.absolute)(src)
104
+
105
+
106
+ @computation_function()
107
+ def real(src: ImageObj) -> ImageObj:
108
+ """Compute real part with :py:func:`numpy.real`
109
+
110
+ Args:
111
+ src: input image object
112
+
113
+ Returns:
114
+ Output image object
115
+ """
116
+ return Wrap1to1Func(np.real)(src)
117
+
118
+
119
+ @computation_function()
120
+ def imag(src: ImageObj) -> ImageObj:
121
+ """Compute imaginary part with :py:func:`numpy.imag`
122
+
123
+ Args:
124
+ src: input image object
125
+
126
+ Returns:
127
+ Output image object
128
+ """
129
+ return Wrap1to1Func(np.imag)(src)
130
+
131
+
132
+ @computation_function()
133
+ def phase(src: ImageObj, p: PhaseParam) -> ImageObj:
134
+ """Compute the phase (argument) of a complex image.
135
+
136
+ The function uses :py:func:`numpy.angle` to compute the argument and
137
+ :py:func:`numpy.unwrap` to unwrap it.
138
+
139
+ Args:
140
+ src: Input image object.
141
+ p: Phase parameters.
142
+
143
+ Returns:
144
+ Image object containing the phase, optionally unwrapped.
145
+ """
146
+ suffix = "unwrap" if p.unwrap else ""
147
+ dst = dst_1_to_1(src, "phase", suffix)
148
+ data = src.get_data()
149
+ argument = np.angle(data)
150
+ if p.unwrap:
151
+ argument = np.unwrap(argument)
152
+ if p.unit == AngleUnit.DEGREE:
153
+ argument = np.rad2deg(argument)
154
+ dst.data = argument
155
+ dst.zunit = p.unit
156
+ restore_data_outside_roi(dst, src)
157
+ return dst
158
+
159
+
160
+ @computation_function()
161
+ def complex_from_magnitude_phase(
162
+ src1: ImageObj, src2: ImageObj, p: AngleUnitParam
163
+ ) -> ImageObj:
164
+ """Combine magnitude and phase images into a complex image.
165
+
166
+ .. warning::
167
+
168
+ This function assumes that the input images have the same dimensions.
169
+
170
+ Args:
171
+ src1: Magnitude (module) image.
172
+ src2: Phase (argument) image.
173
+ p: Parameters (provides unit for the phase).
174
+
175
+ Returns:
176
+ Image object with complex-valued z.
177
+ """
178
+ dst = dst_2_to_1(src1, src2, "mag_phase")
179
+ assert p.unit is not None
180
+ dst.data = coordinates.polar_to_complex(src1.data, src2.data, unit=p.unit)
181
+ return dst
182
+
183
+
184
+ @computation_function()
185
+ def complex_from_real_imag(src1: ImageObj, src2: ImageObj) -> ImageObj:
186
+ """Combine two real images into a complex image using real + i * imag.
187
+
188
+ .. warning::
189
+
190
+ This function assumes that the input images have the same dimensions and are
191
+ properly aligned.
192
+
193
+ Args:
194
+ src1: Real part image.
195
+ src2: Imaginary part image.
196
+
197
+ Returns:
198
+ Image object with complex-valued z.
199
+
200
+ Raises:
201
+ ValueError: If the x or y coordinates of the two images are not the same.
202
+ """
203
+ dst = dst_2_to_1(src1, src2, "real_imag")
204
+ assert src1.data is not None
205
+ assert src2.data is not None
206
+ dst.data = src1.data + 1j * src2.data
207
+ return dst
208
+
209
+
210
+ @computation_function()
211
+ def convolution(src: ImageObj, kernel: ImageObj) -> ImageObj:
212
+ """Convolve an image with a kernel.
213
+
214
+ The kernel should ideally be smaller than the input image and centered.
215
+
216
+ Args:
217
+ src: Input image object.
218
+ kernel: Kernel image object.
219
+
220
+ Returns:
221
+ Output image object.
222
+
223
+ Notes:
224
+ The behavior of kernel normalization is controlled by the global configuration
225
+ option ``sigima.config.options.auto_normalize_kernel``.
226
+ """
227
+ # Get configuration option for kernel normalization
228
+ normalize_kernel = sigima_options.auto_normalize_kernel.get()
229
+
230
+ dst = dst_2_to_1(src, kernel, "⊛")
231
+ dst.data = sigima.tools.image.convolve(
232
+ src.data,
233
+ kernel.data,
234
+ normalize_kernel_flag=normalize_kernel,
235
+ )
236
+ restore_data_outside_roi(dst, src)
237
+ return dst
238
+
239
+
240
+ @computation_function()
241
+ def deconvolution(src: ImageObj, kernel: ImageObj) -> ImageObj:
242
+ """Deconvolve a kernel from an image using Fast Fourier Transform (FFT).
243
+
244
+ Args:
245
+ src: Input image object.
246
+ kernel: Kernel image object.
247
+
248
+ Returns:
249
+ Output image object.
250
+
251
+ Notes:
252
+ The behavior of kernel normalization is controlled by the global configuration
253
+ option ``sigima.config.options.auto_normalize_kernel``.
254
+ """
255
+ # Get configuration option for kernel normalization
256
+ normalize_kernel = sigima_options.auto_normalize_kernel.get()
257
+
258
+ dst = dst_2_to_1(src, kernel, "⊛⁻¹")
259
+ dst.data = sigima.tools.image.deconvolve(
260
+ src.data,
261
+ kernel.data,
262
+ normalize_kernel_flag=normalize_kernel,
263
+ )
264
+ restore_data_outside_roi(dst, src)
265
+ return dst
266
+
267
+
268
+ @computation_function()
269
+ def log10(src: ImageObj) -> ImageObj:
270
+ """Compute log10 with :py:data:`numpy.log10`
271
+
272
+ Args:
273
+ src: input image object
274
+
275
+ Returns:
276
+ Output image object
277
+ """
278
+ return Wrap1to1Func(np.log10)(src)
279
+
280
+
281
+ @computation_function()
282
+ def exp(src: ImageObj) -> ImageObj:
283
+ """Compute exponential with :py:data:`numpy.exp`
284
+
285
+ Args:
286
+ src: input image object
287
+
288
+ Returns:
289
+ Output image object
290
+ """
291
+ return Wrap1to1Func(np.exp)(src)
292
+
293
+
294
+ class Log10ZPlusNParam(gds.DataSet):
295
+ """Log10(z+n) parameters"""
296
+
297
+ n = gds.FloatItem("n")
298
+
299
+
300
+ @computation_function()
301
+ def log10_z_plus_n(src: ImageObj, p: Log10ZPlusNParam) -> ImageObj:
302
+ """Compute log10(z+n) with :py:data:`numpy.log10`
303
+
304
+ Args:
305
+ src: input image object
306
+ p: parameters
307
+
308
+ Returns:
309
+ Output image object
310
+ """
311
+ dst = dst_1_to_1(src, "log10_z_plus_n", f"n={p.n}")
312
+ dst.data = np.log10(src.data + p.n)
313
+ restore_data_outside_roi(dst, src)
314
+ return dst
315
+
316
+
317
+ class DataTypeIParam(gds.DataSet):
318
+ """Convert image data type parameters"""
319
+
320
+ dtype_str = gds.ChoiceItem(
321
+ _("Destination data type"),
322
+ list(zip(ImageObj.get_valid_dtypenames(), ImageObj.get_valid_dtypenames())),
323
+ help=_("Output image data type."),
324
+ )
325
+
326
+
327
+ @computation_function()
328
+ def astype(src: ImageObj, p: DataTypeIParam) -> ImageObj:
329
+ """Convert image data type with :py:func:`sigima.tools.datatypes.clip_astype`
330
+
331
+ Args:
332
+ src: input image object
333
+ p: parameters
334
+
335
+ Returns:
336
+ Output image object
337
+ """
338
+ dst = dst_1_to_1(src, "clip_astype", p.dtype_str)
339
+ dst.data = clip_astype(src.data, p.dtype_str)
340
+ return dst
@@ -0,0 +1,195 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Measurement computation module
5
+ ------------------------------
6
+
7
+ This module provides tools for extracting quantitative information from images,
8
+ such as object centroids, enclosing circles, and region-based statistics.
9
+
10
+ Main features include:
11
+
12
+ - Centroid and enclosing circle computation
13
+ - Region/property measurements
14
+ - Statistical analysis of image regions
15
+
16
+ These functions are useful for image quantification and morphometric analysis.
17
+ """
18
+
19
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
20
+
21
+ # Note:
22
+ # ----
23
+ # - All `guidata.dataset.DataSet` parameter classes must also be imported
24
+ # in the `sigima.params` module.
25
+ # - All functions decorated by `computation_function` must be imported in the upper
26
+ # level `sigima.proc.image` module.
27
+
28
+ from __future__ import annotations
29
+
30
+ import numpy as np
31
+ from numpy import ma
32
+
33
+ import sigima.tools.image
34
+ from sigima.config import _
35
+ from sigima.objects import (
36
+ GeometryResult,
37
+ ImageObj,
38
+ SignalObj,
39
+ TableKind,
40
+ TableResult,
41
+ TableResultBuilder,
42
+ )
43
+ from sigima.proc.base import new_signal_result
44
+ from sigima.proc.decorator import computation_function
45
+ from sigima.proc.image.base import compute_geometry_from_obj
46
+
47
+ # NOTE: Only parameter classes DEFINED in this module should be included in __all__.
48
+ # Parameter classes imported from other modules (like sigima.proc.base) should NOT
49
+ # be re-exported to avoid Sphinx cross-reference conflicts. The sigima.params module
50
+ # serves as the central API point that imports and re-exports all parameter classes.
51
+ __all__ = [
52
+ "centroid",
53
+ "enclosing_circle",
54
+ "horizontal_projection",
55
+ "stats",
56
+ "vertical_projection",
57
+ ]
58
+
59
+
60
+ def get_centroid_coords(data: np.ndarray) -> np.ndarray:
61
+ """Return centroid coordinates
62
+ with :py:func:`sigima.tools.image.get_centroid_auto`
63
+
64
+ Args:
65
+ data: input data
66
+
67
+ Returns:
68
+ Centroid coordinates
69
+ """
70
+ y, x = sigima.tools.image.get_centroid_auto(data)
71
+ return np.array([(x, y)])
72
+
73
+
74
+ @computation_function()
75
+ def centroid(image: ImageObj) -> GeometryResult | None:
76
+ """Compute centroid
77
+ with :py:func:`sigima.tools.image.get_centroid_fourier`
78
+
79
+ Args:
80
+ image: input image
81
+
82
+ Returns:
83
+ Centroid coordinates
84
+ """
85
+ return compute_geometry_from_obj("centroid", "marker", image, get_centroid_coords)
86
+
87
+
88
+ def get_enclosing_circle_coords(data: np.ndarray) -> np.ndarray:
89
+ """Return diameter coords for the circle contour enclosing image
90
+ values above threshold (FWHM)
91
+
92
+ Args:
93
+ data: input data
94
+
95
+ Returns:
96
+ Diameter coords
97
+ """
98
+ x, y, r = sigima.tools.image.get_enclosing_circle(data)
99
+ return np.array([[x, y, r]])
100
+
101
+
102
+ @computation_function()
103
+ def enclosing_circle(image: ImageObj) -> GeometryResult | None:
104
+ """Compute minimum enclosing circle
105
+ with :py:func:`sigima.tools.image.get_enclosing_circle`
106
+
107
+ Args:
108
+ image: input image
109
+
110
+ Returns:
111
+ Diameter coords
112
+ """
113
+ return compute_geometry_from_obj(
114
+ "enclosing_circle", "circle", image, get_enclosing_circle_coords
115
+ )
116
+
117
+
118
+ def __calc_snr_without_warning(data: np.ndarray) -> float:
119
+ """Calculate SNR based on <z>/σ(z), ignoring warnings
120
+
121
+ Args:
122
+ data: input data
123
+
124
+ Returns:
125
+ Signal-to-noise ratio
126
+ """
127
+ with np.errstate(divide="ignore", invalid="ignore"):
128
+ snr = ma.mean(data) / ma.std(data)
129
+ return snr
130
+
131
+
132
+ @computation_function()
133
+ def stats(obj: ImageObj) -> TableResult:
134
+ """Compute statistics on an image
135
+
136
+ Args:
137
+ obj: input image object
138
+
139
+ Returns:
140
+ Result properties
141
+ """
142
+ builder = TableResultBuilder(_("Image statistics"), kind=TableKind.STATISTICS)
143
+ builder.add(ma.min, "min")
144
+ builder.add(ma.max, "max")
145
+ builder.add(ma.mean, "mean")
146
+ builder.add(ma.median, "median")
147
+ builder.add(ma.std, "std")
148
+ builder.add(__calc_snr_without_warning, "snr")
149
+ builder.add(ma.ptp, "ptp")
150
+ builder.add(ma.sum, "sum")
151
+ return builder.compute(obj)
152
+
153
+
154
+ @computation_function()
155
+ def horizontal_projection(image: ImageObj) -> SignalObj:
156
+ """Compute the sum of pixel intensities along each col. (projection on the x-axis).
157
+
158
+ Args:
159
+ image: Input image object.
160
+
161
+ Returns:
162
+ Signal object containing the profile.
163
+ """
164
+ dst_signal = new_signal_result(
165
+ image,
166
+ "horizontal_projection",
167
+ units=(image.xunit, image.zunit),
168
+ labels=(image.xlabel, image.zlabel),
169
+ )
170
+ x = np.linspace(image.x0, image.x0 + image.width - image.dx, image.data.shape[1])
171
+ y = image.data.sum(axis=0, dtype=float)
172
+ dst_signal.set_xydata(x, y)
173
+ return dst_signal
174
+
175
+
176
+ @computation_function()
177
+ def vertical_projection(image: ImageObj) -> SignalObj:
178
+ """Compute the sum of pixel intensities along each row (projection on the y-axis).
179
+
180
+ Args:
181
+ image: Input image object.
182
+
183
+ Returns:
184
+ Signal object containing the profile.
185
+ """
186
+ dst_signal = new_signal_result(
187
+ image,
188
+ "vertical_projection",
189
+ units=(image.yunit, image.zunit),
190
+ labels=(image.ylabel, image.zlabel),
191
+ )
192
+ x = np.linspace(image.y0, image.y0 + image.height - image.dy, image.data.shape[0])
193
+ y = image.data.sum(axis=1, dtype=float)
194
+ dst_signal.set_xydata(x, y)
195
+ return dst_signal
@@ -0,0 +1,155 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Morphology computation module
5
+ -----------------------------
6
+
7
+ This module provides morphological operations for image processing, such as
8
+ dilation, erosion, opening, and closing. These operations are useful for
9
+ removing noise, filling gaps, and extracting structures in binary and grayscale
10
+ images.
11
+ """
12
+
13
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
14
+
15
+ # Note:
16
+ # ----
17
+ # - All `guidata.dataset.DataSet` parameter classes must also be imported
18
+ # in the `sigima.params` module.
19
+ # - All functions decorated by `computation_function` must be imported in the upper
20
+ # level `sigima.proc.image` module.
21
+
22
+ from __future__ import annotations
23
+
24
+ import guidata.dataset as gds
25
+ from skimage import morphology
26
+
27
+ from sigima.config import _
28
+ from sigima.objects.image import ImageObj
29
+ from sigima.proc.base import dst_1_to_1
30
+ from sigima.proc.decorator import computation_function
31
+ from sigima.proc.image.base import restore_data_outside_roi
32
+
33
+ # NOTE: Only parameter classes DEFINED in this module should be included in __all__.
34
+ # Parameter classes imported from other modules (like sigima.proc.base) should NOT
35
+ # be re-exported to avoid Sphinx cross-reference conflicts. The sigima.params module
36
+ # serves as the central API point that imports and re-exports all parameter classes.
37
+ __all__ = [
38
+ "MorphologyParam",
39
+ "black_tophat",
40
+ "closing",
41
+ "dilation",
42
+ "erosion",
43
+ "opening",
44
+ "white_tophat",
45
+ ]
46
+
47
+
48
+ class MorphologyParam(gds.DataSet):
49
+ """White Top-Hat parameters"""
50
+
51
+ radius = gds.IntItem(
52
+ _("Radius"), default=1, min=1, help=_("Footprint (disk) radius.")
53
+ )
54
+
55
+
56
+ @computation_function()
57
+ def white_tophat(src: ImageObj, p: MorphologyParam) -> ImageObj:
58
+ """Compute White Top-Hat with :py:func:`skimage.morphology.white_tophat`
59
+
60
+ Args:
61
+ src: input image object
62
+ p: parameters
63
+
64
+ Returns:
65
+ Output image object
66
+ """
67
+ dst = dst_1_to_1(src, "white_tophat", f"radius={p.radius}")
68
+ dst.data = morphology.white_tophat(src.data, morphology.disk(p.radius))
69
+ restore_data_outside_roi(dst, src)
70
+ return dst
71
+
72
+
73
+ @computation_function()
74
+ def black_tophat(src: ImageObj, p: MorphologyParam) -> ImageObj:
75
+ """Compute Black Top-Hat with :py:func:`skimage.morphology.black_tophat`
76
+
77
+ Args:
78
+ src: input image object
79
+ p: parameters
80
+
81
+ Returns:
82
+ Output image object
83
+ """
84
+ dst = dst_1_to_1(src, "black_tophat", f"radius={p.radius}")
85
+ dst.data = morphology.black_tophat(src.data, morphology.disk(p.radius))
86
+ restore_data_outside_roi(dst, src)
87
+ return dst
88
+
89
+
90
+ @computation_function()
91
+ def erosion(src: ImageObj, p: MorphologyParam) -> ImageObj:
92
+ """Compute Erosion with :py:func:`skimage.morphology.erosion`
93
+
94
+ Args:
95
+ src: input image object
96
+ p: parameters
97
+
98
+ Returns:
99
+ Output image object
100
+ """
101
+ dst = dst_1_to_1(src, "erosion", f"radius={p.radius}")
102
+ dst.data = morphology.erosion(src.data, morphology.disk(p.radius))
103
+ restore_data_outside_roi(dst, src)
104
+ return dst
105
+
106
+
107
+ @computation_function()
108
+ def dilation(src: ImageObj, p: MorphologyParam) -> ImageObj:
109
+ """Compute Dilation with :py:func:`skimage.morphology.dilation`
110
+
111
+ Args:
112
+ src: input image object
113
+ p: parameters
114
+
115
+ Returns:
116
+ Output image object
117
+ """
118
+ dst = dst_1_to_1(src, "dilation", f"radius={p.radius}")
119
+ dst.data = morphology.dilation(src.data, morphology.disk(p.radius))
120
+ restore_data_outside_roi(dst, src)
121
+ return dst
122
+
123
+
124
+ @computation_function()
125
+ def opening(src: ImageObj, p: MorphologyParam) -> ImageObj:
126
+ """Compute morphological opening with :py:func:`skimage.morphology.opening`
127
+
128
+ Args:
129
+ src: input image object
130
+ p: parameters
131
+
132
+ Returns:
133
+ Output image object
134
+ """
135
+ dst = dst_1_to_1(src, "opening", f"radius={p.radius}")
136
+ dst.data = morphology.opening(src.data, morphology.disk(p.radius))
137
+ restore_data_outside_roi(dst, src)
138
+ return dst
139
+
140
+
141
+ @computation_function()
142
+ def closing(src: ImageObj, p: MorphologyParam) -> ImageObj:
143
+ """Compute morphological closing with :py:func:`skimage.morphology.closing`
144
+
145
+ Args:
146
+ src: input image object
147
+ p: parameters
148
+
149
+ Returns:
150
+ Output image object
151
+ """
152
+ dst = dst_1_to_1(src, "closing", f"radius={p.radius}")
153
+ dst.data = morphology.closing(src.data, morphology.disk(p.radius))
154
+ restore_data_outside_roi(dst, src)
155
+ return dst