Skip to content

Difference-of-Gaussians (dog) plugin

patchworks.plugins.dog.dog_label_fn(low_sigma: float | tuple[float, ...], high_sigma: float | tuple[float, ...], threshold: float, *, use_gpu: bool = False, decon_kwargs: dict[str, Any] | None = None, voxel_size: dict[str, float] | None = None, sigma_units: str = 'px') -> Callable[[np.ndarray], np.ndarray]

Return a ready-to-use DoG labeler for tile_process.

Parameters:

Name Type Description Default
low_sigma float | tuple[float, ...]

Gaussian sigmas for the narrow/wide blur, one number or one per axis. dog = blur(low_sigma) - blur(high_sigma). In pixels by default, which on an anisotropic stack blurs z far further (physically) than x/y; see sigma_units.

required
high_sigma float | tuple[float, ...]

Gaussian sigmas for the narrow/wide blur, one number or one per axis. dog = blur(low_sigma) - blur(high_sigma). In pixels by default, which on an anisotropic stack blurs z far further (physically) than x/y; see sigma_units.

required
threshold float

Binary threshold applied to the DoG image (dog > threshold).

required
use_gpu bool

Run gaussian_filter + label on GPU via cupy/cupyx instead of scipy. Independent of decon_kwargs — pycudadecon always needs a CUDA GPU regardless of this flag (it takes/returns plain NumPy), and this flag only picks the backend for the blur/label steps that follow.

False
decon_kwargs dict[str, Any] | None

If given, each tile is first deconvolved via pycudadecon.decon(block, **decon_kwargs) before the DoG step. None (default) skips deconvolution. pycudadecon is CUDA-only, so a SLURM job running this needs a GPU allocated regardless of use_gpu above. Widen tile_process's overlap to cover the PSF support when deconvolving, so edge tiles don't get truncated context.

dxdata/dzdata/dxpsf/dzpsf are filled in from voxel_size when you leave them out, so the voxel sizes cannot drift away from the image they describe. Anything you set explicitly wins.

None
voxel_size dict[str, float] | None

Physical voxel size as {"z": .., "y": .., "x": ..}. The Snakemake workflow passes the image's own calibration automatically; from the API, :func:patchworks.plugins.ome_zarr.read_pixel_size reads it from a store.

None
sigma_units str

"px" (default) or "um". With "um" the sigmas are physical distances, converted per axis with voxel_size -- so a cilium is blurred by the same distance along z as across it, however coarse the z-step.

'px'

Returns:

Type Description
Callable[[ndarray], ndarray]

Picklable function ready for tile_process.

Source code in src/patchworks/plugins/dog.py
def dog_label_fn(
    low_sigma: float | tuple[float, ...],
    high_sigma: float | tuple[float, ...],
    threshold: float,
    *,
    use_gpu: bool = False,
    decon_kwargs: dict[str, Any] | None = None,
    voxel_size: dict[str, float] | None = None,
    sigma_units: str = "px",
) -> Callable[[np.ndarray], np.ndarray]:
    """Return a ready-to-use DoG labeler for ``tile_process``.

    Parameters
    ----------
    low_sigma, high_sigma:
        Gaussian sigmas for the narrow/wide blur, one number or one per axis.
        ``dog = blur(low_sigma) - blur(high_sigma)``. In pixels by default,
        which on an anisotropic stack blurs z far further (physically) than
        x/y; see *sigma_units*.
    threshold:
        Binary threshold applied to the DoG image (``dog > threshold``).
    use_gpu:
        Run gaussian_filter + label on GPU via cupy/cupyx instead of scipy.
        Independent of ``decon_kwargs`` — pycudadecon always needs a CUDA
        GPU regardless of this flag (it takes/returns plain NumPy), and this
        flag only picks the backend for the blur/label steps that follow.
    decon_kwargs:
        If given, each tile is first deconvolved via
        ``pycudadecon.decon(block, **decon_kwargs)`` before the DoG step.
        ``None`` (default) skips deconvolution. pycudadecon is CUDA-only, so
        a SLURM job running this needs a GPU allocated regardless of
        ``use_gpu`` above. Widen ``tile_process``'s ``overlap`` to cover the
        PSF support when deconvolving, so edge tiles don't get truncated
        context.

        ``dxdata``/``dzdata``/``dxpsf``/``dzpsf`` are filled in from
        *voxel_size* when you leave them out, so the voxel sizes cannot drift
        away from the image they describe. Anything you set explicitly wins.
    voxel_size:
        Physical voxel size as ``{"z": .., "y": .., "x": ..}``. The Snakemake
        workflow passes the image's own calibration automatically; from the
        API, :func:`patchworks.plugins.ome_zarr.read_pixel_size` reads it from
        a store.
    sigma_units:
        ``"px"`` (default) or ``"um"``. With ``"um"`` the sigmas are
        physical distances, converted per axis with *voxel_size* -- so a
        cilium is blurred by the same distance along z as across it, however
        coarse the z-step.

    Returns
    -------
    Callable[[ndarray], ndarray]
        Picklable function ready for ``tile_process``.
    """
    if sigma_units not in ("px", "um"):
        raise ValueError(
            f'sigma_units must be "px" or "um", got {sigma_units!r}'
        )
    if sigma_units == "um":
        if not voxel_size:
            raise ValueError('sigma_units="um" needs voxel_size')
        low_sigma = _physical_sigma(low_sigma, voxel_size)
        high_sigma = _physical_sigma(high_sigma, voxel_size)
        logger.info(
            "DoG sigmas in pixels (z, y, x): low %s, high %s",
            low_sigma,
            high_sigma,
        )
    if use_gpu:
        _require_cupy()
    if decon_kwargs is not None:
        _require_pycudadecon()
        if voxel_size:
            # Derived values fill gaps only -- an explicit dxpsf for a PSF
            # sampled differently from the data must not be overwritten.
            derived = decon_voxel_kwargs(voxel_size)
            missing = {
                k: v for k, v in derived.items() if k not in decon_kwargs
            }
            if missing:
                logger.info(
                    "decon voxel sizes taken from the image calibration: %s",
                    missing,
                )
                decon_kwargs = {**decon_kwargs, **missing}
    cfg = {
        "low_sigma": low_sigma,
        "high_sigma": high_sigma,
        "threshold": threshold,
        "use_gpu": use_gpu,
        "decon_kwargs": decon_kwargs,
    }
    return partial(_run, dog_dict=cfg)