Image Class Methods#
Overview#
The Image class is the primary interface for image processing, analysis, and manipulation
within the PhenoTypic framework. It combines data management, color space handling, object detection,
file I/O, and visualization capabilities into a unified interface.
Image data can be provided as NumPy arrays (2-D grayscale or 3-D RGB/RGBA), another Image instance, or loaded from file. The class automatically manages format conversions and maintains internal consistency across multiple data representations.
Key capabilities:
Data Management: Grayscale, RGB, enhanced versions, object maps
Color Spaces: RGB, grayscale, HSV, CIE XYZ, CIE L*a*b*, xy chromaticity
Object Analysis: Detection results, masks, labels, measurements
File I/O: Load/save images with metadata management
Visualization: Display, overlays, plotting for pipeline development
Initialization & Creation#
- Image.__init__(arr: np.ndarray | Image | None = None, name: str | None = None, bit_depth: Literal[8, 16] | None = None, gamma: GAMMA_ENCODINGS | str | None = GAMMA_ENCODINGS.SRGB, illuminant: Literal['D65', 'D50'] | None = 'D65')[source]#
Initialize an Image instance with optional image data and color properties.
Creates a new Image with complete initialization of all data management, color space, I/O, and object handling capabilities. The image can be initialized empty or with data from a NumPy array or another Image instance.
- Parameters:
arr (np.ndarray | Image | None) –
Optional image data. Can be:
A NumPy array of shape (height, width) for grayscale or (height, width, channels) for RGB/RGBA
An existing Image instance to copy from
None to create an empty image
Defaults to None.
name (str | None) – Optional human-readable name for the image. If not provided, the image UUID will be used as the name. Defaults to None.
bit_depth (Literal[8, 16] | None) – The bit depth of the image data (8 or 16 bits). If not specified and arr is provided, bit depth is automatically inferred from the array dtype. Defaults to None.
gamma (GAMMA_ENCODINGS) – The gamma encoding used for color correction. GAMMA_ENCODINGS.SRGB: applies sRGB gamma correction (standard display gamma) GAMMA_ENCODINGS.LINEAR: assumes linear RGB data Defaults to GAMMA_ENCODINGS.SRGB.
illuminant (str | None) – The reference illuminant for color calculations. ‘D65’: standard daylight illuminant (recommended) ‘D50’: standard illumination for imaging Defaults to ‘D65’.
- Raises:
ValueError – If gamma is not a GAMMA_ENCODINGS member.
ValueError – If illuminant is not ‘D65’ or ‘D50’.
TypeError – If arr is provided but is not a NumPy array or Image instance.
Examples
Create empty image:
>>> img = Image(name='empty_image')
Create from grayscale array:
>>> gray_arr = np.random.randint(0, 256, (480, 640), dtype=np.uint8) >>> img = Image(gray_arr, name='grayscale_photo')
Create from RGB array:
>>> rgb_arr = np.random.randint(0, 256, (480, 640, 3), dtype=np.uint8) >>> from phenotypic.sdk\_.constants_ import GAMMA_ENCODINGS >>> img = Image(rgb_arr, name='color_photo', gamma=GAMMA_ENCODINGS.SRGB)
Copy another image:
>>> img1 = Image.imread('original.jpg') >>> img2 = Image(img1, name='copy_of_original')
- Image.copy()#
Creates a copy of the current Image instance, excluding the UUID. .. note:
- The new instance is only informationally a copy. The UUID of the new instance is different.
- Returns:
A copy of the current Image instance.
- Return type:
Image
Data Access - Grayscale#
- property Image.gray: Grayscale#
The image’s grayscale representation. The array form is converted into a gray form since some algorithm’s only handle 2-D
Note
gray elements are not directly mutable in order to preserve image information integrity
Change gray elements by changing the image being represented with Image.set_image()
- Returns:
An immutable container for the image gray that can be accessed like a numpy array, but has extra methods to streamline development.
- Return type:
from phenotypic import Image image = Image(arr) # get the gray data arr = image.gray[:] print(type(arr)) # set the gray data # the shape of the new gray must be the same shape as the original gray image.gray[:] = arr # without the bracket indexing the accessor is returned instead print(image.gray[:])
See Also:
ImageMatrix
The gray property provides access to the grayscale representation of the image.
For RGB images, the grayscale version is automatically computed on first access.
For images created from grayscale arrays, this returns the original data.
Grayscale API:
- class phenotypic._core._image_parts.accessors._grayscale_accessor.Grayscale(root_image: Image)[source]#
Bases:
SingleChannelAccessorAccessor for managing and visualizing grayscale image data.
This class provides an interface for interacting with the luminance-based grayscale representation of an image. It supports data access, modification, visualization through histograms, and overlay annotations. The accessor maintains immutability of data at the external interface level while allowing controlled modifications through dedicated methods.
The grayscale data is stored as a 2D floating-point array with normalized values in the range [0.0, 1.0].
- Parameters:
root_image (Image)
- _accessor_property_name#
Property name used to access this accessor from the Image object (set to “gray”).
- Type:
Examples
Access and display grayscale data:
>>> img = Image("path/to/image.png") >>> gray_array = img.gray[:] >>> fig = img.gray.show()
Modify grayscale data with validation:
>>> img.gray[10:20, 10:20] = 0.5 # Set region to mid-gray >>> img.gray[100, 100] = 0.8 # Set single pixel to light gray
Visualize histogram and overlay:
>>> fig, axes = img.gray.histogram() >>> fig, ax = img.show(overlay=True, show_labels=True)
- classmethod load(filepath: str | Path) numpy.ndarray#
Load an image array from file and verify it was saved from this accessor type.
Checks if the image contains PhenoTypic metadata indicating it was saved from the same accessor type (e.g., Image.gray, Image.rgb). If metadata doesn’t match or is missing, a warning is raised but the array is still loaded.
- Parameters:
- Returns:
The loaded image array.
- Return type:
np.ndarray
- Warns:
UserWarning – If metadata is missing or indicates the image was saved from a different accessor type.
Examples
Load a grayscale image from file:
>>> from phenotypic import Image >>> image = Image(arr) >>> # load an object map you saved or hand-graded >>> image.objmap.load("path/to/map.png")
- __array__(dtype=None, copy=None)#
Implements the array interface for numpy compatibility.
This allows numpy functions to operate directly on accessor objects. For example: np.sum(accessor), np.mean(accessor), etc.
- Parameters:
dtype – Optional dtype to cast the array to
copy – Optional copy parameter for NumPy 2.0+ compatibility
- Returns:
The underlying array data
- Return type:
np.ndarray
- __getitem__(key) numpy.ndarray[source]#
Retrieve a read-only view or slice of the grayscale image data.
Allows array-style indexing and slicing to access subsets of the grayscale data. The returned array is marked read-only to prevent accidental modifications. Use __setitem__ for intentional modifications.
- Parameters:
key – Index or slice specification. Can be an integer for single-row access, tuple of slices for multi-dimensional slicing (e.g., [10:20, 5:15]), or boolean arrays for advanced indexing.
- Returns:
- A read-only view of the requested grayscale data. Values are
normalized floating-point numbers in the range [0.0, 1.0].
- Return type:
np.ndarray
- Raises:
EmptyImageError – If the underlying image data is empty (shape[0] == 0).
Examples
Access grayscale data with various indexing techniques:
>>> # Access entire grayscale array >>> full_gray = img.gray[:] >>> # Slice a region >>> region = img.gray[10:20, 5:15] >>> # Access single row >>> row = img.gray[10] >>> # Advanced indexing not recommended but supported >>> mask = img.gray > 0.5
- __len__() int#
Returns the length of the subject array.
This method calculates and returns the total number of elements contained in the underlying array.
- Returns:
The number of elements in the underlying array attribute.
- Return type:
- __setitem__(key, value) None[source]#
Modify grayscale image data at specified indices with validation.
Allows assignment of new values to grayscale data at specified locations. All values must be normalized to the range [0.0, 1.0]. Modifications trigger automatic reset of dependent data structures (detection matrix and object map) to maintain consistency.
- Parameters:
key – Index or slice specification. Same indexing schemes as __getitem__ (e.g., [10:20, 5:15], [100, 100], [:]).
value (np.ndarray | int | float) – New value(s) to assign. Can be: - A NumPy array with shape matching the indexed region. - A scalar (int or float) to broadcast to the indexed region. Must contain values in the range [0.0, 1.0].
- Raises:
ArrayKeyValueShapeMismatchError – If value is an ndarray and its shape does not match the shape of the indexed region.
TypeError – If value is not an ndarray, int, or float.
AssertionError – If values are outside the valid range [0.0, 1.0].
- Return type:
None
Notes
All grayscale values must be normalized to [0.0, 1.0].
Modifications automatically reset detect_mat and objmap to prevent stale data.
For bulk operations, consider using direct array indexing on a copy.
Examples
Modify grayscale data with different assignment patterns:
>>> # Set a region to a specific value >>> img.gray[10:20, 5:15] = 0.5 >>> # Set a single pixel >>> img.gray[100, 100] = 0.8 >>> # Assign from another array >>> region = np.random.rand(10, 10) >>> img.gray[10:20, 5:15] = region
- copy() numpy.ndarray#
- Return type:
- dash(figsize: tuple[int, int] | None = None, title: str | None = None, cmap: str | None = 'gray', foreground_only: bool = False, overlay: bool = True, *, object_label: int | None = None, show_labels: bool = False, show_grid: bool = True, label_settings: dict | None = None, overlay_settings: dict | None = None, plotly_settings: dict | None = None) go.Figure#
Display the single-channel image data using Plotly.
- Parameters:
figsize (tuple[int, int] | None) – Figure size in inches (width, height). If None, auto-calculated from array aspect ratio.
title (str | None) – Title of the plot. If None, no title is displayed.
cmap (str | None) – Colormap name. Defaults to
"gray".foreground_only (bool) – If True, display only foreground elements.
overlay (bool) – If True, overlay the object map on the image. Falls back to plain image when no objects are detected.
object_label (int | None) – Specific object label to highlight. If None, shows all detected objects. Only used when overlay is True.
show_labels (bool) – If True, displays numeric labels at object centroids. Only used when overlay is True.
show_grid (bool) – For GridImage only. If True, draws gridlines and colored section boxes. Only used when overlay is True. Ignored for regular Image.
label_settings (dict | None) – Dict passed to text label rendering.
overlay_settings (dict | None) – Dict passed to overlay composition.
plotly_settings (dict | None) – Additional Plotly layout settings.
- Returns:
A
plotly.graph_objects.Figure.- Raises:
ImportError – If plotly is not installed.
- Return type:
go.Figure
- foreground()#
Extracts and returns the foreground of the image by masking out the background.
This method generates a foreground image by applying the object mask stored in the Image to the current array representation. Pixels outside the object mask are set to zero in the resulting foreground image. This is useful in image processing tasks to isolate the region of interest in the image, such as microbe colonies on an agar plate.
- Returns:
A numpy array containing only the foreground portion of the image, with all non-foreground pixels set to zero.
- Return type:
- histogram(figsize: Tuple[int, int] = (10, 5), *, cmap='gray', linewidth=1, channel_names: list | None = None) Tuple[TypeAliasForwardRef('matplotlib.figure.Figure'), TypeAliasForwardRef('matplotlib.axes.Axes')]#
Plots the histogram(s) of an image along with the image itself. The behavior depends on the dimensionality of the image array (2D or 3D). In the case of 2D, a single image and its histogram are produced. For 3D (multi-channel images), histograms for each channel are created alongside the image. This method supports customization such as figure size, colormap, line width of histograms, and labeling of channels.
- Parameters:
figsize (Tuple[int, int]) – The size of the figure to create. Default is (10, 5).
cmap (str) – Colormap used to render the image when the data is single channel. Default is ‘gray’.
linewidth (int) – Line width of the plotted histograms. Default is 1.
channel_names (list | None) – Optional names for the channels in 3D data. These are used as titles for channel-specific histograms. If None, channels are instead labeled numerically.
- Returns:
The Matplotlib figure and axes objects representing the plotted image and its histograms.
- Return type:
Tuple[plt.Figure, plt.Axes]
- Raises:
ValueError – If the dimensionality of the input image array is unsupported.
Notes
This method uses skimage.exposure.histogram for computing the histogram data.
- imsave(filepath: str | Path | None = None, bit_depth: Literal[8, 16] | None = None) None#
Saves an array representing a microbe colony image to a specified file format while preserving or adjusting metadata and pixel depth as needed. Supports JPEG, PNG, and TIFF formats.
The behavior of the function is context-sensitive based on the file format’s restrictions and array properties. Proper file format selection and bit depth adjustment can have an impact on the accuracy of image analysis and preservation of data integrity.
- Parameters:
filepath (str | Path | None) –
The destination file path where the image will be saved. The extension of the file path determines the image format (e.g., .jpeg, .png, .tiff). Changing the file format influences how the image data is handled during saving:
.jpeg: Compression or loss of data may occur. Maximal value limit (255) for uint8 pixel depth affects the fidelity of rich intensity details in microbe colonies.
.png: Retains high-quality output but supports only 8-bit or 16-bit images. Conversions may occur if the array has a different data type, which could result in data loss.
.tiff: Ideal for high-bit-depth precision and analysis preservation; best for maintaining intricate morphological details of microbial colonies.
bit_depth (Literal[8, 16] | None, optional) –
Specifies the bit depth of the saved image (either 8-bit or 16-bit). The provided bit depth must align with the file format’s capabilities. Misalignment could trigger conversion with possible data truncation or rounding. For example:
8-bit: Useful for efficiently representing intensity when detail is moderate, suitable for JPEG or simple PNG outputs.
16-bit: Allows for higher intensity ranges, especially valuable for preserving subtle morphological gradient differentiation when analyzing colonies.
- Raises:
ValueError – An error occurs when an unsupported file extension is provided in filepath.
- Warns:
UserWarnings – Warnings are issued under the following conditions:
Saving a 16-bit or floating-point array as JPEG, as these conversions may cause information loss due to format restrictions.
Saving a floating-point array as PNG when conversions to 8-bit or 16-bit integers might lead to truncated or altered pixel intensity values.
- Return type:
None
- isempty()#
- napari(name: str | None = None, reset: bool = False, *, viewer: napari.Viewer | None = None, layer_name: str | None = None) napari.Viewer#
Add image to a persistent global napari viewer for Jupyter workflows.
Creates or reuses a single napari viewer instance that persists across multiple method calls. This is particularly useful in Jupyter notebooks where multiple accessors can contribute layers to the same viewer, enabling interactive comparison of different image transformations (e.g., grayscale, RGB, binary masks) on the same data.
The viewer is automatically displayed in Jupyter environments and recreated if it has been closed externally.
- Parameters:
name (str | None) – Optional custom name for the image layer. If provided, the layer will be named
{accessor}_{name}. If not provided, defaults to using the image’s name attribute.reset (bool) – If True, closes the current napari viewer and creates a fresh one. This is useful for starting a new visualization session without lingering layers from previous calls. Defaults to False.
viewer (napari.Viewer | None) – Optional external napari viewer instance to use instead of the global viewer. When provided, global viewer management (creation, reset, smart-grid installation) is bypassed entirely. Defaults to None.
layer_name (str | None) – Optional full layer name to use instead of the auto-generated
{accessor}_{image_name}pattern. Defaults to None.
- Returns:
- The global napari viewer instance with the current
image added as a new layer.
- Return type:
napari.Viewer
- Raises:
ImportError – If napari is not installed. Install with
pip install phenotypic[napari].
Examples
View multiple image transformations in one viewer:
>>> from phenotypic import Image >>> img = Image(arr) >>> # Add grayscale version to viewer >>> viewer = img.gray.napari() >>> # Add RGB version to same viewer >>> viewer = img.rgb.napari() >>> # Add binary segmentation with custom name >>> viewer = img.objmask.napari(name="segmentation_v2")
Using custom names for comparison:
>>> viewer = img.gray.napari(name="raw_grayscale") >>> viewer = img.objmask.napari(name="segmentation_v2")
Resetting the viewer for a fresh session:
>>> viewer = img.gray.napari() >>> viewer = img.rgb.napari() # Same viewer, added layer >>> viewer = img.gray.napari(reset=True) # Fresh viewer, old layers gone
Note
Layers are named using the pattern
{accessor}_{image_name}to ensure descriptive identification. If a layer with the same name already exists, it is replaced with the new image data. This allows for easy updates and comparison of different processing stages.
- save_overlay(filepath: str | Path, overlay_alpha: float = 0.3, bg_label: int = 0, colors: list | None = None, show_grid: bool = True, gridline_color: tuple[int, int, int] = (0, 255, 255), section_box_colors: list[tuple[int, int, int]] | None = None, **label2rgb_kwargs) None#
Save a full-resolution overlay image blending objmap with the subject array.
Creates an RGB overlay by blending the object map labels with the underlying image data and saves it to disk. Unlike show(overlay=True) which produces a matplotlib figure, this method saves the raw pixel data at full resolution, suitable for pixel-level quality validation of detection results.
For GridImage objects, gridlines and section boxes are automatically drawn when
show_gridis True. The line widths scale dynamically with image size.- Parameters:
filepath (str | Path) – Destination file path. Should have .png or .jpeg extension.
overlay_alpha (float) – Alpha value for label overlay (0.0 = transparent, 1.0 = opaque). Defaults to 0.3.
bg_label (int) – Label value to treat as background. Defaults to 0.
colors (list | None) – List of RGB colors to use for labels. If None, uses default colormap.
show_grid (bool) – Whether to draw gridlines and section boxes on overlay for GridImage objects. Ignored for regular Image objects. Defaults to True.
gridline_color (tuple[int, int, int]) – RGB color tuple for gridlines. Defaults to cyan (0, 255, 255).
section_box_colors (list[tuple[int, int, int]] | None) – List of RGB tuples for cycling through section box colors. Defaults to tab20 colormap colors.
**label2rgb_kwargs – Additional keyword arguments for label2rgb.
- Raises:
ValueError – If the file extension is not supported.
- Return type:
None
Examples
Save full-resolution overlay:
>>> from phenotypic.data import load_synth_yeast_plate >>> image = load_synth_yeast_plate() >>> image.rgb.save_overlay("overlay_rgb.png", overlay_alpha=0.4)
- show(figsize: tuple[int, int] | None = None, title: str | None = None, cmap: str | None = 'gray', foreground_only: bool = False, overlay: bool = True, *, object_label: int | None = None, show_labels: bool = False, show_grid: bool = True, label_settings: dict | None = None, overlay_settings: dict | None = None) tuple[TypeAliasForwardRef('matplotlib.figure.Figure'), TypeAliasForwardRef('matplotlib.axes.Axes')]#
Display the single-channel image data using matplotlib.
- Parameters:
figsize (tuple[int, int] | None) – Figure size in inches (width, height). If None, auto-calculated from array aspect ratio.
title (str | None) – Title of the plot. If None, no title is displayed.
cmap (str | None) – Colormap name. Defaults to
"gray".foreground_only (bool) – If True, display only foreground elements.
overlay (bool) – If True, overlay the object map on the image. Falls back to plain image when no objects are detected.
object_label (int | None) – Specific object label to highlight. If None, shows all detected objects. Only used when overlay is True.
show_labels (bool) – If True, displays numeric labels at object centroids. Only used when overlay is True.
show_grid (bool) – For GridImage only. If True, draws gridlines and colored section boxes. Only used when overlay is True. Ignored for regular Image.
label_settings (dict | None) – Dict passed to text label rendering.
overlay_settings (dict | None) – Dict passed to overlay composition.
- Returns:
A
(plt.Figure, plt.Axes)tuple.- Return type:
tuple[TypeAliasForwardRef(‘matplotlib.figure.Figure’), TypeAliasForwardRef(‘matplotlib.axes.Axes’)]
- val_range() pd.Interval#
Return the closed interval [min, max] of the subject array values.
- Returns:
A single closed interval including both endpoints.
- Return type:
pd.Interval
- vmax() float[source]#
Returns the maximum grayscale value in the image. Since the grayscale is normalized to [0.0, 1.0], it returns 1.0.
- Return type:
- vmin() float[source]#
Returns the minimum grayscale value in the image. Since the grayscale is normalized to [0.0, 1.0], it returns 0.0.
- Return type:
- property dtype#
- property ndim: int#
Returns the number of dimensions of the underlying array.
The ndim property provides access to the dimensionality of the array being encapsulated in the object. This value corresponds to the number of axes or dimensions the underlying array possesses. It can be useful for understanding the structure of the contained data.
- Returns:
The number of dimensions of the underlying array.
- Return type:
- property shape: Tuple[int, ...]#
Returns the shape of the current image data.
This method retrieves the dimensions of the array stored in the _main_arr attribute as a tuple, which indicates its size along each axis.
- Returns:
A tuple representing the dimensions of the _main_arr attribute.
- Return type:
Tuple[int, …]
Data Access - RGB#
- property Image.rgb: ImageRGB#
Returns the ImageArray accessor; An image rgb represents the color information with a range either between [0-255] or [0-65536] depending on the bit-depth.
Note
rgb/gray element data is synced
change image shape by changing the image being represented with Image.set_image()
Raises an error if the arr image has no rgb form
- Returns:
A class that can be accessed like a numpy rgb, but has extra methods to streamline development, or None if not set
- Return type:
- Raises:
NoArrayError – If no multichannel image data is set as arr.
Example
Image.rgb:
>>> from phenotypic import Image >>> from phenotypic.data import load_colony >>> image = Image(load_colony()) >>> # get the rgb data >>> arr = image.rgb[:] >>> print(type(arr)) >>> # set the rgb data >>> # the shape of the new rgb must be the same shape as the original rgb >>> image.rgb[:] = arr >>> # without the bracket indexing the accessor is returned instead >>> print(image.rgb[:])
See Also:
ImageArray
The rgb property provides access to the RGB/RGBA image data if available.
For grayscale-only images, this property may be empty. The RGB accessor supports
numpy-like indexing and slicing operations.
ImageRGB API:
- class phenotypic._core._image_parts.accessors._rgb_accessor.ImageRGB(root_image: Image)[source]#
Bases:
MultiChannelAccessorAccessor for interacting with RGB multichannel image data.
ImageRGB provides a comprehensive interface for accessing, modifying, visualizing, and analyzing RGB image arrays. It acts as a bridge to the underlying RGB data stored in the parent Image object, exposing the data through intuitive indexing operations and utility methods.
This accessor supports advanced visualization capabilities including display of individual channels or composite images, overlays with segmentation maps, and channel-specific histograms. Users can seamlessly manipulate image arrays, explore geometric and structural attributes, and analyze segmented objects.
The class inherits from MultiChannelAccessor and extends functionality for 3-channel (RGB) images specifically. All visualization and analysis methods from the base class are available and can handle 3-channel color data.
- _accessor_property_name#
Property name on Image that returns this accessor. Set to “rgb” to identify this as the RGB accessor.
- Type:
- Raises:
EmptyImageError – If attempting to access data when no image is loaded.
NoArrayError – If attempting to access RGB data when the image is 2D (no RGB array form exists).
- Parameters:
root_image (Image)
Examples
Access RGB data from an Image object:
>>> rgb_accessor = image.rgb >>> # Get a copy of the full RGB array >>> rgb_data = rgb_accessor[:] >>> # Modify a region >>> rgb_accessor[10:20, 10:20] = [255, 0, 0] >>> # Display the image >>> fig = rgb_accessor.show()
- classmethod load(filepath: str | Path) numpy.ndarray#
Load an image array from file and verify it was saved from this accessor type.
Checks if the image contains PhenoTypic metadata indicating it was saved from the same accessor type (e.g., Image.gray, Image.rgb). If metadata doesn’t match or is missing, a warning is raised but the array is still loaded.
- Parameters:
- Returns:
The loaded image array.
- Return type:
np.ndarray
- Warns:
UserWarning – If metadata is missing or indicates the image was saved from a different accessor type.
Examples
Load a grayscale image from file:
>>> from phenotypic import Image >>> image = Image(arr) >>> # load an object map you saved or hand-graded >>> image.objmap.load("path/to/map.png")
- __array__(dtype=None, copy=None)#
Implements the array interface for numpy compatibility.
This allows numpy functions to operate directly on accessor objects. For example: np.sum(accessor), np.mean(accessor), etc.
- Parameters:
dtype – Optional dtype to cast the array to
copy – Optional copy parameter for NumPy 2.0+ compatibility
- Returns:
The underlying array data
- Return type:
np.ndarray
- __getitem__(key) ndarray[source]#
Return a read-only view of the RGB subregion specified by the given key.
This method supports NumPy-style indexing and slicing to extract subregions from the RGB image array. The returned array is read-only to prevent accidental modifications outside of the __setitem__ interface.
- Parameters:
key – Index or slice specifying the subregion to extract. Supports standard NumPy indexing (e.g., integer indices, slices, boolean masks, advanced indexing). For 3D RGB data, can use notation like [:, :, channel] to select specific channels.
- Returns:
- A read-only NumPy array containing the extracted subregion
with shape matching the selected region.
- Return type:
np.ndarray
- Raises:
EmptyImageError – If the image contains no RGB data and no grayscale fallback is available.
NoArrayError – If the image is 2D (grayscale only) and no RGB array form exists.
Examples
Extract the full RGB array:
>>> full_rgb = image.rgb[:]
Extract a rectangular region:
>>> region = image.rgb[10:50, 20:60, :]
Extract a specific channel:
>>> red_channel = image.rgb[:, :, 0]
- __len__() int#
Returns the length of the subject array.
This method calculates and returns the total number of elements contained in the underlying array.
- Returns:
The number of elements in the underlying array attribute.
- Return type:
- __setitem__(key, value)[source]#
Modify a subregion of the RGB image array.
This method allows in-place modification of the underlying RGB image data using NumPy-style indexing. The provided value must either be a numeric scalar or a NumPy array with shape matching the indexed subregion.
- Parameters:
key – Index or slice specifying the subregion to modify. Supports standard NumPy indexing (e.g., integer indices, slices, boolean masks, advanced indexing).
value (int | float | np.number | np.ndarray) – The new value(s) to assign. Can be a numeric scalar (int, float, or np.number) which will be broadcast to all elements in the indexed region, or a NumPy array with dtype compatible with the image array. If an array, its shape must exactly match the shape of the indexed subregion.
- Raises:
TypeError – If value is a scalar that is not numeric (int, float, or np.number).
TypeError – If value is an array with non-numeric dtype.
TypeError – If value is neither a scalar nor a numpy array.
ArrayKeyValueShapeMismatchError – If value is an array and its shape does not match the shape of the indexed subregion.
Note
To replace the entire RGB image data, use Image.set_image() instead of this method. This method only modifies specific regions of the existing image array.
After modification, the parent image is updated to reflect changes made through this accessor.
Examples
Set a region to a solid color:
>>> image.rgb[10:20, 10:20] = [255, 128, 64]
Set a region from another array:
>>> patch = np.ones((10, 10, 3), dtype=np.uint8) * 128 >>> image.rgb[10:20, 10:20] = patch
Modify a single channel:
>>> image.rgb[:, :, 0] = 255 # Set red channel to maximum
- copy() numpy.ndarray#
- Return type:
- dash(figsize: tuple[int, int] | None = None, title: str | None = None, channel: int | None = None, foreground_only: bool = False, overlay: bool = True, *, object_label: int | None = None, show_labels: bool = False, show_grid: bool = True, label_settings: dict | None = None, overlay_settings: dict | None = None, plotly_settings: dict | None = None) go.Figure#
Display the multichannel image data using Plotly.
- Parameters:
figsize (tuple[int, int] | None) – Figure size in inches (width, height). If None, auto-calculated from array aspect ratio.
title (str | None) – Title of the plot. If None, a default title is generated based on the image and channel.
channel (int | None) – Specific channel index to plot. If None, all channels are displayed as RGB.
foreground_only (bool) – If True, only foreground is displayed.
overlay (bool) – If True, overlay the object map on the image. Falls back to plain image when no objects are detected.
object_label (int | None) – Specific object label to highlight. If None, shows all detected objects. Only used when overlay is True.
show_labels (bool) – If True, displays numeric labels at object centroids. Only used when overlay is True.
show_grid (bool) – For GridImage only. If True, draws gridlines and colored section boxes. Only used when overlay is True. Ignored for regular Image.
label_settings (dict | None) – Dict passed to text label rendering.
overlay_settings (dict | None) – Dict passed to overlay composition.
plotly_settings (dict | None) – Additional Plotly layout settings.
- Returns:
A
plotly.graph_objects.Figure.- Raises:
ImportError – If plotly is not installed.
- Return type:
go.Figure
- foreground()#
Extracts and returns the foreground of the image by masking out the background.
This method generates a foreground image by applying the object mask stored in the Image to the current array representation. Pixels outside the object mask are set to zero in the resulting foreground image. This is useful in image processing tasks to isolate the region of interest in the image, such as microbe colonies on an agar plate.
- Returns:
A numpy array containing only the foreground portion of the image, with all non-foreground pixels set to zero.
- Return type:
- histogram(figsize: Tuple[int, int] = (10, 5), *, cmap='gray', linewidth=1, channel_names: list | None = None) Tuple[TypeAliasForwardRef('matplotlib.figure.Figure'), TypeAliasForwardRef('matplotlib.axes.Axes')]#
Plots the histogram(s) of an image along with the image itself. The behavior depends on the dimensionality of the image array (2D or 3D). In the case of 2D, a single image and its histogram are produced. For 3D (multi-channel images), histograms for each channel are created alongside the image. This method supports customization such as figure size, colormap, line width of histograms, and labeling of channels.
- Parameters:
figsize (Tuple[int, int]) – The size of the figure to create. Default is (10, 5).
cmap (str) – Colormap used to render the image when the data is single channel. Default is ‘gray’.
linewidth (int) – Line width of the plotted histograms. Default is 1.
channel_names (list | None) – Optional names for the channels in 3D data. These are used as titles for channel-specific histograms. If None, channels are instead labeled numerically.
- Returns:
The Matplotlib figure and axes objects representing the plotted image and its histograms.
- Return type:
Tuple[plt.Figure, plt.Axes]
- Raises:
ValueError – If the dimensionality of the input image array is unsupported.
Notes
This method uses skimage.exposure.histogram for computing the histogram data.
- imsave(filepath: str | Path, bit_depth: Literal[8, 16] | None = None) None#
Save the multichannel image array to a file with PhenoTypic metadata embedded.
Metadata is embedded in format-specific locations: - JPEG: EXIF UserComment tag - PNG: tEXt chunk with key ‘phenotypic’ - TIFF: ImageDescription tag (270)
- Parameters:
- Raises:
AttributeError – If bit depth is not 8 or 16.
- Return type:
None
- isempty()#
- napari(name: str | None = None, reset: bool = False, *, viewer: napari.Viewer | None = None, layer_name: str | None = None) napari.Viewer#
Add image to a persistent global napari viewer for Jupyter workflows.
Creates or reuses a single napari viewer instance that persists across multiple method calls. This is particularly useful in Jupyter notebooks where multiple accessors can contribute layers to the same viewer, enabling interactive comparison of different image transformations (e.g., grayscale, RGB, binary masks) on the same data.
The viewer is automatically displayed in Jupyter environments and recreated if it has been closed externally.
- Parameters:
name (str | None) – Optional custom name for the image layer. If provided, the layer will be named
{accessor}_{name}. If not provided, defaults to using the image’s name attribute.reset (bool) – If True, closes the current napari viewer and creates a fresh one. This is useful for starting a new visualization session without lingering layers from previous calls. Defaults to False.
viewer (napari.Viewer | None) – Optional external napari viewer instance to use instead of the global viewer. When provided, global viewer management (creation, reset, smart-grid installation) is bypassed entirely. Defaults to None.
layer_name (str | None) – Optional full layer name to use instead of the auto-generated
{accessor}_{image_name}pattern. Defaults to None.
- Returns:
- The global napari viewer instance with the current
image added as a new layer.
- Return type:
napari.Viewer
- Raises:
ImportError – If napari is not installed. Install with
pip install phenotypic[napari].
Examples
View multiple image transformations in one viewer:
>>> from phenotypic import Image >>> img = Image(arr) >>> # Add grayscale version to viewer >>> viewer = img.gray.napari() >>> # Add RGB version to same viewer >>> viewer = img.rgb.napari() >>> # Add binary segmentation with custom name >>> viewer = img.objmask.napari(name="segmentation_v2")
Using custom names for comparison:
>>> viewer = img.gray.napari(name="raw_grayscale") >>> viewer = img.objmask.napari(name="segmentation_v2")
Resetting the viewer for a fresh session:
>>> viewer = img.gray.napari() >>> viewer = img.rgb.napari() # Same viewer, added layer >>> viewer = img.gray.napari(reset=True) # Fresh viewer, old layers gone
Note
Layers are named using the pattern
{accessor}_{image_name}to ensure descriptive identification. If a layer with the same name already exists, it is replaced with the new image data. This allows for easy updates and comparison of different processing stages.
- normed() ndarray[source]#
Return a copy of the RGB image array normalized between 0 and 1.
- Return type:
- save_overlay(filepath: str | Path, overlay_alpha: float = 0.3, bg_label: int = 0, colors: list | None = None, show_grid: bool = True, gridline_color: tuple[int, int, int] = (0, 255, 255), section_box_colors: list[tuple[int, int, int]] | None = None, **label2rgb_kwargs) None#
Save a full-resolution overlay image blending objmap with the subject array.
Creates an RGB overlay by blending the object map labels with the underlying image data and saves it to disk. Unlike show(overlay=True) which produces a matplotlib figure, this method saves the raw pixel data at full resolution, suitable for pixel-level quality validation of detection results.
For GridImage objects, gridlines and section boxes are automatically drawn when
show_gridis True. The line widths scale dynamically with image size.- Parameters:
filepath (str | Path) – Destination file path. Should have .png or .jpeg extension.
overlay_alpha (float) – Alpha value for label overlay (0.0 = transparent, 1.0 = opaque). Defaults to 0.3.
bg_label (int) – Label value to treat as background. Defaults to 0.
colors (list | None) – List of RGB colors to use for labels. If None, uses default colormap.
show_grid (bool) – Whether to draw gridlines and section boxes on overlay for GridImage objects. Ignored for regular Image objects. Defaults to True.
gridline_color (tuple[int, int, int]) – RGB color tuple for gridlines. Defaults to cyan (0, 255, 255).
section_box_colors (list[tuple[int, int, int]] | None) – List of RGB tuples for cycling through section box colors. Defaults to tab20 colormap colors.
**label2rgb_kwargs – Additional keyword arguments for label2rgb.
- Raises:
ValueError – If the file extension is not supported.
- Return type:
None
Examples
Save full-resolution overlay:
>>> from phenotypic.data import load_synth_yeast_plate >>> image = load_synth_yeast_plate() >>> image.rgb.save_overlay("overlay_rgb.png", overlay_alpha=0.4)
- show(figsize: tuple[int, int] | None = None, title: str | None = None, channel: int | None = None, foreground_only: bool = False, overlay: bool = True, *, object_label: int | None = None, show_labels: bool = False, show_grid: bool = True, label_settings: dict | None = None, overlay_settings: dict | None = None) tuple[TypeAliasForwardRef('matplotlib.figure.Figure'), TypeAliasForwardRef('matplotlib.axes.Axes')]#
Display the multichannel image data using matplotlib.
- Parameters:
figsize (tuple[int, int] | None) – Figure size in inches (width, height). If None, auto-calculated from array aspect ratio.
title (str | None) – Title of the plot. If None, a default title is generated based on the image and channel.
channel (int | None) – Specific channel index to plot. If None, all channels are displayed as RGB.
foreground_only (bool) – If True, only foreground is displayed.
overlay (bool) – If True, overlay the object map on the image. Falls back to plain image when no objects are detected.
object_label (int | None) – Specific object label to highlight. If None, shows all detected objects. Only used when overlay is True.
show_labels (bool) – If True, displays numeric labels at object centroids. Only used when overlay is True.
show_grid (bool) – For GridImage only. If True, draws gridlines and colored section boxes. Only used when overlay is True. Ignored for regular Image.
label_settings (dict | None) – Dict passed to text label rendering.
overlay_settings (dict | None) – Dict passed to overlay composition.
- Returns:
A
(plt.Figure, plt.Axes)tuple.- Return type:
tuple[TypeAliasForwardRef(‘matplotlib.figure.Figure’), TypeAliasForwardRef(‘matplotlib.axes.Axes’)]
- val_range() pd.Interval#
Return the closed interval [min, max] of the subject array values.
- Returns:
A single closed interval including both endpoints.
- Return type:
pd.Interval
- vmax() int[source]#
Returns the maximum value in the RGB image array. The max value depends on the image bit depth. 8 bit-depth->255 and 16 bit-depth->65536
- Return type:
- vmin() int[source]#
Returns the minimum value in the RGB image array. For RGB arrays, this is 0
- Return type:
- property dtype#
- property ndim: int#
Returns the number of dimensions of the underlying array.
The ndim property provides access to the dimensionality of the array being encapsulated in the object. This value corresponds to the number of axes or dimensions the underlying array possesses. It can be useful for understanding the structure of the contained data.
- Returns:
The number of dimensions of the underlying array.
- Return type:
- property shape: Tuple[int, ...]#
Returns the shape of the current image data.
This method retrieves the dimensions of the array stored in the _main_arr attribute as a tuple, which indicates its size along each axis.
- Returns:
A tuple representing the dimensions of the _main_arr attribute.
- Return type:
Tuple[int, …]
Data Access - Enhanced#
- property Image.detect_mat: DetectMatAccessor#
Returns the image’s detection matrix accessor. Preprocessing steps can be applied to this component to improve detection performance.
The detection matrix is derived from the image’s grayscale (default) or a single RGB channel, controlled by
detect_mode. It can be modified and used to improve detection performance while the original gray data is left intact to preserve image information integrity for measurements.- Returns:
A mutable container that stores a copy of the source channel.
- Return type:
from phenotypic import Image from phenotypic.data import load_colony image = Image(load_colony()) # get the detect_mat data arr = image.detect_mat[:] print(type(arr)) # set the detect_mat data # the shape must match the original image.detect_mat[:] = arr # without the bracket indexing the accessor is returned instead print(image.detect_mat[:])
The detect_mat property provides access to an enhanceable copy of the grayscale image.
This is designed for processing pipelines where enhancement operations should be applied
without modifying the original grayscale data. Changes to detection matrix are tracked
separately from the base image.
DetectMatAccessor API:
- class phenotypic._core._image_parts.accessors._detect_mat_accessor.DetectMatAccessor(root_image: Image)[source]#
Bases:
SingleChannelAccessorProvides the detection matrix channel accessor for image data.
The DetectMatAccessor class represents an accessor for managing and manipulating the detection matrix for an entire image or specific regions. This class extends SingleChannelAccessor to include special behaviors and restrictions when working with a normalized representation of microbial colony images on solid media agar. Detection matrix values are typically normalized to range between 0.0 and 1.0.
The detection matrix source channel is controlled by the image’s
detect_modesetting ('gray','red','green', or'blue').This accessor facilitates retrieving and modifying detection matrix values for both visualization and computational purposes while enforcing integrity checks to avoid data inconsistency.
- Parameters:
root_image (Image)
- classmethod load(filepath: str | Path) numpy.ndarray#
Load an image array from file and verify it was saved from this accessor type.
Checks if the image contains PhenoTypic metadata indicating it was saved from the same accessor type (e.g., Image.gray, Image.rgb). If metadata doesn’t match or is missing, a warning is raised but the array is still loaded.
- Parameters:
- Returns:
The loaded image array.
- Return type:
np.ndarray
- Warns:
UserWarning – If metadata is missing or indicates the image was saved from a different accessor type.
Examples
Load a grayscale image from file:
>>> from phenotypic import Image >>> image = Image(arr) >>> # load an object map you saved or hand-graded >>> image.objmap.load("path/to/map.png")
- __array__(dtype=None, copy=None)#
Implements the array interface for numpy compatibility.
This allows numpy functions to operate directly on accessor objects. For example: np.sum(accessor), np.mean(accessor), etc.
- Parameters:
dtype – Optional dtype to cast the array to
copy – Optional copy parameter for NumPy 2.0+ compatibility
- Returns:
The underlying array data
- Return type:
np.ndarray
- __getitem__(key) numpy.ndarray[source]#
Return a non-writeable view of the detection matrix data for the given index.
Retrieves a portion of the detection matrix array using standard NumPy indexing. The returned view is read-only to prevent unintended modifications outside of the proper __setitem__ interface.
- Parameters:
key – Array indexing expression (integer, slice, tuple of indices, or boolean mask). Follows standard NumPy indexing conventions.
- Returns:
- A non-writeable view of the detection matrix data at the specified
index. The returned array shares memory with the underlying data but cannot be modified.
- Return type:
np.ndarray
- Raises:
EmptyImageError – If the image has no data loaded (empty shape).
Examples
Retrieve a single pixel value:
>>> pixel_value = detect_mat[100, 200]
Retrieve a rectangular region:
>>> region = detect_mat[100:200, 50:150]
- __len__() int#
Returns the length of the subject array.
This method calculates and returns the total number of elements contained in the underlying array.
- Returns:
The number of elements in the underlying array attribute.
- Return type:
- __setitem__(key, value)[source]#
Set detection matrix data at the specified index with validation.
Sets data in the detection matrix array at the specified location. The method validates that the input is either a scalar numeric value (int or float) or a NumPy array with a shape matching the indexed region. After successful assignment, the parent image’s object map is reset to maintain consistency with the modified detection matrix data.
- Parameters:
key – Array indexing expression (integer, slice, tuple of indices, or boolean mask). Follows standard NumPy indexing conventions and must be compatible with the detection matrix array structure.
value (int | float | np.ndarray) – The value(s) to assign. Can be: - A scalar (int or float) that will be broadcast to all indexed elements - A NumPy array whose shape must exactly match the indexed region’s shape
- Raises:
ArrayKeyValueShapeMismatchError – If value is a NumPy array and its shape does not match the shape of the indexed region.
TypeError – If value is neither a scalar (int or float) nor a NumPy array.
Examples
Set a single pixel to a scalar value:
>>> detect_mat[100, 200] = 128
Set a rectangular region with an array:
>>> region_data = np.ones((100, 100), dtype=np.uint8) * 150 >>> detect_mat[100:200, 50:150] = region_data
Broadcast a scalar to a region:
>>> detect_mat[0:50, 0:50] = 255 # Set all pixels in region to 255
- copy() numpy.ndarray#
- Return type:
- dash(figsize: tuple[int, int] | None = None, title: str | None = None, cmap: str | None = 'gray', foreground_only: bool = False, overlay: bool = True, *, object_label: int | None = None, show_labels: bool = False, show_grid: bool = True, label_settings: dict | None = None, overlay_settings: dict | None = None, plotly_settings: dict | None = None) go.Figure#
Display the single-channel image data using Plotly.
- Parameters:
figsize (tuple[int, int] | None) – Figure size in inches (width, height). If None, auto-calculated from array aspect ratio.
title (str | None) – Title of the plot. If None, no title is displayed.
cmap (str | None) – Colormap name. Defaults to
"gray".foreground_only (bool) – If True, display only foreground elements.
overlay (bool) – If True, overlay the object map on the image. Falls back to plain image when no objects are detected.
object_label (int | None) – Specific object label to highlight. If None, shows all detected objects. Only used when overlay is True.
show_labels (bool) – If True, displays numeric labels at object centroids. Only used when overlay is True.
show_grid (bool) – For GridImage only. If True, draws gridlines and colored section boxes. Only used when overlay is True. Ignored for regular Image.
label_settings (dict | None) – Dict passed to text label rendering.
overlay_settings (dict | None) – Dict passed to overlay composition.
plotly_settings (dict | None) – Additional Plotly layout settings.
- Returns:
A
plotly.graph_objects.Figure.- Raises:
ImportError – If plotly is not installed.
- Return type:
go.Figure
- foreground()#
Extracts and returns the foreground of the image by masking out the background.
This method generates a foreground image by applying the object mask stored in the Image to the current array representation. Pixels outside the object mask are set to zero in the resulting foreground image. This is useful in image processing tasks to isolate the region of interest in the image, such as microbe colonies on an agar plate.
- Returns:
A numpy array containing only the foreground portion of the image, with all non-foreground pixels set to zero.
- Return type:
- histogram(figsize: Tuple[int, int] = (10, 5), *, cmap='gray', linewidth=1, channel_names: list | None = None) Tuple[TypeAliasForwardRef('matplotlib.figure.Figure'), TypeAliasForwardRef('matplotlib.axes.Axes')]#
Plots the histogram(s) of an image along with the image itself. The behavior depends on the dimensionality of the image array (2D or 3D). In the case of 2D, a single image and its histogram are produced. For 3D (multi-channel images), histograms for each channel are created alongside the image. This method supports customization such as figure size, colormap, line width of histograms, and labeling of channels.
- Parameters:
figsize (Tuple[int, int]) – The size of the figure to create. Default is (10, 5).
cmap (str) – Colormap used to render the image when the data is single channel. Default is ‘gray’.
linewidth (int) – Line width of the plotted histograms. Default is 1.
channel_names (list | None) – Optional names for the channels in 3D data. These are used as titles for channel-specific histograms. If None, channels are instead labeled numerically.
- Returns:
The Matplotlib figure and axes objects representing the plotted image and its histograms.
- Return type:
Tuple[plt.Figure, plt.Axes]
- Raises:
ValueError – If the dimensionality of the input image array is unsupported.
Notes
This method uses skimage.exposure.histogram for computing the histogram data.
- imsave(filepath: str | Path | None = None, bit_depth: Literal[8, 16] | None = None) None#
Saves an array representing a microbe colony image to a specified file format while preserving or adjusting metadata and pixel depth as needed. Supports JPEG, PNG, and TIFF formats.
The behavior of the function is context-sensitive based on the file format’s restrictions and array properties. Proper file format selection and bit depth adjustment can have an impact on the accuracy of image analysis and preservation of data integrity.
- Parameters:
filepath (str | Path | None) –
The destination file path where the image will be saved. The extension of the file path determines the image format (e.g., .jpeg, .png, .tiff). Changing the file format influences how the image data is handled during saving:
.jpeg: Compression or loss of data may occur. Maximal value limit (255) for uint8 pixel depth affects the fidelity of rich intensity details in microbe colonies.
.png: Retains high-quality output but supports only 8-bit or 16-bit images. Conversions may occur if the array has a different data type, which could result in data loss.
.tiff: Ideal for high-bit-depth precision and analysis preservation; best for maintaining intricate morphological details of microbial colonies.
bit_depth (Literal[8, 16] | None, optional) –
Specifies the bit depth of the saved image (either 8-bit or 16-bit). The provided bit depth must align with the file format’s capabilities. Misalignment could trigger conversion with possible data truncation or rounding. For example:
8-bit: Useful for efficiently representing intensity when detail is moderate, suitable for JPEG or simple PNG outputs.
16-bit: Allows for higher intensity ranges, especially valuable for preserving subtle morphological gradient differentiation when analyzing colonies.
- Raises:
ValueError – An error occurs when an unsupported file extension is provided in filepath.
- Warns:
UserWarnings – Warnings are issued under the following conditions:
Saving a 16-bit or floating-point array as JPEG, as these conversions may cause information loss due to format restrictions.
Saving a floating-point array as PNG when conversions to 8-bit or 16-bit integers might lead to truncated or altered pixel intensity values.
- Return type:
None
- isempty()#
- napari(name: str | None = None, reset: bool = False, *, viewer: napari.Viewer | None = None, layer_name: str | None = None) napari.Viewer#
Add image to a persistent global napari viewer for Jupyter workflows.
Creates or reuses a single napari viewer instance that persists across multiple method calls. This is particularly useful in Jupyter notebooks where multiple accessors can contribute layers to the same viewer, enabling interactive comparison of different image transformations (e.g., grayscale, RGB, binary masks) on the same data.
The viewer is automatically displayed in Jupyter environments and recreated if it has been closed externally.
- Parameters:
name (str | None) – Optional custom name for the image layer. If provided, the layer will be named
{accessor}_{name}. If not provided, defaults to using the image’s name attribute.reset (bool) – If True, closes the current napari viewer and creates a fresh one. This is useful for starting a new visualization session without lingering layers from previous calls. Defaults to False.
viewer (napari.Viewer | None) – Optional external napari viewer instance to use instead of the global viewer. When provided, global viewer management (creation, reset, smart-grid installation) is bypassed entirely. Defaults to None.
layer_name (str | None) – Optional full layer name to use instead of the auto-generated
{accessor}_{image_name}pattern. Defaults to None.
- Returns:
- The global napari viewer instance with the current
image added as a new layer.
- Return type:
napari.Viewer
- Raises:
ImportError – If napari is not installed. Install with
pip install phenotypic[napari].
Examples
View multiple image transformations in one viewer:
>>> from phenotypic import Image >>> img = Image(arr) >>> # Add grayscale version to viewer >>> viewer = img.gray.napari() >>> # Add RGB version to same viewer >>> viewer = img.rgb.napari() >>> # Add binary segmentation with custom name >>> viewer = img.objmask.napari(name="segmentation_v2")
Using custom names for comparison:
>>> viewer = img.gray.napari(name="raw_grayscale") >>> viewer = img.objmask.napari(name="segmentation_v2")
Resetting the viewer for a fresh session:
>>> viewer = img.gray.napari() >>> viewer = img.rgb.napari() # Same viewer, added layer >>> viewer = img.gray.napari(reset=True) # Fresh viewer, old layers gone
Note
Layers are named using the pattern
{accessor}_{image_name}to ensure descriptive identification. If a layer with the same name already exists, it is replaced with the new image data. This allows for easy updates and comparison of different processing stages.
- preview_modes(reset: bool = False) napari.Viewer[source]#
Open a napari viewer with all registered detection mode matrices.
Computes every registered detection mode and adds each as a separate image layer in a dedicated napari viewer. The current (possibly enhanced) detection matrix is also included. Toggle layer visibility in napari’s layer list to compare modes.
This viewer is independent of the main
image.gray.napari()viewer.- Parameters:
reset (bool) – If True, closes the existing preview viewer and creates a fresh one. Defaults to False.
- Returns:
- A viewer with one layer per detection mode plus
the current detection matrix.
- Return type:
napari.Viewer
Examples
Compare all detection modes interactively:
>>> from phenotypic.data import load_synth_yeast_plate >>> image = load_synth_yeast_plate() >>> viewer = image.detect_mat.preview_modes()
Reset and re-preview after applying enhancers:
>>> viewer = image.detect_mat.preview_modes(reset=True)
- reset()[source]#
Reset the detection matrix to a fresh copy of the current mode’s source channel.
Discards all modifications made to the detection matrix and restores it from the source determined by the image’s
detect_modesetting.Examples
Reset after applying unsuccessful enhancement:
>>> detect_mat.reset() # Revert to source channel
- save_overlay(filepath: str | Path, overlay_alpha: float = 0.3, bg_label: int = 0, colors: list | None = None, show_grid: bool = True, gridline_color: tuple[int, int, int] = (0, 255, 255), section_box_colors: list[tuple[int, int, int]] | None = None, **label2rgb_kwargs) None#
Save a full-resolution overlay image blending objmap with the subject array.
Creates an RGB overlay by blending the object map labels with the underlying image data and saves it to disk. Unlike show(overlay=True) which produces a matplotlib figure, this method saves the raw pixel data at full resolution, suitable for pixel-level quality validation of detection results.
For GridImage objects, gridlines and section boxes are automatically drawn when
show_gridis True. The line widths scale dynamically with image size.- Parameters:
filepath (str | Path) – Destination file path. Should have .png or .jpeg extension.
overlay_alpha (float) – Alpha value for label overlay (0.0 = transparent, 1.0 = opaque). Defaults to 0.3.
bg_label (int) – Label value to treat as background. Defaults to 0.
colors (list | None) – List of RGB colors to use for labels. If None, uses default colormap.
show_grid (bool) – Whether to draw gridlines and section boxes on overlay for GridImage objects. Ignored for regular Image objects. Defaults to True.
gridline_color (tuple[int, int, int]) – RGB color tuple for gridlines. Defaults to cyan (0, 255, 255).
section_box_colors (list[tuple[int, int, int]] | None) – List of RGB tuples for cycling through section box colors. Defaults to tab20 colormap colors.
**label2rgb_kwargs – Additional keyword arguments for label2rgb.
- Raises:
ValueError – If the file extension is not supported.
- Return type:
None
Examples
Save full-resolution overlay:
>>> from phenotypic.data import load_synth_yeast_plate >>> image = load_synth_yeast_plate() >>> image.rgb.save_overlay("overlay_rgb.png", overlay_alpha=0.4)
- show(figsize: tuple[int, int] | None = None, title: str | None = None, cmap: str | None = 'gray', foreground_only: bool = False, overlay: bool = True, *, object_label: int | None = None, show_labels: bool = False, show_grid: bool = True, label_settings: dict | None = None, overlay_settings: dict | None = None) tuple[TypeAliasForwardRef('matplotlib.figure.Figure'), TypeAliasForwardRef('matplotlib.axes.Axes')]#
Display the single-channel image data using matplotlib.
- Parameters:
figsize (tuple[int, int] | None) – Figure size in inches (width, height). If None, auto-calculated from array aspect ratio.
title (str | None) – Title of the plot. If None, no title is displayed.
cmap (str | None) – Colormap name. Defaults to
"gray".foreground_only (bool) – If True, display only foreground elements.
overlay (bool) – If True, overlay the object map on the image. Falls back to plain image when no objects are detected.
object_label (int | None) – Specific object label to highlight. If None, shows all detected objects. Only used when overlay is True.
show_labels (bool) – If True, displays numeric labels at object centroids. Only used when overlay is True.
show_grid (bool) – For GridImage only. If True, draws gridlines and colored section boxes. Only used when overlay is True. Ignored for regular Image.
label_settings (dict | None) – Dict passed to text label rendering.
overlay_settings (dict | None) – Dict passed to overlay composition.
- Returns:
A
(plt.Figure, plt.Axes)tuple.- Return type:
tuple[TypeAliasForwardRef(‘matplotlib.figure.Figure’), TypeAliasForwardRef(‘matplotlib.axes.Axes’)]
- val_range() pd.Interval#
Return the closed interval [min, max] of the subject array values.
- Returns:
A single closed interval including both endpoints.
- Return type:
pd.Interval
- vmax() float[source]#
Returns the maximum value in the detection matrix. Since it is normalized to [0.0, 1.0], it returns 1.0.
- Return type:
- vmin() float[source]#
Returns the minimum value in the detection matrix. Since it is normalized to [0.0, 1.0], it returns 0.0.
- Return type:
- property dtype#
- property ndim: int#
Returns the number of dimensions of the underlying array.
The ndim property provides access to the dimensionality of the array being encapsulated in the object. This value corresponds to the number of axes or dimensions the underlying array possesses. It can be useful for understanding the structure of the contained data.
- Returns:
The number of dimensions of the underlying array.
- Return type:
- property shape: Tuple[int, ...]#
Returns the shape of the current image data.
This method retrieves the dimensions of the array stored in the _main_arr attribute as a tuple, which indicates its size along each axis.
- Returns:
A tuple representing the dimensions of the _main_arr attribute.
- Return type:
Tuple[int, …]
Data Access - Objects (Detection Results)#
- property Image.objects: ObjectsAccessor#
Accessor for performing operations on detected objects in the image.
Provides access to individual or grouped objects detected in the image, enabling measurement calculations, filtering, and object-specific analyses. Objects are identified through the object map (objmap) component which stores integer labels for each detected object.
- Returns:
- An accessor instance that manages object-specific operations
and measurements.
- Return type:
- Raises:
NoObjectsError – If no objects are present in the image. This occurs when num_objects == 0, indicating that either no object detection has been performed yet, or the detection found no objects. Apply an ObjectDetector first to identify and label objects.
Examples
Measure object properties:
>>> img = Image.imread('sample.jpg') >>> detector = ObjectDetector() >>> detector.detect(img) >>> obj_accessor = img.objects >>> measurements = img.objects.measure.area()
The objects property provides a high-level interface to detected objects, including
object properties, statistics, and analysis capabilities. This requires that object
detection has been performed on the image (e.g., via an ObjectDetector).
ObjectsAccessor API:
- class phenotypic._core._image_parts.accessors._objects_accessor.ObjectsAccessor(root_image: Image)[source]#
Bases:
objectProvide access to detected microbial colonies and their properties in agar plate images.
This accessor enables researchers to analyze individual colonies in arrayed microbial cultures after colony detection has been performed. It provides methods for accessing colony labels, retrieving colony properties (area, intensity, position), extracting individual colony crops, and organizing colony data for high-throughput phenotypic screening workflows.
The accessor operates on labeled object maps where each pixel value indicates which colony it belongs to (0 for background, 1+ for individual colonies). Properties are computed using scikit-image’s regionprops functionality, providing standardized morphological and intensity measurements for each colony.
Note
This accessor can only be used after an ObjectDetector has been applied to the Image to identify and label individual colonies. Attempting to access before detection raises NoObjectsError.
- Parameters:
root_image (Image)
- _root_image#
The parent Image containing the labeled colony map (objmap).
- Type:
Image
Examples
Access detected colonies and measure their properties:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> # Load plate image and detect colonies >>> plate = Image.from_file("colony_array.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # Access colony properties >>> print(f"Detected {len(plate.objects)} colonies") >>> # Iterate over all colonies >>> for colony in plate.objects: ... print(f"Colony area: {colony.gray.sum()}") >>> # Get information for all colonies >>> colony_info = plate.objects.info() >>> print(colony_info[["Object_Label", "Bbox_CenterRR", "Bbox_CenterCC"]])
- __getitem__(index: int) Image[source]#
Extract a specific colony by its position index.
This enables bracket notation (e.g., plate.objects[0]) to access individual colonies by their sequential position. The returned Image is cropped to the colony’s bounding box and contains only that colony in its object map.
This is useful when you need to access a specific colony by position, such as the first or last detected colony, or when iterating with enumerate() to track both index and colony.
- Parameters:
index (int) – Zero-based position index of the desired colony. Must be in the range [0, len(objects)-1]. Negative indexing is not supported.
- Returns:
- A cropped Image containing only the specified colony. The Image is cropped to
the colony’s bounding box, has metadata updated to ImageType=’Object’, and has an objmap where pixels belonging to the colony retain their label value while all other pixels are set to 0.
- Return type:
Image
- Raises:
IndexError – If index is negative or >= the total number of colonies.
Examples
Extract the first detected colony:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("colony_plate.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # Get first colony >>> first_colony = plate.objects[0] >>> print(f"First colony label: {first_colony.objmap.max()}") >>> print(f"Colony size: {(first_colony.objmap > 0).sum()} pixels")
Access specific colonies for comparison:
>>> # Compare first and last colonies >>> first = plate.objects[0] >>> last = plate.objects[len(plate.objects) - 1] >>> print(f"First colony mean intensity: {first.gray.mean()}") >>> print(f"Last colony mean intensity: {last.gray.mean()}")
Use with enumerate for indexed processing:
>>> for idx, colony in enumerate(plate.objects): ... if idx % 10 == 0: ... # Process every 10th colony ... colony.show()
- __init__(root_image: Image)[source]#
Initialize the ObjectsAccessor with a parent Image.
This method is called automatically when accessing the objects property of an Image. Users should not instantiate this class directly; instead, access it through the Image.objects property after applying an ObjectDetector.
- Parameters:
root_image (Image) – The parent Image containing detected colonies. Must have an objmap (object map) populated by an ObjectDetector that has been applied to identify and label individual colonies.
Examples
Accessor is created automatically when accessing colonies:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("plate.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # ObjectsAccessor is automatically initialized >>> accessor = plate.objects # Uses __init__ internally >>> print(f"Found {len(accessor)} colonies")
- __iter__() Generator[Image, Any, None][source]#
Iterate over all detected colonies, yielding each as a cropped Image.
This enables using the accessor in for loops and comprehensions to process each colony individually. Each yielded Image is cropped to the colony’s bounding box and contains only that colony’s pixels in its object map (all other pixels set to 0).
This is particularly useful for batch processing colonies, computing per-colony metrics, or performing quality control by visually inspecting individual colonies.
- Yields:
Image –
- A cropped Image for each colony, in order by position index (0 to N-1).
Each cropped Image has its metadata updated with ImageType=’Object’ and contains only the pixels within that colony’s bounding box. The objmap of each yielded Image contains only the current colony’s label, with all other pixels set to 0.
- Return type:
Generator[Image, Any, None]
Examples
Compute average intensity for each colony:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("fluorescent_colonies.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # Calculate mean fluorescence for each colony >>> intensities = [] >>> for colony in plate.objects: ... mean_intensity = colony.gray.mean() ... intensities.append(mean_intensity) >>> print(f"Average colony intensity: {sum(intensities) / len(intensities)}")
Filter colonies by size:
>>> # Get all colonies larger than 500 pixels >>> large_colonies = [ ... colony for colony in plate.objects ... if (colony.objmap > 0).sum() > 500 ... ] >>> print(f"Found {len(large_colonies)} large colonies")
Extract colony names for tracking:
>>> colony_names = [ ... obj.metadata[METADATA.IMAGE_NAME] ... for obj in plate.objects ... ]
- __len__() int[source]#
Return the number of detected colonies in the plate image.
This enables using Python’s built-in len() function to quickly check how many colonies were detected by the object detector. Useful for quality control and validating that colony detection worked as expected.
- Returns:
- The total number of labeled colonies in the object map. Returns 0 if no
colonies have been detected.
- Return type:
Examples
Check colony count after detection:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("96well_array.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # Check if expected number of colonies detected >>> colony_count = len(plate.objects) >>> expected_count = 96 >>> if colony_count != expected_count: ... print(f"Warning: Expected {expected_count} colonies, found {colony_count}")
Use in conditional logic:
>>> if len(plate.objects) == 0: ... raise RuntimeError("No colonies detected. Check detector parameters.")
- get_label_idx(object_label: int) int[source]#
Convert a colony label to its position index in the labels list.
This method maps from label identifiers (which may have gaps or start from values other than 0) to position indices (which are always contiguous from 0 to N-1). This is useful when you know a colony’s label but need its position for indexing into lists or arrays organized by position.
- Parameters:
object_label (int) – The label identifier to look up. This is the value stored in the objmap for pixels belonging to the desired colony, typically a positive integer starting from 1.
- Returns:
- The zero-based position index where this label appears in the labels list.
This index can be used with methods like iloc(), slices[], or props[].
- Return type:
- Raises:
IndexError – If object_label is not present in the current labels list. This occurs when the label doesn’t exist, was filtered out, or does not match any detected colony.
Examples
Map label to index for accessing properties:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("colony_array.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # Find the position index for colony label 5 >>> idx = plate.objects.get_label_idx(5) >>> print(f"Colony with label 5 is at position {idx}") >>> # Use the index to access properties >>> colony_slice = plate.objects.slices[idx] >>> colony_props = plate.objects.props[idx] >>> print(f"Colony 5 area: {colony_props.area}")
Use with non-contiguous labels:
>>> # After filtering, labels may not be contiguous >>> labels = plate.objects.labels # e.g., [1, 2, 5, 8, 10] >>> # Get position index for label 8 (which is at position 3) >>> idx = plate.objects.get_label_idx(8) # Returns 3 >>> colony_8 = plate.objects.iloc(idx)
Verify label exists before accessing:
>>> desired_label = 42 >>> if desired_label in plate.objects.labels: ... idx = plate.objects.get_label_idx(desired_label) ... print(f"Found colony {desired_label} at index {idx}") ... else: ... print(f"Colony {desired_label} not found")
- iloc(index: int) Image[source]#
Access a colony by position index using pandas-style iloc syntax.
This method provides a pandas-like interface for accessing colonies by their position index. Unlike __getitem__ (which also uses position), iloc() returns a crop that preserves all labels in the objmap, while __getitem__ zeros out non-matching labels for isolation.
Use iloc() when you need the minimal bounding box crop but want to preserve the original label structure and neighboring colonies within the bounding box, which can be useful for context-aware analysis workflows.
- Parameters:
index (int) – Zero-based position index of the colony to extract. Must be in the range [0, num_objects-1].
- Returns:
- A cropped Image containing the bounding box region of the specified colony.
Unlike __getitem__, this crop preserves all label values in the objmap without zeroing non-matching pixels. The metadata is inherited from the parent Image, and ImageType is not changed to ‘Object’.
- Return type:
Image
- Raises:
IndexError – If index is negative or >= num_objects.
Examples
Access first colony with pandas-style syntax:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("colony_array.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # Access first colony >>> first = plate.objects.iloc(0) >>> print(f"Bounding box shape: {first.shape}")
Compare iloc() vs __getitem__:
>>> # iloc preserves all labels in the crop >>> crop_iloc = plate.objects.iloc(5) >>> print(f"All labels in crop (iloc): {set(crop_iloc.objmap.flatten())}") >>> # May show {0, 5} if other colonies are nearby >>> # __getitem__ zeros out non-matching labels for isolation >>> crop_getitem = plate.objects[5] >>> print(f"Labels in isolated crop ([5]): {crop_getitem.objmap.max()}") >>> # Shows only label 5 (others zeroed)
Extract multiple specific colonies:
>>> # Get colonies at positions 0, 5, and 10 with preserved context >>> selected_indices = [0, 5, 10] >>> selected_colonies = [plate.objects.iloc(i) for i in selected_indices]
- info(include_metadata: bool = True) pandas.DataFrame[source]#
Generate a summary table of colony positions and bounding boxes.
This method creates a pandas DataFrame containing key positional information for all detected colonies, including their labels, centroid coordinates, and bounding box coordinates. This is particularly useful for organizing colony data for downstream analysis, quality control, or exporting to other tools.
The table includes one row per colony with columns for the colony label, centroid position (row and column), and bounding box coordinates (min/max row and column). Optionally, image metadata can be prepended to provide experimental context.
- Parameters:
include_metadata (bool, optional) – If True, prepend image metadata columns (such as ImageName, UUID, ImageType) to the DataFrame using the Image’s metadata.insert_metadata() method. This adds experimental context to the colony information. Defaults to True.
- Returns:
- A DataFrame with one row per colony containing:
Object_Label: The colony’s label identifier
Bbox_CenterRR: Row coordinate of the colony centroid
Bbox_CenterCC: Column coordinate of the colony centroid
Bbox_MinRR: Minimum row coordinate of the bounding box
Bbox_MinCC: Minimum column coordinate of the bounding box
Bbox_MaxRR: Maximum row coordinate of the bounding box
Bbox_MaxCC: Maximum column coordinate of the bounding box
If include_metadata=True, additional metadata columns are prepended.
- Return type:
pd.DataFrame
Examples
Get basic colony information:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("colony_array.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # Get colony information >>> colony_info = plate.objects.info() >>> print(colony_info.head()) >>> print(f"Columns: {colony_info.columns.tolist()}")
Access specific columns:
>>> # Get just labels and centroids >>> labels_centroids = colony_info[["Object_Label", "Bbox_CenterRR", "Bbox_CenterCC"]] >>> print(labels_centroids)
Export colony positions for other tools:
>>> # Get info without metadata for cleaner export >>> colony_positions = plate.objects.info(include_metadata=False) >>> colony_positions.to_csv("colony_positions.csv", index=False)
Filter colonies by position:
>>> info = plate.objects.info(include_metadata=False) >>> # Find colonies in the upper half of the image >>> upper_colonies = info[info["Bbox_CenterRR"] < 500] >>> print(f"Found {len(upper_colonies)} colonies in upper half")
Calculate bounding box dimensions:
>>> info = plate.objects.info(include_metadata=False) >>> # Calculate width and height of each colony's bounding box >>> info["BBox_Width"] = info["Bbox_MaxCC"] - info["Bbox_MinCC"] >>> info["BBox_Height"] = info["Bbox_MaxRR"] - info["Bbox_MinRR"] >>> print(f"Average colony width: {info['BBox_Width'].mean():.1f} pixels") >>> print(f"Average colony height: {info['BBox_Height'].mean():.1f} pixels")
- labels2series() pandas.Series[source]#
Convert colony labels to a pandas Series for joining with measurement DataFrames.
This method creates a pandas Series containing all colony labels with a properly named column (‘Object_Label’) and indexed by position. This is specifically designed to facilitate joining labels with measurement DataFrames that are indexed by position, which is a common pattern in high-throughput phenotypic analysis workflows.
The returned Series can be easily joined or merged with other pandas DataFrames containing per-colony measurements to add label information.
- Returns:
- A pandas Series with:
data: The colony labels (integers)
index: Position indices (0 to N-1)
name: ‘Object_Label’ for proper DataFrame column naming
- Return type:
pd.Series
Examples
Join labels with measurement data:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> from phenotypic.measure import AreaMeasurer >>> import pandas as pd >>> plate = Image.from_file("colony_array.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # Calculate measurements (indexed by position) >>> measurer = AreaMeasurer() >>> measurements = measurer.measure(plate) >>> # Add labels to measurements >>> labels = plate.objects.labels2series() >>> measurements_with_labels = measurements.join(labels) >>> print(measurements_with_labels.head())
Merge with custom analysis results:
>>> import numpy as np >>> import pandas as pd >>> # Custom analysis results indexed by position >>> custom_analysis = pd.DataFrame({ ... 'mean_intensity': [125.3, 142.7, 98.1], ... 'max_intensity': [255, 243, 189] ... }, index=range(len(plate.objects))) >>> # Add colony labels >>> labels_series = plate.objects.labels2series() >>> analysis_with_labels = custom_analysis.join(labels_series) >>> # Now can group or filter by label >>> print(analysis_with_labels)
Use as a lookup table:
>>> labels_series = plate.objects.labels2series() >>> # Get label for position 5 >>> label_at_pos_5 = labels_series.iloc[5] >>> print(f"Colony at position 5 has label {label_at_pos_5}")
Handle potential label suffix conflicts:
>>> # If DataFrame already has an 'Object_Label' column >>> labels = plate.objects.labels2series() >>> measurements_with_labels = measurements.join(labels, rsuffix="_new") >>> # Creates 'Object_Label' and 'Object_Label_new' columns
- loc(label_number: int) Image[source]#
Access a colony by its label identifier using pandas-style loc syntax.
This method provides a pandas-like interface for accessing colonies by their label value (rather than position index). This is useful when you know the specific label ID of a colony from the objmap and want to extract just that colony’s bounding box region.
Unlike iloc() which uses position, loc() uses the actual label value assigned in the object map. This is particularly helpful when labels are non-contiguous or when working with specific colonies identified by their label in previous analysis steps.
- Parameters:
label_number (int) – The label identifier assigned to the colony in the objmap. This is typically a positive integer (1, 2, 3, …) but may have gaps if colonies were filtered or removed.
- Returns:
- A cropped Image containing the bounding box region of the colony with the
specified label. The crop preserves all label values in the objmap without zeroing non-matching pixels.
- Return type:
Image
- Raises:
IndexError – If label_number does not exist in the current labels list.
Examples
Access colony by its label:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("colony_array.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # Access colony with label 5 >>> colony_5 = plate.objects.loc(5) >>> print(f"Colony 5 bounding box: {colony_5.shape}")
Access first colony by its label (not position):
>>> # Get the label of the first colony >>> first_label = plate.objects.labels[0] # e.g., could be 1 >>> # Access by that label >>> first_colony = plate.objects.loc(first_label)
Use with non-contiguous labels:
>>> # Labels might be: [1, 2, 5, 8, 10] after filtering >>> labels = plate.objects.labels >>> # Access colony with label 8 (not position 8) >>> colony_8 = plate.objects.loc(8) >>> # Compare with position-based access >>> colony_at_pos_3 = plate.objects.iloc(3) # Also gets label 8
Safe access with label validation:
>>> desired_label = 42 >>> if desired_label in plate.objects.labels: ... colony = plate.objects.loc(desired_label) ... print(f"Found colony {desired_label}") ... else: ... print(f"Colony {desired_label} not found")
- relabel() None[source]#
Renumber colony labels to be sequential and contiguous.
This method relabels all colonies in the object map so that labels are sequential integers starting from 1 (i.e., 1, 2, 3, …, N for N colonies). This is useful after filtering or removing colonies, which can leave gaps in the label sequence, or when you need consistent, predictable label numbering for downstream analysis.
The relabeling preserves the spatial relationships between colonies but assigns new labels in a consistent order. Connected components (colonies) are assigned sequential IDs based on their position in the label image.
- Returns:
- This method modifies the parent Image’s objmap in-place. Labels are
renumbered directly in the object map, and no value is returned.
- Return type:
None
Examples
Relabel after filtering to remove gaps:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("colony_array.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # Before relabeling (may have gaps) >>> print(f"Labels before: {plate.objects.labels}") >>> # e.g., [1, 2, 5, 7, 10, 15] >>> # Relabel to make sequential >>> plate.objects.relabel() >>> # After relabeling (sequential) >>> print(f"Labels after: {plate.objects.labels}") >>> # e.g., [1, 2, 3, 4, 5, 6]
Ensure consistent labeling for reproducibility:
>>> # After any colony filtering or modification >>> plate.objects.relabel() >>> # Now labels are guaranteed to be 1, 2, 3, ..., N >>> assert plate.objects.labels == list(range(1, len(plate.objects) + 1))
Relabel after manual objmap modifications:
>>> # After custom filtering or editing the objmap >>> import numpy as np >>> # Remove small colonies (custom filtering) >>> for prop in plate.objects.props: ... if prop.area < 100: ... mask = plate.objmap[:] == prop.label ... plate.objmap[:][mask] = 0 >>> # Relabel to clean up the label sequence >>> plate.objects.relabel() >>> print(f"Remaining colonies: {len(plate.objects)}") >>> print(f"New labels: {plate.objects.labels}")
Compare before and after relabeling:
>>> labels_before = plate.objects.labels.copy() >>> plate.objects.relabel() >>> labels_after = plate.objects.labels >>> print(f"Before: {labels_before}") >>> print(f"After: {labels_after}") >>> print(f"Same count: {len(labels_before) == len(labels_after)}")
- reset() None[source]#
Clear all colony labels from the object map.
This method resets the object map to its initial empty state by setting all pixels to 0, effectively removing all colony detections. After calling reset(), the image reverts to having no detected colonies (num_objects = 0) and the entire image becomes the analysis target again.
This is useful when you want to re-run colony detection with different parameters or when you need to clear previous detection results before applying a different detection method.
- Returns:
- This method modifies the parent Image in-place by clearing its objmap. No value
is returned.
- Return type:
None
Examples
Clear detections to re-run with different parameters:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("colony_array.png") >>> # First detection attempt >>> detector1 = RoundPeaksDetector(thresh_method="otsu") >>> detector1.apply(plate) >>> print(f"First attempt: {plate.objects.num_objects} colonies") >>> # Clear and try with different parameters >>> plate.objects.reset() >>> print(f"After reset: {plate.objects.num_objects} colonies") # 0 >>> detector2 = RoundPeaksDetector(thresh_method="mean") >>> detector2.apply(plate) >>> print(f"Second attempt: {plate.objects.num_objects} colonies")
Verify reset clears all colonies:
>>> plate.objects.reset() >>> assert plate.num_objects == 0 >>> assert len(plate.objects.labels) == 0 >>> assert plate.objmap.max() == 0
- property labels: List[int]#
Get the unique label identifiers for all detected colonies.
Each colony in the object map is assigned a unique positive integer label (typically starting from 1). This property returns all such labels, which can be used to select specific colonies with the loc() method or to verify which colonies are present.
Labels are extracted from scikit-image’s regionprops to ensure consistency with all property calculations, rather than using numpy.unique() on the object map directly.
- Returns:
- A list of unique colony labels in ascending order. Returns an empty list
if no colonies have been detected. Background pixels (labeled 0) are excluded.
- Return type:
Examples
Check which colonies are present:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("colony_array.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> labels = plate.objects.labels >>> print(f"Detected colonies with labels: {labels}") >>> print(f"Labels range from {min(labels)} to {max(labels)}")
Check if a specific colony exists:
>>> if 5 in plate.objects.labels: ... colony_5 = plate.objects.loc(5) ... print(f"Colony 5 area: {colony_5.gray.sum()}") ... else: ... print("Colony 5 not found")
Verify contiguous labeling:
>>> labels = plate.objects.labels >>> expected_labels = list(range(1, len(labels) + 1)) >>> if labels == expected_labels: ... print("Labels are contiguous") ... else: ... print("Labels have gaps - consider using relabel()")
- property num_objects: int#
Get the total number of detected colonies.
This property provides the count of unique colony labels in the object map. It is equivalent to len(image.objects) but provides a more explicit property-based interface. The count excludes background pixels (label 0).
- Returns:
- The number of unique colony labels currently tracked in the objmap. Returns 0
if no colonies have been detected.
- Return type:
Examples
Verify expected colony count:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("96well_plate.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # Check if detection found the expected number of colonies >>> expected = 96 >>> actual = plate.objects.num_objects >>> if actual != expected: ... print(f"Warning: Expected {expected} colonies, found {actual}")
Verify consistency with len():
>>> assert plate.objects.num_objects == len(plate.objects)
- property props: list#
Compute region properties for all detected colonies using scikit-image.
This property provides access to scikit-image’s RegionProperties objects, which contain detailed morphological and intensity measurements for each colony. Each RegionProperties object provides lazy-evaluated properties like area, perimeter, centroid, bounding box coordinates, mean intensity, and many morphological descriptors.
The properties are computed dynamically each time this property is accessed (cache=False), ensuring measurements always reflect the current state of the object map and grayscale intensity image.
- Returns:
- A list of RegionProperties objects, one per
detected colony, sorted by label. Each object provides lazy access to properties:
area: Number of pixels in the colony
centroid: (row, col) coordinates of the colony center
bbox: Bounding box as (min_row, min_col, max_row, max_col)
mean_intensity: Mean pixel intensity within the colony region
perimeter, eccentricity, solidity, major_axis_length, minor_axis_length, moments, moments_central, moments_hu, and many more standard morphological measurements from scikit-image.measure.regionprops
Refer to scikit-image documentation for the complete list of available properties.
- Return type:
list[skimage.measure.RegionProperties]
Examples
Extract colony areas:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("colony_array.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # Get areas of all colonies >>> areas = [prop.area for prop in plate.objects.props] >>> print(f"Colony sizes: {areas}") >>> print(f"Mean colony size: {sum(areas) / len(areas):.1f} pixels")
Access multiple properties per colony:
>>> for prop in plate.objects.props: ... print(f"Colony {prop.label}:") ... print(f" Area: {prop.area} pixels") ... print(f" Centroid: ({prop.centroid[0]:.1f}, {prop.centroid[1]:.1f})") ... print(f" Mean intensity: {prop.mean_intensity:.2f}") ... print(f" Eccentricity: {prop.eccentricity:.3f}")
Filter colonies by morphology:
>>> # Find circular colonies (low eccentricity) >>> circular_colonies = [ ... prop for prop in plate.objects.props ... if prop.eccentricity < 0.5 ... ] >>> print(f"Found {len(circular_colonies)} circular colonies")
- property slices: list#
Get bounding box slices for efficiently cropping to each colony region.
This property returns NumPy-compatible slice objects that define the minimal rectangular bounding box around each colony. These slices can be used directly with NumPy array indexing to extract bounding box regions, which is much more efficient than processing the full plate image when analyzing individual colonies.
Each slice is a tuple of (row_slice, col_slice) that can be used with NumPy standard indexing syntax: array[row_slice, col_slice] to extract the bounding box region from any array with the same dimensions.
- Returns:
- A list of slice tuples, one per colony, in the same order
as the labels. Each tuple contains (row_slice, col_slice) where: - row_slice: slice(min_row, max_row) - includes rows from min_row to max_row-1 - col_slice: slice(min_col, max_col) - includes cols from min_col to max_col-1
- Return type:
Examples
Extract bounding box regions from the grayscale image:
>>> from phenotypic import Image >>> from phenotypic.detect import RoundPeaksDetector >>> plate = Image.from_file("colony_array.png") >>> detector = RoundPeaksDetector() >>> detector.apply(plate) >>> # Get the bounding box region for the first colony >>> first_slice = plate.objects.slices[0] >>> first_colony_region = plate.gray[first_slice] >>> print(f"First colony bounding box shape: {first_colony_region.shape}")
Process all colonies using their bounding boxes:
>>> for idx, bbox_slice in enumerate(plate.objects.slices): ... colony_region = plate.gray[bbox_slice] ... mean_intensity = colony_region.mean() ... print(f"Colony {idx}: mean intensity = {mean_intensity:.2f}")
Extract bounding boxes from multiple image channels:
>>> # Process RGB channels for each colony >>> for bbox_slice in plate.objects.slices: ... r_channel = plate.rgb[bbox_slice][..., 0] ... g_channel = plate.rgb[bbox_slice][..., 1] ... b_channel = plate.rgb[bbox_slice][..., 2] ... print(f"R: {r_channel.mean():.1f}, G: {g_channel.mean():.1f}, " ... f"B: {b_channel.mean():.1f}")
- property Image.objmap: ObjectMap#
Returns the ObjectMap accessor; The object map is a mutable integer gray that identifies the different objects in an image to be analyzed. Changes to elements of the object_map sync to the object_mask.
The object_map is stored as a compressed sparse column gray in the backend. This is to save on memory consumption at the cost of adding increased computational overhead between converting between sparse and dense matrices.
Note
Has accessor methods to get sparse representations of the object map that can streamline measurement calculations.
- Returns:
A mutable integer gray that identifies the different objects in an image to be analyzed.
- Return type:
from phenotypic import Image from phenotypic.data import load_colony image = Image(load_colony()) # get the objmap data arr = image.objmap[:] print(type(arr)) # set the objmap data # the shape of the new objmap must be the same shape as the original objmap image.objmap[:] = arr # without the bracket indexing the accessor is returned instead print(image.objmap[:])
See Also:
ObjectMap
The objmap property provides access to the labeled object map, where each pixel
contains an integer label corresponding to the detected object it belongs to (0 for
background). This is the result of instance segmentation operations.
ObjectMap API:
- class phenotypic._core._image_parts.accessors._objmap_accessor.ObjectMap(root_image: Image)[source]#
Bases:
NapariLabelsMixin,SingleChannelAccessorManages an object map for labeled regions in an image.
This class provides a mechanism to manipulate and access labeled object maps within a given image. It is tightly coupled with the parent image object and provides methods for accessing sparse and dense representations, relabeling, resetting, and visualization.
The object map is stored internally as a compressed sparse column (CSC) matrix for memory efficiency. All public methods expose the data through dense array interfaces for ease of use while maintaining the sparse representation backend. Changes to the object map shapes are automatically reflected in the object mask.
The class supports array-like indexing and slicing operations, sparse format conversion, and visualization with matplotlib.
- Parameters:
root_image (Image)
- _root_image#
The parent Image object that this accessor is associated with.
Note
Changes to the object map shapes will be automatically reflected in the object mask.
- classmethod load(filepath: str | Path) numpy.ndarray#
Load an image array from file and verify it was saved from this accessor type.
Checks if the image contains PhenoTypic metadata indicating it was saved from the same accessor type (e.g., Image.gray, Image.rgb). If metadata doesn’t match or is missing, a warning is raised but the array is still loaded.
- Parameters:
- Returns:
The loaded image array.
- Return type:
np.ndarray
- Warns:
UserWarning – If metadata is missing or indicates the image was saved from a different accessor type.
Examples
Load a grayscale image from file:
>>> from phenotypic import Image >>> image = Image(arr) >>> # load an object map you saved or hand-graded >>> image.objmap.load("path/to/map.png")
- __array__(dtype=None, copy=None)[source]#
Implement the array interface for NumPy compatibility.
This method enables NumPy functions to operate directly on ObjectMap instances by converting the sparse representation to a dense array. It allows usage patterns such as np.sum(objmap), np.max(objmap), and array unpacking operations.
- Parameters:
dtype (type, optional) – Optional NumPy dtype to cast the array to. If None, the array maintains its native dtype. Defaults to None.
copy (bool, optional) – Control whether the underlying data is copied. If True, a copy is guaranteed. If False (NumPy 2.0+), no copy is made. If None, a copy is made only if necessary for dtype conversion. Defaults to None.
- Returns:
- A dense NumPy array representation of the object map
with shape matching the image dimensions (height, width).
- Return type:
np.ndarray
Examples
Using ObjectMap with NumPy functions:
>>> import numpy as np >>> objmap = image.objmap >>> max_label = np.max(objmap) >>> unique_labels = np.unique(objmap) >>> arr = np.asarray(objmap, dtype=np.uint32)
- __getitem__(key)[source]#
Return a slice of the object map as if it were a dense array.
This method implements NumPy-style slicing and indexing for the ObjectMap. The sparse representation is converted to dense for the indexing operation, allowing all standard NumPy slicing patterns including integer indexing, boolean masking, and multi-dimensional slicing.
- Parameters:
key – Index or slice specification. Can be an integer, tuple of integers, slice object, boolean array, or integer array for advanced indexing. All NumPy indexing patterns are supported.
- Returns:
- The sliced portion of the object map as a dense array.
The returned shape depends on the indexing pattern. Returns a scalar if a single element is indexed, otherwise returns an ndarray.
- Return type:
np.ndarray
Examples
NumPy-style indexing and slicing:
>>> objmap = image.objmap >>> row = objmap[5] # Get row 5 >>> region = objmap[10:20, 30:40] # Get a rectangular region >>> pixel = objmap[5, 10] # Get a single pixel >>> mask = objmap[objmap > 0] # Boolean indexing
- __len__() int#
Returns the length of the subject array.
This method calculates and returns the total number of elements contained in the underlying array.
- Returns:
The number of elements in the underlying array attribute.
- Return type:
- __setitem__(key, value)[source]#
Set values in the object map as if it were a dense array.
This method implements NumPy-style assignment for the ObjectMap. It accepts both array and scalar values, validates shapes and types, and atomically updates the internal sparse representation. The operation is atomic with respect to the backend reference.
- Parameters:
key – Index or slice specification for the location to update. Can be an integer, tuple of integers, slice object, boolean array, or integer array. All NumPy indexing patterns are supported.
value – The value(s) to assign. Can be: - A NumPy array matching the shape of the key selection - A scalar integer, bool, or float (converted to int)
- Raises:
ArrayKeyValueShapeMismatchError – If the shape or dtype of a supplied array does not match the shape of the key selection, or if the dtypes are incompatible.
InvalidMapValueError – If value is not a supported type (not an array, int, bool, or float).
Notes
After assignment, the sparse matrix is compressed and zeros are eliminated to maintain memory efficiency.
All values are internally cast to uint16 to match the sparse matrix dtype and represent object labels.
The operation is atomic: if an exception occurs, the map is not modified.
Examples
Assigning values to the object map:
>>> objmap = image.objmap >>> # Set a single pixel >>> objmap[5, 10] = 3 >>> # Set a region with a scalar value >>> objmap[10:20, 30:40] = 0 >>> # Set a region with an array >>> region_labels = np.array([[1, 1], [1, 1]]) >>> objmap[10:12, 30:32] = region_labels
- as_coo() coo_matrix[source]#
Return the object map in COOrdinate (ijv) sparse format.
Converts the internal object map representation to COO (Coordinate or ijv) format, which stores non-zero elements as (row, column, value) tuples. This format is useful for constructing sparse matrices or analyzing individual non-zero entries.
- Returns:
A copy of the object map in COO sparse format.
- Return type:
Examples
Converting to COO sparse format and accessing entries:
>>> sparse_coo = image.objmap.as_coo() >>> # Access non-zero entries directly >>> for i, j, v in zip(sparse_coo.row, sparse_coo.col, sparse_coo.data): ... print(f"Object label {v} at position ({i}, {j})")
- as_csc() csc_matrix[source]#
Return the object map as a compressed sparse column matrix.
Converts the internal object map representation to CSC (Compressed Sparse Column) format. CSC format is optimized for column slicing and matrix operations.
- Returns:
A copy of the object map in CSC sparse format.
- Return type:
Examples
Converting to CSC sparse format:
>>> sparse_csc = image.objmap.as_csc() >>> # Efficient column operations >>> first_column = sparse_csc[:, 0].toarray()
- copy() numpy.ndarray[source]#
Return a dense copy of the object map.
Creates and returns a dense NumPy array copy of the object map. The returned array is independent and modifications to it will not affect the original object map.
- Returns:
- A dense copy of the object map with shape (height, width)
and dtype uint16.
- Return type:
np.ndarray
Examples
Creating an independent copy of the object map:
>>> objmap_copy = image.objmap.copy() >>> objmap_copy[0, 0] = 999 # Modifications don't affect the original >>> assert image.objmap[0, 0] != 999
- dash(figsize: tuple[int, int] | None = None, title: str | None = None, cmap: str | None = 'gray', foreground_only: bool = False, overlay: bool = True, *, object_label: int | None = None, show_labels: bool = False, show_grid: bool = True, label_settings: dict | None = None, overlay_settings: dict | None = None, plotly_settings: dict | None = None) go.Figure#
Display the single-channel image data using Plotly.
- Parameters:
figsize (tuple[int, int] | None) – Figure size in inches (width, height). If None, auto-calculated from array aspect ratio.
title (str | None) – Title of the plot. If None, no title is displayed.
cmap (str | None) – Colormap name. Defaults to
"gray".foreground_only (bool) – If True, display only foreground elements.
overlay (bool) – If True, overlay the object map on the image. Falls back to plain image when no objects are detected.
object_label (int | None) – Specific object label to highlight. If None, shows all detected objects. Only used when overlay is True.
show_labels (bool) – If True, displays numeric labels at object centroids. Only used when overlay is True.
show_grid (bool) – For GridImage only. If True, draws gridlines and colored section boxes. Only used when overlay is True. Ignored for regular Image.
label_settings (dict | None) – Dict passed to text label rendering.
overlay_settings (dict | None) – Dict passed to overlay composition.
plotly_settings (dict | None) – Additional Plotly layout settings.
- Returns:
A
plotly.graph_objects.Figure.- Raises:
ImportError – If plotly is not installed.
- Return type:
go.Figure
- draw(*, viewer: NapariViewer | None = None) Image#
Open a napari editor to hand-edit these labels and save them back.
Launches a blocking PyQt napari viewer showing
rgb(when present),gray, anddetect_matas image layers plus this accessor’s data as an editable labels layer. Use napari’s built-in paintbrush, fill, and eraser tools to correct the segmentation, then click Save to Image in the dock panel to commit the edits to the parent image (or Discard & Close to abandon them).Editing
objmappreserves the original integer label IDs. Editingobjmaskis strictly binary and relabels the object map on save (skimage.measure.label), so original IDs are not retained — callimage.objmap.draw()instead when stable IDs matter. Preview the existing detections withshow()ornapari()before editing.- Parameters:
viewer (NapariViewer | None) – Optional existing napari viewer to reuse instead of opening a fresh one. Defaults to None.
- Returns:
The parent image, mutated in place if edits were saved.
- Return type:
Image
- Raises:
ImportError – If napari is not installed. Install with
pip install phenotypic[napari].
Examples
Hand-correct an auto-detected object map:
>>> from phenotypic.data import load_synth_yeast_plate >>> from phenotypic.detect import OtsuDetector >>> image = OtsuDetector().apply(load_synth_yeast_plate()) >>> image = image.objmap.draw()
- foreground()#
Extracts and returns the foreground of the image by masking out the background.
This method generates a foreground image by applying the object mask stored in the Image to the current array representation. Pixels outside the object mask are set to zero in the resulting foreground image. This is useful in image processing tasks to isolate the region of interest in the image, such as microbe colonies on an agar plate.
- Returns:
A numpy array containing only the foreground portion of the image, with all non-foreground pixels set to zero.
- Return type:
- histogram(figsize: Tuple[int, int] = (10, 5), *, cmap='gray', linewidth=1, channel_names: list | None = None) Tuple[TypeAliasForwardRef('matplotlib.figure.Figure'), TypeAliasForwardRef('matplotlib.axes.Axes')]#
Plots the histogram(s) of an image along with the image itself. The behavior depends on the dimensionality of the image array (2D or 3D). In the case of 2D, a single image and its histogram are produced. For 3D (multi-channel images), histograms for each channel are created alongside the image. This method supports customization such as figure size, colormap, line width of histograms, and labeling of channels.
- Parameters:
figsize (Tuple[int, int]) – The size of the figure to create. Default is (10, 5).
cmap (str) – Colormap used to render the image when the data is single channel. Default is ‘gray’.
linewidth (int) – Line width of the plotted histograms. Default is 1.
channel_names (list | None) – Optional names for the channels in 3D data. These are used as titles for channel-specific histograms. If None, channels are instead labeled numerically.
- Returns:
The Matplotlib figure and axes objects representing the plotted image and its histograms.
- Return type:
Tuple[plt.Figure, plt.Axes]
- Raises:
ValueError – If the dimensionality of the input image array is unsupported.
Notes
This method uses skimage.exposure.histogram for computing the histogram data.
- imsave(filepath: str | Path | None = None, bit_depth: Literal[8, 16] | None = None, use_label2rgb: bool = False) None[source]#
Save the object map to a file.
Saves the object map array to a specified file format. The raw object map contains integer labels (0 = background, 1+ = object IDs). When use_label2rgb is True, labels are colorized for visualization but NOT blended with the original image.
- Parameters:
filepath (str | Path | None) – Destination file path (.png, .jpeg, or .tiff).
bit_depth (Literal[8, 16] | None) – Target bit depth (8 or 16). If None, uses image’s bit depth.
use_label2rgb (bool) – If True, colorize labels using skimage.color.label2rgb for visual inspection. Note: This does NOT blend with the original image - it only colorizes the labels against a black background. For overlays blended with the original image at full resolution, use
Image.rgb.save_overlay()orImage.gray.save_overlay()instead. Defaults to False.
- Raises:
ValueError – If the file extension is not supported.
- Return type:
None
See also
- ImageAccessorBase.save_overlay: For saving overlays that blend the
object labels with the original image at full resolution.
Examples
Save raw object map vs colorized:
>>> from phenotypic.data import load_synth_yeast_plate >>> image = load_synth_yeast_plate() >>> # Save raw labeled map (integer values) >>> image.objmap.imsave("objmap_raw.png") >>> # Save colorized labels (no background image) >>> image.objmap.imsave("objmap_colored.png", use_label2rgb=True) >>> # For overlay with original image, use save_overlay: >>> image.rgb.save_overlay("overlay.png", overlay_alpha=0.3)
- isempty()#
- napari(name: str | None = None, reset: bool = False, colormap: dict | None = None, opacity: float = 0.7, contour: int = 0, *, viewer: napari.Viewer | None = None, layer_name: str | None = None) napari.Viewer#
Add labeled regions to a persistent global napari viewer.
Creates or reuses a single napari viewer instance with a labels layer for visualizing discrete labeled regions. Unlike the base class image layer implementation, this uses napari’s labels API which assigns distinct colors to each unique label value, making it ideal for visualizing segmented colonies, object maps, and binary masks.
The viewer persists across multiple method calls, allowing comparison of different processing stages and data types in the same visualization window.
- Parameters:
name (str | None) – Optional custom name for the labels layer. If provided, the layer will be named
{accessor}_{name}. If not provided, defaults to using the image’s name attribute. Defaults to None.reset (bool) – If True, closes the current napari viewer and creates a fresh one. This is useful for starting a new visualization session without lingering layers from previous calls. Defaults to False.
colormap (dict | None) – Optional dictionary mapping label values to RGB colors. Keys are integer label IDs, values are RGB tuples/lists with values in [0, 1] range. If None, napari uses its default label colormap which assigns distinct colors automatically. Example:
{1: [1.0, 0, 0], 2: [0, 1.0, 0]}for red/green colonies. Defaults to None.opacity (float) – Layer opacity from 0.0 (fully transparent) to 1.0 (fully opaque). This controls the visibility of the labels layer. Values outside this range will raise ValueError. Defaults to 0.7.
contour (int) – Contour thickness in pixels. When > 0, renders only the outline of each labeled region rather than filled regions. Useful for overlaying object boundaries on other layers. Must be >= 0. Defaults to 0 (filled).
viewer (napari.Viewer | None) – Optional external napari viewer instance to use instead of the global viewer. When provided, global viewer management (creation, reset, smart-grid installation) is bypassed entirely. Defaults to None.
layer_name (str | None) – Optional full layer name to use instead of the auto-generated
{accessor}_{image_name}pattern. Defaults to None.
- Returns:
- The global napari viewer instance with the labeled regions
added as a labels layer.
- Return type:
napari.Viewer
- Raises:
ValueError – If opacity is not in [0.0, 1.0] range or contour is negative.
Examples
Basic labels visualization:
>>> from phenotypic import Image >>> from phenotypic.detect import OtsuDetector >>> img = Image.imread("colonies.jpg") >>> detector = OtsuDetector() >>> img = detector.apply(img) >>> >>> # View detected colonies as labels >>> viewer = img.objmap.napari()
Customizing labels appearance:
>>> # Semi-transparent labels with contours >>> viewer = img.objmap.napari(opacity=0.5, contour=2) >>> >>> # Custom color mapping for specific colonies >>> cmap = { ... 1: [1.0, 0, 0], # Red for colony 1 ... 2: [0, 1.0, 0], # Green for colony 2 ... 3: [0, 0, 1.0], # Blue for colony 3 ... } >>> viewer = img.objmap.napari(colormap=cmap)
Comparing masks and maps in same viewer:
>>> # Add grayscale base image >>> viewer = img.gray.napari() >>> >>> # Overlay binary mask with transparency >>> viewer = img.objmask.napari(opacity=0.4) >>> >>> # Add full object map with contours only >>> viewer = img.objmap.napari(name="boundaries", contour=1)
Using reset for fresh visualization sessions:
>>> viewer = img.objmap.napari() >>> # ... do some analysis ... >>> # Start fresh without old layers >>> viewer = img.objmap.napari(reset=True)
Note
Labels layers are specifically designed for discrete/categorical data where each unique integer value represents a distinct object or region. This is fundamentally different from image layers which handle continuous intensity data. Labels layers provide:
Automatic distinct coloring per label
Contour visualization mode
Optimized rendering for segmentation data
Better interactivity for object selection
For colony analysis, this means each detected colony gets a unique color, making visual QC and counting much easier than grayscale intensity display.
- relabel(connectivity: int = 2)[source]#
Relabel all connected components in the object map.
This method reassigns labels to all connected components in the current object map based on the specified connectivity criterion. It uses scikit-image’s label function to identify connected components and assigns them new sequential labels starting from 1. This is useful when:
Object labels are non-sequential or have gaps
The labeling needs to be reset to sequential labels
Connectivity needs to be changed (e.g., from 8-connectivity to 4-connectivity)
The operation treats the current object map as a binary mask (foreground vs. background) and relabels the foreground regions.
- Parameters:
connectivity (int, optional) – Maximum number of orthogonal hops to consider a pixel as a neighbor of another. For 2D images: - 1: 4-connectivity (horizontal and vertical neighbors only) - 2: 8-connectivity (including diagonal neighbors) Higher values are supported for higher dimensional data. Defaults to 1.
- Returns:
The operation modifies the object map in-place.
- Return type:
None
Notes
Background (label 0) is preserved in its original location.
After relabeling, object labels will be sequential (1, 2, 3, …).
The relabeling process may change existing label values.
Examples
Relabeling connected components:
>>> # Relabel with 4-connectivity >>> image.objmap.relabel(connectivity=1) >>> # Relabel with 8-connectivity for diagonal neighbors >>> image.objmap.relabel(connectivity=2)
See also
scikit-image.measure.label(): The underlying function used for connected component labeling.
- reset() None[source]#
Reset the object map to an empty state with no labeled objects.
Clears all object labels from the object map, effectively removing all detected or manually-set objects. The resulting map contains only zeros (background). The shape of the map is preserved to match the parent image’s dimensions.
This method is useful when you want to clear the current segmentation and prepare for a new detection or labeling operation.
Examples
Clearing all objects from the object map:
>>> image.objmap.reset() >>> # Now image.objmap contains no objects >>> assert image.objmap[:].max() == 0
- Return type:
None
- save_overlay(filepath: str | Path, overlay_alpha: float = 0.3, bg_label: int = 0, colors: list | None = None, show_grid: bool = True, gridline_color: tuple[int, int, int] = (0, 255, 255), section_box_colors: list[tuple[int, int, int]] | None = None, **label2rgb_kwargs) None#
Save a full-resolution overlay image blending objmap with the subject array.
Creates an RGB overlay by blending the object map labels with the underlying image data and saves it to disk. Unlike show(overlay=True) which produces a matplotlib figure, this method saves the raw pixel data at full resolution, suitable for pixel-level quality validation of detection results.
For GridImage objects, gridlines and section boxes are automatically drawn when
show_gridis True. The line widths scale dynamically with image size.- Parameters:
filepath (str | Path) – Destination file path. Should have .png or .jpeg extension.
overlay_alpha (float) – Alpha value for label overlay (0.0 = transparent, 1.0 = opaque). Defaults to 0.3.
bg_label (int) – Label value to treat as background. Defaults to 0.
colors (list | None) – List of RGB colors to use for labels. If None, uses default colormap.
show_grid (bool) – Whether to draw gridlines and section boxes on overlay for GridImage objects. Ignored for regular Image objects. Defaults to True.
gridline_color (tuple[int, int, int]) – RGB color tuple for gridlines. Defaults to cyan (0, 255, 255).
section_box_colors (list[tuple[int, int, int]] | None) – List of RGB tuples for cycling through section box colors. Defaults to tab20 colormap colors.
**label2rgb_kwargs – Additional keyword arguments for label2rgb.
- Raises:
ValueError – If the file extension is not supported.
- Return type:
None
Examples
Save full-resolution overlay:
>>> from phenotypic.data import load_synth_yeast_plate >>> image = load_synth_yeast_plate() >>> image.rgb.save_overlay("overlay_rgb.png", overlay_alpha=0.4)
- show(figsize=None, title=None, cmap: str = 'tab10', ax: None | plt.Axes = None, mpl_params: None | dict = None) tuple[plt.Figure, plt.Axes][source]#
Display the object map using matplotlib’s imshow.
This method visualizes the labeled object map using matplotlib. Each unique label is assigned a distinct color from the specified colormap, allowing visual distinction between labeled objects. The background (label 0) is typically shown in a neutral color.
- Parameters:
figsize (tuple[int, int], optional) – Tuple specifying the figure size in inches (width, height). If None, uses the default matplotlib figure size. Defaults to None.
title (str, optional) – Title text for the plot. If None, no title is displayed. Defaults to None.
cmap (str, optional) – The colormap name used for rendering the labeled object map. A diverse colormap like ‘nipy_spectral’ is recommended for clearly distinguishing between many objects. Defaults to ‘nipy_spectral’.
ax (plt.Axes, optional) – Existing Matplotlib Axes object where the object map will be plotted. If None, a new figure and axes are created. Defaults to None.
mpl_params (dict, optional) – Additional parameters passed to matplotlib’s imshow function for plot customization (e.g., interpolation, normalization). If None, no extra parameters are applied. Defaults to None.
- Returns:
- A tuple containing the matplotlib Figure
and Axes objects where the object map is rendered. If an existing axes was provided, its parent figure is returned.
- Return type:
tuple[plt.Figure, plt.Axes]
Examples
Displaying the object map with various options:
>>> # Basic visualization >>> fig = image.objmap.show() >>> # Custom figure size and title >>> fig = image.objmap.show(figsize=(10, 8), title='Labeled Objects') >>> # Use a different colormap >>> fig = image.objmap.show(cmap='tab20')
- val_range() pd.Interval#
Return the closed interval [min, max] of the subject array values.
- Returns:
A single closed interval including both endpoints.
- Return type:
pd.Interval
- vmax() int[source]#
Returns the maximum value for the object map data type.
Object maps are stored as uint16 arrays where values represent object labels. This returns the theoretical maximum value that the uint16 dtype can represent.
- Return type:
- vmin() int[source]#
Returns the minimum value for the object map data type.
Object maps are stored as uint16 arrays where 0 represents background. This returns the theoretical minimum value that the uint16 dtype can represent.
- Return type:
- property dtype#
- property ndim: int#
Returns the number of dimensions of the underlying array.
The ndim property provides access to the dimensionality of the array being encapsulated in the object. This value corresponds to the number of axes or dimensions the underlying array possesses. It can be useful for understanding the structure of the contained data.
- Returns:
The number of dimensions of the underlying array.
- Return type:
- property shape: tuple[int, int]#
Return the shape of the object map.
Returns the dimensions of the object map as a tuple of (height, width). This matches the shape of the parent image’s grayscale representation.
- Returns:
- A tuple (height, width) representing the spatial
dimensions of the object map.
- Return type:
Examples
Getting object map dimensions:
>>> height, width = image.objmap.shape >>> print(f"Object map dimensions: {width}x{height}")
- property Image.objmask: ObjectMask#
Returns the ObjectMask Accessor; The object mask is a mutable binary representation of the objects in an image to be analyzed. Changing elements of the mask will reset object_map labeling.
Note
- If the image has not been processed by a detector, the target for analysis is the entire image itself. Accessing the object_mask in this case
will return a 2-D array entirely with other_image 1 that is the same shape as the gray
Changing elements of the mask will relabel of objects in the object_map
- Returns:
A mutable binary representation of the objects in an image to be analyzed.
- Return type:
ObjectMaskErrors
from phenotypic import Image from phenotypic.data import load_colony image = Image(load_colony()) # get the objmask data arr = image.objmask[:] print(type(arr)) # set the objmask data # the shape of the new objmask must be the same shape as the original objmask image.objmask[:] = arr # without the bracket indexing the accessor is returned instead print(image.objmask[:])
See Also:
ObjectMask
The objmask property provides access to the binary mask of all detected objects,
where pixels belonging to any object are marked as True/1 and background pixels are
marked as False/0.
ObjectMask API:
- class phenotypic._core._image_parts.accessors._objmask_accessor.ObjectMask(root_image: Image)[source]#
Bases:
NapariLabelsMixin,SingleChannelAccessorManages a binary object mask linked to a parent image.
ObjectMask provides array-like access and manipulation of a binary mask indicating object locations in the parent image. It supports slicing, item assignment, copying, and visualization. The mask is backed by a sparse representation stored in the parent image’s sparse_object_map, with automatic relabeling via scikit-image’s label() function to maintain consistent object IDs after modifications.
The object mask distinguishes between foreground (object) pixels (True) and background pixels (False). Any modification to the mask via __setitem__ triggers automatic relabeling to ensure object label consistency across the parent image’s object map.
- Parameters:
root_image (Image)
- _root_image#
The parent Image object containing this mask.
- Type:
Image
Note
Changes to the object mask will trigger automatic relabeling of the object map to maintain consistent object IDs. This ensures data integrity when mask regions are directly modified.
Examples
Basic access and slicing:
>>> # Access the mask as a dense array >>> mask_array = np.array(objmask) >>> # Slice operations >>> region = objmask[10:50, 20:60] >>> # Modify mask regions >>> objmask[10:50, 20:60] = np.zeros((40, 40))
Creating foreground images:
>>> # Get foreground of a grayscale channel >>> foreground = image.gray.foreground()
- classmethod load(filepath: str | Path) numpy.ndarray#
Load an image array from file and verify it was saved from this accessor type.
Checks if the image contains PhenoTypic metadata indicating it was saved from the same accessor type (e.g., Image.gray, Image.rgb). If metadata doesn’t match or is missing, a warning is raised but the array is still loaded.
- Parameters:
- Returns:
The loaded image array.
- Return type:
np.ndarray
- Warns:
UserWarning – If metadata is missing or indicates the image was saved from a different accessor type.
Examples
Load a grayscale image from file:
>>> from phenotypic import Image >>> image = Image(arr) >>> # load an object map you saved or hand-graded >>> image.objmap.load("path/to/map.png")
- __and__(other) numpy.ndarray[source]#
Perform element-wise logical AND with the object mask.
Returns the element-wise logical AND between the mask and another operand. This is useful for intersecting masks or filtering foreground regions based on additional criteria.
- Parameters:
other – Operand to AND with. Can be: - ObjectMask: Uses its binary mask values - np.ndarray or array-like: Must match mask shape - bool: Applied to all mask elements
- Returns:
Bool array with AND results (True/False).
- Return type:
np.ndarray
- Raises:
ValueError – If array operand shape doesn’t match mask shape.
Examples
Intersect two masks to find overlapping regions:
>>> mask1 = image.objmask >>> mask2 = other_image.objmask >>> intersection = mask1 & mask2 >>> print(intersection.shape) (1024, 1024)
Filter mask using a region of interest:
>>> roi = np.zeros(image.shape, dtype=bool) >>> roi[100:500, 100:500] = True >>> filtered_mask = image.objmask & roi
- __array__(dtype=None, copy=None)[source]#
Implement the NumPy array interface for seamless integration with NumPy.
Converts the sparse binary mask to a dense NumPy array, enabling direct use of NumPy functions and operations on the ObjectMask. The mask is returned as bool (False for background, True for foreground).
- Parameters:
- Returns:
- A dense bool array of shape matching the parent image
(True/False values), or the specified dtype.
- Return type:
np.ndarray
Examples
Using with NumPy functions and type conversion:
>>> # Use with NumPy functions >>> num_foreground_pixels = np.count_nonzero(objmask) >>> total_pixels = np.sum(objmask) >>> # Explicit type conversion >>> mask_float = np.array(objmask, dtype=np.float32)
- __getitem__(key)[source]#
Return a slice of the binary object mask with NumPy-compatible indexing.
Supports all standard NumPy slicing operations (integer indexing, slice objects, boolean masks, fancy indexing). The sparse mask is converted to dense form and bool values (True/False) are returned.
- Parameters:
key (int, slice, tuple, np.ndarray) – Index or slice to retrieve. Follows NumPy indexing conventions for 2D arrays.
- Returns:
- Bool array (True/False values) representing the sliced region of
the mask, with the same shape as the indexed region.
- Return type:
np.ndarray
Examples
NumPy slicing and indexing operations:
>>> # Single row >>> row = objmask[10] >>> # Rectangular region >>> region = objmask[10:50, 20:60] >>> # Column >>> col = objmask[:, 5] >>> # Boolean indexing >>> foreground_indices = objmask > 0
- __iand__(other) ObjectMask[source]#
Perform in-place logical AND with the object mask.
Modifies the mask by performing element-wise logical AND with another operand. After modification, automatically relabels the mask to maintain consistent object IDs.
- Parameters:
other – Operand to AND with. Can be: - ObjectMask: Uses its binary mask values - np.ndarray or array-like: Must match mask shape - bool: Applied to all mask elements
- Returns:
Returns self for method chaining.
- Return type:
- Raises:
ValueError – If array operand shape doesn’t match mask shape.
Examples
Remove objects outside a region of interest:
>>> roi = np.zeros(image.shape, dtype=bool) >>> roi[100:900, 100:900] = True >>> image.objmask &= roi # Keep only objects in ROI
Intersect with another detection result:
>>> from phenotypic.detect import OtsuDetector >>> detector = OtsuDetector() >>> refined_result = detector.apply(image) >>> image.objmask &= refined_result.objmask
Note
This operation triggers automatic relabeling of the object map to maintain consistent object IDs. Existing object labels may change.
- __invert__() numpy.ndarray[source]#
Perform logical NOT on the object mask.
Returns the logical negation of the mask, inverting foreground and background pixels. Useful for selecting background regions or creating inverted masks.
- Returns:
Bool array with inverted mask values.
- Return type:
np.ndarray
Examples
Get background pixels for analysis:
>>> background_mask = ~image.objmask >>> background_intensity = image.gray[:][background_mask].mean()
Combine with other operations to exclude detected regions:
>>> from phenotypic.enhance import GaussianBlur >>> # Apply blur only to background >>> blurred = GaussianBlur(sigma=2.0).operate(image) >>> combined = image.gray[:] * image.objmask[:] + blurred.gray[:] * ~image.objmask
- __ior__(other) ObjectMask[source]#
Perform in-place logical OR with the object mask.
Modifies the mask by performing element-wise logical OR with another operand. Useful for progressively adding detections or manually expanding mask regions. Automatically relabels after modification.
- Parameters:
other – Operand to OR with. Can be: - ObjectMask: Uses its binary mask values - np.ndarray or array-like: Must match mask shape - bool: Applied to all mask elements
- Returns:
Returns self for method chaining.
- Return type:
- Raises:
ValueError – If array operand shape doesn’t match mask shape.
Examples
Add manually drawn colonies to existing detection:
>>> manual_additions = np.zeros(image.shape, dtype=bool) >>> manual_additions[250:300, 250:300] = True >>> image.objmask |= manual_additions
Combine multiple detection passes:
>>> for detector in [OtsuDetector(), CannyDetector(), WatershedDetector()]: >>> result = detector.operate(image) >>> image.objmask |= result.objmask
Note
This operation triggers automatic relabeling, which may change existing object IDs. Use with caution in measurement workflows.
- __ixor__(other) ObjectMask[source]#
Perform in-place logical XOR with the object mask.
Modifies the mask by performing element-wise logical XOR with another operand. Useful for selectively toggling mask regions or removing specific patterns. Automatically relabels after modification.
- Parameters:
other – Operand to XOR with. Can be: - ObjectMask: Uses its binary mask values - np.ndarray or array-like: Must match mask shape - bool: Applied to all mask elements
- Returns:
Returns self for method chaining.
- Return type:
- Raises:
ValueError – If array operand shape doesn’t match mask shape.
Examples
Toggle mask values in a specific region:
>>> toggle_region = np.zeros(image.shape, dtype=bool) >>> toggle_region[300:400, 300:400] = True >>> image.objmask ^= toggle_region # Flip mask in region
Remove overlapping regions between two masks:
>>> artifact_mask = artifact_detector.operate(image).objmask >>> image.objmask ^= artifact_mask & image.objmask
Note
This operation triggers automatic relabeling. XOR with True will invert the entire mask.
- __len__() int#
Returns the length of the subject array.
This method calculates and returns the total number of elements contained in the underlying array.
- Returns:
The number of elements in the underlying array attribute.
- Return type:
- __or__(other) numpy.ndarray[source]#
Perform element-wise logical OR with the object mask.
Returns the element-wise logical OR between the mask and another operand. Useful for combining masks from different detections or merging foreground regions.
- Parameters:
other – Operand to OR with. Can be: - ObjectMask: Uses its binary mask values - np.ndarray or array-like: Must match mask shape - bool: Applied to all mask elements
- Returns:
Bool array with OR results (True/False).
- Return type:
np.ndarray
- Raises:
ValueError – If array operand shape doesn’t match mask shape.
Examples
Combine detections from two different methods:
>>> from phenotypic.detect import OtsuDetector, CannyDetector >>> otsu_result = OtsuDetector().operate(image) >>> canny_result = CannyDetector().operate(image) >>> combined_mask = otsu_result.objmask | canny_result.objmask
Add a manually drawn region to existing detections:
>>> manual_region = np.zeros(image.shape, dtype=bool) >>> manual_region[50:150, 50:150] = True >>> expanded_mask = image.objmask | manual_region
- __setitem__(key, value: numpy.ndarray)[source]#
Update mask values at specified locations with automatic relabeling.
Sets mask values at the specified indices or slices, then automatically relabels the entire mask using scikit-image’s label() function to ensure object IDs remain consistent across the parent image. This maintains data integrity when mask regions are directly modified.
The operation accepts scalar values (0, 1, bool) or arrays. Non-zero values are converted to 1 (foreground), zero values to 0 (background). The updated mask is then relabeled atomically to avoid inconsistent states.
- Parameters:
- Raises:
InvalidMaskScalarValueError – If a scalar value cannot be converted to a valid binary value (not int, bool, or convertible to these types).
InvalidMaskValueError – If value is not an int, bool, or ndarray.
ArrayKeyValueShapeMismatchError – If an ndarray value’s shape does not match the shape of the indexed mask region.
Examples
Setting mask regions with scalars and arrays:
>>> # Set a rectangular region to background (0) >>> objmask[10:50, 20:60] = 0 >>> # Set with a matching array >>> region_mask = np.ones((40, 40)) >>> objmask[10:50, 20:60] = region_mask >>> # Set single pixel >>> objmask[5, 10] = True
Note
The entire mask is relabeled after any modification. This ensures that object IDs in the parent image remain consistent, but may change existing object labels if the relabeling alters connectivity.
- __xor__(other) numpy.ndarray[source]#
Perform element-wise logical XOR with the object mask.
Returns the element-wise logical XOR between the mask and another operand. Useful for finding symmetric differences between masks or detecting regions unique to each mask.
- Parameters:
other – Operand to XOR with. Can be: - ObjectMask: Uses its binary mask values - np.ndarray or array-like: Must match mask shape - bool: Applied to all mask elements
- Returns:
Bool array with XOR results (True/False).
- Return type:
np.ndarray
- Raises:
ValueError – If array operand shape doesn’t match mask shape.
Examples
Find regions detected by one method but not the other:
>>> detector1_mask = detector1.operate(image).objmask >>> detector2_mask = detector2.operate(image).objmask >>> unique_regions = detector1_mask ^ detector2_mask
Invert mask in a specific ROI:
>>> roi = np.zeros(image.shape, dtype=bool) >>> roi[200:400, 200:400] = True >>> modified = image.objmask ^ roi # Flip bits in ROI
- copy() numpy.ndarray[source]#
Return an independent copy of the binary object mask.
Creates a new bool array containing the same values (True/False) as the current mask. Modifications to the returned array do not affect the original mask or the parent image.
- Returns:
- A dense copy of the binary mask with bool dtype, independent
of the original sparse representation.
- Return type:
np.ndarray
Examples
Creating an independent mask copy:
>>> # Create a modifiable copy for processing >>> mask_copy = objmask.copy() >>> mask_copy[10:50, 20:60] = 0 # Doesn't affect objmask
- dash(figsize: tuple[int, int] | None = None, title: str | None = None, cmap: str | None = 'gray', foreground_only: bool = False, overlay: bool = True, *, object_label: int | None = None, show_labels: bool = False, show_grid: bool = True, label_settings: dict | None = None, overlay_settings: dict | None = None, plotly_settings: dict | None = None) go.Figure#
Display the single-channel image data using Plotly.
- Parameters:
figsize (tuple[int, int] | None) – Figure size in inches (width, height). If None, auto-calculated from array aspect ratio.
title (str | None) – Title of the plot. If None, no title is displayed.
cmap (str | None) – Colormap name. Defaults to
"gray".foreground_only (bool) – If True, display only foreground elements.
overlay (bool) – If True, overlay the object map on the image. Falls back to plain image when no objects are detected.
object_label (int | None) – Specific object label to highlight. If None, shows all detected objects. Only used when overlay is True.
show_labels (bool) – If True, displays numeric labels at object centroids. Only used when overlay is True.
show_grid (bool) – For GridImage only. If True, draws gridlines and colored section boxes. Only used when overlay is True. Ignored for regular Image.
label_settings (dict | None) – Dict passed to text label rendering.
overlay_settings (dict | None) – Dict passed to overlay composition.
plotly_settings (dict | None) – Additional Plotly layout settings.
- Returns:
A
plotly.graph_objects.Figure.- Raises:
ImportError – If plotly is not installed.
- Return type:
go.Figure
- draw(*, viewer: NapariViewer | None = None) Image#
Open a napari editor to hand-edit these labels and save them back.
Launches a blocking PyQt napari viewer showing
rgb(when present),gray, anddetect_matas image layers plus this accessor’s data as an editable labels layer. Use napari’s built-in paintbrush, fill, and eraser tools to correct the segmentation, then click Save to Image in the dock panel to commit the edits to the parent image (or Discard & Close to abandon them).Editing
objmappreserves the original integer label IDs. Editingobjmaskis strictly binary and relabels the object map on save (skimage.measure.label), so original IDs are not retained — callimage.objmap.draw()instead when stable IDs matter. Preview the existing detections withshow()ornapari()before editing.- Parameters:
viewer (NapariViewer | None) – Optional existing napari viewer to reuse instead of opening a fresh one. Defaults to None.
- Returns:
The parent image, mutated in place if edits were saved.
- Return type:
Image
- Raises:
ImportError – If napari is not installed. Install with
pip install phenotypic[napari].
Examples
Hand-correct an auto-detected object map:
>>> from phenotypic.data import load_synth_yeast_plate >>> from phenotypic.detect import OtsuDetector >>> image = OtsuDetector().apply(load_synth_yeast_plate()) >>> image = image.objmap.draw()
- foreground()#
Extracts and returns the foreground of the image by masking out the background.
This method generates a foreground image by applying the object mask stored in the Image to the current array representation. Pixels outside the object mask are set to zero in the resulting foreground image. This is useful in image processing tasks to isolate the region of interest in the image, such as microbe colonies on an agar plate.
- Returns:
A numpy array containing only the foreground portion of the image, with all non-foreground pixels set to zero.
- Return type:
- histogram(figsize: Tuple[int, int] = (10, 5), *, cmap='gray', linewidth=1, channel_names: list | None = None) Tuple[TypeAliasForwardRef('matplotlib.figure.Figure'), TypeAliasForwardRef('matplotlib.axes.Axes')]#
Plots the histogram(s) of an image along with the image itself. The behavior depends on the dimensionality of the image array (2D or 3D). In the case of 2D, a single image and its histogram are produced. For 3D (multi-channel images), histograms for each channel are created alongside the image. This method supports customization such as figure size, colormap, line width of histograms, and labeling of channels.
- Parameters:
figsize (Tuple[int, int]) – The size of the figure to create. Default is (10, 5).
cmap (str) – Colormap used to render the image when the data is single channel. Default is ‘gray’.
linewidth (int) – Line width of the plotted histograms. Default is 1.
channel_names (list | None) – Optional names for the channels in 3D data. These are used as titles for channel-specific histograms. If None, channels are instead labeled numerically.
- Returns:
The Matplotlib figure and axes objects representing the plotted image and its histograms.
- Return type:
Tuple[plt.Figure, plt.Axes]
- Raises:
ValueError – If the dimensionality of the input image array is unsupported.
Notes
This method uses skimage.exposure.histogram for computing the histogram data.
- imsave(filepath: str | Path | None = None, bit_depth: Literal[8, 16] | None = None) None#
Saves an array representing a microbe colony image to a specified file format while preserving or adjusting metadata and pixel depth as needed. Supports JPEG, PNG, and TIFF formats.
The behavior of the function is context-sensitive based on the file format’s restrictions and array properties. Proper file format selection and bit depth adjustment can have an impact on the accuracy of image analysis and preservation of data integrity.
- Parameters:
filepath (str | Path | None) –
The destination file path where the image will be saved. The extension of the file path determines the image format (e.g., .jpeg, .png, .tiff). Changing the file format influences how the image data is handled during saving:
.jpeg: Compression or loss of data may occur. Maximal value limit (255) for uint8 pixel depth affects the fidelity of rich intensity details in microbe colonies.
.png: Retains high-quality output but supports only 8-bit or 16-bit images. Conversions may occur if the array has a different data type, which could result in data loss.
.tiff: Ideal for high-bit-depth precision and analysis preservation; best for maintaining intricate morphological details of microbial colonies.
bit_depth (Literal[8, 16] | None, optional) –
Specifies the bit depth of the saved image (either 8-bit or 16-bit). The provided bit depth must align with the file format’s capabilities. Misalignment could trigger conversion with possible data truncation or rounding. For example:
8-bit: Useful for efficiently representing intensity when detail is moderate, suitable for JPEG or simple PNG outputs.
16-bit: Allows for higher intensity ranges, especially valuable for preserving subtle morphological gradient differentiation when analyzing colonies.
- Raises:
ValueError – An error occurs when an unsupported file extension is provided in filepath.
- Warns:
UserWarnings – Warnings are issued under the following conditions:
Saving a 16-bit or floating-point array as JPEG, as these conversions may cause information loss due to format restrictions.
Saving a floating-point array as PNG when conversions to 8-bit or 16-bit integers might lead to truncated or altered pixel intensity values.
- Return type:
None
- isempty()#
- napari(name: str | None = None, reset: bool = False, colormap: dict | None = None, opacity: float = 0.7, contour: int = 0, *, viewer: napari.Viewer | None = None, layer_name: str | None = None) napari.Viewer#
Add labeled regions to a persistent global napari viewer.
Creates or reuses a single napari viewer instance with a labels layer for visualizing discrete labeled regions. Unlike the base class image layer implementation, this uses napari’s labels API which assigns distinct colors to each unique label value, making it ideal for visualizing segmented colonies, object maps, and binary masks.
The viewer persists across multiple method calls, allowing comparison of different processing stages and data types in the same visualization window.
- Parameters:
name (str | None) – Optional custom name for the labels layer. If provided, the layer will be named
{accessor}_{name}. If not provided, defaults to using the image’s name attribute. Defaults to None.reset (bool) – If True, closes the current napari viewer and creates a fresh one. This is useful for starting a new visualization session without lingering layers from previous calls. Defaults to False.
colormap (dict | None) – Optional dictionary mapping label values to RGB colors. Keys are integer label IDs, values are RGB tuples/lists with values in [0, 1] range. If None, napari uses its default label colormap which assigns distinct colors automatically. Example:
{1: [1.0, 0, 0], 2: [0, 1.0, 0]}for red/green colonies. Defaults to None.opacity (float) – Layer opacity from 0.0 (fully transparent) to 1.0 (fully opaque). This controls the visibility of the labels layer. Values outside this range will raise ValueError. Defaults to 0.7.
contour (int) – Contour thickness in pixels. When > 0, renders only the outline of each labeled region rather than filled regions. Useful for overlaying object boundaries on other layers. Must be >= 0. Defaults to 0 (filled).
viewer (napari.Viewer | None) – Optional external napari viewer instance to use instead of the global viewer. When provided, global viewer management (creation, reset, smart-grid installation) is bypassed entirely. Defaults to None.
layer_name (str | None) – Optional full layer name to use instead of the auto-generated
{accessor}_{image_name}pattern. Defaults to None.
- Returns:
- The global napari viewer instance with the labeled regions
added as a labels layer.
- Return type:
napari.Viewer
- Raises:
ValueError – If opacity is not in [0.0, 1.0] range or contour is negative.
Examples
Basic labels visualization:
>>> from phenotypic import Image >>> from phenotypic.detect import OtsuDetector >>> img = Image.imread("colonies.jpg") >>> detector = OtsuDetector() >>> img = detector.apply(img) >>> >>> # View detected colonies as labels >>> viewer = img.objmap.napari()
Customizing labels appearance:
>>> # Semi-transparent labels with contours >>> viewer = img.objmap.napari(opacity=0.5, contour=2) >>> >>> # Custom color mapping for specific colonies >>> cmap = { ... 1: [1.0, 0, 0], # Red for colony 1 ... 2: [0, 1.0, 0], # Green for colony 2 ... 3: [0, 0, 1.0], # Blue for colony 3 ... } >>> viewer = img.objmap.napari(colormap=cmap)
Comparing masks and maps in same viewer:
>>> # Add grayscale base image >>> viewer = img.gray.napari() >>> >>> # Overlay binary mask with transparency >>> viewer = img.objmask.napari(opacity=0.4) >>> >>> # Add full object map with contours only >>> viewer = img.objmap.napari(name="boundaries", contour=1)
Using reset for fresh visualization sessions:
>>> viewer = img.objmap.napari() >>> # ... do some analysis ... >>> # Start fresh without old layers >>> viewer = img.objmap.napari(reset=True)
Note
Labels layers are specifically designed for discrete/categorical data where each unique integer value represents a distinct object or region. This is fundamentally different from image layers which handle continuous intensity data. Labels layers provide:
Automatic distinct coloring per label
Contour visualization mode
Optimized rendering for segmentation data
Better interactivity for object selection
For colony analysis, this means each detected colony gets a unique color, making visual QC and counting much easier than grayscale intensity display.
- reset()[source]#
Reset the object mask and linked object map to a cleared state.
Delegates to the parent image’s object map’s reset method, which clears the mask and resets all object labels and properties. This is useful when re-segmenting the image or clearing previous detection results.
Examples
Resetting the mask to cleared state:
>>> # Clear the mask and object map >>> objmask.reset() >>> # Now objmask contains only background (0s)
Note
This operation affects both the object mask and the parent image’s object map and properties. Use with caution as it discards all segmentation data.
- save_overlay(filepath: str | Path, overlay_alpha: float = 0.3, bg_label: int = 0, colors: list | None = None, show_grid: bool = True, gridline_color: tuple[int, int, int] = (0, 255, 255), section_box_colors: list[tuple[int, int, int]] | None = None, **label2rgb_kwargs) None#
Save a full-resolution overlay image blending objmap with the subject array.
Creates an RGB overlay by blending the object map labels with the underlying image data and saves it to disk. Unlike show(overlay=True) which produces a matplotlib figure, this method saves the raw pixel data at full resolution, suitable for pixel-level quality validation of detection results.
For GridImage objects, gridlines and section boxes are automatically drawn when
show_gridis True. The line widths scale dynamically with image size.- Parameters:
filepath (str | Path) – Destination file path. Should have .png or .jpeg extension.
overlay_alpha (float) – Alpha value for label overlay (0.0 = transparent, 1.0 = opaque). Defaults to 0.3.
bg_label (int) – Label value to treat as background. Defaults to 0.
colors (list | None) – List of RGB colors to use for labels. If None, uses default colormap.
show_grid (bool) – Whether to draw gridlines and section boxes on overlay for GridImage objects. Ignored for regular Image objects. Defaults to True.
gridline_color (tuple[int, int, int]) – RGB color tuple for gridlines. Defaults to cyan (0, 255, 255).
section_box_colors (list[tuple[int, int, int]] | None) – List of RGB tuples for cycling through section box colors. Defaults to tab20 colormap colors.
**label2rgb_kwargs – Additional keyword arguments for label2rgb.
- Raises:
ValueError – If the file extension is not supported.
- Return type:
None
Examples
Save full-resolution overlay:
>>> from phenotypic.data import load_synth_yeast_plate >>> image = load_synth_yeast_plate() >>> image.rgb.save_overlay("overlay_rgb.png", overlay_alpha=0.4)
- show(ax: plt.Axes | None = None, figsize: tuple[int, int] | None = None, cmap: str = 'gray', title: str | None = None) tuple[plt.Figure, plt.Axes][source]#
Display the binary object mask as a Matplotlib image.
Renders the object mask using Matplotlib’s imshow with customizable appearance. The mask is shown as a grayscale image where white represents foreground (objects) and black represents background.
- Parameters:
ax (plt.Axes, optional) – An existing Matplotlib Axes object to plot on. If None, a new figure and axes are created. Defaults to None.
figsize (tuple[int, int], optional) – Size of the figure in inches as (width, height). Only used if ax is None. Defaults to None (uses default size).
cmap (str, optional) – Colormap to apply. Defaults to ‘gray’, which shows foreground pixels in white and background in black.
title (str, optional) – Title for the plot. If None, no title is displayed. Defaults to None.
- Returns:
- Matplotlib Figure and Axes objects containing
the rendered mask.
- Return type:
tuple[plt.Figure, plt.Axes]
Examples
Displaying the mask with various options:
>>> # Display with default settings >>> fig = objmask.show() >>> # Display with custom size and title >>> fig = objmask.show(figsize=(8, 8), title='Object Mask')
- val_range() pd.Interval#
Return the closed interval [min, max] of the subject array values.
- Returns:
A single closed interval including both endpoints.
- Return type:
pd.Interval
- vmax() bool[source]#
Returns the maximum value for the object mask (True for foreground).
- Return type:
- vmin() bool[source]#
Returns the minimum value for the object mask (False for background).
- Return type:
- property dtype#
- property ndim: int#
Returns the number of dimensions of the underlying array.
The ndim property provides access to the dimensionality of the array being encapsulated in the object. This value corresponds to the number of axes or dimensions the underlying array possesses. It can be useful for understanding the structure of the contained data.
- Returns:
The number of dimensions of the underlying array.
- Return type:
- property shape#
Return the shape of the object mask.
The shape is always identical to the parent image’s shape, since the mask covers the entire image extent.
- Returns:
- Shape of the mask as (height, width), matching the
parent image dimensions.
- Return type:
Examples
Accessing mask shape:
>>> height, width = objmask.shape >>> assert objmask.shape == image.gray.shape
Color Space Operations#
- property Image.color: ColorAccessor
Access all color space representations through a unified interface.
This property provides access to the ColorAccessor object, which groups all color space transformations and representations including:
XYZ: CIE XYZ color space
XYZ_D65: CIE XYZ under D65 illuminant
Lab: CIE L*a*b* perceptually uniform color space
xy: CIE xy chromaticity coordinates
hsv: HSV (Hue, Saturation, Value) color space
- Returns:
Unified accessor for all color space representations.
- Return type:
Examples
Access color spaces:
>>> img = Image.imread('sample.jpg') >>> xyz_data = img.color.XYZ[:] >>> lab_data = img.color.Lab[:] >>> hue = img.color.hsv[..., 0] # hue is the first matrix in the array
The color property provides unified access to multiple color space representations
through the ColorAccessor interface. This groups together device-dependent (HSV) and
CIE standard color spaces (XYZ, XYZ-D65, L*a*b*, xy chromaticity).
All color space conversions are computed on-demand and cached to avoid redundant computations. The parent Image configuration (illuminant, observer, gamma) is used consistently across all transformations.
ColorAccessor API:
- class phenotypic._core._image_parts.accessors._color_accessor.ColorAccessor(root_image: Image)[source]#
Bases:
objectProvides unified access to all color space representations of an image.
This accessor class serves as a facade to multiple specialized color space accessors, grouping together various color space transformations and representations. It provides convenient access to both device-dependent color spaces (HSV) and CIE standard color spaces (XYZ, XYZ-D65, L*a*b*, and xy chromaticity).
All color space conversions are computed on-demand and returned as read-only numpy arrays. Individual accessor objects maintain caching to avoid redundant computations when the same color space is accessed multiple times.
The parent Image object configuration (illuminant, _observer model, gamma encoding) is used consistently across all color space transformations to ensure coherent color space analysis.
- Parameters:
root_image (Image)
- _root_image#
The parent Image object that this accessor is bound to. Used to access raw RGB/grayscale data and color properties (illuminant, _observer).
- Type:
Image
- _xyz#
Accessor for CIE XYZ color space representation.
- Type:
XyzAccessor
- _xyz_d65#
Accessor for CIE XYZ under D65 illuminant.
- Type:
XyzD65Accessor
- _cielab#
Accessor for perceptually uniform L*a*b* color space.
- Type:
CieLabAccessor
- _xy#
Accessor for CIE xy chromaticity coordinates.
- Type:
xyChromaticityAccessor
- _hsv#
Accessor for HSV color space representation.
- Type:
HsvAccessor
Examples
Access different color spaces from an image:
>>> from phenotypic import Image >>> img = Image.imread('sample.jpg') >>> # Access CIE XYZ color space >>> xyz_data = img.color.XYZ[:] >>> print(xyz_data.shape) # (height, width, 3) >>> # Access perceptually uniform Lab color space >>> lab_data = img.color.Lab[:] >>> # Access HSV components (hue is first channel) >>> hue_channel = img.color.hsv[..., 0] >>> saturation_channel = img.color.hsv[..., 1] >>> brightness_channel = img.color.hsv[..., 2] >>> # Access chromaticity coordinates >>> xy_coords = img.color.xy[:]
Use color spaces for analysis:
>>> import numpy as np >>> # Calculate color differences using Lab space >>> lab_data = img.color.Lab[:] >>> differences = np.sqrt( ... (lab_data[..., 0] - 50)**2 + ... (lab_data[..., 1] - 25)**2 + ... (lab_data[..., 2] - 10)**2 ... ) >>> # Extract hue for color classification >>> hue = img.color.hsv[..., 0] * 360 # Convert to degrees >>> red_mask = (hue < 30) | (hue > 330)
- __init__(root_image: Image)[source]#
Initialize the ColorAccessor with a reference to the parent image.
Creates all subordinate color space accessor objects, each providing specialized access to a specific color space representation. All accessors share the same parent Image reference to ensure consistent color properties (illuminant, _observer) are used across all color space transformations.
- Parameters:
root_image (Image) – The Image object that this accessor is bound to. Used to access RGB/grayscale data and color configuration properties (illuminant, _observer, gamma encoding).
Examples
Access ColorAccessor through Image.color property:
>>> from phenotypic import Image >>> img = Image.imread('photo.jpg') >>> # Direct initialization is not typically needed - use img.color instead >>> accessor = img.color # Returns ColorAccessor instance
- property Lab: CieLabAccessor#
Access the CIE L*a*b* color space representation.
Provides access to the perceptually uniform CIE L*a*b* color space, derived from the image’s XYZ representation. The Lab color space is designed to approximate human visual perception, making it ideal for color analysis, color correction, and calculating perceptually meaningful color differences.
The three channels represent: - L* (lightness): Ranges from 0 (black) to 100 (white), representing perceptual brightness - a* (green-red opponent): Negative values indicate green, positive indicate red - b* (blue-yellow opponent): Negative values indicate blue, positive indicate yellow
Because Lab is perceptually uniform, Euclidean distances in Lab space correspond to perceptual color differences as seen by human observers. This makes it superior to RGB for color analysis and comparison tasks.
- Returns:
- Accessor providing numpy-like interface to Lab data.
Supports array indexing and slicing. Shape is (height, width, 3) where the three channels correspond to L*, a*, and b* values.
- Return type:
CieLabAccessor
See also
XYZ: Device-independent color space basis for Lab calculation. XYZ_D65: XYZ under standard D65 illuminant (Lab typically computed from this).
Examples
Access Lab color space and calculate color differences:
>>> from phenotypic import Image >>> import numpy as np >>> img = Image.imread('photo.jpg') >>> # Access Lab color space >>> lab = img.color.Lab[:] >>> L = img.color.Lab[..., 0] # Lightness (0-100) >>> a = img.color.Lab[..., 1] # Green (-) to Red (+) >>> b = img.color.Lab[..., 2] # Blue (-) to Yellow (+) >>> # Calculate perceptually meaningful color difference >>> reference_lab = np.array([50, 0, 0]) # Mid-gray >>> color_difference = np.sqrt( ... (lab[..., 0] - reference_lab[0])**2 + ... (lab[..., 1] - reference_lab[1])**2 + ... (lab[..., 2] - reference_lab[2])**2 ... ) >>> # Find pixels close to a reference color (within deltaE of 5) >>> similar_mask = color_difference < 5 >>> # Adjust lightness across entire image >>> brightened = lab.copy() >>> brightened[..., 0] += 10 # Increase L* by 10
- property XYZ: XyzAccessor#
Access the CIE XYZ color space representation.
Provides access to the CIE XYZ color space representation of the image, computed under the parent Image’s configured illuminant. XYZ is a device-independent color space that forms the basis for many other color space transformations.
The XYZ color space separates color information into lightness-related luminance (Y) and chromaticity values (X, Z). It is particularly useful as an intermediate representation for converting between different color spaces.
- Returns:
- Accessor providing numpy-like interface to XYZ data.
Supports array indexing and slicing. Shape is (height, width, 3) where the three channels correspond to X, Y, and Z values.
- Return type:
XyzAccessor
See also
XYZ_D65: XYZ representation specifically under D65 illuminant conditions. xy: Normalized chromaticity coordinates derived from XYZ.
Examples
Access and work with XYZ color space:
>>> from phenotypic import Image >>> img = Image.imread('photo.jpg') >>> # Get full XYZ array >>> xyz_array = img.color.XYZ[:] >>> print(xyz_array.shape) # (height, width, 3) >>> # Extract individual channels >>> X = img.color.XYZ[..., 0] >>> Y = img.color.XYZ[..., 1] # Luminance >>> Z = img.color.XYZ[..., 2] >>> # Slice specific region >>> roi_xyz = img.color.XYZ[100:200, 100:200, :]
- property XYZ_D65: XyzD65Accessor#
Access the CIE XYZ color space under D65 illuminant.
Provides XYZ representation specifically under D65 (standard daylight) illuminant viewing conditions. If the parent Image uses a different illuminant (e.g., D50), chromatic adaptation is automatically applied to transform the data to D65 conditions.
D65 is the CIE standard daylight illuminant with a color temperature of approximately 6504 K. It is the most commonly used illuminant in color science, photography, and display technology. Using D65 as a reference standard enables comparison of color data across different imaging systems.
- Returns:
- Accessor providing numpy-like interface to XYZ D65 data.
Supports array indexing and slicing. Shape is (height, width, 3) where the three channels correspond to X, Y, and Z values under D65 conditions.
- Return type:
XyzD65Accessor
See also
XYZ: XYZ representation under the image’s configured illuminant. Lab: Perceptually uniform color space (typically uses D65).
Examples
Access XYZ color space under D65 illuminant:
>>> from phenotypic import Image >>> img = Image.imread('photo.jpg') >>> # Get XYZ D65 representation >>> xyz_d65 = img.color.XYZ_D65[:] >>> # Use D65 for standardized color comparison >>> luminance_d65 = img.color.XYZ_D65[..., 1] >>> # If original illuminant differs from D65, chromatic adaptation is applied >>> # For images originally in D65, this is equivalent to XYZ
- property hsv: HsvAccessor#
Access the HSV (Hue, Saturation, Value) color space representation.
Provides access to the device-dependent HSV color space, which represents colors in a way that is intuitive for human color selection and manipulation. HSV is particularly useful for color-based filtering, hue-specific analysis, and applications where color properties need to be adjusted independently.
The three channels represent (all normalized to range [0, 1]): - H (hue): Color type, ranges from 0 to 1 (corresponds to 0 to 360 degrees) - S (saturation): Color intensity/purity, 0 (grayscale) to 1 (pure color) - V (value): Brightness/luminosity, 0 (black) to 1 (brightest)
HSV is computed from RGB and is device-dependent (unlike CIE color spaces). However, it is more intuitive for color-based operations like selecting all red pixels or adjusting hue.
The HsvAccessor includes additional analysis methods such as histograms and visualization of HSV components. Note: HSV is only available for RGB images; grayscale images do not have HSV representation.
- Returns:
- Accessor providing numpy-like interface to HSV data.
Supports array indexing and slicing. Shape is (height, width, 3) where the three channels correspond to H, S, V values (each in range [0, 1]).
- Return type:
HsvAccessor
- Raises:
AttributeError – If called on a grayscale image without RGB data.
See also
XYZ: Device-independent color space alternative. Lab: Perceptually uniform color space alternative.
Examples
Access HSV components and perform color-based filtering:
>>> from phenotypic import Image >>> img = Image.imread('photo.jpg') >>> # Access HSV components >>> hsv = img.color.hsv[:] >>> hue = img.color.hsv[..., 0] # 0 to 1 >>> saturation = img.color.hsv[..., 1] # 0 to 1 >>> brightness = img.color.hsv[..., 2] # 0 to 1 >>> # Convert hue to degrees (0-360) >>> hue_degrees = hue * 360 >>> # Extract red pixels (hue near 0 or near 360) >>> red_hue = hue_degrees >>> red_mask = (red_hue < 30) | (red_hue > 330) >>> # Extract highly saturated colors >>> saturated_mask = saturation > 0.5 >>> # Find bright colors >>> bright_mask = brightness > 0.7 >>> # Visualize HSV components >>> fig, axes = img.color.hsv.show()
- property xy: xyChromaticityAccessor#
Access the CIE xy chromaticity coordinates.
Provides 2D chromaticity representation derived from the CIE XYZ color space. Chromaticity coordinates express color independently of luminance, isolating the hue and saturation information. This is particularly useful for color analysis, gamut visualization, and studying color without brightness variation.
The xy coordinates are derived from XYZ using the formulas: x = X / (X + Y + Z), y = Y / (X + Y + Z)
This normalized representation is device-independent and widely used in color science for visualizing color spaces on the CIE 1931 chromaticity diagram.
- Returns:
- Accessor providing numpy-like interface to xy data.
Supports array indexing and slicing. Shape is (height, width, 2) where the two channels correspond to x and y chromaticity coordinates (both in range [0, 1]).
- Return type:
xyChromaticityAccessor
See also
XYZ: Full 3D color space representation including luminance. Lab: Perceptually uniform color space incorporating both chromaticity and lightness.
Examples
Access and visualize xy chromaticity coordinates:
>>> from phenotypic import Image >>> import matplotlib.pyplot as plt >>> img = Image.imread('photo.jpg') >>> # Get chromaticity coordinates >>> xy_coords = img.color.xy[:] >>> x = img.color.xy[..., 0] >>> y = img.color.xy[..., 1] >>> # Plot color on CIE 1931 chromaticity diagram >>> plt.scatter(x.flatten(), y.flatten(), c=img.rgb[:].reshape(-1, 3)/255) >>> plt.xlabel('x') >>> plt.ylabel('y') >>> plt.show() >>> # Analyze color composition without luminance effects >>> roi_xy = img.color.xy[100:200, 100:200, :]
Detailed documentation for individual color space operations is available in a dedicated section.
Visualization & Plotting#
- property Image.plot: PlotAccessor
The plot property provides quality-of-life visualizations for pipeline development,
specifically designed for colony detection parameter tuning on arrayed microbe cultures
on agar plates. These methods help understand how morphological operations, size filtering,
and spatial patterns affect detection results.
All methods support flexible data requirements, automatically detecting whether labeled objects (objmap) or binary masks (objmask) are available.
PlotAccessor API:
- class phenotypic._core._image_parts.accessors._plot_accessor.PlotAccessor(root_image: Image)[source]#
Bases:
ImageAccessorBaseProvides quality-of-life plots for developing image processing pipelines.
This accessor offers sophisticated visualization methods to help understand how morphological operations, size filtering, and spatial patterns affect colony detection in arrayed microbial cultures on solid agar media. These plots are designed for pipeline development and parameter tuning rather than publication.
All methods support flexible data requirements, automatically detecting whether labeled objects (objmap) or binary masks (objmask) are available, and adapting their analysis accordingly.
Built-in plot methods (
all,morph_progression, etc.) are defined as explicit methods for IDE autocomplete. User-registered plotters added via@register_plotterare still accessible through dynamic dispatch.For overlay visualization, use
image.show(overlay=True)orimage.dash(overlay=True)instead.Note
For large images (>3000x3000 pixels), memory usage can be significant. Caller is responsible for closing returned figures with
plt.close(fig)after saving to free memory and prevent accumulation of matplotlib figure objects in memory.Examples
Access plot methods through an Image instance:
>>> from phenotypic import Image >>> from phenotypic.detect import OtsuDetector >>> # Load and detect colonies >>> image = Image.imread('plate.jpg') >>> detector = OtsuDetector() >>> detected = detector.apply(image) >>> # Access plot methods >>> fig, axes = detected.plot.morph_progression() >>> plt.savefig('morph.png') >>> plt.close(fig) # Important: free memory >>> fig, ax = detected.plot.size_distribution() >>> plt.savefig('size.png') >>> plt.close(fig)
List available plotters:
>>> from phenotypic._core._image_parts.plot_accessor import available_plotters >>> print(available_plotters()) ('all', 'diagnostics', 'morph_progression', ...)
- Parameters:
root_image (Image)
- classmethod load(filepath: str | Path) numpy.ndarray#
Load an image array from file and verify it was saved from this accessor type.
Checks if the image contains PhenoTypic metadata indicating it was saved from the same accessor type (e.g., Image.gray, Image.rgb). If metadata doesn’t match or is missing, a warning is raised but the array is still loaded.
- Parameters:
- Returns:
The loaded image array.
- Return type:
np.ndarray
- Warns:
UserWarning – If metadata is missing or indicates the image was saved from a different accessor type.
Examples
Load a grayscale image from file:
>>> from phenotypic import Image >>> image = Image(arr) >>> # load an object map you saved or hand-graded >>> image.objmap.load("path/to/map.png")
- __array__(dtype=None, copy=None)#
Implements the array interface for numpy compatibility.
This allows numpy functions to operate directly on accessor objects. For example: np.sum(accessor), np.mean(accessor), etc.
- Parameters:
dtype – Optional dtype to cast the array to
copy – Optional copy parameter for NumPy 2.0+ compatibility
- Returns:
The underlying array data
- Return type:
np.ndarray
- __getattr__(name: str) Any[source]#
Dispatch attribute access to user-registered plotter methods.
Built-in plotters are resolved as explicit methods above. This fallback handles plotters added at runtime via
@register_plotter.- Parameters:
name (str) – Name of the plotter method to access.
- Returns:
The bound method from the registered plotter instance.
- Raises:
AttributeError – If name is not found on any registered plotter.
- Return type:
- __init__(root_image: Image) None[source]#
Initialize PlotAccessor with a reference to the parent Image.
- Parameters:
root_image (Image) – The parent Image instance containing detection results and image data.
- Return type:
None
- __len__() int#
Returns the length of the subject array.
This method calculates and returns the total number of elements contained in the underlying array.
- Returns:
The number of elements in the underlying array attribute.
- Return type:
- all(*args: Any, **kwargs: Any) Any[source]#
Plot all available image data layers side by side.
See
all().
- boundary_displacement(*args: Any, **kwargs: Any) Any[source]#
Visualize boundary displacement from morphological operations.
See
boundary_displacement().
- copy() numpy.ndarray#
- Return type:
- detect_modes(*args: Any, **kwargs: Any) Any[source]#
Faceted comparison of every registered detection mode.
See
detect_modes().
- diagnostics(*args: Any, **kwargs: Any) Any[source]#
Comprehensive image quality diagnostics dashboard.
See
diagnostics().
- foreground()#
Extracts and returns the foreground of the image by masking out the background.
This method generates a foreground image by applying the object mask stored in the Image to the current array representation. Pixels outside the object mask are set to zero in the resulting foreground image. This is useful in image processing tasks to isolate the region of interest in the image, such as microbe colonies on an agar plate.
- Returns:
A numpy array containing only the foreground portion of the image, with all non-foreground pixels set to zero.
- Return type:
- histogram(figsize: Tuple[int, int] = (10, 5), *, cmap='gray', linewidth=1, channel_names: list | None = None) Tuple[TypeAliasForwardRef('matplotlib.figure.Figure'), TypeAliasForwardRef('matplotlib.axes.Axes')]#
Plots the histogram(s) of an image along with the image itself. The behavior depends on the dimensionality of the image array (2D or 3D). In the case of 2D, a single image and its histogram are produced. For 3D (multi-channel images), histograms for each channel are created alongside the image. This method supports customization such as figure size, colormap, line width of histograms, and labeling of channels.
- Parameters:
figsize (Tuple[int, int]) – The size of the figure to create. Default is (10, 5).
cmap (str) – Colormap used to render the image when the data is single channel. Default is ‘gray’.
linewidth (int) – Line width of the plotted histograms. Default is 1.
channel_names (list | None) – Optional names for the channels in 3D data. These are used as titles for channel-specific histograms. If None, channels are instead labeled numerically.
- Returns:
The Matplotlib figure and axes objects representing the plotted image and its histograms.
- Return type:
Tuple[plt.Figure, plt.Axes]
- Raises:
ValueError – If the dimensionality of the input image array is unsupported.
Notes
This method uses skimage.exposure.histogram for computing the histogram data.
- imsave(filepath: str | Path | None = None, bit_depth: Literal[8, 16] | None = None) None#
Saves an array representing a microbe colony image to a specified file format while preserving or adjusting metadata and pixel depth as needed. Supports JPEG, PNG, and TIFF formats.
The behavior of the function is context-sensitive based on the file format’s restrictions and array properties. Proper file format selection and bit depth adjustment can have an impact on the accuracy of image analysis and preservation of data integrity.
- Parameters:
filepath (str | Path | None) –
The destination file path where the image will be saved. The extension of the file path determines the image format (e.g., .jpeg, .png, .tiff). Changing the file format influences how the image data is handled during saving:
.jpeg: Compression or loss of data may occur. Maximal value limit (255) for uint8 pixel depth affects the fidelity of rich intensity details in microbe colonies.
.png: Retains high-quality output but supports only 8-bit or 16-bit images. Conversions may occur if the array has a different data type, which could result in data loss.
.tiff: Ideal for high-bit-depth precision and analysis preservation; best for maintaining intricate morphological details of microbial colonies.
bit_depth (Literal[8, 16] | None, optional) –
Specifies the bit depth of the saved image (either 8-bit or 16-bit). The provided bit depth must align with the file format’s capabilities. Misalignment could trigger conversion with possible data truncation or rounding. For example:
8-bit: Useful for efficiently representing intensity when detail is moderate, suitable for JPEG or simple PNG outputs.
16-bit: Allows for higher intensity ranges, especially valuable for preserving subtle morphological gradient differentiation when analyzing colonies.
- Raises:
ValueError – An error occurs when an unsupported file extension is provided in filepath.
- Warns:
UserWarnings – Warnings are issued under the following conditions:
Saving a 16-bit or floating-point array as JPEG, as these conversions may cause information loss due to format restrictions.
Saving a floating-point array as PNG when conversions to 8-bit or 16-bit integers might lead to truncated or altered pixel intensity values.
- Return type:
None
- isempty()#
- morph_progression(*args: Any, **kwargs: Any) Any[source]#
Show effects of morphological operations at increasing kernel sizes.
See
morph_progression().
- napari(name: str | None = None, reset: bool = False, *, viewer: napari.Viewer | None = None, layer_name: str | None = None) napari.Viewer#
Add image to a persistent global napari viewer for Jupyter workflows.
Creates or reuses a single napari viewer instance that persists across multiple method calls. This is particularly useful in Jupyter notebooks where multiple accessors can contribute layers to the same viewer, enabling interactive comparison of different image transformations (e.g., grayscale, RGB, binary masks) on the same data.
The viewer is automatically displayed in Jupyter environments and recreated if it has been closed externally.
- Parameters:
name (str | None) – Optional custom name for the image layer. If provided, the layer will be named
{accessor}_{name}. If not provided, defaults to using the image’s name attribute.reset (bool) – If True, closes the current napari viewer and creates a fresh one. This is useful for starting a new visualization session without lingering layers from previous calls. Defaults to False.
viewer (napari.Viewer | None) – Optional external napari viewer instance to use instead of the global viewer. When provided, global viewer management (creation, reset, smart-grid installation) is bypassed entirely. Defaults to None.
layer_name (str | None) – Optional full layer name to use instead of the auto-generated
{accessor}_{image_name}pattern. Defaults to None.
- Returns:
- The global napari viewer instance with the current
image added as a new layer.
- Return type:
napari.Viewer
- Raises:
ImportError – If napari is not installed. Install with
pip install phenotypic[napari].
Examples
View multiple image transformations in one viewer:
>>> from phenotypic import Image >>> img = Image(arr) >>> # Add grayscale version to viewer >>> viewer = img.gray.napari() >>> # Add RGB version to same viewer >>> viewer = img.rgb.napari() >>> # Add binary segmentation with custom name >>> viewer = img.objmask.napari(name="segmentation_v2")
Using custom names for comparison:
>>> viewer = img.gray.napari(name="raw_grayscale") >>> viewer = img.objmask.napari(name="segmentation_v2")
Resetting the viewer for a fresh session:
>>> viewer = img.gray.napari() >>> viewer = img.rgb.napari() # Same viewer, added layer >>> viewer = img.gray.napari(reset=True) # Fresh viewer, old layers gone
Note
Layers are named using the pattern
{accessor}_{image_name}to ensure descriptive identification. If a layer with the same name already exists, it is replaced with the new image data. This allows for easy updates and comparison of different processing stages.
- save_overlay(filepath: str | Path, overlay_alpha: float = 0.3, bg_label: int = 0, colors: list | None = None, show_grid: bool = True, gridline_color: tuple[int, int, int] = (0, 255, 255), section_box_colors: list[tuple[int, int, int]] | None = None, **label2rgb_kwargs) None#
Save a full-resolution overlay image blending objmap with the subject array.
Creates an RGB overlay by blending the object map labels with the underlying image data and saves it to disk. Unlike show(overlay=True) which produces a matplotlib figure, this method saves the raw pixel data at full resolution, suitable for pixel-level quality validation of detection results.
For GridImage objects, gridlines and section boxes are automatically drawn when
show_gridis True. The line widths scale dynamically with image size.- Parameters:
filepath (str | Path) – Destination file path. Should have .png or .jpeg extension.
overlay_alpha (float) – Alpha value for label overlay (0.0 = transparent, 1.0 = opaque). Defaults to 0.3.
bg_label (int) – Label value to treat as background. Defaults to 0.
colors (list | None) – List of RGB colors to use for labels. If None, uses default colormap.
show_grid (bool) – Whether to draw gridlines and section boxes on overlay for GridImage objects. Ignored for regular Image objects. Defaults to True.
gridline_color (tuple[int, int, int]) – RGB color tuple for gridlines. Defaults to cyan (0, 255, 255).
section_box_colors (list[tuple[int, int, int]] | None) – List of RGB tuples for cycling through section box colors. Defaults to tab20 colormap colors.
**label2rgb_kwargs – Additional keyword arguments for label2rgb.
- Raises:
ValueError – If the file extension is not supported.
- Return type:
None
Examples
Save full-resolution overlay:
>>> from phenotypic.data import load_synth_yeast_plate >>> image = load_synth_yeast_plate() >>> image.rgb.save_overlay("overlay_rgb.png", overlay_alpha=0.4)
- size_distribution(*args: Any, **kwargs: Any) Any[source]#
Plot object size distribution with optional threshold lines.
See
size_distribution().
- size_scatter(*args: Any, **kwargs: Any) Any[source]#
Scatter plot of object sizes colored by a secondary metric.
See
size_scatter().
- size_viewer(*args: Any, **kwargs: Any) Any[source]#
Interactive size distribution viewer with threshold selection.
See
size_viewer().
- spatial_size_map(*args: Any, **kwargs: Any) Any[source]#
Heatmap of object sizes across spatial positions.
See
spatial_size_map().
- structural_response_curve(*args: Any, **kwargs: Any) Any[source]#
Plot structural response metrics across kernel sizes.
See
structural_response_curve().
- try_thresh(*args: Any, **kwargs: Any) Any[source]#
Compare multiple thresholding techniques side by side.
See
try_thresh().
- val_range() pd.Interval#
Return the closed interval [min, max] of the subject array values.
- Returns:
A single closed interval including both endpoints.
- Return type:
pd.Interval
- property dash: Any#
image.plot.dash.<name>().Dispatches to a registered
FigureProviderplotter’s.dash()— a composedgo.Figurefor control-free providers, or an ipywidgets dashboard when the figures declareControl``s. Mirrors the ``@register_plotterregistry used byimage.plot.<name>().Examples
>>> from phenotypic.data import load_synth_yeast_plate >>> image = load_synth_yeast_plate() >>> dashboard = image.plot.dash.diagnostics() # ipywidgets dashboard
- Type:
Interactive Plotly/ipywidgets views
- property dtype#
- property ndim: int#
Returns the number of dimensions of the underlying array.
The ndim property provides access to the dimensionality of the array being encapsulated in the object. This value corresponds to the number of axes or dimensions the underlying array possesses. It can be useful for understanding the structure of the contained data.
- Returns:
The number of dimensions of the underlying array.
- Return type:
- property shape: Tuple[int, ...]#
Returns the shape of the current image data.
This method retrieves the dimensions of the array stored in the _main_arr attribute as a tuple, which indicates its size along each axis.
- Returns:
A tuple representing the dimensions of the _main_arr attribute.
- Return type:
Tuple[int, …]
Detailed documentation for individual plotting methods is available in a dedicated section.
File I/O#
- classmethod Image.imread(filepath: PathLike, rawpy_params: dict | None = None, **kwargs) Image#
imread is a class method responsible for reading an image file from the specified path and performing necessary preprocessing based on the file format and additional parameters. The method supports a variety of image file types including common formats (e.g., JPEG, PNG) as well as raw sensor data. It uses the scikit-image library for loading standard images and rawpy for processing raw image files. This method also handles additional configurations for raw image preprocessing via rawpy parameters, such as white balance, gamma correction, and demosaic algorithm.
- Parameters:
filepath (PathLike) – Path to the image file to be read. It can be any valid file path-like object (e.g., str, pathlib.Path).
rawpy_params (dict | None) – Optional dictionary of parameters for processing raw image files when using rawpy. Supports options like white balance settings, demosaic algorithm, gamma correction, and others. Defaults to None.
**kwargs – Arbitrary keyword arguments to be passed for additional configurations specific to the Image instantiation.
- Returns:
- An instance of the Image class containing the processed image array and any
additional metadata.
- Return type:
Image
- Raises:
UnsupportedFileTypeError – If the file type of the provided filepath is not supported by the method, either due to its extension not being recognized or due to the absence of required libraries like rawpy.
Load an image from various file formats including JPEG, PNG, TIFF, and RAW camera files. Automatically extracts metadata when available.
- Image.save2pickle(filename: str) None#
Save the image to a pickle file for fast serialization and deserialization.
Stores all image data components and metadata in Python’s pickle format, which preserves data types and structure exactly. This is the fastest serialization method but produces larger files than HDF5 and is not suitable for inter-language data exchange.
- Parameters:
filename (str | PathLike) – Path to the pickle file to write (.pkl or .pickle extension recommended).
- Return type:
None
Notes
Pickle format is Python-specific and cannot be read by other languages.
File size is typically larger than HDF5 compressed files.
Load/save is faster than HDF5 for small to medium images.
Pickle files may not be compatible across Python versions.
Examples
Save to pickle:
>>> img = Image.imread('photo.jpg') >>> img.save2pickle('image.pkl') >>> loaded = Image.load_pickle('image.pkl')
Save the complete Image state (data, metadata, detection results) to a pickle file for later restoration.
- Image.save2hdf5(filename, compression='gzip', compression_opts=4)#
Save the image to an HDF5 file with all data and metadata.
Stores the complete image data (RGB, gray, detection matrix, object map) and metadata (protected and public) directly at the HDF5 file’s root group. The file is always overwritten if it already exists.
- Parameters:
filename – Path to the HDF5 file (.h5 extension recommended). Created or overwritten on each call.
compression – Compression filter to apply to datasets. Options: ‘gzip’ (recommended), ‘szip’, or None. Defaults to ‘gzip’.
compression_opts – Compression level for ‘gzip’ (1-9, where 1=fastest, 9=best). Ignored for ‘szip’ and None. Defaults to 4 (balanced).
Examples
Save to HDF5:
>>> img = Image.imread('photo.jpg') >>> img.save2hdf5('output.h5') >>> img.save2hdf5('output.h5', compression='szip')
Save the image to HDF5 format with metadata. HDF5 provides efficient storage and supports compression.
- classmethod Image.load_hdf5(filename, **kwargs) Image#
Loads an image object from an HDF5 file.
- Parameters:
filename (str) – The path to the HDF5 file containing the image data. Providing an incorrect or improperly structured file may result in incomplete or corrupted image data being loaded.
**kwargs – Additional keyword arguments that may alter the image import and processing behavior. These settings may include options for subsampling, resizing, or preprocessing specific to the characteristics of the microbe images. Proper configurations can optimize the processing performance while preserving essential colony features critical to analysis.
- Returns:
An image object constructed from the data stored in the HDF5 file. The fidelity of this object depends on both the input file’s quality and the parameters provided through kwargs, as they affect the image’s suitability for detailed microbe colony studies.
- Return type:
Image
Load an Image from HDF5 file created with save2hdf5.
Image Manipulation#
- Image.rotate(angle_of_rotation: int, mode: str = 'constant', cval=0, order=0, preserve_range=True) None#
Rotates various data attributes of the object by a specified angle.
The method applies rotation transformations image data. It data that falls outside the border is clipped.
- Parameters:
angle_of_rotation (int) – The angle, in degrees, by which to rotate the data attributes. Positive values indicate counterclockwise rotation.
mode (str) – Mode parameter determining how borders are handled during the rotation. Default is ‘constant’.
cval – Constant value to fill edges in ‘constant’ mode. Default is 0.
order (int) – The order of the spline interpolation for rotating images. Must be an integer in the range [0, 5]. Default is 0 for nearest-neighbor interpolation.
preserve_range (bool) – Whether to keep the original input range of values after performing the rotation. Default is True.
- Returns:
None
- Return type:
None
Rotate the image by a specified angle with optional centering and resampling control.
- Image.__getitem__(key) Image#
Returns a new subimage from the current object based on the provided key. The subimage is initialized as a new instance of the same class, maintaining the schema and format consistency as the original image object. This method supports 2-dimensional slicing and indexing.
Note
The subimage arrays are copied from the original image object. This means that any changes made to the subimage will not affect the original image.
We may add this functionality in future updates if there is demand for it.
- Parameters:
key – A slicing key or index used to extract a subset or part of the image object.
- Returns:
An instance of the Image representing the subimage corresponding to the provided key.
- Return type:
Image
- Raises:
KeyError – If the provided key does not match the expected slicing format or dimensions.
Support for numpy-like slicing to extract spatial regions or specific channels. Enables intuitive image manipulation with bracket notation.
Example:
img = Image.imread('sample.jpg')
# Extract region of interest
roi = img[100:300, 100:300]
# Extract specific channel (RGB)
red_channel = img[..., 0]
Visualization (Basic Display)#
- Image.show(figsize: Tuple[int, int] | None = None, **kwargs) tuple[TypeAliasForwardRef('matplotlib.figure.Figure'), TypeAliasForwardRef('matplotlib.axes.Axes')]#
Display the image using matplotlib.
Delegates to
self.rgb.show()for color images orself.gray.show()for grayscale images.- Parameters:
- Returns:
A
(matplotlib.figure.Figure, matplotlib.axes.Axes)tuple.- Return type:
tuple[TypeAliasForwardRef(‘matplotlib.figure.Figure’), TypeAliasForwardRef(‘matplotlib.axes.Axes’)]
Display the image using matplotlib. Supports grayscale and RGB images with automatic colormap selection.
Display the image with detection results overlaid. Shows object boundaries, labels, or other annotations on top of the original image.
Display detected objects with object-specific visualization, including individual object highlighting and labeling.
Metadata Management#
- property Image.metadata: MetadataAccessor#
Access the metadata accessor for reading and writing image metadata. Metadata is categorized into private, protected, public, and imported categories for organized management.
MetadataAccessor API:
- class phenotypic._core._image_parts.accessors._metadata_accessor.MetadataAccessor(image: Image)[source]#
Bases:
objectAccessor for managing image metadata with hierarchical read/write permissions.
This class provides dictionary-like access to image metadata with three permission levels: private (read-only), protected (read/write), and public (read/write/delete). All metadata is combined using ChainMap for unified access while preserving permission constraints.
Private metadata is typically reserved for internal use (e.g., UUID), protected metadata contains system properties (e.g., image name, type), and public metadata contains user-defined or imported metadata that can be freely modified.
- Parameters:
image (Image)
- _parent_image#
The parent Image instance containing the metadata storage.
- Type:
Image
Examples
Access metadata like a dictionary:
>>> img = Image(arr, name='sample') >>> # Get metadata value >>> image_name = img.metadata['ImageName'] >>> # Set public metadata >>> img.metadata['user_notes'] = 'A sample image' >>> # Check if key exists >>> if 'user_notes' in img.metadata: ... print(img.metadata['user_notes'])
Iterate through metadata:
>>> for key, value in img.metadata.items(): ... print(f'{key}: {value}')
- __contains__(key)[source]#
Check if a metadata key exists at any permission level.
- Parameters:
key – The metadata key to check.
- Returns:
True if the key exists in private, protected, or public metadata.
- Return type:
- __delitem__(key)[source]#
Delete a metadata entry with permission checking.
Only public metadata can be deleted. Private and protected metadata cannot be removed.
- Parameters:
key – The metadata key to delete.
- Raises:
PermissionError – If attempting to delete private or protected metadata.
KeyError – If the key does not exist in public metadata.
Examples
Delete public metadata entries:
>>> del img.metadata['user_notes'] # Deletes public metadata
- __getitem__(key)[source]#
Retrieve a metadata value by key with hierarchical search.
Searches in order: private -> protected -> public. Returns the first match found.
- Parameters:
key – The metadata key to retrieve.
- Returns:
The metadata value associated with the key.
- Return type:
Any
- Raises:
KeyError – If the key does not exist in any metadata level.
- __init__(image: Image) None[source]#
Initialize the metadata accessor.
- Parameters:
image (Image) – The parent Image instance containing the metadata storage.
- Return type:
None
- __setitem__(key, value)[source]#
Set a metadata value with validation and permission checking.
Only scalar types (str, int, float, bool) or None are allowed as values. If the key exists in protected metadata, updates the protected value. Otherwise, creates or updates a public metadata entry. Private metadata cannot be modified.
- Parameters:
key – The metadata key to set.
value – The metadata value (must be str, int, float, bool, or None).
- Raises:
ValueError – If value is not a scalar type or None.
PermissionError – If attempting to modify private metadata.
Examples
Set metadata values with permission checking:
>>> img.metadata['resolution'] = 300 # Creates public metadata >>> img.metadata['ImageName'] = 'updated_name' # Updates protected metadata
- get(key, default=None)[source]#
Retrieve a metadata value with a default fallback.
Searches across all permission levels (private -> protected -> public) and returns the first match found.
- Parameters:
key – The metadata key to retrieve.
default – The value to return if the key is not found. Defaults to None.
- Returns:
The metadata value if found, otherwise the default value.
- Return type:
Any
Examples
Retrieve metadata with default fallback:
>>> resolution = img.metadata.get('resolution', 100) >>> name = img.metadata.get('ImageName') # Returns None if not found
- insert_metadata(df: pandas.DataFrame, inplace=False, allow_duplicates=False) pandas.DataFrame[source]#
Insert metadata as columns into a DataFrame.
Adds public and protected metadata as new columns at the beginning of the DataFrame. Column names are prefixed with
Metadata_if not already present. Image name is retrieved from the parent image instance rather than metadata storage.- Parameters:
df (pd.DataFrame) – The DataFrame to insert metadata columns into.
inplace (bool, optional) – If True, modifies the input DataFrame in place. If False, creates a copy before modification. Defaults to False.
allow_duplicates (bool, optional) – If True, allows duplicate column names to be inserted. If False, skips insertion for columns that already exist. Defaults to False.
- Returns:
- The DataFrame with metadata columns inserted at the beginning
(position 0). If inplace=True, returns the same object as input.
- Return type:
pd.DataFrame
Notes
Only public and protected metadata are included (private metadata is excluded)
IMAGE_NAME metadata is populated from parent_image.name instead of the metadata dict
Columns are inserted from right to left at position 0, so iteration order determines final order
Metadata columns without
Metadata_prefix are automatically prefixed
Examples
Insert metadata as DataFrame columns:
>>> import pandas as pd >>> df = pd.DataFrame({'data': [1, 2, 3]}) >>> img = Image(arr, name='sample') >>> img.metadata['resolution'] = 300 >>> result_df = img.metadata.insert_metadata(df) >>> # result_df now has Metadata_ImageName and Metadata_resolution columns at position 0
- items()[source]#
Get all metadata key-value pairs across all permission levels.
- Returns:
- A view of all key-value pairs from combined metadata (private,
protected, public). Items from private metadata take precedence.
- Return type:
ItemsView
- keys()[source]#
Get all metadata keys across all permission levels.
- Returns:
- A view of all keys from combined metadata (private, protected, public).
Keys from private metadata take precedence in the view.
- Return type:
KeysView
- pop(key)[source]#
Remove and return a metadata value.
Only public metadata can be popped. Private and protected metadata cannot be removed.
- Parameters:
key – The metadata key to remove.
- Returns:
The value associated with the key before removal.
- Return type:
Any
- Raises:
PermissionError – If attempting to pop private or protected metadata.
KeyError – If the key does not exist in public metadata.
Examples
Remove and return a public metadata value:
>>> old_value = img.metadata.pop('user_notes')
- table() pandas.Series[source]#
Convert metadata to a pandas Series.
Creates a Series containing all metadata (private, protected, and public) with the parent image name as the Series name.
- Returns:
- A Series where the index is metadata keys and values are
metadata values. The Series name is the parent image name.
- Return type:
pd.Series
Examples
Convert metadata to pandas Series:
>>> img = Image(arr, name='sample_image') >>> img.metadata['resolution'] = 300 >>> series = img.metadata.table() >>> print(series.name) # 'sample_image' >>> print(series['ImageName']) # 'sample_image'
Comparison & Utility#
- Image.__eq__(other: Image) bool#
Compares the current object with another object for equality.
This method checks if the current object’s attributes are equal to another object’s attributes. Equality is determined by verifying that the numerical arrays (rgb, gray, detect_mat, objmap) are element-wise identical.
Note
Only checks image data, and not any other attributes such as metadata.
- Parameters:
other (Image) – The object to compare with the current instance.
- Returns:
True if all the attributes of the current object are identical to those of the other object. Returns False otherwise.
- Return type:
Compare two Image instances for equality based on their data content.
- Image.__hash__()#
Return hash(self).
Compute a hash value for the Image based on its unique identifier.
- Image.__repr__()#
Return repr(self).
Return a string representation of the Image with key information (shape, type, name).
- Image.__str__()#
Return str(self).
Return a human-readable string description of the Image.