- Home
- Documentation
- API reference
- Core
- hyperproc.align
hyperproc.align¶
Source-derived reference
Generated from the current hyperproc 0.1.2 checkout.
Implementation: hyperproc/align.py. Signatures, defaults, docstrings, and expandable source are extracted statically; the module is not imported or executed. Names beginning with _ are implementation details, not a stable public API.
Use the function signature as the authority for individual parameter defaults and return annotations. Original docstrings sometimes group parameter names or wrap return descriptions across lines; these descriptions are preserved rather than inferred or rewritten.
Exported entry points¶
| Importable name | Definition |
|---|---|
hyperproc.align.estimate_shift |
hyperproc.align.estimate_shift |
hyperproc.align.tie_points |
hyperproc.align.tie_points |
hyperproc.align.apply_shift |
hyperproc.align.apply_shift |
hyperproc.align.coregister |
hyperproc.align.coregister |
hyperproc.align.DEFAULT_WAVELENGTH |
hyperproc.align.DEFAULT_WAVELENGTH |
Coregistration: measuring and removing the misalignment between two scenes.
Two products of the same ground rarely land on the same pixel. Geolocation errors of one to two pixels are normal even in operational products, and they are fatal to anything that compares scenes pixel by pixel: fusing a coarse hyperspectral cube with a fine multispectral one, stacking dates into a time series, or validating one sensor against another. Cropping both to a common extent and trusting the headers, which is the usual shortcut, aligns the corners and leaves the content offset.
import hyperproc as hp
fit = hp.estimate_shift(emit, planet) # how far off, and how sure
print(fit["report"])
aligned = hp.coregister(emit, planet) # same, then fixed
How it measures¶
Phase correlation between one band of each scene, resampled onto the reference's grid. It uses the phase of the cross-power spectrum and not its amplitude, so a brightness or calibration difference between two sensors does not move the answer, which is what makes it usable across instruments. The peak is refined by a parabolic fit to about a tenth of a pixel.
Whether to believe it¶
A correlation peak always exists, even between unrelated images, so two
numbers come back with the shift. snr is the peak height against the rest
of the surface, and the scene is also split into tiles that are matched
independently: a real misregistration is the same in every tile, while a
spurious one scatters. consistent is False when the tiles disagree, and
that is the signal to look at the images rather than to apply the shift.
How it corrects¶
By default the georeferencing is moved and the pixels are left alone, which is
exact and costs nothing. resample=True puts the cube on the reference's
own grid instead, which is what pixel-to-pixel work needs, at the cost of one
interpolation.
DEFAULT_WAVELENGTH = 860.0
module-attribute
¶
_grid_of(ds: xr.Dataset) -> tuple
¶
(affine, crs, height, width) of a projected dataset.
Source code in hyperproc/align.py
_band_on(ds: xr.Dataset, wavelength: float, affine, crs, shape, var=None, tolerance: float = 60.0) -> np.ndarray
¶
One band of ds, resampled onto the given grid.
Source code in hyperproc/align.py
_prepare(a: np.ndarray) -> np.ndarray
¶
Mean-removed, NaN-filled and windowed, ready for an FFT.
The Hann window matters: an image is not periodic, and without it the discontinuity at the wrap-around produces a cross-shaped artefact through the correlation surface that can outrank the real peak.
Source code in hyperproc/align.py
_common_box(a: np.ndarray, b: np.ndarray) -> tuple
¶
Slices of the smallest box containing every pixel finite in both.
Two scenes rarely cover exactly the same ground, and the part of the grid only one of them reaches is NaN. Filling that with zeros leaves a hard step in the middle of the array, and a step correlates with a step: the spurious peak can beat the real one outright. Cropping both to their common box removes it, and a crop applied equally to both cannot change the shift between them.
Source code in hyperproc/align.py
_phase_shift(moving: np.ndarray, reference: np.ndarray) -> tuple
¶
(dy, dx, snr): how far moving must move to sit on reference.
Source code in hyperproc/align.py
tie_points(moving: xr.Dataset, reference: xr.Dataset, wavelength: float = DEFAULT_WAVELENGTH, tiles: int = 4, min_snr: float = 3.0, min_finite: float = 0.25, var: str | None = None, ref_var: str | None = None) -> dict
¶
Match a grid of tiles independently, to see whether one shift describes the scene.
| PARAMETER | DESCRIPTION |
|---|---|
moving
|
the dataset to be aligned.
TYPE:
|
reference
|
the dataset defining the grid and the truth.
TYPE:
|
wavelength
|
band used for matching, nm.
TYPE:
|
tiles
|
the scene is split
TYPE:
|
min_snr
|
tiles whose correlation peak is weaker than this are dropped.
TYPE:
|
min_finite
|
tiles with less than this fraction of valid pixels are dropped.
TYPE:
|
var, ref_var
|
variable names; the main cube of each by default.
|
| RETURNS | DESCRIPTION |
|---|---|
dict
|
dict with per-tile |
dict
|
and how many tiles were kept. |
Source code in hyperproc/align.py
_to_metres(dy_map: float, dx_map: float, crs: str, reference: xr.Dataset) -> tuple
¶
Map units to metres on the ground.
A projected grid is already in metres; a geographic one is in degrees, and reporting "0.0 degrees" for a shift of three EMIT pixels tells nobody anything. Longitude shrinks by cos(latitude), so the scene's own latitude is used rather than a constant.
Source code in hyperproc/align.py
_nearest_band(ds, wavelength, var=None) -> int
¶
estimate_shift(moving: xr.Dataset, reference: xr.Dataset, wavelength: float = DEFAULT_WAVELENGTH, tiles: int = 4, min_snr: float = 3.0, max_scatter: float = 1.0, var: str | None = None, ref_var: str | None = None, verbose: bool = False) -> dict
¶
How far moving sits from reference, and whether to believe it.
| PARAMETER | DESCRIPTION |
|---|---|
moving, reference
|
projected datasets covering the same ground.
|
wavelength
|
band used for matching, nm.
TYPE:
|
tiles
|
tile grid for the consistency check; 0 skips it.
TYPE:
|
min_snr
|
below this the whole-scene peak is not trusted.
TYPE:
|
max_scatter
|
tiles must agree to within this many pixels (median absolute deviation) for the result to count as consistent.
TYPE:
|
var, ref_var
|
variable names; the main cube of each by default.
|
verbose
|
print the report as it is produced.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
dict
|
dict with |
dict
|
reference's map units, |
dict
|
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
the two do not overlap, or are not projected. |
Source code in hyperproc/align.py
apply_shift(ds: xr.Dataset, dy: float, dx: float, unit: str = 'pixel') -> xr.Dataset
¶
Move a dataset's georeferencing by a shift, leaving the pixels untouched.
| PARAMETER | DESCRIPTION |
|---|---|
ds
|
the dataset to move.
TYPE:
|
dy, dx
|
how far its content must move, down and right.
|
unit
|
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Dataset
|
A copy with |
Dataset
|
Nothing is resampled, so this is exact and free. |
Source code in hyperproc/align.py
coregister(moving: xr.Dataset, reference: xr.Dataset, *, resample: bool = False, wavelength: float = DEFAULT_WAVELENGTH, tiles: int = 4, min_snr: float = 3.0, max_scatter: float = 1.0, force: bool = False, var: str | None = None, ref_var: str | None = None, verbose: bool = True) -> xr.Dataset
¶
Measure the misalignment against a reference and correct it.
| PARAMETER | DESCRIPTION |
|---|---|
moving, reference
|
projected datasets covering the same ground.
|
resample
|
put the corrected cube on the reference's own grid. False, the default, only moves the georeferencing, which is exact.
TYPE:
|
wavelength, tiles, min_snr, max_scatter, var, ref_var
|
see
:func:
|
force
|
apply the shift even when the match is not consistent.
TYPE:
|
verbose
|
print the report.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Dataset
|
The corrected dataset, carrying the measurement in |
Dataset
|
|
| RAISES | DESCRIPTION |
|---|---|
ValueError
|
the match is not consistent and |
Source code in hyperproc/align.py
_to_reference_grid(ds: xr.Dataset, reference: xr.Dataset, var=None) -> xr.Dataset
¶
Put every band of ds on the reference's grid, one band at a time.