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
sigima/objects/shape.py
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Coordinates objects module
|
|
5
|
+
==========================
|
|
6
|
+
|
|
7
|
+
Coordinate objects are 2D geometric entities that are used to represent and manipulate
|
|
8
|
+
shapes in a two-dimensional space. Coordinates are typically defined in the physical
|
|
9
|
+
coordinate system (as opposed to the image pixel coordinate system).
|
|
10
|
+
Geometric transformations, such as translation, rotation, and scaling, can be applied
|
|
11
|
+
to those objects to manipulate their position and size.
|
|
12
|
+
|
|
13
|
+
Applications
|
|
14
|
+
------------
|
|
15
|
+
|
|
16
|
+
Coordinate objects have two main applications:
|
|
17
|
+
|
|
18
|
+
1. ROIs (Regions of Interest) for image processing tasks.
|
|
19
|
+
2. Geometry results of signal and image processing tasks.
|
|
20
|
+
|
|
21
|
+
In both cases, geometric transformations can be applied to coordinate objects (rotation,
|
|
22
|
+
translation, horizontal flipping, vertical flipping, transposition, and scaling), in
|
|
23
|
+
order to apply the same transformation as the one applied to the image or signal data.
|
|
24
|
+
|
|
25
|
+
.. note::
|
|
26
|
+
|
|
27
|
+
Geometric transformations currently support only the necessary transformations
|
|
28
|
+
for image processing (not for signal processing).
|
|
29
|
+
|
|
30
|
+
Design choices
|
|
31
|
+
--------------
|
|
32
|
+
|
|
33
|
+
Coordinate objects are built around a `data` attribute that holds the characteristics
|
|
34
|
+
defining the shape in the form of a 1D array:
|
|
35
|
+
|
|
36
|
+
- (x, y) coordinates are stored in a flattened format: (x1, y1, x2, y2, ..., xn, yn)
|
|
37
|
+
- Point coordinates are represented as (x, y).
|
|
38
|
+
- Segment coordinates are represented as (x1, y1, x2, y2),
|
|
39
|
+
where (x1, y1) is the start point and (x2, y2) is the end point.
|
|
40
|
+
- Rectangle coordinates are represented as (x0, y0, dx, dy),
|
|
41
|
+
where (x0, y0) is the top-left corner and (dx, dy) are the width and height.
|
|
42
|
+
- Circle coordinates are represented as (x, y, r),
|
|
43
|
+
where (x, y) is the center and r is the radius.
|
|
44
|
+
- Ellipse coordinates are represented as (x, y, a, b),
|
|
45
|
+
where (x, y) is the center, a is the semi-major axis, and b is the semi-minor axis.
|
|
46
|
+
- Polygon coordinates are represented as a flattened array of (x, y) pairs:
|
|
47
|
+
(x1, y1, x2, y2, ..., xn, yn).
|
|
48
|
+
|
|
49
|
+
At construction, the coordinates are validated to ensure they conform to the expected
|
|
50
|
+
format for each shape type.
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
from __future__ import annotations
|
|
54
|
+
|
|
55
|
+
import abc
|
|
56
|
+
|
|
57
|
+
import numpy as np
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class BaseCoordinates(abc.ABC):
|
|
61
|
+
"""Base class for 2D coordinates representation of shapes.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
data: 1D array or list of characteristics defining the shape.
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
VALID_SHAPE: tuple[int, int] | None = None # To be defined by subclasses
|
|
68
|
+
REQUIRES_EVEN_NUMBER_OF_VALUES: bool = False
|
|
69
|
+
|
|
70
|
+
def __init__(self, points: np.ndarray | list[int] | list[float]):
|
|
71
|
+
self.data = np.array(points, dtype=float)
|
|
72
|
+
self.validate()
|
|
73
|
+
|
|
74
|
+
def validate(self) -> None:
|
|
75
|
+
"""Validate the coordinates.
|
|
76
|
+
|
|
77
|
+
Raises:
|
|
78
|
+
ValueError: If the coordinates are invalid.
|
|
79
|
+
"""
|
|
80
|
+
if self.data.ndim != 1:
|
|
81
|
+
raise ValueError(
|
|
82
|
+
f"Invalid {self.__class__.__name__} coordinates ndim: "
|
|
83
|
+
f"{self.data.ndim} (expected 1)"
|
|
84
|
+
)
|
|
85
|
+
if self.VALID_SHAPE is not None and self.data.shape != self.VALID_SHAPE:
|
|
86
|
+
raise ValueError(
|
|
87
|
+
f"Invalid {self.__class__.__name__} coordinates shape: "
|
|
88
|
+
f"{self.data.shape} (expected {self.VALID_SHAPE})"
|
|
89
|
+
)
|
|
90
|
+
if self.REQUIRES_EVEN_NUMBER_OF_VALUES and self.data.size % 2 != 0:
|
|
91
|
+
raise ValueError(
|
|
92
|
+
f"Invalid {self.__class__.__name__} coordinates: "
|
|
93
|
+
f"even number of values expected (got {self.data.size})"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
def transform_affine(self, matrix: np.ndarray) -> None:
|
|
97
|
+
"""Apply a 2D affine transformation to the coordinates inplace.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
matrix: 3x3 affine transformation matrix.
|
|
101
|
+
"""
|
|
102
|
+
coords = self.data
|
|
103
|
+
if coords.size % 2 == 0:
|
|
104
|
+
pts = coords.reshape(-1, 2)
|
|
105
|
+
homo = np.c_[pts, np.ones(len(pts))]
|
|
106
|
+
out = (homo @ matrix.T)[:, :2].reshape(-1)
|
|
107
|
+
self.data[:] = out
|
|
108
|
+
else:
|
|
109
|
+
pts = coords[:2].reshape(1, 2)
|
|
110
|
+
homo = np.c_[pts, np.ones(1)]
|
|
111
|
+
out = (homo @ matrix.T)[:, :2].reshape(-1)
|
|
112
|
+
self.data[:2] = out
|
|
113
|
+
|
|
114
|
+
def copy(self) -> BaseCoordinates:
|
|
115
|
+
"""Return a copy of the coordinate object.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
BaseCoordinates: A new object with the same data.
|
|
119
|
+
"""
|
|
120
|
+
return self.__class__(self.data.copy())
|
|
121
|
+
|
|
122
|
+
def rotate(self, angle: float, center: tuple[float, float] = (0, 0)) -> None:
|
|
123
|
+
"""Rotate coordinates by a given angle around a center inplace.
|
|
124
|
+
|
|
125
|
+
Args:
|
|
126
|
+
angle: Rotation angle in radians (counterclockwise).
|
|
127
|
+
center: Center of rotation (x, y). Defaults to (0, 0).
|
|
128
|
+
"""
|
|
129
|
+
cx, cy = center
|
|
130
|
+
c, s = np.cos(angle), np.sin(angle)
|
|
131
|
+
t1 = np.array([[1, 0, -cx], [0, 1, -cy], [0, 0, 1]], float)
|
|
132
|
+
r = np.array([[c, -s, 0], [s, c, 0], [0, 0, 1]], float)
|
|
133
|
+
t2 = np.array([[1, 0, cx], [0, 1, cy], [0, 0, 1]], float)
|
|
134
|
+
matrix = t2 @ r @ t1
|
|
135
|
+
self.transform_affine(matrix)
|
|
136
|
+
|
|
137
|
+
def translate(self, dx: float, dy: float) -> None:
|
|
138
|
+
"""Translate coordinates by (dx, dy) inplace.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
dx: Translation along x-axis.
|
|
142
|
+
dy: Translation along y-axis.
|
|
143
|
+
"""
|
|
144
|
+
matrix = np.array([[1, 0, dx], [0, 1, dy], [0, 0, 1]], float)
|
|
145
|
+
self.transform_affine(matrix)
|
|
146
|
+
|
|
147
|
+
def fliph(self, cx: float = 0.0) -> None:
|
|
148
|
+
"""Flip coordinates horizontally around a vertical line x=cx inplace.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
cx: x-coordinate of the vertical axis. Defaults to 0.0.
|
|
152
|
+
"""
|
|
153
|
+
matrix = np.array([[-1, 0, 2 * cx], [0, 1, 0], [0, 0, 1]], float)
|
|
154
|
+
self.transform_affine(matrix)
|
|
155
|
+
|
|
156
|
+
def flipv(self, cy: float = 0.0) -> None:
|
|
157
|
+
"""Flip coordinates vertically around a horizontal line y=cy inplace.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
cy: y-coordinate of the horizontal axis. Defaults to 0.0.
|
|
161
|
+
"""
|
|
162
|
+
matrix = np.array([[1, 0, 0], [0, -1, 2 * cy], [0, 0, 1]], float)
|
|
163
|
+
self.transform_affine(matrix)
|
|
164
|
+
|
|
165
|
+
def transpose(self) -> None:
|
|
166
|
+
"""Transpose coordinates (swap x and y) inplace."""
|
|
167
|
+
matrix = np.array([[0, 1, 0], [1, 0, 0], [0, 0, 1]], float)
|
|
168
|
+
self.transform_affine(matrix)
|
|
169
|
+
|
|
170
|
+
def scale(self, sx: float, sy: float, center: tuple[float, float] = (0, 0)) -> None:
|
|
171
|
+
"""Scale coordinates by (sx, sy) around a center inplace.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
sx: Scaling factor along x-axis.
|
|
175
|
+
sy: Scaling factor along y-axis.
|
|
176
|
+
center: Center of scaling (x, y). Defaults to (0, 0).
|
|
177
|
+
"""
|
|
178
|
+
cx, cy = center
|
|
179
|
+
t1 = np.array([[1, 0, -cx], [0, 1, -cy], [0, 0, 1]], float)
|
|
180
|
+
s = np.array([[sx, 0, 0], [0, sy, 0], [0, 0, 1]], float)
|
|
181
|
+
t2 = np.array([[1, 0, cx], [0, 1, cy], [0, 0, 1]], float)
|
|
182
|
+
matrix = t2 @ s @ t1
|
|
183
|
+
self.transform_affine(matrix)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class PointCoordinates(BaseCoordinates):
|
|
187
|
+
"""Class for point coordinates.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
data: 1D array point coordinates (x, y).
|
|
191
|
+
"""
|
|
192
|
+
|
|
193
|
+
VALID_SHAPE = (2,)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class SegmentCoordinates(BaseCoordinates):
|
|
197
|
+
"""Class for segment coordinates.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
data: 1D array point coordinates (x1, y1, x2, y2).
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
VALID_SHAPE = (4,)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
class RectangleCoordinates(BaseCoordinates):
|
|
207
|
+
"""Class for a rectangle coordinates.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
data: 1D array point coordinates (x0, y0, dx, dy).
|
|
211
|
+
"""
|
|
212
|
+
|
|
213
|
+
VALID_SHAPE = (4,)
|
|
214
|
+
|
|
215
|
+
def transform_affine(self, matrix: np.ndarray) -> None:
|
|
216
|
+
"""
|
|
217
|
+
Apply 2D affine transformation to rectangle coordinates.
|
|
218
|
+
|
|
219
|
+
For rectangles in (x0, y0, dx, dy) format, we transform the corner points
|
|
220
|
+
and then convert back to (x0, y0, dx, dy) format.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
matrix: 3x3 affine transformation matrix.
|
|
224
|
+
"""
|
|
225
|
+
x0, y0, dx, dy = self.data
|
|
226
|
+
|
|
227
|
+
# Convert to corner coordinates
|
|
228
|
+
x1, y1 = x0, y0
|
|
229
|
+
x2, y2 = x0 + dx, y0 + dy
|
|
230
|
+
|
|
231
|
+
# Transform both corners
|
|
232
|
+
corners = np.array([[x1, y1], [x2, y2]])
|
|
233
|
+
homo = np.c_[corners, np.ones(2)]
|
|
234
|
+
transformed = (homo @ matrix.T)[:, :2]
|
|
235
|
+
|
|
236
|
+
# Get the new bounding box
|
|
237
|
+
x_min, y_min = transformed.min(axis=0)
|
|
238
|
+
x_max, y_max = transformed.max(axis=0)
|
|
239
|
+
|
|
240
|
+
# Update data with new (x0, y0, dx, dy)
|
|
241
|
+
self.data[:] = [x_min, y_min, x_max - x_min, y_max - y_min]
|
|
242
|
+
|
|
243
|
+
def rotate(self, angle: float, center: tuple[float, float] = (0, 0)) -> None:
|
|
244
|
+
"""Rotate rectangle by a given angle around a center.
|
|
245
|
+
|
|
246
|
+
For rectangles, rotation may change the bounding box, so we transform
|
|
247
|
+
all corners and compute the new axis-aligned bounding rectangle.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
angle: Rotation angle in radians (counterclockwise).
|
|
251
|
+
center: Center of rotation (x, y). Defaults to (0, 0).
|
|
252
|
+
"""
|
|
253
|
+
cx, cy = center
|
|
254
|
+
c, s = np.cos(angle), np.sin(angle)
|
|
255
|
+
t1 = np.array([[1, 0, -cx], [0, 1, -cy], [0, 0, 1]], float)
|
|
256
|
+
r = np.array([[c, -s, 0], [s, c, 0], [0, 0, 1]], float)
|
|
257
|
+
t2 = np.array([[1, 0, cx], [0, 1, cy], [0, 0, 1]], float)
|
|
258
|
+
matrix = t2 @ r @ t1
|
|
259
|
+
self.transform_affine(matrix)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
class CircleCoordinates(BaseCoordinates):
|
|
263
|
+
"""Class for a circle coordinates.
|
|
264
|
+
|
|
265
|
+
Args:
|
|
266
|
+
data: 1D array point coordinates (x, y, r).
|
|
267
|
+
"""
|
|
268
|
+
|
|
269
|
+
VALID_SHAPE = (3,)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class EllipseCoordinates(BaseCoordinates):
|
|
273
|
+
"""Class for an ellipse coordinates.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
data: 1D array point coordinates (x, y, a, b).
|
|
277
|
+
"""
|
|
278
|
+
|
|
279
|
+
VALID_SHAPE = (4,)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
class PolygonCoordinates(BaseCoordinates):
|
|
283
|
+
"""Class for a polygon coordinates.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
data: 1D array point coordinates (x1, y1, x2, y2, ..., xn, yn).
|
|
287
|
+
"""
|
|
288
|
+
|
|
289
|
+
VALID_SHAPE = None
|
|
290
|
+
REQUIRES_EVEN_NUMBER_OF_VALUES = True
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Signal objects subpackage
|
|
5
|
+
=========================
|
|
6
|
+
|
|
7
|
+
This subpackage provides signal data structures and utilities.
|
|
8
|
+
|
|
9
|
+
The subpackage is organized into the following modules:
|
|
10
|
+
|
|
11
|
+
- `roi`: Region of Interest (ROI) classes and parameters for 1D signals
|
|
12
|
+
- `object`: Main SignalObj class for handling 1D signal data
|
|
13
|
+
- `creation`: Signal creation utilities and parameter classes
|
|
14
|
+
|
|
15
|
+
All classes and functions are re-exported at the subpackage level for backward
|
|
16
|
+
compatibility. Existing imports like `from sigima.objects.signal import SignalObj`
|
|
17
|
+
will continue to work.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
# Import all public classes and functions from submodules
|
|
21
|
+
from .creation import (
|
|
22
|
+
# Constants
|
|
23
|
+
DEFAULT_TITLE,
|
|
24
|
+
# Mathematical function parameter classes
|
|
25
|
+
BaseGaussLorentzVoigtParam,
|
|
26
|
+
BasePeriodicParam,
|
|
27
|
+
BasePulseParam,
|
|
28
|
+
CosineParam,
|
|
29
|
+
CustomSignalParam,
|
|
30
|
+
# Pulse signal classes
|
|
31
|
+
ExpectedFeatures,
|
|
32
|
+
ExponentialParam,
|
|
33
|
+
FeatureTolerances,
|
|
34
|
+
# Periodic function parameter classes
|
|
35
|
+
FreqUnits,
|
|
36
|
+
GaussParam,
|
|
37
|
+
# Other signal types
|
|
38
|
+
LinearChirpParam,
|
|
39
|
+
LogisticParam,
|
|
40
|
+
LorentzParam,
|
|
41
|
+
# Base parameter classes
|
|
42
|
+
NewSignalParam,
|
|
43
|
+
NormalDistribution1DParam,
|
|
44
|
+
PlanckParam,
|
|
45
|
+
PoissonDistribution1DParam,
|
|
46
|
+
# Polynomial and custom signals
|
|
47
|
+
PolyParam,
|
|
48
|
+
PulseParam,
|
|
49
|
+
SawtoothParam,
|
|
50
|
+
# Enums
|
|
51
|
+
SignalTypes,
|
|
52
|
+
SincParam,
|
|
53
|
+
SineParam,
|
|
54
|
+
SquareParam,
|
|
55
|
+
SquarePulseParam,
|
|
56
|
+
StepParam,
|
|
57
|
+
StepPulseParam,
|
|
58
|
+
TriangleParam,
|
|
59
|
+
UniformDistribution1DParam,
|
|
60
|
+
VoigtParam,
|
|
61
|
+
# Distribution parameter classes
|
|
62
|
+
ZeroParam,
|
|
63
|
+
check_all_signal_parameters_classes,
|
|
64
|
+
# Core creation functions
|
|
65
|
+
create_signal,
|
|
66
|
+
create_signal_from_param,
|
|
67
|
+
# Factory and utility functions
|
|
68
|
+
create_signal_parameters,
|
|
69
|
+
get_next_signal_number,
|
|
70
|
+
# Registration functions
|
|
71
|
+
register_signal_parameters_class,
|
|
72
|
+
triangle_func,
|
|
73
|
+
)
|
|
74
|
+
from .object import (
|
|
75
|
+
# Main signal class
|
|
76
|
+
SignalObj,
|
|
77
|
+
)
|
|
78
|
+
from .roi import (
|
|
79
|
+
# ROI classes
|
|
80
|
+
ROI1DParam,
|
|
81
|
+
SegmentROI,
|
|
82
|
+
SignalROI,
|
|
83
|
+
# ROI functions
|
|
84
|
+
create_signal_roi,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Define __all__ for explicit public API
|
|
88
|
+
__all__ = [
|
|
89
|
+
"DEFAULT_TITLE",
|
|
90
|
+
"BaseGaussLorentzVoigtParam",
|
|
91
|
+
"BasePeriodicParam",
|
|
92
|
+
"BasePulseParam",
|
|
93
|
+
"CosineParam",
|
|
94
|
+
"CustomSignalParam",
|
|
95
|
+
"ExpectedFeatures",
|
|
96
|
+
"ExponentialParam",
|
|
97
|
+
"FeatureTolerances",
|
|
98
|
+
"FreqUnits",
|
|
99
|
+
"GaussParam",
|
|
100
|
+
"LinearChirpParam",
|
|
101
|
+
"LogisticParam",
|
|
102
|
+
"LorentzParam",
|
|
103
|
+
"NewSignalParam",
|
|
104
|
+
"NormalDistribution1DParam",
|
|
105
|
+
"PlanckParam",
|
|
106
|
+
"PoissonDistribution1DParam",
|
|
107
|
+
"PolyParam",
|
|
108
|
+
"PulseParam",
|
|
109
|
+
"ROI1DParam",
|
|
110
|
+
"SawtoothParam",
|
|
111
|
+
"SegmentROI",
|
|
112
|
+
"SignalObj",
|
|
113
|
+
"SignalROI",
|
|
114
|
+
"SignalTypes",
|
|
115
|
+
"SincParam",
|
|
116
|
+
"SineParam",
|
|
117
|
+
"SquareParam",
|
|
118
|
+
"SquarePulseParam",
|
|
119
|
+
"StepParam",
|
|
120
|
+
"StepPulseParam",
|
|
121
|
+
"TriangleParam",
|
|
122
|
+
"UniformDistribution1DParam",
|
|
123
|
+
"VoigtParam",
|
|
124
|
+
"ZeroParam",
|
|
125
|
+
"check_all_signal_parameters_classes",
|
|
126
|
+
"create_signal",
|
|
127
|
+
"create_signal_from_param",
|
|
128
|
+
"create_signal_parameters",
|
|
129
|
+
"create_signal_roi",
|
|
130
|
+
"get_next_signal_number",
|
|
131
|
+
"register_signal_parameters_class",
|
|
132
|
+
"triangle_func",
|
|
133
|
+
]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Copyright (c) DataLab Platform Developers, BSD 3-Clause license, see LICENSE file.
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Signal I/O constants - especially for datetime metadata handling
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
# Datetime metadata keys
|
|
8
|
+
# These keys are used to store datetime-related information in SignalObj.metadata
|
|
9
|
+
DATETIME_X_KEY = "x_datetime" # Boolean: True if x represents datetime data
|
|
10
|
+
DATETIME_X_FORMAT_KEY = "x_datetime_format" # String: format for display
|
|
11
|
+
|
|
12
|
+
# Time unit conversion factors (to seconds)
|
|
13
|
+
# Used to convert datetime values to float timestamps
|
|
14
|
+
TIME_UNIT_FACTORS = {
|
|
15
|
+
"ns": 1e-9, # nanoseconds
|
|
16
|
+
"us": 1e-6, # microseconds
|
|
17
|
+
"ms": 1e-3, # milliseconds
|
|
18
|
+
"s": 1.0, # seconds (base unit)
|
|
19
|
+
"min": 60.0, # minutes
|
|
20
|
+
"h": 3600.0, # hours
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# Valid time units (ordered from smallest to largest)
|
|
24
|
+
VALID_TIME_UNITS = list(TIME_UNIT_FACTORS.keys())
|
|
25
|
+
|
|
26
|
+
# Default datetime format string
|
|
27
|
+
DEFAULT_DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
|