Skip to content

Segmentation API

Programmatic interface for seed detection and segmentation.

SeedSegmenter

The SeedSegmenter class provides a unified interface for applying various segmentation algorithms with validation and visualization.

Basic Usage

from hyperseed.core.segmentation.segmenter import SeedSegmenter
from hyperseed.config.settings import Settings

# Create segmenter with default settings
settings = Settings()
segmenter = SeedSegmenter(settings.segmentation)

# Segment seeds
mask, n_seeds = segmenter.segment(preprocessed_data)

# Get seed properties
properties = segmenter.get_seed_properties()

With Custom Configuration

from hyperseed.config.settings import SegmentationConfig

# Create custom configuration
config = SegmentationConfig(
    algorithm="watershed",
    min_pixels=200,
    max_pixels=5000,
    reject_overlapping=True,
    morphology_operations=True,
    morphology_kernel_size=5,
    remove_outliers=True,
    outlier_min_area=75,
    outlier_max_area=1800
)

# Create segmenter
segmenter = SeedSegmenter(config)

# Segment
mask, n_seeds = segmenter.segment(data)

SeedSegmenter Methods

__init__(config: Optional[SegmentationConfig] = None)

Initialize the seed segmenter.

Parameters: - config (SegmentationConfig, optional): Segmentation configuration object. If None, uses defaults.

Example:

from hyperseed.config.settings import SegmentationConfig

config = SegmentationConfig(algorithm="watershed", min_pixels=200)
segmenter = SeedSegmenter(config)

segment(data: np.ndarray, band_index: Optional[int] = None, validate: bool = True) -> Tuple[np.ndarray, int]

Perform seed segmentation on hyperspectral data.

Parameters: - data (np.ndarray): Hyperspectral data array with shape (lines, samples, bands) or (lines, samples) - band_index (int, optional): Specific band to use for segmentation. If None, uses automatic selection based on variance - validate (bool, default: True): Whether to apply validation after segmentation (size filtering, overlap rejection)

Returns: - mask (np.ndarray): Labeled mask array where each seed has a unique ID (0 = background) - n_seeds (int): Number of seeds detected

Example:

# Segment using all bands (automatic selection)
mask, n_seeds = segmenter.segment(data)
print(f"Found {n_seeds} seeds")

# Segment using specific band
mask, n_seeds = segmenter.segment(data, band_index=50)

# Segment without validation
mask, n_seeds = segmenter.segment(data, validate=False)

Note: The segmentation process includes: 1. Apply selected algorithm (threshold/watershed/connected/combined) 2. Apply morphological operations (if enabled) 3. Validate seeds (if validate=True): size filtering, overlap rejection 4. Filter border seeds (if enabled)

visualize(data: np.ndarray, band_index: Optional[int] = None, save_path: Optional[Union[str, Path]] = None, show_labels: bool = True, show_boundaries: bool = True) -> plt.Figure

Visualize segmentation results.

Parameters: - data (np.ndarray): Original hyperspectral data - band_index (int, optional): Band to use for background image. If None, uses mean of middle bands - save_path (str or Path, optional): Path to save the figure. If None, displays interactive plot - show_labels (bool, default: True): Whether to show seed ID numbers - show_boundaries (bool, default: True): Whether to show seed boundaries

Returns: - fig (matplotlib.figure.Figure): Matplotlib figure object

Example:

# Visualize with all features
fig = segmenter.visualize(data, show_labels=True, show_boundaries=True)

# Save to file
segmenter.visualize(
    data,
    save_path="segmentation_result.png",
    band_index=50
)

# Simple visualization without labels
fig = segmenter.visualize(data, show_labels=False)
plt.show()

Visualization layout: - Left panel: Original image - Middle panel: Colored segmentation with numbered seeds - Right panel: Seed boundaries overlay

get_seed_properties() -> list

Get morphological properties of all segmented seeds.

Returns: - properties (list of dict): List of property dictionaries, one per seed

Property dictionary keys: - label (int): Seed ID - area (int): Seed area in pixels - centroid (tuple): (y, x) centroid coordinates - bbox (tuple): (min_row, min_col, max_row, max_col) bounding box - eccentricity (float): Elongation (0=circle, 1=line) - solidity (float): Area/convex_hull_area (shape regularity) - coords (np.ndarray): All pixel coordinates belonging to seed

Example:

properties = segmenter.get_seed_properties()

for prop in properties:
    print(f"Seed {prop['label']}:")
    print(f"  Area: {prop['area']} pixels")
    print(f"  Centroid: {prop['centroid']}")
    print(f"  Eccentricity: {prop['eccentricity']:.3f}")
    print(f"  Solidity: {prop['solidity']:.3f}")

get_validation_stats() -> Optional[Dict[str, Any]]

Get validation statistics from the last segmentation.

Returns: - stats (dict or None): Validation statistics dictionary, or None if validation not performed

Statistics dictionary keys: - initial_count (int): Number of seeds before validation - final_count (int): Number of seeds after validation - removed_by_size (int): Seeds removed by size filtering - removed_by_overlap (int): Seeds removed by overlap rejection - removed_by_shape (int): Seeds removed by shape criteria

Example:

mask, n_seeds = segmenter.segment(data, validate=True)
stats = segmenter.get_validation_stats()

if stats:
    print(f"Initial seeds: {stats['initial_count']}")
    print(f"Final seeds: {stats['final_count']}")
    print(f"Removed by size: {stats['removed_by_size']}")
    print(f"Removed by overlap: {stats['removed_by_overlap']}")

export_mask(path: Union[str, Path], format: str = "npy") -> None

Export segmentation mask to file.

Parameters: - path (str or Path): Output file path - format (str, default: "npy"): Export format. Options: "npy", "png", "tiff"

Example:

# Export as NumPy array (recommended)
segmenter.export_mask("results/mask.npy", format="npy")

# Export as PNG image (scaled to 0-255)
segmenter.export_mask("results/mask.png", format="png")

# Export as TIFF
segmenter.export_mask("results/mask.tiff", format="tiff")

Format details: - npy: Native NumPy format, preserves exact labels, recommended for further processing - png: 8-bit PNG, labels scaled to 0-255, useful for visualization - tiff: TIFF format, preserves labels

export_properties(path: Union[str, Path], format: str = "csv") -> None

Export seed properties to file.

Parameters: - path (str or Path): Output file path - format (str, default: "csv"): Export format. Options: "csv", "json"

Example:

# Export as CSV
segmenter.export_properties("results/seed_props.csv", format="csv")

# Export as JSON
segmenter.export_properties("results/seed_props.json", format="json")

CSV format: Tabular format with columns for label, area, centroid_y, centroid_x, bbox, eccentricity, solidity

JSON format: List of property dictionaries (excludes pixel coordinates)

describe() -> Dict[str, Any]

Get description of segmentation results.

Returns: - description (dict): Dictionary describing the segmentation

Description dictionary keys: - algorithm (str): Algorithm used - n_seeds (int): Number of seeds detected - mask_shape (tuple): Shape of segmentation mask - config (dict): Configuration parameters - validation (dict, optional): Validation statistics - seed_statistics (dict, optional): Area statistics (min, max, mean, std)

Example:

desc = segmenter.describe()
print(f"Algorithm: {desc['algorithm']}")
print(f"Seeds detected: {desc['n_seeds']}")
print(f"Mask shape: {desc['mask_shape']}")

if 'seed_statistics' in desc:
    stats = desc['seed_statistics']
    print(f"Area range: {stats['min_area']}-{stats['max_area']} pixels")
    print(f"Mean area: {stats['mean_area']:.1f} pixels")

Individual Segmentation Functions

For advanced use, individual segmentation algorithms can be called directly.

threshold_segmentation

from hyperseed.core.segmentation.algorithms import threshold_segmentation

mask, n_seeds = threshold_segmentation(
    data,
    method="otsu",  # or "adaptive", "manual"
    threshold_value=None,  # for manual method only
    min_seed_size=200,
    max_seed_size=None,
    band_index=None
)

Parameters: - data (np.ndarray): Hyperspectral data - method (str): "otsu", "adaptive", or "manual" - threshold_value (float, optional): Manual threshold (for method="manual") - min_seed_size (int, default: 200): Minimum seed size in pixels - max_seed_size (int, optional): Maximum seed size in pixels - band_index (int, optional): Specific band to use

Returns: - mask (np.ndarray): Labeled mask - n_seeds (int): Number of seeds

Methods: - otsu: Automatic global threshold using Otsu's method - adaptive: Local adaptive thresholding (block size=35) - manual: Requires explicit threshold_value parameter

watershed_segmentation

from hyperseed.core.segmentation.algorithms import watershed_segmentation

mask, n_seeds = watershed_segmentation(
    data,
    min_seed_size=200,
    max_seed_size=None,
    band_index=None,
    min_distance=20
)

Parameters: - data (np.ndarray): Hyperspectral data - min_seed_size (int, default: 200): Minimum seed size in pixels - max_seed_size (int, optional): Maximum seed size in pixels - band_index (int, optional): Specific band to use - min_distance (int, default: 20): Minimum distance between seed centers

Returns: - mask (np.ndarray): Labeled mask - n_seeds (int): Number of seeds

How it works: 1. Initial Otsu thresholding 2. Distance transform computation 3. Local maxima detection (seed centers) 4. Watershed algorithm to separate regions 5. Size filtering

connected_components_segmentation

from hyperseed.core.segmentation.algorithms import connected_components_segmentation

mask, n_seeds = connected_components_segmentation(
    data,
    min_seed_size=200,
    max_seed_size=None,
    band_index=None,
    connectivity=2
)

Parameters: - data (np.ndarray): Hyperspectral data - min_seed_size (int, default: 200): Minimum seed size in pixels - max_seed_size (int, optional): Maximum seed size in pixels - band_index (int, optional): Specific band to use - connectivity (int, default: 2): Connectivity for labeling (1 or 2)

Returns: - mask (np.ndarray): Labeled mask - n_seeds (int): Number of seeds

How it works: 1. Otsu thresholding 2. Morphological cleanup (closing + opening) 3. Connected component labeling 4. Size filtering 5. Shape filtering (eccentricity < 0.95, solidity > 0.7)

combined_segmentation

from hyperseed.core.segmentation.algorithms import combined_segmentation

mask, n_seeds = combined_segmentation(
    data,
    min_seed_size=200,
    max_seed_size=None,
    band_index=None,
    methods=["threshold", "watershed"]
)

Parameters: - data (np.ndarray): Hyperspectral data - min_seed_size (int, default: 200): Minimum seed size in pixels - max_seed_size (int, optional): Maximum seed size in pixels - band_index (int, optional): Specific band to use - methods (list, default: ["threshold", "watershed"]): List of algorithms to combine

Returns: - mask (np.ndarray): Labeled mask - n_seeds (int): Number of seeds

How it works: 1. Runs each specified algorithm 2. Converts results to binary masks 3. Combines using majority voting (consensus threshold = ceil(n_methods/2)) 4. Labels final consensus mask 5. Size filtering

apply_morphological_operations

from hyperseed.core.segmentation.algorithms import apply_morphological_operations

cleaned_mask = apply_morphological_operations(
    mask,
    operations=["closing", "opening"],
    kernel_size=3
)

Parameters: - mask (np.ndarray): Binary or labeled mask - operations (list, default: ["closing", "opening"]): Operations to apply in order - kernel_size (int, default: 3): Size of morphological kernel (disk shape)

Returns: - cleaned_mask (np.ndarray): Processed mask

Available operations: - closing: Fills small holes (dilation → erosion) - opening: Removes small protrusions (erosion → dilation) - erosion: Shrinks objects - dilation: Expands objects

Complete Example

import numpy as np
from hyperseed.core.io.envi_reader import ENVIReader
from hyperseed.core.calibration.reflectance import ReflectanceCalibrator
from hyperseed.core.preprocessing.pipeline import PreprocessingPipeline
from hyperseed.core.segmentation.segmenter import SeedSegmenter
from hyperseed.config.settings import Settings, SegmentationConfig

# Load data
reader = ENVIReader("path/to/data.hdr")
data = reader.read_data()
wavelengths = reader.get_wavelengths()

# Calibrate
calibrator = ReflectanceCalibrator(clip_negative=True, clip_max=1.0)
calibrated, reader = calibrator.calibrate_from_directory("path/to/dataset")

# Preprocess (minimal for segmentation)
settings = Settings()
settings.preprocessing.method = "minimal"
preprocessor = PreprocessingPipeline(settings.preprocessing)
processed = preprocessor.fit_transform(calibrated)

# Configure segmentation
seg_config = SegmentationConfig(
    algorithm="watershed",
    min_pixels=200,
    morphology_operations=True,
    morphology_kernel_size=5,
    filter_border_seeds=True,
    remove_outliers=True,
    outlier_min_area=75,
    outlier_max_area=1800,
    outlier_iqr_lower=1.5,
    outlier_iqr_upper=3.0,
    use_shape_filtering=True,
    outlier_eccentricity=0.90,
    outlier_solidity=0.75
)

# Segment
segmenter = SeedSegmenter(seg_config)
mask, n_seeds = segmenter.segment(processed, validate=True)

print(f"Segmented {n_seeds} seeds")

# Get properties
properties = segmenter.get_seed_properties()
for prop in properties[:5]:  # Show first 5
    print(f"Seed {prop['label']}: {prop['area']} pixels at {prop['centroid']}")

# Get validation stats
stats = segmenter.get_validation_stats()
if stats:
    print(f"\nValidation:")
    print(f"  Initial: {stats['initial_count']} seeds")
    print(f"  Final: {stats['final_count']} seeds")
    print(f"  Removed by size: {stats['removed_by_size']}")

# Visualize
segmenter.visualize(
    calibrated,
    save_path="segmentation_result.png",
    show_labels=True,
    show_boundaries=True
)

# Export
segmenter.export_mask("segmentation_mask.npy")
segmenter.export_properties("seed_properties.csv")

# Get description
desc = segmenter.describe()
print(f"\nDescription: {desc}")

See Also