Enhanced imagery

Baseline image and CF-modulated RGB, Eqs. 23-29.

DEBRA enhanced imagery, Eqs. 23-29 (Eqs. 24-25 per the 2020 erratum).

Builds the day/night blended baseline image (Eqs. 23-26) and modulates it by the combined confidence factor in each color gun (Eqs. 27-29). Pure array numerics; map rendering is in shachen.render.

shachen.imagery.baseline_image(scene: Dataset, zenith_deg: DataArray, constants: ImageryConstants = ImageryConstants(bg_blend_zenith_deg=Bounds(min=79.0, max=89.0), bg_blend_exponent=1.5, cf_cap=0.5, blue_dimming=0.1, gun_max=1.2)) Dataset[source]

Day/night blended baseline image BI (Eqs. 23-26).

scene needs refl_vis_064 (any linear reflectance unit; the Eq. 23 domain min/max normalization cancels units) and bt_tir_104 (K); zenith_deg is the solar zenith angle in degrees. Missing variables and 2-D shape mismatches raise ValueError.

Returns a Dataset on dims (y, x) with

  • vis_bg (Eq. 23): VIS normalized by the domain min/max reflectance;

  • ir_bg (Eq. 24, erratum): inverted normalized BT10.4, 1.0 at the domain cold bound;

  • b_bg (Eq. 25, erratum): 1 - N(zenith; 79, 89)**1.5 evaluated in zenith-degree space (unlike the cos-space Eqs. 20-21);

  • bi (Eq. 26): b_bg*vis_bg + (1 - b_bg)*ir_bg, in [0, 1].

NaN semantics: NaN pixels propagate, except a component whose Eq. 26 blend weight is exactly zero is ignored (a NaN VIS pixel on the night side leaves bi = ir_bg). A degenerate component domain (all-NaN, or domain max == min, e.g. an all-dark night VIS band) yields 0.0 for that component everywhere instead of dividing by zero.

shachen.imagery.enhanced_rgb(baseline: DataArray, cf_comb: DataArray, constants: ImageryConstants = ImageryConstants(bg_blend_zenith_deg=Bounds(min=79.0, max=89.0), bg_blend_exponent=1.5, cf_cap=0.5, blue_dimming=0.1, gun_max=1.2), dimming: tuple[float, float, float] | None = None) DataArray[source]

Color-modulated composite (Eqs. 27-29 + the Eq. 3 gun rescale).

Each gun is BI*(1 - min(CF, cf_cap)) + D_gun*CF with the per-gun dimming triple dimming (None selects COLOR_DIMMING["yellow"], i.e. D = 1.0 on red/green and blue_dimming on blue), then rescaled with N(gun; 0, gun_max) onto [0, 1].

Returns a float DataArray with dims ("y", "x", "gun") and coordinate gun = ["r", "g", "b"] (the dim is not named rgb so the array can live in a Dataset as variable rgb without a name collision). NaN propagates; a shape mismatch between baseline and cf_comb raises ValueError.

shachen.imagery.to_uint8(rgb: DataArray) ndarray[source]

Convert the [0, 1] float RGB composite to a (y, x, 3) uint8 array.

rgb is an enhanced_rgb()-shaped DataArray (gun axis last). Values are scaled by 255 and rounded with numpy.rint(); NaN pixels (off-disk) become 0 (black).

shachen.imagery.debra_imagery(scene: Dataset, debra: Dataset, constants: DebraConstants = DebraConstants(cloud_mask=CloudMaskConstants(cm1_cold_offset_k=50.0, cm2=Bounds(min=0.0, max=25.0), cm3=Bounds(min=2.0, max=4.5), cm4=Bounds(min=5.0, max=8.0), r1=Bounds(min=0.0, max=3.5), r2=Bounds(min=-1.0, max=3.0), cm_norm=Bounds(min=0.45, max=0.8)), dust_tests=DustTestConstants(dt1_max_rsw_k=3.5, dt2_max_btd_k=3.0, dt3_shift_land_k=-10.0, dt3_shift_ocean_k=5.0, dt3_depth_k=50.0), confidence=ConfidenceConstants(dt3_weight_trm=0.5, dt3_weight_ngt=0.5, cf_norm=Bounds(min=0.25, max=2.5), blend_exponent=1.5, ngt_trm_zenith_deg=Bounds(min=105.0, max=90.0), trm_day_zenith_deg=Bounds(min=90.0, max=75.0)), imagery=ImageryConstants(bg_blend_zenith_deg=Bounds(min=79.0, max=89.0), bg_blend_exponent=1.5, cf_cap=0.5, blue_dimming=0.1, gun_max=1.2)), dimming: tuple[float, float, float] | None = None) Dataset[source]

Full imagery chain (Eqs. 23-29) from a scene and a run_debra output.

scene needs refl_vis_064 and bt_tir_104; debra needs cf_comb and zenith_deg (from shachen.pipeline.run_debra()). Missing variables raise ValueError.

Returns a Dataset with the baseline_image() fields (vis_bg, ir_bg, b_bg, bi) plus rgb from enhanced_rgb(), with scene’s attrs preserved.