Source code for phenotypic.enhance._unsharp_mask

from __future__ import annotations

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from phenotypic import Image

from skimage.filters import unsharp_mask

from ..abc_ import ImageEnhancer


[docs] class UnsharpMask(ImageEnhancer): """ Unsharp masking for enhanced colony edge definition on agar plates. Unsharp masking is a classical sharpening technique that enhances edges by subtracting a blurred copy of the image from the original, then scaling the difference to emphasize high-contrast boundaries. On fungal colony plates, this makes soft or indistinct colony edges more pronounced, improving the ability of thresholding and edge-detection algorithms to identify colony boundaries precisely. Use cases (agar plates): - Low-contrast colonies with soft, gradual edges (translucent growth) - Dense plates where colonies blend into background - Pre-threshold sharpening to improve segmentation accuracy - Enhancing subtle colony morphologies before downstream measurement - Improving edge definition when scanner or lens causes slight blurring Tuning and effects: - radius: Controls the scale of features enhanced. Small values (0.5–2) sharpen fine details like small colony boundaries and surface texture; larger values (5–15+) enhance broader features and colony-background contrast. For fungal colonies, keep radius smaller than the minimum colony radius to avoid creating visible halos or merging adjacent colonies. Start at 2.0 for general-purpose enhancement. - amount: Determines the magnitude of edge enhancement (how much darker/brighter the edges become). Low values (0.3–0.7) produce subtle improvements safe for noisy images; standard values (1.0–1.5) give moderate sharpening suitable for most colony plates; high values (2.0+) create aggressive enhancement but risk amplifying noise and creating visible bright/dark halos around colonies. Negative amounts produce blur (opposite effect). - preserve_range: Leave as False for consistency with other enhancers in the framework. Caveats: - Amplifies noise: In noisy images, unsharp masking sharpens both signal (colony edges) and noise artifacts. Consider denoising first (e.g., with GaussianBlur, BilateralDenoise, or MedianFilter) on very grainy agar scans. - Halo artifacts: Excessive radius or amount creates bright/dark rims around colonies, which can be mistaken for separate objects or cause thresholding to fail. - Already-sharp images: Applying unsharp mask to crisp, high-contrast colonies may be redundant and introduce artifacts. Reserve for low-contrast scenarios. Attributes: radius (float): Standard deviation of Gaussian blur used to compute edges, in pixels. Controls the scale of features enhanced. amount (float): Multiplier for the sharpening effect. Controls intensity of edge enhancement. preserve_range (bool): Whether to keep the original range of pixel values (False by default). Examples: .. dropdown:: Sharpening low-contrast fungal colonies before detection .. code-block:: python from phenotypic import Image from phenotypic.enhance import UnsharpMask from phenotypic.detect import OtsuDetector # Load image of low-contrast plate (e.g., translucent yeasts) image = Image.from_image_path("yeast_plate.jpg") # Apply unsharp masking with moderate settings sharpener = UnsharpMask(radius=2.0, amount=1.2) sharpened = sharpener.apply(image) # Detect colonies in sharpened enhanced grayscale detector = OtsuDetector() detected = detector.apply(sharpened) # Original image untouched, detection on enhanced data colonies = detected.objects print(f"Detected {len(colonies)} colonies") .. dropdown:: Tuning radius and amount for dense high-throughput plates .. code-block:: python from phenotypic import Image, ImagePipeline from phenotypic.enhance import UnsharpMask, GaussianBlur from phenotypic.detect import OtsuDetector # For high-resolution 384-well plate scans with tiny colonies, # use small radius to avoid merging adjacent growth pipeline = ImagePipeline() # Step 1: Light blur to reduce scanner noise pipeline.add(GaussianBlur(sigma=1)) # Step 2: Enhance edges with small radius for dense plates # radius=1.0 emphasizes only fine features (individual colonies) pipeline.add(UnsharpMask(radius=1.0, amount=1.5)) # Step 3: Detect in enhanced grayscale pipeline.add(OtsuDetector()) # Process a batch of images images = [Image.from_image_path(f) for f in image_paths] results = pipeline.operate(images) for i, result in enumerate(results): print(f"Plate {i}: {len(result.objects)} colonies") .. dropdown:: Aggressive sharpening for very translucent colonies .. code-block:: python from phenotypic import Image from phenotypic.enhance import UnsharpMask # For extremely low-contrast colonies (e.g., slow-growing mutants, # low-turbidity liquid culture plates), use higher amount image = Image.from_image_path("faint_colonies.jpg") # Aggressive parameters: larger radius for broader features, # higher amount for stronger enhancement aggressive_sharpener = UnsharpMask(radius=5.0, amount=2.5) enhanced = aggressive_sharpener.apply(image) # Inspect result for artifacts (halos); adjust if needed # If halos appear, reduce amount to 1.5–2.0 print("Sharpening applied. Check for halo artifacts around large colonies.") """
[docs] def __init__( self, radius: float = 2.0, amount: float = 1.0, preserve_range: bool = False, ): """ Parameters: radius (float): Standard deviation (sigma) of the Gaussian blur in pixels. Defines the scale of features to enhance. Small values (0.5–2) sharpen fine details (thin colony edges, small morphologies); larger values (5–15) enhance broad features (large colonies, colony-background separation). Must be > 0. For fungal colonies, keep below the typical colony radius to avoid merging adjacent colonies. Recommended: 2.0–3.0 for general-purpose use, 1.0 for high-density plates, 5.0+ for emphasizing large-scale features on low-resolution images. amount (float): Amplification factor for the sharpening effect. Controls how much the edge enhancement contributes to the output. Typical range: 0.3–2.5. Low values (0.3–0.7) produce subtle enhancement suitable for noisy images; standard values (1.0–1.5) give balanced sharpening; high values (2.0+) create aggressive enhancement for very low-contrast colonies. Can be negative to produce blurring instead. Excessive amounts risk visible artifacts and noise amplification. preserve_range (bool): If False (default), output may be rescaled if necessary. If True, the original range of input values is preserved. Keep as False for consistency with other enhancers. """ if radius <= 0: raise ValueError("radius must be > 0") self.radius = float(radius) self.amount = float(amount) self.preserve_range = bool(preserve_range)
def _operate(self, image: Image) -> Image: """Apply unsharp masking to enhance colony edges in the enhanced grayscale channel.""" image.enh_gray[:] = unsharp_mask( image=image.enh_gray[:], radius=self.radius, amount=self.amount, preserve_range=self.preserve_range, channel_axis=None, ) return image