Source code for opticks.imaging_model.processing

# opticks Models and analysis tools for optical system engineering
#
# Copyright (C) Egemen Imre
#
# Licensed under GNU GPL v3.0. See LICENSE.md for more info.
"""
Image processing component: resampling, sharpening, and related MTF models.
"""

from typing import Self

from astropy.units import Quantity
from pydantic import BaseModel, ConfigDict, model_validator

from opticks.contrast_model.mtf import MTF_Model_1D
from opticks.contrast_model.processing_mtf import (
    ResamplingKernel,
    validate_resampling_params,
)
from opticks.imaging_model.imager_component import ImagerComponent
from opticks.utils.parser_helpers import PositivePydanticQty


[docs] class ProcessingParams(BaseModel): """Image processing configuration parameters. Stores the fixed (pipeline-level) processing settings. Runtime-varying inputs (local SSD) are passed as arguments to the ``get_*`` methods on ``Processing``. The ``output_pitch`` is stored here as the default output grid pitch but can be overridden at call time. """ model_config = ConfigDict(arbitrary_types_allowed=True) # Resampling kernel selection resampling_kernel: str | None = None # Default output grid pitch (can be overridden per call) output_pitch: PositivePydanticQty | None = None # Kernel-specific shape parameters bicubic_a: float | None = None lanczos_n: int | None = None @model_validator(mode="after") def _check_resampling_params(self) -> Self: if self.resampling_kernel is None: return self if self.output_pitch is None: raise ValueError("output_pitch is required when resampling_kernel is set.") kernel = ResamplingKernel[self.resampling_kernel.upper()] validate_resampling_params(kernel, self.bicubic_a, self.lanczos_n) return self
[docs] class Processing(ImagerComponent): """Image processing component (resampling, sharpening, etc.). Loaded from ``processing.yaml``. Holds the fixed processing configuration; the local SSD (``input_pitch``) is supplied at call time and can vary per image region. """ name: str processing_params: ProcessingParams | None = None # ---------- begin modelling functions ----------
[docs] def get_resampling_mtf_1d( self, input_pitch: Quantity, output_pitch: Quantity | None = None, ) -> MTF_Model_1D: """Return the resampling MTF model for a given local input pitch. Vary ``input_pitch`` (= local SSD on the ground) per image region to map the SSD-driven MTF variation across the frame. ``output_pitch`` defaults to the value in ``processing_params`` but can be overridden at call time (e.g. to compare different output resolutions). Parameters ---------- input_pitch : Quantity["length"] Local input sample spacing (= SSD on the ground for ortho correction). Varies per image region. output_pitch : Quantity["length"], optional Output resampling grid pitch. Defaults to ``processing_params.output_pitch``. Returns ------- MTF_Model_1D Resampling MTF model for this (input_pitch, output_pitch) pair. Raises ------ ValueError If ``processing_params`` is not configured, ``resampling_kernel`` is not set, or no ``output_pitch`` is available. """ p = self.processing_params if p is None: raise ValueError( "processing_params is not configured. " "Add a processing_params block to the YAML." ) kernel = p.resampling_kernel if kernel is None: raise ValueError( "resampling_kernel is not configured in processing_params." ) resolved_output_pitch = ( output_pitch if output_pitch is not None else p.output_pitch ) if resolved_output_pitch is None: raise ValueError( "output_pitch must be supplied either in processing_params " "or as an argument to get_resampling_mtf_1d()." ) return MTF_Model_1D.resampling( kernel=kernel, input_pitch=input_pitch, output_pitch=resolved_output_pitch, bicubic_a=p.bicubic_a, lanczos_n=p.lanczos_n, )