Python API
The Python library provides flexible integration into existing workflows and custom processing pipelines.
Quick Start
Install the package:
Basic usage with RGB imagery:
from glint_mask_tools.sensors import rgb_sensor
# Create masker using sensor configuration
masker = rgb_sensor.create_masker(
img_dir="/path/to/images",
mask_dir="/path/to/masks",
thresholds=[0.85, 0.85, 0.75], # R, G, B thresholds
pixel_buffer=2
)
# Process all images
masker(max_workers=4)
Supported Sensor Types
The library includes built-in support for multiple sensor types:
| Sensor | CLI Command | Bands | Default Thresholds | File Pattern |
|---|---|---|---|---|
| RGB | rgb |
Red, Green, Blue | [1.0, 1.0, 0.875] | Single file |
| CIR | cir |
Red, Green, Blue, Near-IR | [1.0, 1.0, 0.875, 1.0] | Single file |
| DJI P4MS | p4ms |
Blue, Green, Red, RedEdge, Near-IR | [0.875, 1.0, 1.0, 1.0, 1.0] | DJI_###[1-5].TIF |
| DJI M3M | m3m |
Green, Red, RedEdge, Near-IR | [0.875, 1.0, 1.0, 1.0] | DJI_*_MS_[G\|R\|RE\|NIR].TIF |
| MicaSense RedEdge | msre |
Blue, Green, Red, RedEdge, Near-IR | [0.875, 1.0, 1.0, 1.0, 1.0] | IMG_####_[1-5].tif |
| MicaSense RedEdge-MX Dual | msre-dual |
10 bands (various wavelengths) | [1.0, 0.875, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0] | IMG_####_[1-10].tif |
Using Sensor Configurations
Each sensor has a pre-configured setup accessible via the sensors module:
from glint_mask_tools.sensors import p4ms_sensor, msre_sensor, cir_sensor
# DJI Phantom 4 Multispectral
masker = p4ms_sensor.create_masker(
img_dir="/path/to/p4ms_images",
mask_dir="/path/to/masks",
thresholds=p4ms_sensor.get_default_thresholds(),
pixel_buffer=3
)
# MicaSense RedEdge
masker = msre_sensor.create_masker(
img_dir="/path/to/micasense_images",
mask_dir="/path/to/masks",
pixel_buffer=2
)
# MicaSense RedEdge-MX Dual (10-band)
from glint_mask_tools.sensors import msre_dual_sensor
masker = msre_dual_sensor.create_masker(
img_dir="/path/to/micasense_dual_images",
mask_dir="/path/to/masks",
thresholds=msre_dual_sensor.get_default_thresholds(), # 10 thresholds
pixel_buffer=2
)
# Color Infrared (large images with tiling)
masker = cir_sensor.create_masker(
img_dir="/path/to/cir_images",
mask_dir="/path/to/masks"
)
Advanced Usage with Components
For more control, you can directly use the individual components:
from glint_mask_tools.image_loaders import SingleFileImageLoader
from glint_mask_tools.glint_algorithms import ThresholdAlgorithm
from glint_mask_tools.maskers import Masker
from glint_mask_tools.utils import normalize_8bit_img
# Custom RGB setup with advanced algorithm
loader = SingleFileImageLoader("/path/to/images", "/path/to/masks")
algorithm = ThresholdAlgorithm(thresholds=[0.8, 0.8, 0.8])
masker = Masker(algorithm, loader, normalize_8bit_img, pixel_buffer=1)
# Process with callbacks
def progress_callback(completed_paths):
print(f"Completed: {len(completed_paths)} images")
def error_callback(failed_paths, exception):
print(f"Error processing {failed_paths}: {exception}")
masker(max_workers=2, callback=progress_callback, err_callback=error_callback)
Image Loader Classes
The library uses a hierarchical image loader system:
Single-File Loaders
SingleFileImageLoader: Standard 8-bit RGB imagery in one file
- Supports: JPG, PNG, TIFF formats
- Use case: Standard photography, drone RGB cameras
BigTiffLoader: 8-bit Color Infrared imagery in BigTIFF format
- Features: Memory-efficient tiled processing (256x256 tiles)
- Use case: Large 4-band CIR images that don't fit in memory
Multi-File Loaders
MicasenseRedEdgeLoader: 16-bit multi-file MicaSense format
- Pattern:
IMG_####_[1-5].tif(Blue, Green, Red, RedEdge, NIR) - Use case: MicaSense RedEdge cameras
P4MSLoader: 16-bit multi-file DJI P4 Multispectral format
- Pattern:
DJI_###[1-5].TIF(Blue, Green, Red, RedEdge, NIR) - Use case: DJI Phantom 4 Multispectral camera
DJIM3MLoader: 16-bit multi-file DJI Mavic 3M format
- Pattern:
DJI_*_MS_[G|R|RE|NIR].TIF(Green, Red, RedEdge, NIR) - Use case: DJI Mavic 3 Multispectral camera
Implementing Custom Sensor Classes
To support a new sensor type, create a sensor configuration:
from glint_mask_tools.image_loaders import MultiFileImageLoader
from glint_mask_tools.sensors import Sensor, Band
import glob
import os
# Step 1: Create custom ImageLoader subclass
class CustomSensorLoader(MultiFileImageLoader):
"""Loader for custom sensor with pattern: SENSOR_####_[B1|B2|B3].tif"""
@property
def paths(self) -> list[list[str]]: # This method should return a list of lists of strings for multi-file loaders
"""Group related band files together"""
pattern = os.path.join(self.img_dir, "SENSOR_*_B1.tif")
base_files = glob.glob(pattern)
groups = []
for base_file in sorted(base_files):
# Find corresponding band files
base_name = base_file.replace("_B1.tif", "")
band_files = [
f"{base_name}_B1.tif", # Blue
f"{base_name}_B2.tif", # Green
f"{base_name}_B3.tif", # Red
]
# Verify all files exist
if all(os.path.exists(f) for f in band_files):
groups.append(band_files)
return groups
# Step 2: Create and use the custom sensor
custom_sensor = Sensor(
name="Custom Sensor",
bands=[Band("Blue"), Band("Green"), Band("Red")],
bit_depth=8,
loader_class=CustomSensorLoader,
)
masker = custom_sensor.create_masker(
img_dir="/path/to/custom_images",
mask_dir="/path/to/masks",
thresholds=[0.8, 0.8, 0.8],
pixel_buffer=2
)
masker(max_workers=4)
Custom ImageLoader Implementation
For single-file sensors with custom loading requirements:
from glint_mask_tools.image_loaders import SingleFileImageLoader
import glob
import os
import numpy as np
from pathlib import Path
import tifffile
class CustomSingleFileLoader(SingleFileImageLoader):
"""Custom loader for multi-file sensor format"""
@staticmethod
def load_image(paths: list[str | Path]) -> np.ndarray:
"""Custom loader to build a numpy array."""
# e.g. We override this method to load images with tifffile instead of using default PIL.Image loader
imgs = [tifffile.imread(p) for p in paths]
# e.g. Maybe we just want the first 3 bands in these tif files
imgs = imgs[:, :, :3]
return np.stack(imgs, axis=2).astype(float)
@property
def paths(self) -> list[str]: # This method should return a list of strings for single-file loaders
"""Get grouped paths of imagery to load."""
# Find base files (e.g., files ending with specific pattern)
base_pattern = os.path.join(self.img_dir, "*_RGBA.tif")
return glob.glob(base_pattern)
Glint Detection Algorithms
The library provides two built-in algorithms:
ThresholdAlgorithm (Default)
Simple per-band thresholding with OR logic:
from glint_mask_tools.glint_algorithms import ThresholdAlgorithm
# Different threshold per band
algorithm = ThresholdAlgorithm([0.8, 0.9, 0.7, 0.85]) # B, G, R, NIR
IntensityRatioAlgorithm (Advanced)
Estimates specular reflection component for RGB imagery:
from glint_mask_tools.glint_algorithms import IntensityRatioAlgorithm
# Advanced glint detection for RGB
algorithm = IntensityRatioAlgorithm(
percent_diffuse=0.95, # Assumed diffuse reflection percentage
threshold=0.99 # Specular component threshold
)
Error Handling and Progress Tracking
from glint_mask_tools.sensors import rgb_sensor
def progress_callback(completed_paths):
"""Called after each successful image processing"""
print(f"✓ Processed {len(completed_paths)} images")
def error_callback(failed_paths, exception):
"""Called when image processing fails"""
print(f"✗ Failed to process {failed_paths}: {str(exception)}")
masker = rgb_sensor.create_masker("/input", "/output")
masker(
max_workers=4,
callback=progress_callback,
err_callback=error_callback
)
API Reference
For complete API documentation, see the source code or use Python's help system: