Advanced Examples
This page provides advanced usage examples for the HSI Mars package.
Batch Processing Multiple Images
Process multiple hyperspectral images in a loop:
from pathlib import Path
from hsimars import HSIMars
# Directory containing CRISM data
data_dir = Path("data/crism_images")
output_dir = Path("results/batch_analysis")
output_dir.mkdir(parents=True, exist_ok=True)
# Find all .hdr files
hdr_files = list(data_dir.glob("*.hdr"))
print(f"Processing {len(hdr_files)} images...")
for hdr_path in hdr_files:
print(f"\nProcessing: {hdr_path.name}")
# Load image
hsi = HSIMars(hdr_path=hdr_path)
img_data = hsi.get_img()
# Save spectrum from center pixel
center = [img_data.height // 2, img_data.width // 2]
output_file = output_dir / f"{hdr_path.stem}_spectrum.png"
hsi.plot_spectra(
px=center,
convex_hull=True,
bands=True,
output=output_file
)
print(f" - Saved spectrum to {output_file}")
Region of Interest Analysis
Analyze a specific region of interest within an image:
import numpy as np
from hsimars import HSIMars
# Load image
hsi = HSIMars(hdr_path="data/sample.hdr")
img_data = hsi.get_img()
# Define region of interest (ROI)
roi_top_left = [100, 150]
roi_bottom_right = [200, 250]
# Extract all pixels in ROI
roi_pixels = []
for r in range(roi_top_left[0], roi_bottom_right[0] + 1):
for c in range(roi_top_left[1], roi_bottom_right[1] + 1):
roi_pixels.append([r, c])
# Plot average spectrum of ROI with standard deviation
hsi.plot_spectra(
px=roi_pixels,
convex_hull=True,
bands=True,
output="results/roi_spectrum.png"
)
# Calculate statistics
roi_spectra = img_data.hsi[
roi_top_left[0]:roi_bottom_right[0]+1,
roi_top_left[1]:roi_bottom_right[1]+1,
:
]
print(f"ROI dimensions: {roi_spectra.shape[:2]}")
print(f"ROI pixels: {roi_spectra.shape[0] * roi_spectra.shape[1]}")
print(f"Mean intensity: {roi_spectra.mean():.2f}")
print(f"Std intensity: {roi_spectra.std():.2f}")
Class-Based Spectral Analysis
Analyze spectral signatures for different annotated classes:
import numpy as np
from hsimars import HSIMars
# Load data with annotations
hsi = HSIMars(
hdr_path="data/sample.hdr",
annotations="data/sample_labels.mat"
)
img_data, ann_data = hsi.data()
# Get unique class labels (excluding background = 0)
classes = np.unique(ann_data.labels)
classes = classes[classes > 0]
print(f"Found {len(classes)} classes")
# Analyze each class
for class_id in classes:
# Find all pixels belonging to this class
class_mask = ann_data.labels == class_id
class_coords = np.argwhere(class_mask)
# Convert to list of [row, col] pairs
class_pixels = class_coords.tolist()
print(f"\nClass {class_id}: {len(class_pixels)} pixels")
# Plot average spectrum for this class
if len(class_pixels) > 0:
hsi.plot_spectra(
px=class_pixels,
convex_hull=True,
bands=True,
output=f"results/class_{class_id}_spectrum.png"
)
Spectral Band Comparison
Compare specific spectral bands across the image:
import numpy as np
import matplotlib.pyplot as plt
from hsimars import HSIMars
# Load image
hsi = HSIMars(hdr_path="data/sample.hdr")
img_data = hsi.get_img()
# Select wavelengths of interest
wavelengths_of_interest = [700, 1000, 1500, 2000] # nm
# Find closest band indices
band_indices = [
np.argmin(np.abs(img_data.wavelength - wl))
for wl in wavelengths_of_interest
]
# Create comparison plot
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
axes = axes.ravel()
for idx, (band_idx, wl) in enumerate(zip(band_indices, wavelengths_of_interest)):
actual_wl = img_data.wavelength[band_idx]
band_data = img_data.hsi[:, :, band_idx]
im = axes[idx].imshow(band_data, cmap='gray')
axes[idx].set_title(f'Band: {actual_wl:.1f} nm (target: {wl} nm)')
axes[idx].axis('off')
plt.colorbar(im, ax=axes[idx], fraction=0.046)
plt.tight_layout()
plt.savefig('results/band_comparison.png', dpi=150, bbox_inches='tight')
print("Saved band comparison to results/band_comparison.png")
Statistical Summary Generation
Generate comprehensive statistics for a dataset:
import numpy as np
from hsimars import HSIMars
def generate_statistics_report(hsi_path, ann_path=None, output_file="report.txt"):
"""Generate a comprehensive statistics report."""
# Load data
if ann_path:
hsi = HSIMars(hdr_path=hsi_path, annotations=ann_path)
img_data, ann_data = hsi.data()
else:
hsi = HSIMars(hdr_path=hsi_path)
img_data = hsi.get_img()
ann_data = None
# Prepare report
lines = []
lines.append("="*60)
lines.append("Hyperspectral Image Statistics Report")
lines.append("="*60)
lines.append(f"\nFile: {hsi_path}")
lines.append(f"\nImage Properties:")
lines.append(f" - Dimensions: {img_data.height} x {img_data.width}")
lines.append(f" - Spectral bands: {img_data.channels}")
lines.append(f" - Data type: {img_data.dtype}")
lines.append(f" - Total pixels: {img_data.height * img_data.width:,}")
lines.append(f"\nSpectral Information:")
lines.append(f" - Wavelength range: {img_data.wavelength.min():.2f} - {img_data.wavelength.max():.2f} nm")
lines.append(f" - Wavelength spacing: {np.diff(img_data.wavelength).mean():.2f} nm (mean)")
lines.append(f"\nIntensity Statistics:")
lines.append(f" - Global mean: {img_data.hsi.mean():.4f}")
lines.append(f" - Global std: {img_data.hsi.std():.4f}")
lines.append(f" - Global min: {img_data.hsi.min():.4f}")
lines.append(f" - Global max: {img_data.hsi.max():.4f}")
# Per-band statistics
band_means = img_data.hsi.mean(axis=(0, 1))
band_stds = img_data.hsi.std(axis=(0, 1))
lines.append(f"\nPer-Band Statistics:")
lines.append(f" - Mean intensity range: {band_means.min():.4f} - {band_means.max():.4f}")
lines.append(f" - Highest mean at: {img_data.wavelength[band_means.argmax()]:.2f} nm")
lines.append(f" - Lowest mean at: {img_data.wavelength[band_means.argmin()]:.2f} nm")
# Annotation statistics
if ann_data is not None:
unique_labels, counts = np.unique(ann_data.labels, return_counts=True)
lines.append(f"\nAnnotation Statistics:")
lines.append(f" - Total classes: {len(unique_labels)}")
lines.append(f" - Class distribution:")
for label, count in zip(unique_labels, counts):
percentage = (count / ann_data.labels.size) * 100
label_name = "Background" if label == 0 else f"Class {label}"
lines.append(f" * {label_name}: {count:,} pixels ({percentage:.2f}%)")
lines.append("\n" + "="*60)
# Write to file
report_text = "\n".join(lines)
with open(output_file, 'w') as f:
f.write(report_text)
print(report_text)
print(f"\nReport saved to: {output_file}")
return report_text
# Usage
generate_statistics_report(
hsi_path="data/sample.hdr",
ann_path="data/sample_labels.mat",
output_file="results/statistics_report.txt"
)
Working with Specific Wavelength Ranges
Extract and analyze specific portions of the spectrum:
import numpy as np
from hsimars import HSIMars
# Load image
hsi = HSIMars(hdr_path="data/sample.hdr")
img_data = hsi.get_img()
# Define wavelength range of interest (e.g., SWIR: 1400-3000 nm)
wl_min, wl_max = 1400, 3000
# Find bands within range
mask = (img_data.wavelength >= wl_min) & (img_data.wavelength <= wl_max)
selected_bands = np.where(mask)[0]
selected_wavelengths = img_data.wavelength[mask]
print(f"Selected {len(selected_bands)} bands in range {wl_min}-{wl_max} nm")
print(f"Wavelength range: {selected_wavelengths.min():.1f} - {selected_wavelengths.max():.1f} nm")
# Extract subset
swir_data = img_data.hsi[:, :, selected_bands]
# Analyze average spectrum in this range
center = [img_data.height // 2, img_data.width // 2]
center_spectrum = swir_data[center[0], center[1], :]
# Plot
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
plt.plot(selected_wavelengths, center_spectrum, 'k-')
plt.xlabel('Wavelength (nm)')
plt.ylabel('Intensity (a.u.)')
plt.title(f'SWIR Spectrum ({wl_min}-{wl_max} nm) at Center Pixel')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig('results/swir_spectrum.png', dpi=150, bbox_inches='tight')
print("Saved SWIR spectrum plot")
Custom Visualisation
Create custom visualisations using matplotlib:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from hsimars import HSIMars
# Load data
hsi = HSIMars(
hdr_path="data/sample.hdr",
annotations="data/sample_labels.mat"
)
img_data, ann_data = hsi.data()
# Create custom figure
fig = plt.figure(figsize=(15, 5))
# Panel 1: False-colour image
ax1 = plt.subplot(131)
# Use specific bands for RGB
false_colour = img_data.hsi[:, :, [50, 100, 150]]
false_colour = (false_colour - false_colour.min()) / (false_colour.max() - false_colour.min())
ax1.imshow(false_colour)
ax1.set_title('False Colour Image')
ax1.axis('off')
# Panel 2: Annotations
ax2 = plt.subplot(132)
# Create custom colourmap
n_classes = len(np.unique(ann_data.labels))
colours = plt.cm.tab10(np.linspace(0, 1, n_classes))
cmap = ListedColormap(colours)
im2 = ax2.imshow(ann_data.labels, cmap=cmap, interpolation='nearest')
ax2.set_title('Ground Truth Labels')
ax2.axis('off')
plt.colorbar(im2, ax=ax2, fraction=0.046)
# Panel 3: Single band
ax3 = plt.subplot(133)
band_idx = img_data.channels // 2 # Middle band
im3 = ax3.imshow(img_data.hsi[:, :, band_idx], cmap='gray')
ax3.set_title(f'Band {band_idx} ({img_data.wavelength[band_idx]:.1f} nm)')
ax3.axis('off')
plt.colorbar(im3, ax=ax3, fraction=0.046)
plt.tight_layout()
plt.savefig('results/custom_visualization.png', dpi=150, bbox_inches='tight')
print("Saved custom visualisation")
Performance Tips
For Large Datasets
# Process in chunks to manage memory
import numpy as np
from hsimars import HSIMars
hsi = HSIMars(hdr_path="data/large_image.hdr")
img_data = hsi.get_img()
# Process image in tiles
tile_size = 100
results = []
for i in range(0, img_data.height, tile_size):
for j in range(0, img_data.width, tile_size):
tile = img_data.hsi[
i:min(i+tile_size, img_data.height),
j:min(j+tile_size, img_data.width),
:
]
# Process tile
result = tile.mean() # Example operation
results.append(result)
print(f"Processed {len(results)} tiles")
Parallel Processing
from pathlib import Path
from multiprocessing import Pool
from hsimars import HSIMars
def process_image(hdr_path):
"""Process a single image."""
hsi = HSIMars(hdr_path=hdr_path)
img_data = hsi.get_img()
# Extract some metric
mean_spectrum = img_data.hsi.mean(axis=(0, 1))
return {
'filename': hdr_path.name,
'mean_intensity': mean_spectrum.mean(),
'shape': img_data.shape
}
# Find all images
data_dir = Path("data/crism_images")
hdr_files = list(data_dir.glob("*.hdr"))
# Process in parallel
with Pool(processes=4) as pool:
results = pool.map(process_image, hdr_files)
# Print summary
for result in results:
print(f"{result['filename']}: mean={result['mean_intensity']:.4f}")
Further Resources
See the HSIMars for complete API documentation
Check the GitHub repository for example notebooks
Join discussions on GitHub Issues