sigima 0.0.1.dev0__py3-none-any.whl → 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sigima/__init__.py +142 -2
- sigima/client/__init__.py +105 -0
- sigima/client/base.py +780 -0
- sigima/client/remote.py +469 -0
- sigima/client/stub.py +814 -0
- sigima/client/utils.py +90 -0
- sigima/config.py +444 -0
- sigima/data/logo/Sigima.svg +135 -0
- sigima/data/tests/annotations.json +798 -0
- sigima/data/tests/curve_fitting/exponential_fit.txt +511 -0
- sigima/data/tests/curve_fitting/gaussian_fit.txt +100 -0
- sigima/data/tests/curve_fitting/piecewiseexponential_fit.txt +1022 -0
- sigima/data/tests/curve_fitting/polynomial_fit.txt +100 -0
- sigima/data/tests/curve_fitting/twohalfgaussian_fit.txt +1000 -0
- sigima/data/tests/curve_formats/bandwidth.txt +201 -0
- sigima/data/tests/curve_formats/boxcar.npy +0 -0
- sigima/data/tests/curve_formats/datetime.txt +1001 -0
- sigima/data/tests/curve_formats/dynamic_parameters.txt +4000 -0
- sigima/data/tests/curve_formats/fw1e2.txt +301 -0
- sigima/data/tests/curve_formats/fwhm.txt +319 -0
- sigima/data/tests/curve_formats/multiple_curves.csv +29 -0
- sigima/data/tests/curve_formats/noised_saw.mat +0 -0
- sigima/data/tests/curve_formats/oscilloscope.csv +111 -0
- sigima/data/tests/curve_formats/other/other2/recursive2.txt +5 -0
- sigima/data/tests/curve_formats/other/recursive1.txt +5 -0
- sigima/data/tests/curve_formats/paracetamol.npy +0 -0
- sigima/data/tests/curve_formats/paracetamol.txt +1010 -0
- sigima/data/tests/curve_formats/paracetamol_dx_dy.csv +1000 -0
- sigima/data/tests/curve_formats/paracetamol_dy.csv +1001 -0
- sigima/data/tests/curve_formats/pulse1.npy +0 -0
- sigima/data/tests/curve_formats/pulse2.npy +0 -0
- sigima/data/tests/curve_formats/simple.txt +5 -0
- sigima/data/tests/curve_formats/spectrum.mca +2139 -0
- sigima/data/tests/curve_formats/square2.npy +0 -0
- sigima/data/tests/curve_formats/step.npy +0 -0
- sigima/data/tests/fabry-perot1.jpg +0 -0
- sigima/data/tests/fabry-perot2.jpg +0 -0
- sigima/data/tests/flower.npy +0 -0
- sigima/data/tests/image_formats/NF 180338201.scor-data +11003 -0
- sigima/data/tests/image_formats/binary_image.npy +0 -0
- sigima/data/tests/image_formats/binary_image.png +0 -0
- sigima/data/tests/image_formats/centroid_test.npy +0 -0
- sigima/data/tests/image_formats/coordinated_text/complex_image.txt +10011 -0
- sigima/data/tests/image_formats/coordinated_text/complex_ref_image.txt +10010 -0
- sigima/data/tests/image_formats/coordinated_text/image.txt +15 -0
- sigima/data/tests/image_formats/coordinated_text/image2.txt +14 -0
- sigima/data/tests/image_formats/coordinated_text/image_no_unit_no_label.txt +14 -0
- sigima/data/tests/image_formats/coordinated_text/image_with_nan.txt +15 -0
- sigima/data/tests/image_formats/coordinated_text/image_with_unit.txt +14 -0
- sigima/data/tests/image_formats/fiber.csv +480 -0
- sigima/data/tests/image_formats/fiber.jpg +0 -0
- sigima/data/tests/image_formats/fiber.png +0 -0
- sigima/data/tests/image_formats/fiber.txt +480 -0
- sigima/data/tests/image_formats/gaussian_spot_with_noise.npy +0 -0
- sigima/data/tests/image_formats/mr-brain.dcm +0 -0
- sigima/data/tests/image_formats/noised_gaussian.mat +0 -0
- sigima/data/tests/image_formats/sif_reader/nd_lum_image_no_glue.sif +0 -0
- sigima/data/tests/image_formats/sif_reader/raman1.sif +0 -0
- sigima/data/tests/image_formats/tiling.txt +10 -0
- sigima/data/tests/image_formats/uint16.tiff +0 -0
- sigima/data/tests/image_formats/uint8.tiff +0 -0
- sigima/data/tests/laser_beam/TEM00_z_13.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_18.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_23.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_30.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_35.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_40.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_45.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_50.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_55.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_60.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_65.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_70.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_75.jpg +0 -0
- sigima/data/tests/laser_beam/TEM00_z_80.jpg +0 -0
- sigima/enums.py +195 -0
- sigima/io/__init__.py +123 -0
- sigima/io/base.py +311 -0
- sigima/io/common/__init__.py +5 -0
- sigima/io/common/basename.py +164 -0
- sigima/io/common/converters.py +189 -0
- sigima/io/common/objmeta.py +181 -0
- sigima/io/common/textreader.py +58 -0
- sigima/io/convenience.py +157 -0
- sigima/io/enums.py +17 -0
- sigima/io/ftlab.py +395 -0
- sigima/io/image/__init__.py +9 -0
- sigima/io/image/base.py +177 -0
- sigima/io/image/formats.py +1016 -0
- sigima/io/image/funcs.py +414 -0
- sigima/io/signal/__init__.py +9 -0
- sigima/io/signal/base.py +129 -0
- sigima/io/signal/formats.py +290 -0
- sigima/io/signal/funcs.py +723 -0
- sigima/objects/__init__.py +260 -0
- sigima/objects/base.py +937 -0
- sigima/objects/image/__init__.py +88 -0
- sigima/objects/image/creation.py +556 -0
- sigima/objects/image/object.py +524 -0
- sigima/objects/image/roi.py +904 -0
- sigima/objects/scalar/__init__.py +57 -0
- sigima/objects/scalar/common.py +215 -0
- sigima/objects/scalar/geometry.py +502 -0
- sigima/objects/scalar/table.py +784 -0
- sigima/objects/shape.py +290 -0
- sigima/objects/signal/__init__.py +133 -0
- sigima/objects/signal/constants.py +27 -0
- sigima/objects/signal/creation.py +1428 -0
- sigima/objects/signal/object.py +444 -0
- sigima/objects/signal/roi.py +274 -0
- sigima/params.py +405 -0
- sigima/proc/__init__.py +96 -0
- sigima/proc/base.py +381 -0
- sigima/proc/decorator.py +330 -0
- sigima/proc/image/__init__.py +513 -0
- sigima/proc/image/arithmetic.py +335 -0
- sigima/proc/image/base.py +260 -0
- sigima/proc/image/detection.py +519 -0
- sigima/proc/image/edges.py +329 -0
- sigima/proc/image/exposure.py +406 -0
- sigima/proc/image/extraction.py +458 -0
- sigima/proc/image/filtering.py +219 -0
- sigima/proc/image/fourier.py +147 -0
- sigima/proc/image/geometry.py +661 -0
- sigima/proc/image/mathops.py +340 -0
- sigima/proc/image/measurement.py +195 -0
- sigima/proc/image/morphology.py +155 -0
- sigima/proc/image/noise.py +107 -0
- sigima/proc/image/preprocessing.py +182 -0
- sigima/proc/image/restoration.py +235 -0
- sigima/proc/image/threshold.py +217 -0
- sigima/proc/image/transformations.py +393 -0
- sigima/proc/signal/__init__.py +376 -0
- sigima/proc/signal/analysis.py +206 -0
- sigima/proc/signal/arithmetic.py +551 -0
- sigima/proc/signal/base.py +262 -0
- sigima/proc/signal/extraction.py +60 -0
- sigima/proc/signal/features.py +310 -0
- sigima/proc/signal/filtering.py +484 -0
- sigima/proc/signal/fitting.py +276 -0
- sigima/proc/signal/fourier.py +259 -0
- sigima/proc/signal/mathops.py +420 -0
- sigima/proc/signal/processing.py +580 -0
- sigima/proc/signal/stability.py +175 -0
- sigima/proc/title_formatting.py +227 -0
- sigima/proc/validation.py +272 -0
- sigima/tests/__init__.py +7 -0
- sigima/tests/common/__init__.py +0 -0
- sigima/tests/common/arithmeticparam_unit_test.py +26 -0
- sigima/tests/common/basename_unit_test.py +126 -0
- sigima/tests/common/client_unit_test.py +412 -0
- sigima/tests/common/converters_unit_test.py +77 -0
- sigima/tests/common/decorator_unit_test.py +176 -0
- sigima/tests/common/examples_unit_test.py +104 -0
- sigima/tests/common/kernel_normalization_unit_test.py +242 -0
- sigima/tests/common/roi_basic_unit_test.py +73 -0
- sigima/tests/common/roi_geometry_unit_test.py +171 -0
- sigima/tests/common/scalar_builder_unit_test.py +142 -0
- sigima/tests/common/scalar_unit_test.py +991 -0
- sigima/tests/common/shape_unit_test.py +183 -0
- sigima/tests/common/stat_unit_test.py +138 -0
- sigima/tests/common/title_formatting_unit_test.py +338 -0
- sigima/tests/common/tools_coordinates_unit_test.py +60 -0
- sigima/tests/common/transformations_unit_test.py +178 -0
- sigima/tests/common/validation_unit_test.py +205 -0
- sigima/tests/conftest.py +129 -0
- sigima/tests/data.py +998 -0
- sigima/tests/env.py +280 -0
- sigima/tests/guiutils.py +163 -0
- sigima/tests/helpers.py +532 -0
- sigima/tests/image/__init__.py +28 -0
- sigima/tests/image/binning_unit_test.py +128 -0
- sigima/tests/image/blob_detection_unit_test.py +312 -0
- sigima/tests/image/centroid_unit_test.py +170 -0
- sigima/tests/image/check_2d_array_unit_test.py +63 -0
- sigima/tests/image/contour_unit_test.py +172 -0
- sigima/tests/image/convolution_unit_test.py +178 -0
- sigima/tests/image/datatype_unit_test.py +67 -0
- sigima/tests/image/edges_unit_test.py +155 -0
- sigima/tests/image/enclosingcircle_unit_test.py +88 -0
- sigima/tests/image/exposure_unit_test.py +223 -0
- sigima/tests/image/fft2d_unit_test.py +189 -0
- sigima/tests/image/filtering_unit_test.py +166 -0
- sigima/tests/image/geometry_unit_test.py +654 -0
- sigima/tests/image/hough_circle_unit_test.py +147 -0
- sigima/tests/image/imageobj_unit_test.py +737 -0
- sigima/tests/image/morphology_unit_test.py +71 -0
- sigima/tests/image/noise_unit_test.py +57 -0
- sigima/tests/image/offset_correction_unit_test.py +72 -0
- sigima/tests/image/operation_unit_test.py +518 -0
- sigima/tests/image/peak2d_limits_unit_test.py +41 -0
- sigima/tests/image/peak2d_unit_test.py +133 -0
- sigima/tests/image/profile_unit_test.py +159 -0
- sigima/tests/image/projections_unit_test.py +121 -0
- sigima/tests/image/restoration_unit_test.py +141 -0
- sigima/tests/image/roi2dparam_unit_test.py +53 -0
- sigima/tests/image/roi_advanced_unit_test.py +588 -0
- sigima/tests/image/roi_grid_unit_test.py +279 -0
- sigima/tests/image/spectrum2d_unit_test.py +40 -0
- sigima/tests/image/threshold_unit_test.py +91 -0
- sigima/tests/io/__init__.py +0 -0
- sigima/tests/io/addnewformat_unit_test.py +125 -0
- sigima/tests/io/convenience_funcs_unit_test.py +470 -0
- sigima/tests/io/coordinated_text_format_unit_test.py +495 -0
- sigima/tests/io/datetime_csv_unit_test.py +198 -0
- sigima/tests/io/imageio_formats_test.py +41 -0
- sigima/tests/io/ioregistry_unit_test.py +69 -0
- sigima/tests/io/objmeta_unit_test.py +87 -0
- sigima/tests/io/readobj_unit_test.py +130 -0
- sigima/tests/io/readwriteobj_unit_test.py +67 -0
- sigima/tests/signal/__init__.py +0 -0
- sigima/tests/signal/analysis_unit_test.py +135 -0
- sigima/tests/signal/check_1d_arrays_unit_test.py +169 -0
- sigima/tests/signal/convolution_unit_test.py +404 -0
- sigima/tests/signal/datetime_unit_test.py +176 -0
- sigima/tests/signal/fft1d_unit_test.py +303 -0
- sigima/tests/signal/filters_unit_test.py +403 -0
- sigima/tests/signal/fitting_unit_test.py +929 -0
- sigima/tests/signal/fwhm_unit_test.py +111 -0
- sigima/tests/signal/noise_unit_test.py +128 -0
- sigima/tests/signal/offset_correction_unit_test.py +34 -0
- sigima/tests/signal/operation_unit_test.py +489 -0
- sigima/tests/signal/peakdetection_unit_test.py +145 -0
- sigima/tests/signal/processing_unit_test.py +657 -0
- sigima/tests/signal/pulse/__init__.py +112 -0
- sigima/tests/signal/pulse/crossing_times_unit_test.py +123 -0
- sigima/tests/signal/pulse/plateau_detection_unit_test.py +102 -0
- sigima/tests/signal/pulse/pulse_unit_test.py +1824 -0
- sigima/tests/signal/roi_advanced_unit_test.py +392 -0
- sigima/tests/signal/signalobj_unit_test.py +603 -0
- sigima/tests/signal/stability_unit_test.py +431 -0
- sigima/tests/signal/uncertainty_unit_test.py +611 -0
- sigima/tests/vistools.py +1030 -0
- sigima/tools/__init__.py +59 -0
- sigima/tools/checks.py +290 -0
- sigima/tools/coordinates.py +308 -0
- sigima/tools/datatypes.py +26 -0
- sigima/tools/image/__init__.py +97 -0
- sigima/tools/image/detection.py +451 -0
- sigima/tools/image/exposure.py +77 -0
- sigima/tools/image/extraction.py +48 -0
- sigima/tools/image/fourier.py +260 -0
- sigima/tools/image/geometry.py +190 -0
- sigima/tools/image/preprocessing.py +165 -0
- sigima/tools/signal/__init__.py +86 -0
- sigima/tools/signal/dynamic.py +254 -0
- sigima/tools/signal/features.py +135 -0
- sigima/tools/signal/filtering.py +171 -0
- sigima/tools/signal/fitting.py +1171 -0
- sigima/tools/signal/fourier.py +466 -0
- sigima/tools/signal/interpolation.py +70 -0
- sigima/tools/signal/peakdetection.py +126 -0
- sigima/tools/signal/pulse.py +1626 -0
- sigima/tools/signal/scaling.py +50 -0
- sigima/tools/signal/stability.py +258 -0
- sigima/tools/signal/windowing.py +90 -0
- sigima/worker.py +79 -0
- sigima-1.0.0.dist-info/METADATA +233 -0
- sigima-1.0.0.dist-info/RECORD +262 -0
- {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/licenses/LICENSE +29 -29
- sigima-0.0.1.dev0.dist-info/METADATA +0 -60
- sigima-0.0.1.dev0.dist-info/RECORD +0 -6
- {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/WHEEL +0 -0
- {sigima-0.0.1.dev0.dist-info → sigima-1.0.0.dist-info}/top_level.txt +0 -0
|
@@ -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()
|