File: coordinate_systems.py

package info (click to toggle)
python-sigima 1.0.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 24,956 kB
  • sloc: python: 33,326; makefile: 3
file content (294 lines) | stat: -rw-r--r-- 10,727 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
"""
Uniform and Non-Uniform Coordinate Systems
==========================================

This example demonstrates the use of uniform and non-uniform coordinate systems
with images in Sigima. It shows how to create, visualize, and work with both
types of coordinate systems, highlighting their differences and appropriate
use cases.

The example shows:

* Creating images with uniform coordinate systems
* Creating images with non-uniform coordinate systems
* Visualizing the coordinate grids
* Comparing pixel spacing and coordinate mapping
* Working with real-world units and coordinates
* Understanding when to use each coordinate system type

This tutorial uses PlotPy for visualization, providing interactive plots
that allow you to explore the coordinate system effects in detail.
"""

# %%
# Importing necessary modules
# ---------------------------
# We'll start by importing all the required modules for image processing
# and visualization.

import numpy as np

from sigima.objects import create_image
from sigima.tests.vistools import view_images_side_by_side

# %%
# Creating test images with uniform coordinates
# ---------------------------------------------
# Uniform coordinates have constant spacing between pixels in both directions.
# This is the most common case for regular imaging systems.

# Create a simple test pattern - a sine wave pattern
size = 100
x_uniform = np.linspace(0, 4 * np.pi, size)
y_uniform = np.linspace(0, 4 * np.pi, size)
X_uniform, Y_uniform = np.meshgrid(x_uniform, y_uniform)

# Create a 2D sine wave pattern
data_uniform = np.sin(X_uniform) * np.cos(Y_uniform)

# Create the image object with uniform coordinates
uniform_image = create_image(
    title="Uniform Coordinates",
    data=data_uniform,
    units=("μm", "μm", "intensity"),
    labels=("X position", "Y position", "Signal"),
)

# Set uniform coordinate system with specific spacing and origin
dx = 0.1  # 0.1 μm per pixel in X
dy = 0.1  # 0.1 μm per pixel in Y
x0 = -2.0  # X origin at -2.0 μm
y0 = -2.0  # Y origin at -2.0 μm

uniform_image.set_uniform_coords(dx, dy, x0=x0, y0=y0)

print("✓ Uniform coordinate image created!")
print(f"Image shape: {uniform_image.data.shape}")
coord_type = "Uniform" if uniform_image.is_uniform_coords else "Non-uniform"
print(f"Coordinate system: {coord_type}")
print(f"X spacing (dx): {uniform_image.dx} μm")
print(f"Y spacing (dy): {uniform_image.dy} μm")
print(f"X origin: {uniform_image.x0} μm")
print(f"Y origin: {uniform_image.y0} μm")
x_end = uniform_image.x0 + uniform_image.dx * (uniform_image.data.shape[1] - 1)
y_end = uniform_image.y0 + uniform_image.dy * (uniform_image.data.shape[0] - 1)
print(f"X range: {uniform_image.x0:.1f} to {x_end:.1f} μm")
print(f"Y range: {uniform_image.y0:.1f} to {y_end:.1f} μm")

# %%
# Creating test images with non-uniform coordinates
# -------------------------------------------------
# Non-uniform coordinates allow for variable spacing between pixels,
# useful for adaptive sampling, curved coordinates, or irregular grids.

# Create the same sine wave pattern but with non-uniform coordinates
data_nonuniform = data_uniform.copy()

# Create non-uniform coordinate arrays
# X coordinates: denser near the center, sparser at edges
x_center = 2 * np.pi
x_range = 4 * np.pi
x_nonuniform = x_center + (x_range / 2) * np.tanh(np.linspace(-2, 2, size))

# Y coordinates: quadratic spacing (denser at bottom)
y_start = 0
y_end = 4 * np.pi
y_nonuniform = y_start + (y_end - y_start) * (np.linspace(0, 1, size) ** 2)

# Create the image object with non-uniform coordinates
nonuniform_image = create_image(
    title="Non-Uniform Coordinates",
    data=data_nonuniform,
    units=("μm", "μm", "intensity"),
    labels=("X position", "Y position", "Signal"),
)

# Set non-uniform coordinate system
nonuniform_image.set_coords(xcoords=x_nonuniform, ycoords=y_nonuniform)

print("\n✓ Non-uniform coordinate image created!")
print(f"Image shape: {nonuniform_image.data.shape}")
coord_type = "Uniform" if nonuniform_image.is_uniform_coords else "Non-uniform"
print(f"Coordinate system: {coord_type}")
print(f"X coordinates range: {x_nonuniform[0]:.3f} to {x_nonuniform[-1]:.3f} μm")
print(f"Y coordinates range: {y_nonuniform[0]:.3f} to {y_nonuniform[-1]:.3f} μm")
x_spacing_min = np.min(np.diff(x_nonuniform))
x_spacing_max = np.max(np.diff(x_nonuniform))
y_spacing_min = np.min(np.diff(y_nonuniform))
y_spacing_max = np.max(np.diff(y_nonuniform))
print(f"X spacing varies from {x_spacing_min:.4f} to {x_spacing_max:.4f} μm")
print(f"Y spacing varies from {y_spacing_min:.4f} to {y_spacing_max:.4f} μm")

# %%
# Visualizing coordinate system differences
# -----------------------------------------
# Let's create coordinate grid visualizations to highlight the differences
# between uniform and non-uniform coordinate systems.

# Create coordinate grid images for visualization
grid_uniform = np.zeros_like(data_uniform)
grid_nonuniform = np.zeros_like(data_nonuniform)

# Add grid lines every 10 pixels for uniform coordinates
grid_uniform[::10, :] = 1.0  # Horizontal lines
grid_uniform[:, ::10] = 1.0  # Vertical lines

# Add grid lines every 10 pixels for non-uniform coordinates
grid_nonuniform[::10, :] = 1.0  # Horizontal lines
grid_nonuniform[:, ::10] = 1.0  # Vertical lines

# Create grid visualization images
uniform_grid = create_image(
    title="Uniform Grid",
    data=grid_uniform,
    units=("μm", "μm", "grid"),
    labels=("X position", "Y position", "Grid lines"),
)
uniform_grid.set_uniform_coords(dx, dy, x0=x0, y0=y0)

nonuniform_grid = create_image(
    title="Non-Uniform Grid",
    data=grid_nonuniform,
    units=("μm", "μm", "grid"),
    labels=("X position", "Y position", "Grid lines"),
)
nonuniform_grid.set_coords(xcoords=x_nonuniform, ycoords=y_nonuniform)

print("\n✓ Coordinate grid visualizations created!")

# Display the coordinate system comparison
view_images_side_by_side(
    [uniform_image, nonuniform_image],
    ["Uniform Coordinates", "Non-Uniform Coordinates"],
    title="Coordinate Systems Comparison - Data Images",
    share_axes=False,
)

view_images_side_by_side(
    [uniform_grid, nonuniform_grid],
    ["Uniform Grid", "Non-Uniform Grid"],
    title="Coordinate Systems Comparison - Grid Visualization",
    share_axes=False,
)

# %%
# Creating specialized non-uniform coordinate examples
# ----------------------------------------------------
# Let's create some more realistic examples of non-uniform coordinates
# that might be encountered in real applications.

# Example 1: Logarithmic spacing (common in spectroscopy)
size_log = 80
wavelengths = np.logspace(np.log10(400), np.log10(800), size_log)  # 400-800 nm
intensities = np.linspace(0, 1, size_log)
W, intensity_grid = np.meshgrid(wavelengths, intensities)

# Create a spectral response pattern
spectral_data = np.exp(-(((W - 550) / 50) ** 2)) * (
    1 + 0.3 * np.sin(10 * intensity_grid)
)

spectral_image = create_image(
    title="Spectroscopy Data (Log Wavelength)",
    data=spectral_data,
    units=("nm", "a.u.", "counts"),
    labels=("Wavelength", "Intensity", "Signal"),
)
spectral_image.set_coords(xcoords=wavelengths, ycoords=intensities)

print("\n✓ Spectroscopy example created!")
print(f"Wavelength range: {wavelengths[0]:.1f} to {wavelengths[-1]:.1f} nm")
wl_spacing_min = np.min(np.diff(wavelengths))
wl_spacing_max = np.max(np.diff(wavelengths))
print(f"Log spacing: {wl_spacing_min:.2f} to {wl_spacing_max:.2f} nm")

# Example 2: Polar to Cartesian mapping
size_polar = 60
r_coords = np.linspace(1, 10, size_polar)
theta_coords = np.linspace(0, 2 * np.pi, size_polar)

# Convert to Cartesian coordinates for non-uniform mapping
x_polar = np.zeros((size_polar, size_polar))
y_polar = np.zeros((size_polar, size_polar))

for i, r in enumerate(r_coords):
    for j, theta in enumerate(theta_coords):
        x_polar[i, j] = r * np.cos(theta)
        y_polar[i, j] = r * np.sin(theta)

# Create a radial pattern
polar_data = np.zeros((size_polar, size_polar))
for i, r in enumerate(r_coords):
    for j, theta in enumerate(theta_coords):
        polar_data[i, j] = np.sin(3 * theta) * np.exp(-r / 5)

# Note: For this example, we'll use the polar coordinates directly
# In practice, you might want to interpolate to a regular Cartesian grid
polar_image = create_image(
    title="Polar Coordinate Mapping",
    data=polar_data,
    units=("mm", "rad", "signal"),
    labels=("Radius", "Angle", "Amplitude"),
)
polar_image.set_coords(xcoords=r_coords, ycoords=theta_coords)

print("\n✓ Polar coordinate example created!")
print(f"Radial range: {r_coords[0]:.1f} to {r_coords[-1]:.1f} mm")
print(f"Angular range: {theta_coords[0]:.2f} to {theta_coords[-1]:.2f} rad")

# Display the specialized examples
view_images_side_by_side(
    [spectral_image, polar_image],
    ["Spectroscopy (Log Scale)", "Polar Coordinates"],
    title="Specialized Non-Uniform Coordinate Examples",
    share_axes=False,
)

# %%
# Summary and best practices
# --------------------------
# Let's summarize when to use each coordinate system type.

print("\n" + "=" * 60)
print("COORDINATE SYSTEMS SUMMARY")
print("=" * 60)

print("\n🔲 UNIFORM COORDINATES:")
print("   ✓ Regular imaging systems (cameras, microscopes)")
print("   ✓ Constant pixel spacing in physical units")
print("   ✓ Simple and memory-efficient")
print("   ✓ Fast computations and interpolations")
print("   ✓ Easy integration with standard image processing")

print("\n🔳 NON-UNIFORM COORDINATES:")
print("   ✓ Adaptive sampling systems")
print("   ✓ Curved or distorted coordinate systems")
print("   ✓ Logarithmic or specialized scales")
print("   ✓ Irregular measurement grids")
print("   ✓ Coordinate transformations (polar to Cartesian)")

print("\n📊 PERFORMANCE CONSIDERATIONS:")
print("   • Uniform: O(1) coordinate lookup")
print("   • Non-uniform: O(n) coordinate lookup")
print("   • Memory: Uniform uses 4 parameters, Non-uniform uses 2×N arrays")

print("\n💾 FILE FORMAT SUPPORT:")
print("   • Both coordinate types supported in Sigima HDF5 format")
print("   • Coordinated text format supports non-uniform coordinates")
print("   • Standard image formats (TIFF, etc.) assume uniform coordinates")

# Final comparison view
view_images_side_by_side(
    [uniform_image, nonuniform_image, spectral_image, polar_image],
    [
        "Uniform\n(Regular Grid)",
        "Non-Uniform\n(Variable Grid)",
        "Logarithmic\n(Spectroscopy)",
        "Polar\n(Radial Data)",
    ],
    title="Complete Coordinate Systems Overview",
    share_axes=False,
)

print("\n✨ Example completed successfully!")
print("This demonstrates the flexibility of Sigima's coordinate system support.")