Source code for aicsimageio.aics_image

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import importlib
import logging
from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple, Type, Union

import dask.array as da
import numpy as np
import xarray as xr
from ome_types import OME

from . import dimensions, exceptions, transforms, types
from .formats import FORMAT_IMPLEMENTATIONS, READER_TO_INSTALL
from .image_container import ImageContainer
from .metadata import utils as metadata_utils
from .readers import TiffGlobReader
from .readers.reader import Reader
from .types import PhysicalPixelSizes
from .utils.io_utils import pathlike_to_fs

###############################################################################

log = logging.getLogger(__name__)

###############################################################################


def _load_reader(reader_path: str) -> Type[Reader]:
    module_path, reader_name = reader_path.rsplit(".", 1)
    loaded_mod = importlib.import_module(module_path)
    return getattr(loaded_mod, reader_name)


[docs]class AICSImage(ImageContainer): """ AICSImage takes microscopy image data types (files or arrays) of varying dimensions ("ZYX", "TCZYX", "CYX") and reads them as consistent 5D "TCZYX" ("Time-Channel-Z-Y-X") ordered array(s). The data and metadata are lazy loaded and can be accessed as needed. Parameters ---------- image: types.ImageLike A string, Path, fsspec supported URI, or arraylike to read. reader: Optional[Type[Reader]] The Reader class to specifically use for reading the provided image. Default: None (find matching reader) reconstruct_mosaic: bool Boolean for setting that data for this object to the reconstructed / stitched mosaic image. Default: True (reconstruct the mosaic image from tiles) Notes: If True and image is a mosaic, data will be fully reconstructed and stitched array. If True and base reader doesn't support tile stitching, data won't be stitched and instead will have an `M` dimension for tiles. If False and image is a mosaic, data won't be stitched and instead will have an `M` dimension for tiles. If image is not a mosaic, data won't be stitched or have an `M` dimension for tiles. fs_kwargs: Dict[str, Any] Any specific keyword arguments to pass down to the fsspec created filesystem. Default: {} kwargs: Any Extra keyword arguments that will be passed down to the reader subclass. Examples -------- Initialize an image then read the file and return specified slices as a numpy array. >>> img = AICSImage("my_file.tiff") ... zstack_t8 = img.get_image_data("ZYX", T=8, C=0) Initialize an image, construct a delayed dask array for certain slices, then read only the specified chunk of data. >>> img = AICSImage("my_file.czi") ... zstack_t8 = img.get_image_dask_data("ZYX", T=8, C=0) ... zstack_t8_data = zstack_t8.compute() Initialize an image with a dask or numpy array. >>> data = np.random.rand(100, 100) ... img = AICSImage(data) Initialize an image from S3 with s3fs. >>> img = AICSImage("s3://my_bucket/my_file.tiff") Initialize an image and pass arguments to the reader using kwargs. >>> img = AICSImage("my_file.czi", chunk_dims=["T", "Y", "X"]) Initialize an image, change scene, read data to numpy. >>> img = AICSImage("my_many_scene.czi") ... img.set_scene("Image:3") ... img.data Initialize an image with a specific reader. This is useful if you know the file type in advance or would like to skip a few of the file format checks we do internally. Useful when reading from remote sources to reduce network round trips. >>> img = AICSImage("malformed_metadata.ome.tiff", reader=readers.TiffReader) Data for a mosaic file is returned pre-stitched (if the base reader supports it). >>> img = AICSImage("big_mosaic.czi") ... img.dims # <Dimensions [T: 40, C: 3, Z: 1, Y: 30000, X: 45000]> Data for mosaic file can be explicitly returned as tiles. This is the same data as a reconstructed mosaic except that the tiles are stored in their own dimension (M). >>> img = AICSImage("big_mosaic.czi", reconstruct_mosaic=False) ... img.dims # <Dimensions [M: 150, T: 40, C: 3, Z: 1, Y: 200, X: 300]> Data is mosaic file but reader doesn't support tile stitching. >>> img = AICSImage("unsupported_mosaic.ext") ... img.dims # <Dimensions [M: 100, T: 1, C: 2, Z: 1, Y: 400, X: 400]> Notes ----- If your image is made up of mosaic tiles, data and dimension information returned from this object will be from the tiles already stitched together. If you do not want the image pre-stitched together, you can use the base reader by either instantiating the reader independently or using the `.reader` property. """ # Construct SUPPORTED_READERS as we parse FORMAT_IMPLEMENTATIONS SUPPORTED_READERS: List[Type[Reader]] = [] for reader_paths in FORMAT_IMPLEMENTATIONS.values(): for reader_path in reader_paths: try: ReaderClass = _load_reader(reader_path) if ReaderClass not in SUPPORTED_READERS: SUPPORTED_READERS.append(ReaderClass) except ImportError: pass
[docs] @staticmethod def determine_reader( image: types.ImageLike, fs_kwargs: Dict[str, Any] = {}, **kwargs: Any, ) -> Type[Reader]: """ Cheaply check to see if a given file is a recognized type and return the appropriate reader for the image. Returns ------- ReaderClass: Type[Reader] The reader that supports the provided image. Raises ------ exceptions.UnsupportedFileFormatError No reader could be found that supports the provided image. """ if isinstance(image, list) and isinstance(image[0], (str, Path)): return TiffGlobReader elif isinstance(image, str) and "*" in image: return TiffGlobReader elif isinstance(image, Path) and "*" in str(image): return TiffGlobReader # Try reader detection based off of file path extension if isinstance(image, (str, Path)): _, path = pathlike_to_fs(image, enforce_exists=True, fs_kwargs=fs_kwargs) # Check for extension in FORMAT_IMPLEMENTATIONS for format_ext, readers in FORMAT_IMPLEMENTATIONS.items(): if path.lower().endswith(f".{format_ext}"): for reader in readers: try: ReaderClass = _load_reader(reader) if ReaderClass.is_supported_image( image, fs_kwargs=fs_kwargs, ): return ReaderClass except Exception as e: # _load_readers checks all readers. # bfio readers are an optional installs. if e.__class__ == ModuleNotFoundError and ("'bfio'") in str( e ): log.info( f"Attempted file ({path}) " f"load with reader: {reader}" f"for better performance, " f"consider installing 'bfio'." ) else: log.warning( f"Attempted file ({path}) load with " f"reader: {reader} failed with error: {e}" ) # Try all known readers # Useful in cases where the provided filename is a GUID or similar # Or provided an in-memory object (arraylike) for ReaderClass in AICSImage.SUPPORTED_READERS: try: if ReaderClass.is_supported_image( image, fs_kwargs=fs_kwargs, **kwargs, # type: ignore ): return ReaderClass except Exception: pass # If we haven't hit anything yet, check for suffix and suggest a reader install if isinstance(image, (str, Path)): # Reminder that `path` variable is already populated from prior # path suffix / fast reader lookup. for format_ext, readers in FORMAT_IMPLEMENTATIONS.items(): if path.lower().endswith(f".{format_ext}"): if readers[0] in READER_TO_INSTALL: installer = READER_TO_INSTALL[readers[0]] raise exceptions.UnsupportedFileFormatError( "AICSImage", path, msg_extra=( f"File extension suggests format: '{format_ext}'. " f"Install extra format dependency with: " f"`pip install {installer}`. " f"See all known format extensions and their " f"extra install name with " f"`aicsimageio.formats.FORMAT_IMPLEMENTATIONS`. " f"If the extra dependency is already installed this " f"error may have raised because the file is " f"corrupt or similar issue. For potentially more " f"information and to help debug, try loading the file " f"directly with the desired file format reader " f"instead of with the AICSImage object." ), ) else: raise exceptions.UnsupportedFileFormatError( "AICSImage", path, ) # If we haven't hit anything yet, we likely don't support this file / object image_type = str(type(image)) raise exceptions.UnsupportedFileFormatError( "AICSImage", image_type, msg_extra=( "You may need to install an extra format dependency. " "See all known format extensions and their extra install " "name with `aicsimageio.formats.FORMAT_IMPLEMENTATIONS`." ), )
[docs] def __init__( self, image: types.ImageLike, reader: Optional[Type[Reader]] = None, reconstruct_mosaic: bool = True, fs_kwargs: Dict[str, Any] = {}, **kwargs: Any, ): if reader is None: # Determine reader class and create dask delayed array ReaderClass = self.determine_reader(image, fs_kwargs=fs_kwargs, **kwargs) else: # Init reader ReaderClass = reader # Init and store reader self._reader = ReaderClass(image, fs_kwargs=fs_kwargs, **kwargs) # Store delayed modifiers self._reconstruct_mosaic = reconstruct_mosaic # Lazy load data from reader and reformat to standard dimensions self._xarray_dask_data: Optional[xr.DataArray] = None self._xarray_data: Optional[xr.DataArray] = None self._dims: Optional[dimensions.Dimensions] = None
@property def reader(self) -> Reader: """ Returns ------- reader: Reader The object created to read the image file type. The intent is that if the AICSImage class doesn't provide a raw enough interface then the base class can be used directly. """ return self._reader @property def scenes(self) -> Tuple[str, ...]: """ Returns ------- scenes: Tuple[str, ...] A tuple of valid scene ids in the file. Notes ----- Scene IDs are strings - not a range of integers. When iterating over scenes please use: >>> for id in image.scenes and not: >>> for i in range(len(image.scenes)) """ return self.reader.scenes @property def current_scene(self) -> str: """ Returns ------- scene: str The current operating scene. """ return self.reader.current_scene @property def current_scene_index(self) -> int: """ Returns ------- scene_index: int The current operating scene index in the file. """ return self.scenes.index(self.current_scene)
[docs] def set_scene(self, scene_id: Union[str, int]) -> None: """ Set the operating scene. Parameters ---------- scene_id: Union[str, int] The scene id (if string) or scene index (if integer) to set as the operating scene. Raises ------ IndexError The provided scene id or index is not found in the available scene id list. TypeError The provided value wasn't a string (scene id) or integer (scene index). """ # Update current scene on the base Reader # This clears the base Reader's cache self.reader.set_scene(scene_id) # Reset the data stored in the AICSImage object self._xarray_dask_data = None self._xarray_data = None self._dims = None
def _transform_data_array_to_aics_image_standard( self, arr: xr.DataArray, ) -> xr.DataArray: # Determine if we need to add optionally-standard dims if ( dimensions.DimensionNames.Samples in arr.dims and dimensions.DimensionNames.MosaicTile in arr.dims ): return_dims = ( dimensions.DEFAULT_DIMENSION_ORDER_WITH_MOSAIC_TILES_AND_SAMPLES ) elif dimensions.DimensionNames.Samples in arr.dims: return_dims = dimensions.DEFAULT_DIMENSION_ORDER_WITH_SAMPLES elif dimensions.DimensionNames.MosaicTile in arr.dims: return_dims = dimensions.DEFAULT_DIMENSION_ORDER_WITH_MOSAIC_TILES else: return_dims = dimensions.DEFAULT_DIMENSION_ORDER # Pull the data with the appropriate dimensions data = transforms.reshape_data( data=arr.data, given_dims="".join(arr.dims), return_dims=return_dims, ) # Pull coordinate planes coords: Dict[str, Any] = {} for d in return_dims: if d in arr.coords: coords[d] = arr.coords[d] # Add channel coordinate plane because it is required in AICSImage if dimensions.DimensionNames.Channel not in coords: coords[dimensions.DimensionNames.Channel] = [ metadata_utils.generate_ome_channel_id( image_id=self.current_scene, channel_id=0, ) ] return xr.DataArray( data, dims=tuple([d for d in return_dims]), coords=coords, attrs=arr.attrs, ) @property def xarray_dask_data(self) -> xr.DataArray: """ Returns ------- xarray_dask_data: xr.DataArray The delayed image and metadata as an annotated data array. Notes ----- If the image contains mosaic tiles, data is returned already stitched together. """ if self._xarray_dask_data is None: if ( # Does the user want to get stitched mosaic self._reconstruct_mosaic # Does the data have a tile dim and dimensions.DimensionNames.MosaicTile in self.reader.dims.order ): try: self._xarray_dask_data = ( self._transform_data_array_to_aics_image_standard( self.reader.mosaic_xarray_dask_data ) ) # Catch reader does not support tile stitching except NotImplementedError: self._xarray_dask_data = ( self._transform_data_array_to_aics_image_standard( self.reader.xarray_dask_data ) ) else: self._xarray_dask_data = ( self._transform_data_array_to_aics_image_standard( self.reader.xarray_dask_data ) ) return self._xarray_dask_data @property def xarray_data(self) -> xr.DataArray: """ Returns ------- xarray_data: xr.DataArray The fully read image and metadata as an annotated data array. Notes ----- If the image contains mosaic tiles, data is returned already stitched together. Recommended to use `xarray_dask_data` for large mosaic images. """ if self._xarray_data is None: if ( # Does the user want to get stitched mosaic self._reconstruct_mosaic # Does the data have a tile dim and dimensions.DimensionNames.MosaicTile in self.reader.dims.order ): try: self._xarray_data = ( self._transform_data_array_to_aics_image_standard( self.reader.mosaic_xarray_data ) ) # Catch reader does not support tile stitching except NotImplementedError: self._xarray_data = ( self._transform_data_array_to_aics_image_standard( self.reader.xarray_data ) ) else: self._xarray_data = self._transform_data_array_to_aics_image_standard( self.reader.xarray_data ) # Remake the delayed xarray dataarray object using a rechunked dask array # from the just retrieved in-memory xarray dataarray self._xarray_dask_data = xr.DataArray( da.from_array(self._xarray_data.data), dims=self._xarray_data.dims, coords=self._xarray_data.coords, attrs=self._xarray_data.attrs, ) return self._xarray_data @property def dask_data(self) -> da.Array: """ Returns ------- dask_data: da.Array The image as a dask array with standard dimension ordering. Notes ----- If the image contains mosaic tiles, data is returned already stitched together. """ return self.xarray_dask_data.data @property def data(self) -> np.ndarray: """ Returns ------- data: np.ndarray The image as a numpy array with standard dimension ordering. Notes ----- If the image contains mosaic tiles, data is returned already stitched together. Recommended to use `dask_data` for large mosaic images. """ return self.xarray_data.data @property def dtype(self) -> np.dtype: """ Returns ------- dtype: np.dtype Data-type of the image array's elements. """ return self.xarray_dask_data.dtype @property def shape(self) -> Tuple[int, ...]: """ Returns ------- shape: Tuple[int, ...] Tuple of the image array's dimensions. """ return self.xarray_dask_data.shape @property def dims(self) -> dimensions.Dimensions: """ Returns ------- dims: dimensions.Dimensions Object with the paired dimension names and their sizes. """ if self._dims is None: self._dims = dimensions.Dimensions( dims=self.xarray_dask_data.dims, shape=self.shape ) return self._dims
[docs] def get_image_dask_data( self, dimension_order_out: Optional[str] = None, **kwargs: Any ) -> da.Array: """ Get specific dimension image data out of an image as a dask array. Parameters ---------- dimension_order_out: Optional[str] A string containing the dimension ordering desired for the returned ndarray. Default: dimensions.DEFAULT_DIMENSION_ORDER (with or without Samples) kwargs: Any * C=1: specifies Channel 1 * T=3: specifies the fourth index in T * D=n: D is Dimension letter and n is the index desired. D should not be present in the dimension_order_out. * D=[a, b, c]: D is Dimension letter and a, b, c is the list of indices desired. D should be present in the dimension_order_out. * D=(a, b, c): D is Dimension letter and a, b, c is the tuple of indices desired. D should be present in the dimension_order_out. * D=range(...): D is Dimension letter and range is the standard Python range function. D should be present in the dimension_order_out. * D=slice(...): D is Dimension letter and slice is the standard Python slice function. D should be present in the dimension_order_out. Returns ------- data: da.Array The image data with the specified dimension ordering. Examples -------- Specific index selection >>> img = AICSImage("s_1_t_1_c_10_z_20.ome.tiff") ... c1 = img.get_image_dask_data("ZYX", C=1) List of index selection >>> img = AICSImage("s_1_t_1_c_10_z_20.ome.tiff") ... first_and_second = img.get_image_dask_data("CZYX", C=[0, 1]) Tuple of index selection >>> img = AICSImage("s_1_t_1_c_10_z_20.ome.tiff") ... first_and_last = img.get_image_dask_data("CZYX", C=(0, -1)) Range of index selection >>> img = AICSImage("s_1_t_1_c_10_z_20.ome.tiff") ... first_three = img.get_image_dask_data("CZYX", C=range(3)) Slice selection >>> img = AICSImage("s_1_t_1_c_10_z_20.ome.tiff") ... every_other = img.get_image_dask_data("CZYX", C=slice(0, -1, 2)) Notes ----- If a requested dimension is not present in the data the dimension is added with a depth of 1. See `aicsimageio.transforms.reshape_data` for more details. """ # If no out orientation, simply return current data as dask array if dimension_order_out is None: return self.dask_data # Transform and return return transforms.reshape_data( data=self.dask_data, given_dims=self.dims.order, return_dims=dimension_order_out, **kwargs, )
[docs] def get_image_data( self, dimension_order_out: Optional[str] = None, **kwargs: Any ) -> np.ndarray: """ Read the image as a numpy array then return specific dimension image data. Parameters ---------- dimension_order_out: Optional[str] A string containing the dimension ordering desired for the returned ndarray. Default: dimensions.DEFAULT_DIMENSION_ORDER (with or without Samples) kwargs: Any * C=1: specifies Channel 1 * T=3: specifies the fourth index in T * D=n: D is Dimension letter and n is the index desired. D should not be present in the dimension_order_out. * D=[a, b, c]: D is Dimension letter and a, b, c is the list of indices desired. D should be present in the dimension_order_out. * D=(a, b, c): D is Dimension letter and a, b, c is the tuple of indices desired. D should be present in the dimension_order_out. * D=range(...): D is Dimension letter and range is the standard Python range function. D should be present in the dimension_order_out. * D=slice(...): D is Dimension letter and slice is the standard Python slice function. D should be present in the dimension_order_out. Returns ------- data: np.ndarray The image data with the specified dimension ordering. Examples -------- Specific index selection >>> img = AICSImage("s_1_t_1_c_10_z_20.ome.tiff") ... c1 = img.get_image_data("ZYX", C=1) List of index selection >>> img = AICSImage("s_1_t_1_c_10_z_20.ome.tiff") ... first_and_second = img.get_image_data("CZYX", C=[0, 1]) Tuple of index selection >>> img = AICSImage("s_1_t_1_c_10_z_20.ome.tiff") ... first_and_last = img.get_image_data("CZYX", C=(0, -1)) Range of index selection >>> img = AICSImage("s_1_t_1_c_10_z_20.ome.tiff") ... first_three = img.get_image_dask_data("CZYX", C=range(3)) Slice selection >>> img = AICSImage("s_1_t_1_c_10_z_20.ome.tiff") ... every_other = img.get_image_data("CZYX", C=slice(0, -1, 2)) Notes ----- * If a requested dimension is not present in the data the dimension is added with a depth of 1. * This will preload the entire image before returning the requested data. See `aicsimageio.transforms.reshape_data` for more details. """ # If no out orientation, simply return current data as dask array if dimension_order_out is None: return self.data # Transform and return return transforms.reshape_data( data=self.data, given_dims=self.dims.order, return_dims=dimension_order_out, **kwargs, )
[docs] def get_stack(self, **kwargs: Any) -> np.ndarray: """ Get all scenes stacked in to a single array. Returns ------- stack: np.ndarray The fully stacked array. This can be 6+ dimensions with Scene being the first dimension. kwargs: Any Extra keyword arguments that will be passed down to the generate stack function. See Also -------- aicsimageio.transforms.generate_stack: Underlying function for generating various scene stacks. """ return transforms.generate_stack(self, "data", **kwargs)
[docs] def get_dask_stack(self, **kwargs: Any) -> da.Array: """ Get all scenes stacked in to a single array. Returns ------- stack: da.Array The fully stacked array. This can be 6+ dimensions with Scene being the first dimension. kwargs: Any Extra keyword arguments that will be passed down to the generate stack function. See Also -------- aicsimageio.transforms.generate_stack: Underlying function for generating various scene stacks. """ return transforms.generate_stack(self, "dask_data", **kwargs)
[docs] def get_xarray_stack(self, **kwargs: Any) -> xr.DataArray: """ Get all scenes stacked in to a single array. Returns ------- stack: xr.DataArray The fully stacked array. This can be 6+ dimensions with Scene being the first dimension. kwargs: Any Extra keyword arguments that will be passed down to the generate stack function. See Also -------- aicsimageio.transforms.generate_stack: Underlying function for generating various scene stacks. Notes ----- When requesting an xarray stack, the first scene's coordinate planes are used for the returned xarray DataArray object coordinate planes. """ return transforms.generate_stack(self, "xarray_data", **kwargs)
[docs] def get_xarray_dask_stack(self, **kwargs: Any) -> xr.DataArray: """ Get all scenes stacked in to a single array. Returns ------- stack: xr.DataArray The fully stacked array. This can be 6+ dimensions with Scene being the first dimension. kwargs: Any Extra keyword arguments that will be passed down to the generate stack function. See Also -------- aicsimageio.transforms.generate_stack: Underlying function for generating various scene stacks. Notes ----- When requesting an xarray stack, the first scene's coordinate planes are used for the returned xarray DataArray object coordinate planes. """ return transforms.generate_stack(self, "xarray_dask_data", **kwargs)
@property def metadata(self) -> Any: """ Returns ------- metadata: Any Passthrough to the base image reader metadata property. For more information, see the specific image format reader you are using for details on its metadata property. """ return self.reader.metadata @property def ome_metadata(self) -> OME: """ Returns ------- metadata: OME The original metadata transformed into the OME specfication. This likely isn't a complete transformation but is guarenteed to be a valid transformation. Raises ------ NotImplementedError No metadata transformer available. """ return self.reader.ome_metadata @property def channel_names(self) -> List[str]: """ Returns ------- channel_names: List[str] Using available metadata, the list of strings representing channel names. """ # Unlike the base readers, the AICSImage guarantees a Channel dim return list(self.xarray_dask_data[dimensions.DimensionNames.Channel].values) @property def physical_pixel_sizes(self) -> PhysicalPixelSizes: """ Returns ------- sizes: PhysicalPixelSizes Using available metadata, the floats representing physical pixel sizes for dimensions Z, Y, and X. Notes ----- We currently do not handle unit attachment to these values. Please see the file metadata for unit information. """ return self.reader.physical_pixel_sizes
[docs] def get_mosaic_tile_position( self, mosaic_tile_index: int, **kwargs: int ) -> Tuple[int, int]: """ Get the absolute position of the top left point for a single mosaic tile. Parameters ---------- mosaic_tile_index: int The index for the mosaic tile to retrieve position information for. kwargs: int The keywords below allow you to specify the dimensions that you wish to match. If you under-specify the constraints you can easily end up with a massive image stack. Z = 1 # The Z-dimension. C = 2 # The C-dimension ("channel"). T = 3 # The T-dimension ("time"). Returns ------- top: int The Y coordinate for the tile position. left: int The X coordinate for the tile position. Raises ------ UnexpectedShapeError The image has no mosaic dimension available. """ return self.reader.get_mosaic_tile_position(mosaic_tile_index, **kwargs)
[docs] def get_mosaic_tile_positions(self, **kwargs: int) -> List[Tuple[int, int]]: """ Get the absolute positions of the top left points for each mosaic tile matching the specified dimensions and current scene. Parameters ---------- kwargs: int The keywords below allow you to specify the dimensions that you wish to match. If you under-specify the constraints you can easily end up with a massive image stack. Z = 1 # The Z-dimension. C = 2 # The C-dimension ("channel"). T = 3 # The T-dimension ("time"). M = 4 # The mosaic tile index Returns ------- mosaic_tile_positions: List[Tuple[int, int]] List of the Y and X coordinate for the tile positions. Raises ------ UnexpectedShapeError The image has no mosaic dimension available. NotImplementedError Unable to combine M dimension with other dimensions when finding tiles matching kwargs """ if dimensions.DimensionNames.MosaicTile in kwargs: # Don't support getting positions by M + another dim if len(kwargs) != 1: other_keys = { key for key in kwargs if key != dimensions.DimensionNames.MosaicTile } raise NotImplementedError( "Unable to determine appropriate position using mosaic tile " + "index (M) combined with other dimensions " + f"(including {other_keys})" ) return [ self.get_mosaic_tile_position( kwargs[dimensions.DimensionNames.MosaicTile] ) ] return self.reader.get_mosaic_tile_positions(**kwargs)
@property def mosaic_tile_dims(self) -> Optional[dimensions.Dimensions]: """ Returns ------- tile_dims: Optional[Dimensions] The dimensions for each tile in the mosaic image. If the image is not a mosaic image, returns None. """ return self.reader.mosaic_tile_dims
[docs] def save( self, uri: types.PathLike, select_scenes: Optional[Union[List[str], Tuple[str, ...]]] = None, ) -> None: """ Saves the file data to OME-TIFF format with general naive best practices. Parameters ---------- uri: types.PathLike The URI or local path for where to save the data. Note: Can only write to local file systems. select_scenes: Optional[Union[List[str], Tuple[str, ...]]] Which scenes in the image to save to the file. Default: None (save all scenes) Notes ----- See `aicsimageio.writers.OmeTiffWriter` for more in-depth specification and the `aicsimageio.writers` module as a whole for list of all available file writers. When reading in the produced OME-TIFF file, scenes IDs may have changed. This is due to how certain file and metadata formats do or do-not have IDs and simply names. In converting to OME-TIFF we will always store the scene ids in each Image's name attribute but IDs will be generated. The order of the scenes will be the same (or whatever order was specified / provided). """ from .writers import OmeTiffWriter # Get all parameters as dict of lists, or static because of unchanging values datas: List[types.ArrayLike] = [] dim_orders: List[Optional[str]] = [] channel_names: List[Optional[List[str]]] = [] image_names: List[Optional[str]] = [] physical_pixel_sizes: List[PhysicalPixelSizes] = [] # Get selected scenes / handle None scenes if select_scenes is None: select_scenes = self.scenes # Iter through scenes to get data for scene in select_scenes: self.set_scene(scene) # Append this scene details datas.append(self.dask_data) dim_orders.append(self.dims.order) channel_names.append(self.channel_names) image_names.append(self.current_scene) physical_pixel_sizes.append(self.physical_pixel_sizes) # Save all selected scenes OmeTiffWriter.save( data=datas, uri=uri, dim_order=dim_orders, channel_names=channel_names, image_name=image_names, physical_pixel_sizes=physical_pixel_sizes, )
def __str__(self) -> str: return ( f"<AICSImage [" f"Reader: {type(self.reader).__name__}, " f"Image-is-in-Memory: {self._xarray_data is not None}" f"]>" ) def __repr__(self) -> str: return str(self)
def _construct_img( image: types.ImageLike, scene_id: Optional[str] = None, **kwargs: Any ) -> AICSImage: # Construct image img = AICSImage(image, **kwargs) # Select scene if scene_id is not None: img.set_scene(scene_id) return img
[docs]def imread_xarray_dask( image: types.ImageLike, scene_id: Optional[str] = None, **kwargs: Any, ) -> xr.DataArray: """ Read image as a delayed xarray DataArray. Parameters ---------- image: types.ImageLike A string, Path, fsspec supported URI, or arraylike to read. scene_id: Optional[str] An optional scene id to create the DataArray with. Default: None (First Scene) kwargs: Any Extra keyword arguments to be passed down to the AICSImage and Reader subclass. Returns ------- data: xr.DataArray The image read, scene selected, and returned as an AICS standard shaped delayed xarray DataArray. """ return _construct_img(image, scene_id, **kwargs).xarray_dask_data
[docs]def imread_dask( image: types.ImageLike, scene_id: Optional[str] = None, **kwargs: Any, ) -> da.Array: """ Read image as a delayed dask array. Parameters ---------- image: types.ImageLike A string, Path, fsspec supported URI, or arraylike to read. scene_id: Optional[str] An optional scene id to create the dask array with. Default: None (First Scene) kwargs: Any Extra keyword arguments to be passed down to the AICSImage and Reader subclass. Returns ------- data: da.core.Array The image read, scene selected, and returned as an AICS standard shaped delayed dask array. """ return _construct_img(image, scene_id, **kwargs).dask_data
[docs]def imread_xarray( image: types.ImageLike, scene_id: Optional[str] = None, **kwargs: Any, ) -> xr.DataArray: """ Read image as an in-memory xarray DataArray. Parameters ---------- image: types.ImageLike A string, Path, fsspec supported URI, or arraylike to read. scene_id: Optional[str] An optional scene id to create the DataArray with. Default: None (First Scene) kwargs: Any Extra keyword arguments to be passed down to the AICSImage and Reader subclass. Returns ------- data: xr.DataArray The image read, scene selected, and returned as an AICS standard shaped in-memory DataArray. """ return _construct_img(image, scene_id, **kwargs).xarray_data
[docs]def imread( image: types.ImageLike, scene_id: Optional[str] = None, **kwargs: Any, ) -> np.ndarray: """ Read image as a numpy array. Parameters ---------- image: types.ImageLike A string, Path, fsspec supported URI, or arraylike to read. scene_id: Optional[str] An optional scene id to create the numpy array with. Default: None (First Scene) kwargs: Any Extra keyword arguments to be passed down to the AICSImage and Reader subclass. Returns ------- data: np.ndarray The image read, scene selected, and returned as an AICS standard shaped np.ndarray. """ return _construct_img(image, scene_id, **kwargs).data