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,159 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Profile extraction unit test
5
+ """
6
+
7
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
8
+
9
+ import numpy as np
10
+ import pytest
11
+
12
+ import sigima.objects
13
+ import sigima.params
14
+ import sigima.proc.image
15
+ from sigima.tests.data import create_sincos_image
16
+ from sigima.tests.helpers import check_array_result
17
+
18
+
19
+ @pytest.mark.validation
20
+ def test_line_profile() -> None:
21
+ """Test line profile computation"""
22
+ width, height = 256, 128
23
+ dtype = sigima.objects.ImageDatatypes.UINT16
24
+ newparam = sigima.objects.NewImageParam.create(
25
+ dtype=dtype, height=height, width=width
26
+ )
27
+ ima = create_sincos_image(newparam)
28
+
29
+ # Test horizontal line profile
30
+ row = 100
31
+ param = sigima.params.LineProfileParam.create(row=row, direction="horizontal")
32
+ sig = sigima.proc.image.line_profile(ima, param)
33
+ assert sig is not None
34
+ assert len(sig.y) == width
35
+ exp = np.array(ima.data[row, :], dtype=float)
36
+ check_array_result("Horizontal line profile", sig.y, exp)
37
+
38
+ # Test vertical line profile
39
+ col = 50
40
+ param = sigima.params.LineProfileParam.create(col=col, direction="vertical")
41
+ sig = sigima.proc.image.line_profile(ima, param)
42
+ assert sig is not None
43
+ assert len(sig.y) == height
44
+ exp = np.array(ima.data[:, col], dtype=float)
45
+ check_array_result("Vertical line profile", sig.y, exp)
46
+
47
+
48
+ @pytest.mark.validation
49
+ def test_segment_profile() -> None:
50
+ """Test segment profile computation"""
51
+ width, height = 256, 128
52
+ dtype = sigima.objects.ImageDatatypes.UINT16
53
+ newparam = sigima.objects.NewImageParam.create(
54
+ dtype=dtype, height=height, width=width
55
+ )
56
+ ima = create_sincos_image(newparam)
57
+
58
+ # Test segment profile
59
+ row1, col1, row2, col2 = 10, 20, 200, 20
60
+ param = sigima.params.SegmentProfileParam.create(
61
+ row1=row1, col1=col1, row2=row2, col2=col2
62
+ )
63
+ sig = sigima.proc.image.segment_profile(ima, param)
64
+ assert sig is not None
65
+ assert len(sig.y) == min(row2, height - 1) - max(row1, 0) + 1
66
+ exp = np.array(ima.data[10:200, 20], dtype=float)
67
+ check_array_result("Segment profile", sig.y, exp)
68
+
69
+
70
+ @pytest.mark.validation
71
+ def test_average_profile() -> None:
72
+ """Test average profile computation"""
73
+ width, height = 256, 128
74
+ dtype = sigima.objects.ImageDatatypes.UINT16
75
+ newparam = sigima.objects.NewImageParam.create(
76
+ dtype=dtype, height=height, width=width
77
+ )
78
+ ima = create_sincos_image(newparam)
79
+ row1, col1, row2, col2 = 10, 20, 200, 230
80
+ param = sigima.params.AverageProfileParam.create(
81
+ row1=row1, col1=col1, row2=row2, col2=col2
82
+ )
83
+
84
+ # Test horizontal average profile
85
+ param.direction = "horizontal"
86
+ sig = sigima.proc.image.average_profile(ima, param)
87
+ assert sig is not None
88
+ assert len(sig.y) == col2 - col1 + 1
89
+ exp = np.array(ima.data[row1 : row2 + 1, col1 : col2 + 1].mean(axis=0), dtype=float)
90
+ check_array_result("Horizontal average profile", sig.y, exp)
91
+
92
+ # Test vertical average profile
93
+ param.direction = "vertical"
94
+ sig = sigima.proc.image.average_profile(ima, param)
95
+ assert sig is not None
96
+ assert len(sig.y) == min(row2, height - 1) - max(row1, 0) + 1
97
+ exp = np.array(ima.data[row1 : row2 + 1, col1 : col2 + 1].mean(axis=1), dtype=float)
98
+ check_array_result("Vertical average profile", sig.y, exp)
99
+
100
+
101
+ def __test_radial_profile_center(
102
+ obj: sigima.objects.ImageObj, p: sigima.params.RadialProfileParam
103
+ ) -> sigima.objects.SignalObj:
104
+ """Test radial profile computation with given center.
105
+
106
+ Args:
107
+ obj: Image object
108
+ p: Radial profile parameters
109
+
110
+ Returns:
111
+ Signal object containing the radial profile
112
+ """
113
+ sig = sigima.proc.image.radial_profile(obj, p)
114
+ assert sig is not None
115
+ assert len(sig.x) == len(sig.y)
116
+ assert len(sig.y) > 0
117
+ # Check that profile values are within expected range
118
+ assert np.all(np.isfinite(sig.y))
119
+ assert np.all(sig.y >= 0) # Pixel values should be non-negative
120
+ return sig
121
+
122
+
123
+ @pytest.mark.validation
124
+ def test_radial_profile() -> None:
125
+ """Test radial profile computation"""
126
+ width, height = 256, 128
127
+ dtype = sigima.objects.ImageDatatypes.UINT16
128
+ newparam = sigima.objects.NewImageParam.create(
129
+ dtype=dtype, height=height, width=width
130
+ )
131
+ ima = create_sincos_image(newparam)
132
+
133
+ # Test radial profile with centroid center
134
+ param = sigima.params.RadialProfileParam.create(center="centroid")
135
+ __test_radial_profile_center(ima, param)
136
+
137
+ # Test radial profile with image center
138
+ param = sigima.params.RadialProfileParam.create(center="center")
139
+ __test_radial_profile_center(ima, param)
140
+
141
+ # Test radial profile with user-defined center
142
+ x0, y0 = width // 2, height // 2
143
+ param = sigima.params.RadialProfileParam.create(center="user", x0=x0, y0=y0)
144
+ sig = __test_radial_profile_center(ima, param)
145
+
146
+ # Test that the x-axis represents distance from center (symmetric around 0)
147
+ assert sig.x[0] < 0 # First element should be negative
148
+ assert sig.x[-1] > 0 # Last element should be positive
149
+ assert sig.x[len(sig.x) // 2] == 0 # Center should be at distance 0
150
+
151
+ # Additional validation using the helper function for the last profile
152
+ check_array_result("Radial profile", sig.y, sig.y)
153
+
154
+
155
+ if __name__ == "__main__":
156
+ test_line_profile()
157
+ test_segment_profile()
158
+ test_average_profile()
159
+ test_radial_profile()
@@ -0,0 +1,121 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """Unit tests for image projection functions."""
4
+
5
+ from __future__ import annotations
6
+
7
+ import numpy as np
8
+ import pytest
9
+
10
+ import sigima.objects
11
+ import sigima.proc.image as sipi
12
+ from sigima.tests import guiutils
13
+ from sigima.tests.data import create_sincos_image
14
+ from sigima.tests.helpers import check_array_result, check_scalar_result
15
+
16
+
17
+ @pytest.mark.validation
18
+ def test_image_horizontal_projection() -> None:
19
+ """Test image horizontal projection."""
20
+ width, height = 64, 48
21
+ dtype = sigima.objects.ImageDatatypes.UINT16
22
+ newparam = sigima.objects.NewImageParam.create(
23
+ dtype=dtype, height=height, width=width
24
+ )
25
+ ima = create_sincos_image(newparam)
26
+
27
+ # Add axis labels and units to the image.
28
+ ima.xunit = "px"
29
+ ima.yunit = "mm"
30
+ ima.zunit = "a.u."
31
+ ima.xlabel = "X position"
32
+ ima.ylabel = "Y position"
33
+ ima.zlabel = "Intensity"
34
+
35
+ sig = sipi.horizontal_projection(ima)
36
+ assert sig is not None
37
+
38
+ # Visualize image and result profile during interactive runs.
39
+ guiutils.view_images_if_gui(ima, title="Horizontal projection test image")
40
+ guiutils.view_curves_if_gui(sig, title="Horizontal projection profile")
41
+
42
+ # Signal length should equal the number of columns.
43
+ assert ima.data is not None
44
+ assert len(sig.x) == ima.data.shape[1]
45
+ # X-coordinates spacing should match the image's dx.
46
+ dx = np.mean(np.diff(sig.x))
47
+ assert ima.dx is not None
48
+ check_scalar_result("X-axis spacing", dx, ima.dx)
49
+
50
+ expected = np.sum(ima.data, axis=0, dtype=np.float64)
51
+ check_array_result("Horizontal projection", sig.y, expected)
52
+
53
+ # Check labels and units.
54
+ assert sig.xlabel == ima.xlabel, (
55
+ f"X-axis label mismatch: got {sig.xlabel}, expected {ima.xlabel}"
56
+ )
57
+ assert sig.xunit == ima.xunit, (
58
+ f"X-axis unit mismatch: got {sig.xunit}, expected {ima.xunit}"
59
+ )
60
+ assert sig.ylabel == ima.zlabel, (
61
+ f"Y-axis label mismatch: got {sig.ylabel}, expected {ima.zlabel}"
62
+ )
63
+ assert sig.yunit == ima.zunit, (
64
+ f"Y-axis unit mismatch: got {sig.yunit}, expected {ima.zunit}"
65
+ )
66
+
67
+
68
+ @pytest.mark.validation
69
+ def test_image_vertical_projection() -> None:
70
+ """Test image vertical projection."""
71
+ width, height = 128, 64
72
+ dtype = sigima.objects.ImageDatatypes.UINT16
73
+ newparam = sigima.objects.NewImageParam.create(
74
+ dtype=dtype, height=height, width=width
75
+ )
76
+ ima = create_sincos_image(newparam)
77
+ # Add axis labels and units to the image.
78
+ ima.xunit = "px"
79
+ ima.yunit = "mm"
80
+ ima.zunit = "a.u."
81
+ ima.xlabel = "X position"
82
+ ima.ylabel = "Y position"
83
+ ima.zlabel = "Intensity"
84
+
85
+ sig = sipi.vertical_projection(ima)
86
+ assert sig is not None
87
+
88
+ # Visualize image and result profile during interactive runs.
89
+ guiutils.view_images_if_gui(ima, title="Vertical projection test image")
90
+ guiutils.view_curves_if_gui(sig, title="Vertical projection profile")
91
+
92
+ # Signal length should equal the number of rows.
93
+ assert ima.data is not None
94
+ assert len(sig.x) == ima.data.shape[0]
95
+ # X-coordinates spacing should match the image's dy.
96
+ dx = np.mean(np.diff(sig.x))
97
+ assert ima.dy is not None
98
+ check_scalar_result("X-axis spacing", dx, ima.dy)
99
+
100
+ expected = np.sum(ima.data, axis=1, dtype=np.float64)
101
+ check_array_result("Vertical projection", sig.y, expected)
102
+
103
+ # Check labels and units.
104
+ assert sig.xlabel == ima.ylabel, (
105
+ f"X-axis label mismatch: got {sig.xlabel}, expected {ima.ylabel}"
106
+ )
107
+ assert sig.xunit == ima.yunit, (
108
+ f"X-axis unit mismatch: got {sig.xunit}, expected {ima.yunit}"
109
+ )
110
+ assert sig.ylabel == ima.zlabel, (
111
+ f"Y-axis label mismatch: got {sig.ylabel}, expected {ima.zlabel}"
112
+ )
113
+ assert sig.yunit == ima.zunit, (
114
+ f"Y-axis unit mismatch: got {sig.yunit}, expected {ima.zunit}"
115
+ )
116
+
117
+
118
+ if __name__ == "__main__":
119
+ guiutils.enable_gui()
120
+ test_image_horizontal_projection()
121
+ test_image_vertical_projection()
@@ -0,0 +1,141 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ Unit tests for restoration computation functions.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import numpy as np
10
+ import pytest
11
+ from skimage import morphology, restoration
12
+
13
+ import sigima.enums
14
+ import sigima.objects
15
+ import sigima.params
16
+ import sigima.proc.image
17
+ from sigima.tests import guiutils
18
+ from sigima.tests.data import create_multigaussian_image, get_test_image
19
+ from sigima.tests.helpers import check_array_result
20
+
21
+
22
+ @pytest.mark.validation
23
+ def test_denoise_tv() -> None:
24
+ """Validation test for the image Total Variation denoising processing."""
25
+ # See [1] in sigima\tests\image\__init__.py for more details about the validation.
26
+ src = get_test_image("flower.npy")
27
+ src.data = src.data[::8, ::8]
28
+ for weight, eps, mni in ((0.1, 0.0002, 200), (0.5, 0.0001, 100)):
29
+ p = sigima.params.DenoiseTVParam.create(
30
+ weight=weight, eps=eps, max_num_iter=mni
31
+ )
32
+ dst = sigima.proc.image.denoise_tv(src, p)
33
+ exp = restoration.denoise_tv_chambolle(src.data, weight, eps, mni)
34
+ check_array_result(
35
+ f"DenoiseTV[weight={weight},eps={eps},max_num_iter={mni}]",
36
+ dst.data,
37
+ exp,
38
+ )
39
+
40
+
41
+ @pytest.mark.validation
42
+ def test_denoise_bilateral() -> None:
43
+ """Validation test for the image bilateral denoising processing."""
44
+ # See [1] in sigima\tests\image\__init__.py for more details about the validation.
45
+ src = get_test_image("flower.npy")
46
+ src.data = src.data[::8, ::8]
47
+ for sigma, mode in ((1.0, "constant"), (2.0, "edge")):
48
+ p = sigima.params.DenoiseBilateralParam.create(sigma_spatial=sigma, mode=mode)
49
+ dst = sigima.proc.image.denoise_bilateral(src, p)
50
+ exp = restoration.denoise_bilateral(src.data, sigma_spatial=sigma, mode=mode)
51
+ check_array_result(
52
+ f"DenoiseBilateral[sigma_spatial={sigma},mode={mode}]",
53
+ dst.data,
54
+ exp,
55
+ )
56
+
57
+
58
+ @pytest.mark.validation
59
+ def test_denoise_wavelet() -> None:
60
+ """Validation test for the image wavelet denoising processing."""
61
+ # See [1] in sigima\tests\image\__init__.py for more details about the validation.
62
+ src = get_test_image("flower.npy")
63
+ src.data = src.data[::8, ::8]
64
+ p = sigima.params.DenoiseWaveletParam()
65
+ for wavelets in ("db1", "db2", "db3"):
66
+ for mode in sigima.enums.ThresholdMethod:
67
+ for method in ("BayesShrink",):
68
+ p.wavelets, p.mode, p.method = wavelets, mode, method
69
+ dst = sigima.proc.image.denoise_wavelet(src, p)
70
+ exp = restoration.denoise_wavelet(
71
+ src.data, wavelet=wavelets, mode=mode.value, method=method
72
+ )
73
+ check_array_result(
74
+ f"DenoiseWavelet[wavelets={wavelets},mode={mode},method={method}]",
75
+ dst.data,
76
+ exp,
77
+ atol=0.1,
78
+ )
79
+
80
+
81
+ @pytest.mark.validation
82
+ def test_denoise_tophat() -> None:
83
+ """Validation test for the image top-hat denoising processing."""
84
+ # See [1] in sigima\tests\image\__init__.py for more details about the validation.
85
+ src = get_test_image("flower.npy")
86
+ p = sigima.params.MorphologyParam.create(radius=10)
87
+ dst = sigima.proc.image.denoise_tophat(src, p)
88
+ footprint = morphology.disk(p.radius)
89
+ exp = src.data - morphology.white_tophat(src.data, footprint=footprint)
90
+ check_array_result(f"DenoiseTophat[radius={p.radius}]", dst.data, exp)
91
+
92
+
93
+ @pytest.mark.validation
94
+ def test_erase() -> None:
95
+ """Validation test for the image erase processing."""
96
+ obj = create_multigaussian_image()
97
+
98
+ # Single ROI erase
99
+ coords = [600, 800, 300, 200]
100
+ ix0, iy0, idx, idy = coords
101
+ ix1, iy1 = ix0 + idx, iy0 + idy
102
+ p = sigima.objects.ROI2DParam()
103
+ p.x0, p.y0, p.dx, p.dy = coords
104
+ dst = sigima.proc.image.erase(obj, p)
105
+ exp = obj.data.copy()
106
+ exp[iy0:iy1, ix0:ix1] = np.ma.mean(obj.data[iy0:iy1, ix0:ix1])
107
+ guiutils.view_images_side_by_side_if_gui(
108
+ [obj.data, dst.data, exp], ["Original", "Erased", "Expected"]
109
+ )
110
+ check_array_result("Erase", dst.data, exp)
111
+
112
+ # Multiple ROIs erase
113
+ coords = [
114
+ [600, 800, 300, 200],
115
+ [100, 200, 300, 200],
116
+ [400, 500, 300, 200],
117
+ ]
118
+ params: list[sigima.objects.ROI2DParam] = []
119
+ for c in coords:
120
+ p = sigima.objects.ROI2DParam()
121
+ p.x0, p.y0, p.dx, p.dy = c
122
+ params.append(p)
123
+ dst = sigima.proc.image.erase(obj, params)
124
+ exp = obj.data.copy()
125
+ for p in params:
126
+ ix0, iy0 = int(p.x0), int(p.y0)
127
+ ix1, iy1 = int(p.x0 + p.dx), int(p.y0 + p.dy)
128
+ exp[iy0:iy1, ix0:ix1] = np.ma.mean(obj.data[iy0:iy1, ix0:ix1])
129
+ guiutils.view_images_side_by_side_if_gui(
130
+ [obj.data, dst.data, exp], ["Original", "Erased", "Expected"]
131
+ )
132
+ check_array_result("Erase", dst.data, exp)
133
+
134
+
135
+ if __name__ == "__main__":
136
+ guiutils.enable_gui()
137
+ test_denoise_tv()
138
+ test_denoise_bilateral()
139
+ test_denoise_wavelet()
140
+ test_denoise_tophat()
141
+ test_erase()
@@ -0,0 +1,53 @@
1
+ # Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
2
+
3
+ """
4
+ ROI image parameters unit test.
5
+ """
6
+
7
+ # pylint: disable=invalid-name # Allows short reference names like x, y, ...
8
+
9
+ from __future__ import annotations
10
+
11
+ import guidata.dataset as gds
12
+ import numpy as np
13
+ import pytest
14
+
15
+ from sigima.objects import ROI2DParam
16
+ from sigima.tests import guiutils
17
+ from sigima.tests.env import execenv
18
+
19
+
20
+ def __create_roi_2d_parameters() -> gds.DataSetGroup:
21
+ """Create a group of ROI parameters."""
22
+ p_circ = ROI2DParam("Circular")
23
+ p_circ.geometry = "circle"
24
+ p_circ.xc, p_circ.yc, p_circ.r = 100, 200, 50
25
+ p_rect = ROI2DParam("Rectangular")
26
+ p_rect.geometry = "rectangle"
27
+ p_rect.x0, p_rect.y0, p_rect.dx, p_rect.dy = 50, 150, 150, 250
28
+ p_poly = ROI2DParam("Polygonal")
29
+ p_poly.geometry = "polygon"
30
+ p_poly.points = np.array([50.0, 150.0, 150.0, 150.0, 150.0, 250.0, 50.0, 250.0])
31
+ params = [p_circ, p_rect, p_poly]
32
+ return gds.DataSetGroup(params, title="ROI Parameters")
33
+
34
+
35
+ def test_roi_2d_param_unit():
36
+ """ROI parameters unit test."""
37
+ group = __create_roi_2d_parameters()
38
+ for param in group.datasets:
39
+ execenv.print(param)
40
+
41
+
42
+ @pytest.mark.gui
43
+ def test_roi_2d_param_interactive():
44
+ """ROI parameters interactive test."""
45
+ with guiutils.lazy_qt_app_context(force=True):
46
+ group = __create_roi_2d_parameters()
47
+ if group.edit():
48
+ for param in group.datasets:
49
+ execenv.print(param)
50
+
51
+
52
+ if __name__ == "__main__":
53
+ test_roi_2d_param_interactive()