- Home
- Documentation
- API reference
- Corrections
- hyperproc.correct.topo
hyperproc.correct.topo¶
Source-derived reference
Generated from the current hyperproc 0.1.2 checkout.
Implementation: hyperproc/correct/topo.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.
Topographic (illumination) correction: cosine, C, SCS and SCS+C.
Written from the primary sources:
- Teillet, Guindon & Goodenough (1982) - the cosine correction and the C-correction, with C the ratio of intercept to slope of the regression of reflectance on the cosine of the solar incidence angle.
- Gu & Gillespie (1998) - the sun-canopy-sensor (SCS) correction.
- Soenen, Peddle & Coburn (2005) - SCS+C, eqs 7-8: C fitted exactly as in Teillet, then added to both numerator and denominator of SCS.
The cosine of the local solar incidence angle is
cos i = cos(slope) cos(sza) + sin(slope) sin(sza) cos(saa - aspect)
and the four corrections are multiplicative factors on reflectance:
cosine rho * cos(sza) / cos i
c rho * (cos(sza) + C) / (cos i + C)
scs rho * cos(slope) cos(sza) / cos i
scs+c rho * (cos(slope) cos(sza) + C)/ (cos i + C)
Two deliberate departures from other implementations:
- No sentinel. A common shortcut is to return
C = 100000when the regression slope is zero (or clamped to zero by NNLS), which makes the factor 1 and silently leaves the band uncorrected. Here :func:fit_creturnsC = Nonewith astatusthat says why -insufficient,degenerate(no usable illumination contrast) orinverted(reflectance falls with cos i, as AVIRIS-5 L2A_OE does) - and :func:apply_toporefuses a band without a C. - The decision is measured, not assumed. :func:
illumination_diagnosticreports, per band, how strongly reflectance still depends on cos i in the product as delivered, and how strongly it would after correction, on held-out pixels. That is whatfix_topo="auto"acts on.
METHODS = ('cosine', 'c', 'scs', 'scs+c')
module-attribute
¶
CFit
dataclass
¶
Result of regressing reflectance on cos i for one band.
Source code in hyperproc/correct/topo.py
slope: float | None
instance-attribute
¶
intercept: float | None
instance-attribute
¶
c: float | None
instance-attribute
¶
r: float | None
instance-attribute
¶
n: int
instance-attribute
¶
cos_i_spread: float
instance-attribute
¶
status: str
instance-attribute
¶
method: str
instance-attribute
¶
effect: float | None = None
class-attribute
instance-attribute
¶
t: float | None = None
class-attribute
instance-attribute
¶
__init__(slope: float | None, intercept: float | None, c: float | None, r: float | None, n: int, cos_i_spread: float, status: str, method: str, effect: float | None = None, t: float | None = None) -> None
¶
cos_incidence(sza, saa, slope, aspect)
¶
cos i from solar zenith/azimuth and terrain slope/aspect, all in radians.
Azimuths need only be in a common convention (both clockwise from north); the difference is all that enters.
Source code in hyperproc/correct/topo.py
fit_c(rho, cos_i, method='ols', min_samples=100, min_spread=0.02, neg_tol=0.05)
¶
Fit C = intercept / slope of rho = a cos_i + b (Teillet 1982; Soenen 2005 eq 7-8).
| PARAMETER | DESCRIPTION |
|---|---|
rho, cos_i
|
1-D samples, already masked to the pixels you trust (vegetated, sloped, illuminated).
|
method
|
DEFAULT:
|
neg_tol
|
an OLS intercept more negative than
DEFAULT:
|
min_samples
|
fewer than this ->
DEFAULT:
|
min_spread
|
std of cos i below this ->
DEFAULT:
|
The correlation r is reported but never used to judge the fit: over a
whole flightline most reflectance variance is land cover, so r is tiny
(0.03 on a NEON line) while the illumination effect is large (11% of the
mean at 659 nm). Judge with effect - the change in reflectance across
the central 90% of the illumination range, as a fraction of the mean -
and t, the slope's significance; :func:illumination_diagnostic does.
| RETURNS | DESCRIPTION |
|---|---|
|
class: |
Source code in hyperproc/correct/topo.py
fit_c_from_sums(n, sx, sy, sxy, sxx, syy, cos_i_p05, cos_i_p95, method='ols', min_samples=100, min_spread=0.02, neg_tol=0.05)
¶
:func:fit_c from per-band regression sums over all masked pixels of an
image, accumulated while the cube streams past - so the topographic C is
fitted on every pixel of the calc mask without holding the cube in memory.
n, sx, sy, sxy, sxx, syy are the counts and sums of cos i (x) and
reflectance (y) over the mask; cos_i_p05/p95 the illumination range
the effect size is expressed over. With two parameters the NNLS solution
is exact in closed form: the unconstrained fit when both coefficients are
non-negative, otherwise the better of the two boundary fits (b = 0 or a = 0).
Statuses are the same as :func:fit_c.
Source code in hyperproc/correct/topo.py
_check_c(c)
¶
Any C must be finite and >= 0: a negative C makes the SCS+C / C factor singular inside the valid cos i range.
Source code in hyperproc/correct/topo.py
correction_factor(method, cos_i, sza, slope=None, c=None)
¶
The multiplicative factor for one of :data:METHODS. Radians in, factor out.
c may be a scalar or an array broadcastable against cos_i (one C per
band, with a trailing band axis, is the usual case).
Source code in hyperproc/correct/topo.py
apply_topo(rho, cos_i, sza, slope=None, method='scs+c', c=None, mask=None, cos_i_min=0.0)
¶
Apply a topographic correction to a (..., band) reflectance array.
| PARAMETER | DESCRIPTION |
|---|---|
rho
|
reflectance with the band axis last.
|
cos_i, sza, slope
|
per-pixel arrays (radians for the angles) matching
|
method
|
one of :data:
DEFAULT:
|
c
|
for
DEFAULT:
|
mask
|
boolean
DEFAULT:
|
cos_i_min
|
pixels with
DEFAULT:
|
| RETURNS | DESCRIPTION |
|---|---|
|
Corrected array, float32, same shape. Bands whose C is None are |
|
|
returned unchanged - never silently "corrected" by a factor of 1 |
|
|
dressed up as a result. |
Source code in hyperproc/correct/topo.py
_slope_stats(x, y)
¶
OLS slope of y on x, its t statistic and Pearson r.
Source code in hyperproc/correct/topo.py
illumination_diagnostic(rho, cos_i, sza, slope, mask, method='scs+c', fit_method='ols', holdout=0.5, seed=0, min_effect=0.01, t_threshold=3.0)
¶
How much does reflectance still depend on illumination - and would a correction help? One row per band.
Fits C on a random half of the masked pixels and evaluates on the other
half with the least-squares slope of reflectance against cos i, expressed
as effect = slope x (p95 - p05 of cos i) / mean reflectance: the
illumination-driven change across the central 90% of the scene's
illumination range, as a fraction of the mean - before correction and
after. A correction that helps drives the held-out effect towards zero;
one that hurts drives it negative or leaves it.
Why not the correlation coefficient: over a whole flightline most of the reflectance variance is land cover, so r stays near zero (0.03 on a NEON line) even when the effect is 11% of the mean. r measures how cleanly reflectance follows illumination, not how much.
| RETURNS | DESCRIPTION |
|---|---|
|
dict with per-band arrays |
|
|
|
|
|
information), |
|
|
rho at the top cos-i decile over the bottom decile, minus 1), and a |
|
|
scene-level |
|
|
at least |
|
|
|
|
|
than |
|
|
|
|
|
over-correct), or |
|
|
contrast or too few pixels to tell either way). |
Source code in hyperproc/correct/topo.py
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 | |