Source code for phenotypic.enhance._focus_edge_hessian

from __future__ import annotations
from typing import Annotated, Iterable, TYPE_CHECKING

if TYPE_CHECKING:
    from phenotypic._core._image import Image

from pydantic import field_validator
from skimage.filters import hessian

from phenotypic.abc_ import FocusEdge
from phenotypic.sdk_.typing_ import TuneSpec


[docs] class FocusEdgeHessian(FocusEdge): """Enhance colony boundaries and ridge-like structures via multi-scale Hessian filtering. Computes Hessian matrix eigenvalues at each sigma scale and combines them into a hybrid vesselness score that highlights regions with high curvature — colony edges, filament ridges, biofilm features — while suppressing flat agar background. Unlike the Frangi filter, background pixels (with response ≤ 0) are set to 1, so the output map inverts the agar-to-colony contrast and is best interpreted as a ridge-strength mask. For algorithm details see :doc:`/explanation/what_enhancement_does`. Best For: - Sharp colony-agar boundaries on plates with compact bacterial or yeast colonies resolved at 1--5 px edge width. - Size-heterogeneous plates where a tuple of sigmas spanning the full colony size range provides scale-invariant edge response. - Thin filaments and branching structures with low intensity contrast that global thresholding misses. - Textured colonies or biofilms where internal ridge structure aids downstream morphology analysis. Consider Also: - :class:`FocusEdgeFrangi` for strictly elongated hyphae and mycelial networks where background suppression via the adaptive gamma rule is preferred. - :class:`FocusEdgeMeijering` for very fine neurite-like filaments where the analytic shape-parameter optimum is preferred. - :class:`FocusEdgeLaplace` for simpler single-scale second-derivative edge detection without multi-scale parameter tuning. Args: sigmas: Gaussian standard deviations (pixels) at which the Hessian is evaluated. Each value responds most strongly to ridges and edges whose cross-sectional half-width is approximately that number of pixels; the per-pixel maximum across all scales is taken. Typical range: ``(1, 2, 3)`` for standard plate scans; extend to ``(1, 5)`` or wider when colony sizes vary broadly. A reasonable starting point for whole-plate scans at 600 dpi is ``(1, 2, 3)``; add larger sigmas for mature large colonies or thick filaments. Default: ``(1, 2, 3)``. alpha: Plate-likeness sensitivity in the vesselness formula. In 2-D images this parameter has no numerical effect because the plate-sensitivity ratio is undefined and omitted from the 2-D formula; it is included only for compatibility with 3-D use. Typical range: 0.1--1.0. Default: 0.5. beta: Blob-likeness sensitivity. Lower values make the filter more permissive of rounded, curved, or imperfect ridges (useful for circular colony edges); higher values restrict responses to more elongated, line-like structures. Typical range: 0.1--1.0. Default: 0.5. gamma: Fixed background suppression threshold applied to the Hessian Frobenius norm. Only regions with norm above this level produce nonzero responses; regions below it are set to 1 (background convention of the hybrid Hessian filter). Typical range: 10--20. Lower values (5--10) recover faint colony edges; higher values (20--25) sharpen the contrast between ridges and flat agar. Default: 15. black_ridges: Polarity of the target ridges. ``False`` (default) detects bright ridges on a dark background, matching the ``detect_mat`` convention where colonies and hyphae appear bright. ``True`` detects dark ridges on a bright background. Default: ``False``. mode: Boundary padding mode for Gaussian derivative computation. Accepted values: ``'reflect'``, ``'constant'``, ``'nearest'``, ``'mirror'``, ``'wrap'``. Default: ``'reflect'``. cval: Fill value used when ``mode='constant'``. Has no effect for any other mode. Default: 0. Returns: Image: Input image with ``detect_mat`` replaced by the Hessian ridge response map. ``rgb`` and ``gray`` are unchanged. References: [1] A. F. Frangi, W. J. Niessen, K. L. Vincken, and M. A. Viergever, "Multiscale vessel enhancement filtering," in *Proc. MICCAI*, 1998, pp. 130--137. See Also: :doc:`/tutorials/notebooks/03_enhancing_before_detection` for a visual walkthrough of ridge and edge enhancement on plate images. :doc:`/explanation/what_enhancement_does` for background on Hessian-based structure detection. """ sigmas: tuple[float, ...] = (1, 2, 3) alpha: float = 0.5 beta: Annotated[float, TuneSpec(0.1, 1.0)] = 0.5 gamma: Annotated[float, TuneSpec(5.0, 25.0, log=True)] = 15 black_ridges: bool = False mode: str = "reflect" cval: Annotated[float, TuneSpec(tunable=False)] = 0 @field_validator("sigmas", mode="before") @classmethod def _coerce_sigmas(cls, sigmas: Iterable[float]) -> tuple[float, ...]: """Coerce any iterable of sigmas to a tuple. Reproduces the pre-migration ``__setattr__`` override, which normalized ``sigmas`` (passed as a list or other iterable) to a tuple before storing it. """ return tuple(sigmas) def _operate(self, image: Image) -> Image: image.detect_mat[:] = hessian( image=image.detect_mat[:], sigmas=self.sigmas, alpha=self.alpha, beta=self.beta, gamma=self.gamma, black_ridges=self.black_ridges, mode=self.mode, cval=self.cval, ) return image