msi_processor.computing.enhancement package#

Image-quality-enhancement stage (C-PU-ENH; DPM-M-ENH; ALG-ENH-*).

Mandatory Level-1 image-quality restoration: a profile-configurable denoise sub-step followed by the mandatory MTF compensation (MTFC) via PSF deconvolution. The stage always runs because MTFC is mandatory (REQ-F-ENH-03). It is a pure core plus a thin EnhancementUnit wrapper.

Submodules#

msi_processor.computing.enhancement.core module#

Pure image-quality-enhancement core (C-PU-ENH; ALG-ENH-*).

CPM-free, I/O-free numpy functions implementing the enhancement algorithms of ATBD <5.4> (configurable denoise) and ATBD <5.5> (mandatory MTF compensation / PSF deconvolution), ported faithfully from the heritage level_1.py Denoiser / sharpening classes (RD-10). All arrays are processed in float32 with a fixed operation order for reproducibility (REQ-F-DEP-02, REQ-D-05).

Two enhancement sub-steps are provided:

  • MTF compensation (MTFC)mtf_compensate(), the mandatory restoration (ALG-ENH-DECONV). It convolves the band with a profile/ADF-bound PSF-derived deconvolution kernel (heritage sharpening.deconvolution_kernel / cv2.filter2D). Because a low-pass restoration kernel that integrates to one has unit DC gain, the operation is radiometry-preserving (total radiance / mean is conserved) while the high-spatial-frequency content attenuated by the instrument MTF is restored.

  • Denoisedenoise(), dispatching the profile-configurable sub-step (ALG-ENH-BWLP/WAVE/PCA/MA/GAUSS/FFTDARK). The selector includes "none" so the sub-step can be disabled per sensor; the enhancement stage still always runs because MTFC is mandatory (REQ-F-ENH-03).

Forced deviation from SDD <5.4.4> (libraries). The SDD sketches the denoise bodies as thin wrappers over skimage / pywt / scikit-image (RD-10). scikit-image and PyWavelets are not available in the target runtime (only eopf/numpy/scipy), so — mirroring the dependency-minimal choice already made for the radiometric and TOA cores (which re-implement e.g. the NOAA solar position in pure numpy rather than pull a GPL dependency) — every kernel here is re-implemented in pure numpy:

  • butterworth_lowpass() — FFT-domain Butterworth low-pass built directly (the skimage.filters.butterworth frequency response);

  • wavelet_visushrink() — a periodic, orthonormal multilevel Daubechies DWT with VisuShrink soft/hard thresholding (replacing pywt / skimage.restoration.denoise_wavelet);

  • pca_denoise() — low-rank reconstruction via numpy.linalg.svd() (mathematically identical to the heritage sklearn PCA reconstruction).

Private calibration data (the per-band PSF / MTF and its derived deconvolution kernel) is never embedded; the kernel is supplied to mtf_compensate() by the wrapper from the PSF/MTF ADF / sensor profile (REQ-AD-01, REQ-S-01/05).

Geometry convention: arrays are 2-D (line, detector) in focal-plane geometry (ATBD <4.2>, SDD <5.4.4>).

Trace: REQ-F-ENH-01..03; DPM-M-ENH; ALG-ENH-*.

class msi_processor.computing.enhancement.core.EnhancementParams(denoise_method='none', denoise_params=<factory>, bit_depth=12, fill_value=None, mtfc_regularization=0.0)#

Bases: object

Tunable enhancement parameters (SDD <5.4.4>; DPM-PRM-ENH-01..05).

Parameters:
denoise_method:

Selector for the configurable denoise sub-step (REQ-F-ENH-01). "none" disables denoising; the enhancement stage still runs because MTF compensation is mandatory (REQ-F-ENH-03).

denoise_params:

Per-method keyword parameters (e.g. {"cutoff_ratio": 0.2} for Butterworth); all per-band-overridable by the caller.

bit_depth:

Sensor radiometric depth; valid DN range [0, 2**bit_depth - 1] (DPM-PRM-GEN-01, default 12) used by flag_enhanced().

fill_value:

No-data sentinel DN; flagged QAFlag.NO_DATA when present.

mtfc_regularization:

Reserved regularisation strength for the full-deconvolution MTFC mode (Wiener NSR \(K\) / Tikhonov \(\gamma\)); unused by the reference kernel-convolution path, whose regularisation is baked into the profile/ADF kernel (ATBD <5.5>).

Attributes:
fill_value
max_dn

Upper bound of the valid DN range, 2**bit_depth - 1.

bit_depth: int = 12#
denoise_method: Literal['none', 'butterworth', 'wavelet', 'pca', 'moving_average', 'gaussian', 'fft_dark'] = 'none'#
denoise_params: Mapping[str, Any]#
fill_value: Optional[float] = None#
property max_dn: int#

Upper bound of the valid DN range, 2**bit_depth - 1.

mtfc_regularization: float = 0.0#
msi_processor.computing.enhancement.core.butterworth_lowpass(image, cutoff_ratio=0.2, order=10.0, squared=False, npad=0)#

ALG-ENH-BWLP — frequency-domain Butterworth low-pass denoise.

Re-implements the skimage.filters.butterworth low-pass response in pure numpy (heritage Denoiser.get_filtered_butterworth): :rtype: ndarray[tuple[Any, ...], dtype[float32]]

\[W(\mathbf q) = \Big(1 + (\lVert \mathbf q\rVert / f_c)^{2n}\Big)^{-s},\]

with \(s = 1\) for squared and \(s = 1/2\) otherwise, f_c = cutoff_ratio and n = order. Because \(W(\mathbf 0) = 1\) the DC term is preserved, so the band mean is conserved (radiometry-preserving) while high frequencies (noise) are attenuated. npad edge-pads the band before the FFT to mitigate boundary ringing (Gibbs). Returns float32.

msi_processor.computing.enhancement.core.denoise(image, method, params, dark=None)#

Dispatch to the selected denoiser (heritage Denoiser.*).

Return type:

ndarray[tuple[Any, ...], dtype[float32]]

Parameters:
image:

Input band, dims (line, detector).

method:

One of DenoiseMethod. "none" returns the band unchanged (the configurable sub-step disabled, REQ-F-ENH-01).

params:

Per-method keyword parameters (see each kernel’s defaults).

dark:

Dark reference frame, required only for "fft_dark".

Returns:
numpy.ndarray

The denoised band as float32. Range clipping to the valid DN interval is centralised in flag_enhanced().

msi_processor.computing.enhancement.core.fft_dark_subtract(image, dark)#

ALG-ENH-FFTDARK — FFT-domain dark-pattern subtraction denoise. :rtype: ndarray[tuple[Any, ...], dtype[float32]]

\[\hat I = \Re\big\{\mathcal F^{-1}(\mathcal F(I) - \mathcal F(D))\big\}\]

(heritage Denoiser.dark_noise_removal). By linearity of the Fourier transform this equals the spatial dark subtraction \(I - D\); the FFT route is retained where a frequency-selective dark notch is desired (cf. the radiometric remove_dark_fft). The dark frame is cropped to the band extent and negative results are floored at 0. Returns float32.

msi_processor.computing.enhancement.core.flag_enhanced(image, params)#

Clip to the valid range and flag saturation / no-data (SDD <5.4.4>).

The enhanced band is clipped to [0, 2**bit_depth - 1] (REQ-D-05); samples at or above the ceiling — e.g. MTFC restoration overshoot — are flagged QAFlag.SATURATED; non-finite samples and any equal to params.fill_value are flagged QAFlag.NO_DATA. Mirrors the radiometric flag_saturation contract.

Return type:

tuple[ndarray[tuple[Any, ...], dtype[float32]], ndarray[tuple[Any, ...], dtype[uint16]]]

Returns:
tuple of numpy.ndarray

(clipped[float32], qa[uint16]) of the same shape as image.

msi_processor.computing.enhancement.core.gaussian_smooth(image, ksize=5, sigma=None)#

ALG-ENH-GAUSS — separable Gaussian-blur denoise.

Convolves the band with a normalised, separable 2-D Gaussian of window ksize (heritage Denoiser.gaussian_filter_ips, cv2.GaussianBlur). When sigma is None it defaults to the band standard deviation (the heritage choice). The kernel integrates to one, so the band mean is conserved (radiometry-preserving); a degenerate \(\sigma \le 0\) returns the band unchanged. Returns float32.

Return type:

ndarray[tuple[Any, ...], dtype[float32]]

msi_processor.computing.enhancement.core.moving_average(image, n=60)#

ALG-ENH-MA — along-track \((2N+1)\) sliding-mean denoise.

The canonical centred sliding mean over the line (along-track) axis adopted by msi-processor in place of the heritage row-block-to-scalar reduction (ATBD <5.4>): :rtype: ndarray[tuple[Any, ...], dtype[float32]]

\[\hat I_{l,d} = \frac{1}{|\mathcal W_l|}\sum_{l'\in\mathcal W_l} I_{l',d}, \qquad \mathcal W_l = [l-N,\,l+N] .\]

The window is truncated (and the mean re-normalised by the available count) at the array borders, so a flat band is preserved exactly everywhere. Returns float32.

msi_processor.computing.enhancement.core.mtf_compensate(image, psf_kernel)#

ALG-ENH-DECONV — MTF compensation (MTFC) via PSF deconvolution.

The mandatory Level-1 restoration. The band is filtered with the profile/ADF-bound, PSF-derived spatial deconvolution kernel \(k\) (heritage sharpening.deconvolution_kernel / cv2.filter2D): :rtype: ndarray[tuple[Any, ...], dtype[float32]]

\[\hat I = I \star k ,\]

a cross-correlation with periodic (wrap-around) boundary handling. The kernel is the spatial-domain image of a regularised inverse of the system PSF (Wiener / Tikhonov / Richardson-Lucy candidate, down-selected per sensor; ATBD <5.5>), broader for the higher-resolution (panchromatic) band.

Notes

The kernel is supplied by the caller from the PSF/MTF ADF and is never embedded here (REQ-AD-01). A restoration kernel that integrates to one has unit DC gain, so the global radiance (mean) is conserved — the restoration is radiometry-preserving. Final clipping to the valid DN range is deferred to flag_enhanced() (mirroring the dn_to_radiance / flag_radiance split of the TOA core). Returns float32.

msi_processor.computing.enhancement.core.pca_denoise(image, n_components)#

ALG-ENH-PCA — low-rank PCA reconstruction denoise.

Mathematically identical to the heritage sklearn PCA fit / inverse transform, re-expressed via the (economy) SVD of the column-centred band: with \(X = \bar X + U\Sigma V^{\!\top}\) the rank-\(k\) reconstruction \(\hat X = \bar X + U_k\Sigma_k V_k^{\!\top}\) discards the low-variance (noise) subspace. Rows are samples and columns features, as in the heritage code. n_components is clamped to [1, min(line, detector)]. A flat band (zero centred residual) is preserved exactly. Returns float32.

Return type:

ndarray[tuple[Any, ...], dtype[float32]]

msi_processor.computing.enhancement.core.wavelet_visushrink(image, wavelet='db3', levels=20, sigma_scale=0.3333333333333333, mode='soft')#

ALG-ENH-WAVE — VisuShrink wavelet denoise (periodic Daubechies DWT).

Re-implements skimage.restoration.denoise_wavelet (method="VisuShrink") in pure numpy (heritage Denoiser.wavelet_denoising_cdk): a multilevel orthonormal Daubechies decimated DWT with periodic boundary, MAD noise estimation and universal-threshold shrinkage of every detail band.

The noise level is estimated from the finest diagonal detail band, \(\hat\sigma = \mathrm{median}(|d_{HH}^{(1)}|)/0.6745\), and the universal threshold is \(\lambda = s\,\hat\sigma\sqrt{2\ln N}\) with sigma_scale \(s\) and \(N\) the pixel count. Detail coefficients are soft- or hard-thresholded; the coarse approximation is left intact. A flat band has zero detail energy, so it is preserved exactly (up to float round-off). Returns float32.

Return type:

ndarray[tuple[Any, ...], dtype[float32]]

Notes

The number of levels is capped at the largest depth for which both axes stay even and no shorter than the filter (so the periodic transform stays orthonormal / perfectly reconstructing).

msi_processor.computing.enhancement.unit module#

Thin EOProcessingUnit wrapper for image-quality enhancement (C-PU-ENH).

Adapts the pure core to the EOPF CPM runtime following the wrapper template of SDD <5.4.1>/<5.4.4>: read parameters, extract input bands, load/validate ADFs, call the core per band, propagate QA, and build the output enh EOProduct. No algorithm lives here.

The enhancement stage always runs (REQ-F-ENH-03): the mandatory MTF compensation (mtf_compensate()) is applied to every band, optionally preceded by the profile-configurable denoise sub-step. The denoise sub-step is disabled by selecting denoise_method="none"; the stage still executes because MTFC is mandatory.

Mandatory inputs/ADFs are declared by the CPM computing-model JSON (models/msi_enhancement_1.0.0.json), not by overriding the list methods.

Input convention. The upstream stage is the mandatory radiometric unit; its rad product carries corrected DN under measurements/detector/<band> and QA under quality/mask/<band> (IF-PROD-02). The enh output keeps the same shape so it can feed the downstream toa unit unchanged.

ADF data convention (this increment). The unit reads ADF content from the AuxiliaryDataFile.data_ptr mapping (the CPM data_ptr is documented as holding the opened data):

  • psf -> {"kernel": {band: ndarray2d}} (mandatory; the per-band PSF-derived deconvolution kernel for MTFC, ATBD <5.5>). Deviation note: the SDD <5.4.4> computing-model JSON sketch lists only the optional dark ADF, but MTFC is mandatory and consumes a PSF/MTF kernel, so the kernel ADF is declared mandatory here (per the C-PU-ENH task brief). Private kernel content is supplied via this ADF and never embedded (REQ-AD-01).

  • dark -> {"frame": {band: ndarray2d}} (optional; required only when denoise_method="fft_dark"), matching the radiometric dark ADF shape.

Trace: REQ-F-ENH-01..03; DPM-M-ENH; ALG-ENH-*; ICD IF-PROD-02.

class msi_processor.computing.enhancement.unit.EnhancementUnit(identifier='')#

Bases: EOProcessingUnit

Image-quality-enhancement processing unit (C-PU-ENH; SDD <5.4.4>).

Attributes:
identifier

Identifier of the processing step

Methods

run:

Apply the optional denoise sub-step and the mandatory MTF compensation to every band and emit the enh product.

PROCESSOR_LEVEL = 'L1B'#
PROCESSOR_MODEL = True#
PROCESSOR_NAME = 'msi_enhancement'#
PROCESSOR_VERSION = '1.0.0'#
run(inputs, adfs=None, mode=None, **kwargs)#

Run the image-quality enhancement.

Return type:

Mapping[str, Union[EOProduct, EOContainer, DataTree, Iterable[Union[EOProduct, EOContainer, DataTree]]]]

Parameters:
inputs:

{"rad": EOProduct} with bands under measurements/detector and optional QA under quality/mask.

adfs:

psf (mandatory; per-band MTFC deconvolution kernel); dark (optional; required only for denoise_method="fft_dark").

mode:

"nominal" (the only supported mode); the stage always runs.

**kwargs:

EnhancementParams fields (denoise_method, denoise_params, bit_depth, fill_value, mtfc_regularization); optional name for the output product.

Returns:
Mapping[str, DataType]

{"enh": EOProduct} with the MTFC-restored (optionally denoised) DN under measurements/detector/<band> and the propagated QA under quality/mask/<band>.