def build_irregular_image( tile_identifiers: Iterable[TileIdentifier], image_fetcher: TileFetcher, default_shape: Optional[Mapping[Axes, int]] = None, ) -> Collection: """ Build and returns an image set that can potentially be irregular (i.e., the cardinality of the dimensions are not always consistent). It can also build a regular image. Parameters ---------- tile_identifiers : Iterable[TileIdentifier] Iterable of all the TileIdentifier that are valid in the image. image_fetcher : TileFetcher Instance of TileFetcher that provides the data for the tile. default_shape : Optional[Tuple[int, int]] Default shape of the individual tiles in this image set. Returns ------- The slicedimage collection representing the image. """ def reducer_to_sets( accumulated: Sequence[MutableSet[int]], update: TileIdentifier, ) -> Sequence[MutableSet[int]]: """Reduces to a list of sets of tile identifiers, in the order of FOV, round, ch, and zplane.""" result: MutableSequence[MutableSet[int]] = list() for accumulated_elem, update_elem in zip(accumulated, astuple(update)): accumulated_elem.add(update_elem) result.append(accumulated_elem) return result initial_value: Sequence[MutableSet[int]] = tuple(set() for _ in range(4)) fovs, rounds, chs, zplanes = functools.reduce( reducer_to_sets, tile_identifiers, initial_value) collection = Collection() for expected_fov in fovs: fov_images = TileSet( [ Coordinates.X, Coordinates.Y, Coordinates.Z, Axes.ZPLANE, Axes.ROUND, Axes.CH, Axes.X, Axes.Y, ], {Axes.ROUND: len(rounds), Axes.CH: len(chs), Axes.ZPLANE: len(zplanes)}, default_shape, ImageFormat.TIFF, ) for tile_identifier in tile_identifiers: current_fov, current_round, current_ch, current_zplane = astuple(tile_identifier) # filter out the fovs that are not the one we are currently processing if expected_fov != current_fov: continue image = image_fetcher.get_tile( current_fov, current_round, current_ch, current_zplane ) tile = Tile( image.coordinates, { Axes.ZPLANE: current_zplane, Axes.ROUND: current_round, Axes.CH: current_ch, }, image.shape, extras=image.extras, ) tile.set_numpy_array_future(image.tile_data) # Astute readers might wonder why we set this variable. This is to support in-place # experiment construction. We monkey-patch slicedimage's Tile class such that checksum # computation is done by finding the FetchedTile object, which allows us to calculate # the checksum of the original file. tile.provider = image fov_images.add_tile(tile) collection.add_partition("fov_{:03}".format(expected_fov), fov_images) return collection
def build_image( fovs: Sequence[int], rounds: Sequence[int], chs: Sequence[int], zplanes: Sequence[int], image_fetcher: TileFetcher, default_shape: Optional[Mapping[Axes, int]] = None, axes_order: Sequence[Axes] = DEFAULT_DIMENSION_ORDER, ) -> Collection: """ Build and returns an image set with the following characteristics: Parameters ---------- fovs : Sequence[int] Sequence of field of view ids in this image set. rounds : Sequence[int] Sequence of the round numbers in this image set. chs : Sequence[int] Sequence of the ch numbers in this image set. zplanes : Sequence[int] Sequence of the zplane numbers in this image set. image_fetcher : TileFetcher Instance of TileFetcher that provides the data for the tile. default_shape : Optional[Tuple[int, int]] Default shape of the individual tiles in this image set. axes_order : Sequence[Axes] Ordering for which axes vary, in order of the slowest changing axis to the fastest. For instance, if the order is (ROUND, Z, CH) and each dimension has size 2, then the sequence is: (ROUND=0, CH=0, Z=0) (ROUND=0, CH=1, Z=0) (ROUND=0, CH=0, Z=1) (ROUND=0, CH=1, Z=1) (ROUND=1, CH=0, Z=0) (ROUND=1, CH=1, Z=0) (ROUND=1, CH=0, Z=1) (ROUND=1, CH=1, Z=1) (default = (Axes.Z, Axes.ROUND, Axes.CH)) Returns ------- The slicedimage collection representing the image. """ axes_sizes = join_axes_labels(axes_order, rounds=rounds, chs=chs, zplanes=zplanes) collection = Collection() for fov_id in fovs: fov_images = TileSet( [ Coordinates.X, Coordinates.Y, Coordinates.Z, Axes.ZPLANE, Axes.ROUND, Axes.CH, Axes.X, Axes.Y, ], { Axes.ROUND: len(rounds), Axes.CH: len(chs), Axes.ZPLANE: len(zplanes) }, default_shape, ImageFormat.TIFF, ) for selector in ordered_iterator(axes_sizes): image = image_fetcher.get_tile(fov_id, selector[Axes.ROUND], selector[Axes.CH], selector[Axes.ZPLANE]) tile = Tile( image.coordinates, { Axes.ZPLANE: (selector[Axes.ZPLANE]), Axes.ROUND: (selector[Axes.ROUND]), Axes.CH: (selector[Axes.CH]), }, image.shape, extras=image.extras, ) tile.set_numpy_array_future(image.tile_data) # Astute readers might wonder why we set this variable. This is to support in-place # experiment construction. We monkey-patch slicedimage's Tile class such that checksum # computation is done by finding the FetchedTile object, which allows us to calculate # the checksum of the original file. tile.provider = image fov_images.add_tile(tile) collection.add_partition("fov_{:03}".format(fov_id), fov_images) return collection