Skip to content

Local drone processing

Module: spectralbridge.pipelines.drone.

Direct-module reference; consult the linked workflow for processing context.

API glossary ยท Workflow / scientific context

Signatures and documentation below are collected from the current source. Advanced objects are not newly declared stable by inclusion here.

Audience: advanced.

DroneCorrectionUnavailableError

DroneCorrectionUnavailableError(message: str, audit: dict[str, Any])

Raised when a requested drone correction cannot produce a valid output.

Audience: advanced.

DronePipelineIncompleteError

DronePipelineIncompleteError(message: str, results: dict[str, Any])

A run did not satisfy its requested scientific output contract.

Audience: advanced.

DroneInputSource dataclass

DroneInputSource(source_path: Path, source_type: str, flight_stem: str)

Describe one supported discovered drone HDF5/TIFF source and its provenance.

Audience: advanced.

DroneOutputRequirement dataclass

DroneOutputRequirement(name: str, kind: str, paths: tuple[Path, ...])

Describe one canonical product required by a selected drone extraction/translation workflow.

Audience: advanced.

load_drone_manifest

load_drone_manifest(manifest_path: str | Path) -> dict[str, datetime]

Load drone flight acquisition datetimes from a CSV manifest.

The manifest is expected to include Plot, Day of data collection, and Mean Time of data collection (24 hr clock) columns. Flight identifiers are normalized to uppercase underscore-separated tokens such as AOP_GOLDHILL. Rows with missing identifiers or malformed datetimes are skipped with warnings so a partially messy field manifest can still support valid flights.

Audience: advanced.

lookup_flight_datetime

lookup_flight_datetime(flight_id: str, manifest: dict[str, datetime] | None) -> datetime | None

Return a manifest datetime for a derived drone flight identifier.

Matching rules are deliberately conservative and deterministic:

  • identifiers are compared after uppercasing and collapsing separators to underscores;
  • an exact match wins first;
  • a trailing YYYYMMDD token is ignored, so AOP_GOLDHILL_20230814 matches manifest row AOP_GOLDHILL;
  • if needed, separators are ignored for compact matching, so SPR1 matches manifest row SPR-1;
  • if neither rule matches, the longest manifest key that prefixes the derived flight stem wins.

Audience: advanced.

clean_name

clean_name(name: str) -> str

Normalise a source name minimally for filesystem-safe output filenames.

Audience: advanced.

derive_drone_flight_stem

derive_drone_flight_stem(h5_path: str | Path) -> str

Derive a drone flight stem from the package folder rather than the inner HDF5.

Audience: advanced.

build_drone_output_paths

build_drone_output_paths(output_root: str | Path, *, flight_stem: str) -> dict[str, Path]

Return per-flight drone paths under a dedicated flight directory.

Audience: advanced.

required_drone_outputs

required_drone_outputs(path_map: dict[str, Path], *, extraction_mode: str, translation_targets: Sequence[str] = (), include_report: bool = False) -> tuple[DroneOutputRequirement, ...]

Describe the per-flight artifacts required by the requested workflow.

The same contract drives final validation and orchestration tests. Optional actual-Landsat comparison is excluded because scene availability is external.

Audience: advanced.

summarize_drone_h5_solar_geometry

summarize_drone_h5_solar_geometry(h5_path: str | Path) -> dict[str, Any]

Return solar geometry provenance and summary stats for a drone working H5.

Audience: advanced.

diagnose_drone_h5_solar_geometry

diagnose_drone_h5_solar_geometry(h5_path: str | Path, *, acquisition_datetime: datetime | str | None = None, naive_timezone: str | None = None, candidate_timezones: Sequence[str] = ('UTC',), solar_summary: dict[str, Any] | None = None) -> dict[str, Any]

Compare source H5 angles with scene-center solar position, read-only.

Naive timestamps have unknown provenance unless naive_timezone is explicitly supplied. Candidate interpretations are informational only. Thresholds (5/20 degrees) are deliberately provisional review bands, not a calibration or permission to replace supplied correction geometry.

Audience: advanced.

convert_drone_tiff_to_h5

convert_drone_tiff_to_h5(reflectance_tiff_path: str | Path, *, output_h5_path: str | Path, wavelengths_nm: Sequence[float] | ndarray | None = None, fwhm_nm: Sequence[float] | ndarray | None = None, sensor_zenith_tiff: str | Path | None = None, sensor_azimuth_tiff: str | Path | None = None, slope_tiff: str | Path | None = None, aspect_tiff: str | Path | None = None, solar_zenith_tiff: str | Path | None = None, solar_azimuth_tiff: str | Path | None = None, solar_zenith_deg: float | None = None, solar_azimuth_deg: float | None = None, sensor_zenith_deg: float | None = None, sensor_azimuth_deg: float | None = None, acquisition_datetime: datetime | str | None = None, require_solar_geometry: bool = False, overwrite: bool = False) -> Path

Convert a supported georeferenced multiband reflectance TIFF and aligned ancillary inputs to the drone HDF5 contract.

Audience: advanced.

resolve_band_map

resolve_band_map(wavelengths: list[float] | ndarray, targets: dict[str, int]) -> dict[str, dict[str, float | int]]

Map conceptual drone band names to nearest wavelength coordinates, recording selected indices and distances.

Audience: advanced.

validate_drone_h5_metadata

validate_drone_h5_metadata(h5_path: str | Path) -> dict[str, Any]

Validate minimally required drone H5 metadata and return a structured summary.

Audience: advanced.

export_h5_to_envi

export_h5_to_envi(h5_path: str | Path, *, output_stem: str | Path, brightness_offset: float = 0.0, overwrite: bool = False, cube: NeonCube | None = None) -> tuple[Path, Path]

Export a local H5 cube to ENVI using a drone-native filename stem.

Audience: advanced.

build_drone_config

build_drone_config(*, h5_path: Path, envi_img: Path, envi_hdr: Path, corrected_img: Path, corrected_hdr: Path, wavelengths: list[float], fwhm: list[float] | None, band_map: dict[str, dict[str, float | int]], apply_topo: bool, apply_brdf: bool, use_ndvi_brdf_bins: bool) -> dict[str, Any]

Build the explicit local drone correction configuration from existing paths, wavelengths and correction flags.

Audience: advanced.

apply_drone_corrections

apply_drone_corrections(*, cube: NeonCube, envi_img: Path, envi_hdr: Path, corrected_stem: Path, apply_topo: bool, apply_brdf: bool, use_ndvi_brdf_bins: bool = False, overwrite: bool = False) -> tuple[Path, Path, dict[str, Any]]

Apply optional topo/BRDF corrections to a drone ENVI export.

run_drone_pipeline now requests both topo and BRDF correction by default. Each correction still remains conditional on the required ancillary geometry being available for the current cube.

Audience: advanced.

collect_drone_spatial_diagnostics

collect_drone_spatial_diagnostics(*, raster_img: Path, polygons_path: Path) -> dict[str, Any]

Collect drone-only raster/polygon overlay diagnostics before extraction.

Audience: advanced.

save_drone_overlay_debug_plot

save_drone_overlay_debug_plot(*, polygons_path: Path, raster_bounds: list[float] | tuple[float, float, float, float], raster_crs: str | None, output_path: Path) -> Path

Write a lightweight overlay PNG for drone polygon/raster diagnostics.

Audience: public. Also exported as spectralbridge.pipelines.run_drone_pipeline, spectralbridge.run_drone_pipeline.

run_drone_pipeline

run_drone_pipeline(input_h5_dir: str | Path, polygon_path: str | Path | None = None, output_dir: str | Path = '.', apply_topo: bool = True, apply_brdf: bool = True, use_ndvi_brdf_bins: bool = False, apply_brightness_adjustment: bool = False, overwrite: bool = False, tiff_wavelengths_nm: Sequence[float] | ndarray | None = None, tiff_fwhm_nm: Sequence[float] | ndarray | None = None, tiff_solar_zenith_deg: float | None = None, tiff_solar_azimuth_deg: float | None = None, tiff_sensor_zenith_deg: float | None = None, tiff_sensor_azimuth_deg: float | None = None, drone_manifest_path: str | Path | None = None, drone_manifest_timezone: str | None = 'UTC', require_solar_geometry: bool = True, extraction_mode: str | None = None, parquet_chunk_size: int = 2048, merge_extractions: bool = False, apply_translation: bool = False, translation_coefficients: str | Path | None = None, translation_weighting: str | None = None, translation_strict: bool = False, landsat_qa: bool = False, landsat_product: str | Path | None = None, landsat_search_days: int = 16, comparison_neon_product: str | Path | None = None, raise_on_incomplete: bool = True, solar_qa_timezone: str | None = None) -> dict[str, Any]

Run the drone pipeline from local HDF5 or reflectance TIFF sources.

Parameters:

Name Type Description Default
input_h5_dir str | Path

Existing local supported HDF5/TIFF file or directory; discovery recurses through source packages.

required
polygon_path str | Path | None

Existing polygon vector dataset for extraction; coordinates are handled by the established polygon workflow.

None
output_dir str | Path

Directory for generated products; bulk outputs must be outside the read-only input tree.

'.'
apply_topo bool

Enable the existing topographic correction when required terrain/geometry metadata are available.

True
apply_brdf bool

Enable the existing BRDF correction when required angular metadata are available.

True
use_ndvi_brdf_bins bool

Opt into the existing NDVI-stratified BRDF fitting behavior rather than the default fit.

False
apply_brightness_adjustment bool

Opt into the established brightness adjustment; does not change the packaged coefficients.

False
overwrite bool

Replace existing requested products; False preserves reusable products or rejects a conflicting destination.

False
tiff_wavelengths_nm Sequence[float] | ndarray | None

Explicit per-band center wavelengths in nanometers for TIFF inputs lacking embedded spectral metadata; must match band order/count.

None
tiff_fwhm_nm Sequence[float] | ndarray | None

Per-band full widths at half maximum in nanometers, aligned with TIFF bands; None uses supported metadata.

None
tiff_solar_zenith_deg float | None

Explicit TIFF solar zenith in degrees when valid embedded metadata are unavailable.

None
tiff_solar_azimuth_deg float | None

Explicit TIFF solar azimuth in degrees when valid embedded metadata are unavailable.

None
tiff_sensor_zenith_deg float | None

Explicit TIFF view zenith in degrees when valid embedded metadata are unavailable.

None
tiff_sensor_azimuth_deg float | None

Explicit TIFF view azimuth in degrees when valid embedded metadata are unavailable.

None
drone_manifest_path str | Path | None

Existing flight manifest providing acquisition identity/time; None uses supported discovery or embedded metadata.

None
drone_manifest_timezone str | None

Timezone used to interpret manifest acquisition times; the default is UTC.

'UTC'
require_solar_geometry bool

Require scientifically usable solar geometry before correction rather than silently proceeding without it.

True
extraction_mode str | None

'full' writes pixel Parquet, 'polygon' requires polygons; None preserves the entry point's documented default extraction behavior.

None
parquet_chunk_size int

Positive pixel/window processing budget for bounded extraction; the default and interpretation follow the selected producer.

2048
merge_extractions bool

Explicit opt-in to legacy campaign-wide pixel-table merging; normal bulk consumers use separate completed flights.

False
apply_translation bool

Create separate Landsat-like application products using the reviewed coefficient registry; does not overwrite corrected native MicaSense.

False
translation_coefficients str | Path | None

Optional reviewed registry JSON path; None uses the packaged static coefficient set.

None
translation_weighting str | None

Optional reviewed weighting selection; normal production uses the predetermined site-balanced weighting.

None
translation_strict bool

Treat unsupported/flagged translation conditions as blocking rather than returning the configured non-strict status.

False
landsat_qa bool

Enable actual Landsat comparison QA for translated products; requires apply_translation=True and appropriate data/dependencies.

False
landsat_product str | Path | None

Optional existing actual Landsat product for independent comparison; None permits the documented search path.

None
landsat_search_days int

Nonnegative acquisition-date search radius in days for actual Landsat comparison.

16
comparison_neon_product str | Path | None

Optional independent NEON product for common-support comparison QA.

None
raise_on_incomplete bool

Raise DronePipelineIncompleteError when flights fail or are scientifically blocked; its results attribute retains structured status.

True
solar_qa_timezone str | None

Optional timezone override for solar-geometry QA; None follows the existing metadata/timezone resolution.

None

Returns:

Type Description
dict[str, Any]

Per-flight processed/reused/failed/blocked outcomes and QA/output paths; incomplete runs normally raise with this payload attached.

Raises:

Type Description
DroneCorrectionUnavailableError

If scientifically required correction inputs cannot be validated.

DronePipelineIncompleteError

If any requested flight is incomplete and raise_on_incomplete is True; inspect the attached results.

ValueError

If the supplied options, dimensions, support or provenance violate the input contract.

Notes

extraction_mode="full" writes a full-pixel Parquet table from the corrected drone ENVI product. "polygon" uses polygon_path and the existing polygon extraction path. The default preserves historical behavior: polygon mode when polygons are supplied, otherwise QA-only. Per-flight extraction products remain separate by default; merge_extractions=True opts into legacy campaign-wide pixel-table materialization. Bulk analysis does not require that merge. Translation is opt-in and consumes a versioned packaged registry by default, or an explicitly supplied reviewed bulk artifact. The predetermined production weighting is site-balanced. It creates separate Landsat-like products; corrected native MicaSense is never overwritten. By default an incomplete run raises :class:DronePipelineIncompleteError with the structured result available as exc.results.

See Also

spectralbridge.pipelines.pipeline.process_one_flightline : Related source-derived API contract.

Examples:

Requires an existing supported source tree with usable spectral/spatial/solar metadata. Choose a separate output directory.

>>> from spectralbridge import run_drone_pipeline
>>> result = run_drone_pipeline(input_h5_dir=source_dir, output_dir=output_dir)

Explicitly exported constants and type aliases

These values describe package metadata, schemas or configuration; they are not observations from a production dataset.

Name Source expression
DRONE_TARGET_BANDS {'blue': 444, 'green': 560, 'red': 650, 'nir': 862}