dataset.sampling.sampler¶
sampler ¶
HiRISE-aware geospatial sampler with train/val/test splitting for TorchGeo.
HiRISE satellite passes produce long, narrow, slightly rotated image strips. Sampling patches uniformly from axis-aligned bounding boxes wastes 60–90 % of samples on empty (zero-value) pixels that fall in the corners outside the actual strip.
:class:HiRISEGeoSampler avoids this by pre-computing a grid of patch centres
that are confirmed to lie within each strip's polygon footprint, then sampling
from that pre-computed set at each epoch. Construction runs once; iteration is
O(1) per sample.
Two centre-placement strategies are available via center_mode:
-
"simple"(default, backwards-compatible) — the original bbox-grid-then-filter algorithm. Generates an axis-aligned grid over each strip's bounding box and keeps centres whose patch achievesmin_overlapwith the footprint. Adjacent spacing is controlled bystride. -
"optimal"— the geometric packing algorithm. For each strip the valid centre region (the locus of centres where the patch is guaranteed to meetmin_overlap) is computed analytically, then patches are packed inside it using a row/column sweep. Adjacent spacing is controlled bypatch_overlap(fractional overlap between neighbouring patches, independent ofmin_overlap).
The "optimal" mode typically increases coverage by 20–60 % on narrow
rotated strips because it places patches right up against the footprint
edges. With patch_overlap > 0 it also supports dense augmentation-style
sampling without wasted off-strip centres.
Split support ~~~~~~~~~~~~~
The sampler partitions the dataset's stereo pairs (index rows) into train / val / test subsets. Two splitting strategies are provided:
-
"geographic"— sorts stereo pairs along a spatial axis (longitude or latitude) and assigns contiguous blocks to each split. This prevents spatial data leakage: nearby strips never appear on both sides of the split. -
"random"— assigns stereo pairs uniformly at random using a deterministic seed.
Both strategies support K-fold cross-validation. When n_folds is set,
the data is partitioned into K equally-sized folds. fold_idx selects which
fold is used as the test set; the remaining folds are re-split into train and
val according to val_fraction.
Split assignments are cached to disk so that:
- Every process in a distributed training run sees the same split.
- Re-instantiating the sampler with identical parameters reuses the same assignment without recomputing.
- The cache key incorporates all split-relevant parameters (dataset root, target, bbox, split method, seed, K, fold, fractions) so that changing any parameter produces a fresh split.
Cache files are written next to the dataset's spatial index cache (under
<root>/.cache/) with a filename derived from the configuration hash.
Backwards compatibility. When center_mode="simple" the cache key is
computed exactly as in previous versions of this module, so pre-existing
cache files are transparently reused. The optimal-mode parameters
(center_mode, patch_overlap, packing_phase_steps,
valid_region_rays) are included in the cache key only when
center_mode="optimal", keeping the two regimes isolated on disk.
HiRISEGeoSampler ¶
HiRISEGeoSampler(dataset: GeoDataset, size: float | tuple[float, float], *, split: Literal['train', 'test', 'val', 'all'] | None = 'train', split_fractions: tuple[float, float, float] = (0.8, 0.1, 0.1), split_method: str = 'geographic', split_axis: str = 'longitude', n_folds: int | None = None, fold_idx: int = 0, seed: int = 42, length: int | None = None, stride: float | tuple[float, float] | None = None, roi=None, toi=None, units: Units = Units.CRS, generator: Generator | None = None, min_overlap: float = 0.5, replacement: bool = False, reuse_cache: bool = True, center_mode: Literal['simple', 'optimal'] = 'optimal', patch_overlap: float = 0.0, packing_phase_steps: int = 20, valid_region_rays: int = 3)
Bases: GeoSampler
Sampler that restricts patches to within HiRISE strip polygon footprints, with built-in train/val/test splitting and K-fold cross-validation.
Construction pre-computes a set of candidate patch centres for every
strip in dataset.index. Two strategies are available:
-
center_mode="simple"— classical grid-over-bbox followed by an intersection-area filter. Controlled bysizeandstride. -
center_mode="optimal"— computes each strip's valid centre region analytically (the locus of centres where the patch is guaranteed to meetmin_overlap) and packs centres inside it with a row/column sweep. Adjacent spacing is controlled bypatch_overlap.
The split is performed at the stereo-pair level — entire strips are assigned to train, val, or test. This prevents spatial data leakage (nearby terrain never appears on both sides of the split).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataset
|
GeoDataset
|
The :class: |
required |
size
|
float | tuple[float, float]
|
Patch height and width in CRS units (degrees when
|
required |
split
|
Literal['train', 'test', 'val', 'all'] | None
|
Which split to sample from: |
'train'
|
split_fractions
|
tuple[float, float, float]
|
|
(0.8, 0.1, 0.1)
|
split_method
|
str
|
|
'geographic'
|
split_axis
|
str
|
For geographic splits: |
'longitude'
|
n_folds
|
int | None
|
Number of folds for K-fold cross-validation. |
None
|
fold_idx
|
int
|
Which fold to use as the test set (0 to |
0
|
seed
|
int
|
Random seed for reproducible split assignment. |
42
|
length
|
int | None
|
Number of patches to yield per epoch. Defaults to the total number of pre-computed valid centres for this split. |
None
|
stride
|
float | tuple[float, float] | None
|
(simple mode only) Centre-to-centre grid spacing in the same
units as |
None
|
roi
|
Optional Shapely Polygon to further restrict the spatial domain. |
None
|
|
toi
|
Optional :class: |
None
|
|
units
|
Units
|
Whether size and stride are given in CRS units or pixels. |
CRS
|
generator
|
Generator | None
|
Optional :class: |
None
|
min_overlap
|
float
|
Minimum fraction of patch area that must overlap the strip footprint to be considered valid (default 0.5). |
0.5
|
replacement
|
bool
|
Sample with replacement if |
False
|
reuse_cache
|
bool
|
Reuse cached split assignment if available. |
True
|
center_mode
|
Literal['simple', 'optimal']
|
|
'optimal'
|
patch_overlap
|
float
|
(optimal mode only) Fractional overlap between
adjacent patches in |
0.0
|
packing_phase_steps
|
int
|
(optimal mode only) Number of phase offsets to try per sweep direction when packing. Default 20. |
20
|
valid_region_rays
|
int
|
(optimal mode only) Number of extra rays per polygon edge when approximating the valid centre region. Default 3. |
3
|
Example::
from hirise_sampler import HiRISEGeoSampler
from torchgeo.samplers import Units
# Legacy behaviour (unchanged; reuses existing caches)
train_sampler = HiRISEGeoSampler(
dataset, size=0.005, split="train",
split_fractions=(0.8, 0.1, 0.1),
seed=42,
)
# Dense optimal packing with 50% patch overlap
train_sampler = HiRISEGeoSampler(
dataset, size=0.005, split="train",
split_fractions=(0.8, 0.1, 0.1),
seed=42,
center_mode="optimal",
patch_overlap=0.5,
)
# 5-fold cross-validation, fold 0 as test
train_sampler = HiRISEGeoSampler(
dataset, size=0.005, split="train",
n_folds=5, fold_idx=0, seed=42,
)
Source code in src/dataset/sampling/sampler.py
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 | |
split_summary
property
¶
Return the number of stereo pairs and patch centres per split.
per_strip_stats
property
¶
Per-strip diagnostics collected during centre building.
Useful for comparing "simple" vs "optimal" coverage on a
per-strip basis. Each entry is a dict containing at minimum
pair_idx and n_centers.