Transformations¶
API Documentation
siapy.transformations
The transformations module provides essential image processing and co-registration capabilities. It includes functions for spatial image manipulation, data augmentation, and geometric transformations between different camera coordinate systems.
Image transformations¶
API Documentation
siapy.transformations.image
Basic transformations¶
import numpy as np
from siapy.entities import SpectralImage
from siapy.transformations.image import (
random_crop,
random_mirror,
random_rotation,
rescale,
)
# Create a sample spectral image for demonstration
rng = np.random.default_rng(seed=42)
image_array = rng.random((100, 100, 10)) # height, width, bands
image = SpectralImage.from_numpy(image_array)
# Convert to numpy array for transformations
# image = image.to_numpy() # Not needed, as transformations work directly with SpectralImage
# Resize image to new dimensions
resized_image = rescale(image, (150, 150))
print(f"Original shape: {image.shape}")
print(f"Resized shape: {resized_image.shape}")
# Crop a random section of the image
cropped_image = random_crop(image, (80, 80))
print(f"Cropped shape: {cropped_image.shape}")
# Apply horizontal/vertical mirroring
mirrored_image = random_mirror(image)
print(f"Mirrored shape: {mirrored_image.shape}")
# Rotate image by specified angle (in degrees)
rotated_image = random_rotation(image, angle=30)
print(f"Rotated shape: {rotated_image.shape}")
Data augmentation¶
Data augmentation transformations are useful for expanding training datasets and testing algorithm robustness.
import numpy as np
from siapy.entities import SpectralImage
from siapy.transformations.image import add_gaussian_noise
# Create a sample spectral image
rng = np.random.default_rng(seed=42)
image_array = rng.random((100, 100, 10))
image = SpectralImage.from_numpy(image_array)
# Add Gaussian noise to the image
noisy_image = add_gaussian_noise(
image,
mean=0.0, # Center the noise around zero
std=0.1, # Standard deviation of the noise
clip_to_max=True, # Prevent values from exceeding the original range
)
image_np = image.to_numpy()
print(f"Original image range: [{image_np.min():.3f}, {image_np.max():.3f}]")
print(f"Noisy image range: [{noisy_image.min():.3f}, {noisy_image.max():.3f}]")
# Compare signal-to-noise ratio
signal_power = np.mean(image_np**2)
noise_power = np.mean((noisy_image - image) ** 2)
snr_db = 10 * np.log10(signal_power / noise_power)
print(f"Signal-to-Noise Ratio: {snr_db:.2f} dB")
Normalization¶
The area_normalization
function normalizes spectral signals by their area under the curve, which is particularly useful for comparing spectral shapes regardless of overall intensity.
import numpy as np
from siapy.entities import SpectralImage
from siapy.transformations.image import area_normalization
# Create a sample spectral image
rng = np.random.default_rng(seed=42)
image_array = rng.random((100, 100, 10))
image = SpectralImage.from_numpy(image_array)
# Apply area normalization to standardize spectral intensities
# This normalizes each pixel's spectrum by its total area under the curve
normalized_image = area_normalization(image)
# Compare before and after normalization (e.g., pixel at (25, 25))
original_pixel = image.to_numpy()[25, 25, :]
normalized_pixel = normalized_image[25, 25, :]
print(f"Original pixel spectrum area: {np.trapz(original_pixel):.4f}")
print(f"Normalized pixel spectrum area: {np.trapz(normalized_pixel):.4f}")
print(f"Original intensity range: [{original_pixel.min():.3f}, {original_pixel.max():.3f}]")
print(f"Normalized intensity range: [{normalized_pixel.min():.3f}, {normalized_pixel.max():.3f}]")
Co-registration¶
API Documentation
siapy.transformations.corregistrator
Co-registration enables alignment and coordinate transformation between different spectral images, particularly useful when working with multiple cameras or sensors viewing the same scene.
Alignment workflow¶
The typical co-registration workflow involves selecting corresponding points in both images and computing a transformation matrix:
import numpy as np
from siapy.entities import Pixels, SpectralImage
from siapy.transformations import corregistrator
# Create two sample spectral images representing different cameras/sensors
rng = np.random.default_rng(seed=42)
# VNIR camera image (visible to near-infrared)
vnir_array = rng.random((100, 120, 50)) # Different dimensions to simulate real cameras
vnir_image = SpectralImage.from_numpy(vnir_array)
# SWIR camera image (short-wave infrared)
swir_array = rng.random((90, 110, 30))
swir_image = SpectralImage.from_numpy(swir_array)
# In practice, you would interactively select corresponding points using:
# from siapy.utils.plots import pixels_select_click
# control_points_vnir = pixels_select_click(vnir_image)
# control_points_swir = pixels_select_click(swir_image)
# For demonstration, create synthetic corresponding points
# These represent the same physical locations viewed by both cameras
control_points_vnir = Pixels.from_iterable([(20, 15), (80, 25), (50, 70), (90, 80), (30, 90)])
control_points_swir = Pixels.from_iterable([(18, 12), (75, 22), (45, 65), (85, 75), (28, 85)])
# Compute transformation matrix that maps VNIR coordinates to SWIR coordinates
transformation_matrix, residual_errors = corregistrator.align(
control_points_swir, # Target coordinates (SWIR camera space)
control_points_vnir, # Source coordinates (VNIR camera space)
plot_progress=False,
)
print("Transformation matrix:")
print(transformation_matrix)
print(f"Residual alignment errors: {residual_errors}")
Applying transformations¶
Once you have a transformation matrix, you can transform pixel coordinates between image spaces:
import numpy as np
from siapy.entities import Pixels, SpectralImage
from siapy.transformations import corregistrator
# Assume we have the transformation matrix from the previous example
transformation_matrix = np.array(
[
[9.53012482e-01, 1.36821892e-03, -1.33929429e00],
[6.24099856e-04, 9.68410946e-01, -2.46471435e00],
[2.20958871e-17, -2.81409517e-18, 1.00000000e00],
]
)
# Create a VNIR image for demonstration
rng = np.random.default_rng(seed=42)
vnir_array = rng.random((100, 120, 50))
vnir_image = SpectralImage.from_numpy(vnir_array)
# Define pixels of interest in the VNIR image
# These could be selected regions or any features of interest
vnir_pixels = Pixels.from_iterable([(25, 30), (45, 50), (65, 70), (80, 85)])
# Transform these pixels to SWIR camera coordinate system
swir_pixels = corregistrator.transform(vnir_pixels, transformation_matrix)
print("Original VNIR coordinates:")
print(vnir_pixels.df)
print("\nTransformed SWIR coordinates:")
print(swir_pixels.df)
# Applications of transformed coordinates:
# 1. Extract spectral signatures from corresponding locations in both images
# vnir_signatures = vnir_image.get_signatures_from_pixels(vnir_pixels)
# swir_signatures = swir_image.get_signatures_from_pixels(swir_pixels)
# 2. Perform cross-spectral analysis of identical physical regions
# This enables comparison of vegetation indices, material classification,
# or spectral feature analysis across different wavelength ranges
# 3. Create composite analyses combining VNIR and SWIR data
# Combined data provides enhanced discrimination capabilities for:
# - Mineral identification (clay, carbonate, sulfate detection)
# - Vegetation health assessment (water content, chlorophyll)
# - Material classification with improved accuracy