Source code for PyNutil.image_series

"""Image series and section data containers.

These classes represent a series of sections (images or segmentations) to be
processed through the PyNutil pipeline.  Users with custom segmentation types
can construct :class:`Section` and :class:`ImageSeries` objects directly,
providing their own ``numpy`` arrays instead of reading from disk.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Dict, List, Optional

import numpy as np


[docs] @dataclass class Section: """A single section, identified by number and backed by an image. Either *image* or *path* must be provided. When only *path* is given the image is loaded lazily the first time it is needed by the pipeline. Parameters ---------- section_number: Numeric identifier that must match a section in the alignment JSON. filename: Display name used in :attr:`~PyNutil.ExtractionResult.section_filenames`. Defaults to *path* when not set explicitly. image: Pre-loaded image array (2-D or 3-D ``numpy`` array). Provide this when you have already loaded or generated the image data yourself. path: Path to the image file on disk. The image is loaded on demand by the configured segmentation adapter when the section is processed. """ section_number: int filename: str = "" image: Optional[np.ndarray] = field(default=None, repr=False) path: Optional[str] = None
[docs] def get_image(self, adapter) -> np.ndarray: """Return the image array, loading from *path* if not pre-loaded. Parameters ---------- adapter: A :class:`~PyNutil.processing.adapters.segmentation.SegmentationAdapter` used to load the file when *image* is ``None``. """ if self.image is not None: return self.image if self.path is not None: return adapter.load(self.path) raise ValueError( f"Section {self.section_number} has neither image data nor a file path." )
[docs] @dataclass class ImageSeries: """An ordered collection of :class:`Section` objects. Construct this directly when you want to supply custom image data, or use :func:`~PyNutil.read_segmentation_dir` / :func:`~PyNutil.read_image_dir` to build one from a folder of image files. Parameters ---------- sections: Dictionary mapping ``section_number`` to :class:`Section` objects. pixel_id: RGB value (or label) identifying the segmented class of interest. Set by :func:`~PyNutil.read_segmentation_dir` and consumed by :func:`~PyNutil.seg_to_coords`. segmentation_format: Name of the segmentation adapter to use (e.g. ``"binary"`` or ``"cellpose"``). Set by :func:`~PyNutil.read_segmentation_dir` and consumed by :func:`~PyNutil.seg_to_coords`. """ sections: Dict[int, Section] = field(default_factory=dict) pixel_id: object = field(default_factory=lambda: [0, 0, 0]) segmentation_format: str = "binary" @property def filenames(self) -> List[str]: """Display filenames for all sections.""" return [s.filename for s in self.sections.values()]