Exemple #1
0
    def parse_coordinate_groups(tileset: TileSet) -> List["CropParameters"]:
        """Takes a tileset and compares the physical coordinates on each tile to
         create aligned coordinate groups (groups of tiles that have the same physical coordinates)

         Returns
         -------
         A list of CropParameters. Each entry describes the r/ch/z values of tiles that are aligned
         (have matching coordinates)
         """
        coord_groups: OrderedDict[tuple, CropParameters] = OrderedDict()
        for tile in tileset.tiles():
            x_y_coords = (tile.coordinates[Coordinates.X][0],
                          tile.coordinates[Coordinates.X][1],
                          tile.coordinates[Coordinates.Y][0],
                          tile.coordinates[Coordinates.Y][1])
            # A tile with this (x, y) has already been seen, add tile's Indices to CropParameters
            if x_y_coords in coord_groups:
                crop_params = coord_groups[x_y_coords]
                crop_params._add_permitted_axes(Axes.CH, tile.indices[Axes.CH])
                crop_params._add_permitted_axes(Axes.ROUND,
                                                tile.indices[Axes.ROUND])
                if Axes.ZPLANE in tile.indices:
                    crop_params._add_permitted_axes(Axes.ZPLANE,
                                                    tile.indices[Axes.ZPLANE])
            else:
                coord_groups[x_y_coords] = CropParameters(
                    permitted_chs=[tile.indices[Axes.CH]],
                    permitted_rounds=[tile.indices[Axes.ROUND]],
                    permitted_zplanes=[tile.indices[Axes.ZPLANE]]
                    if Axes.ZPLANE in tile.indices else None)
        return list(coord_groups.values())
Exemple #2
0
 def __init__(self, tileset: TileSet) -> None:
     self.tiles: MutableMapping[TileKey, Tile] = dict()
     for tile in tileset.tiles():
         key = TileKey(
             round=tile.indices[Axes.ROUND],
             ch=tile.indices[Axes.CH],
             zplane=tile.indices.get(Axes.ZPLANE, 0))
         self.tiles[key] = tile
     self._extras = tileset.extras
     self._expectations = _TileSetConsistencyDetector()
Exemple #3
0
    def __init__(self, tileset: TileSet) -> None:
        tile_extras: MutableMapping[TileKey, dict] = dict()
        for tile in tileset.tiles():
            round_ = tile.indices[Indices.ROUND]
            ch = tile.indices[Indices.CH]
            z = tile.indices.get(Indices.Z, 0)

            tile_extras[TileKey(round=round_, ch=ch, z=z)] = tile.extras

        self.tile_extras: Mapping[TileKey, dict] = tile_extras
        self._extras = tileset.extras
Exemple #4
0
    def __init__(self, tileset: TileSet) -> None:
        self._tile_shape = tileset.default_tile_shape

        self.tiles: MutableMapping[TileKey, Tile] = dict()
        for tile in tileset.tiles():
            key = TileKey(round=tile.indices[Axes.ROUND],
                          ch=tile.indices[Axes.CH],
                          zplane=tile.indices.get(Axes.ZPLANE, 0))
            self.tiles[key] = tile

            # if we don't have the tile shape, then we peek at the tile and get its shape.
            if self._tile_shape is None:
                self._tile_shape = tile.tile_shape

        self._extras = tileset.extras
Exemple #5
0
    def parse_aligned_groups(
            tileset: TileSet,
            rounds: Optional[Collection[int]] = None,
            chs: Optional[Collection[int]] = None,
            zplanes: Optional[Collection[int]] = None,
            x: Optional[Union[int, slice]] = None,
            y: Optional[Union[int, slice]] = None) -> List["CropParameters"]:
        """Takes a tileset and any optional selected axes lists compares the physical coordinates on each
         tile to create aligned coordinate groups (groups of tiles that have the same physical
         coordinates)

        Parameters
        ----------
        tileset: TileSet
            The TileSet to parse
        rounds: Optional[Collection[int]]
            The rounds in the tileset to include in the final aligned groups. If this is not set,
            then all rounds are included.
        chs: Optional[Collection[int]]
            The chs in the tileset to include in the final aligned groups. If this is not set,
            then all chs are included.
        zplanes: Optional[Collection[int]]
            The zplanes in the tileset to include in the final aligned groups. If this is not set,
            then all zplanes are included.
        x: Optional[Union[int, slice]]
            The x-range in the x-y tile to include in the final aligned groups.  If this is not set,
            then the entire x-y tile is included.
        y: Optional[Union[int, slice]]
            The y-range in the x-y tile to include in the final aligned groups.  If this is not set,
            then the entire x-y tile is included.

         Returns
         -------
         List["CropParameters"]
             A list of CropParameters. Each entry describes the r/ch/z values of tiles that are
             aligned (have matching coordinates) and are within the selected_axes if provided.
         """
        coord_groups: OrderedDict[tuple, CropParameters] = OrderedDict()
        for tile in tileset.tiles():
            if CropParameters.tile_in_selected_axes(tile, rounds, chs,
                                                    zplanes):
                x_y_coords = (tile.coordinates[Coordinates.X][0],
                              tile.coordinates[Coordinates.X][1],
                              tile.coordinates[Coordinates.Y][0],
                              tile.coordinates[Coordinates.Y][1])
                # A tile with this (x, y) has already been seen, add tile's indices to
                # CropParameters
                if x_y_coords in coord_groups:
                    crop_params = coord_groups[x_y_coords]
                    crop_params._add_permitted_axes(Axes.CH,
                                                    tile.indices[Axes.CH])
                    crop_params._add_permitted_axes(Axes.ROUND,
                                                    tile.indices[Axes.ROUND])
                    if Axes.ZPLANE in tile.indices:
                        crop_params._add_permitted_axes(
                            Axes.ZPLANE, tile.indices[Axes.ZPLANE])
                else:
                    coord_groups[x_y_coords] = CropParameters(
                        permitted_chs=[tile.indices[Axes.CH]],
                        permitted_rounds=[tile.indices[Axes.ROUND]],
                        permitted_zplanes=[tile.indices[Axes.ZPLANE]]
                        if Axes.ZPLANE in tile.indices else None,
                        x_slice=x,
                        y_slice=y)
        return list(coord_groups.values())
Exemple #6
0
    def __init__(self, tileset: TileSet) -> None:
        self._num_rounds = ImageStack._get_dimension_size(
            tileset, Indices.ROUND)
        self._num_chs = ImageStack._get_dimension_size(tileset, Indices.CH)
        self._num_zlayers = ImageStack._get_dimension_size(tileset, Indices.Z)
        self._tile_metadata = TileSetData(tileset)
        self._tile_shape = tileset.default_tile_shape

        # Examine the tiles to figure out the right kind (int, float, etc.) and size.  We require
        # that all the tiles have the same kind of data type, but we do not require that they all
        # have the same size of data type. The # allocated array is the highest size we encounter.
        kind = None
        max_size = 0
        for tile in tqdm(tileset.tiles(),
                         disable=(not StarfishConfig().verbose)):
            dtype = tile.numpy_array.dtype
            if kind is None:
                kind = dtype.kind
            else:
                if kind != dtype.kind:
                    raise TypeError(
                        "All tiles should have the same kind of dtype")
            if dtype.itemsize > max_size:
                max_size = dtype.itemsize
            if self._tile_shape is None:
                self._tile_shape = tile.tile_shape
            elif tile.tile_shape is not None and self._tile_shape != tile.tile_shape:
                raise ValueError(
                    "Starfish does not support tiles that are not identical in shape"
                )

        shape: MutableSequence[int] = []
        dims: MutableSequence[str] = []
        coordinates_shape: MutableSequence[int] = []
        coordinates_dimensions: MutableSequence[str] = []
        coordinates_tick_marks: MutableMapping[str,
                                               Sequence[Union[int,
                                                              str]]] = dict()
        for ix in range(N_AXES):
            size_for_axis: Optional[int] = None
            dim_for_axis: Optional[Indices] = None

            for axis_name, axis_data in AXES_DATA.items():
                if ix == axis_data.order:
                    size_for_axis = ImageStack._get_dimension_size(
                        tileset, axis_name)
                    dim_for_axis = axis_name
                    break

            if size_for_axis is None or dim_for_axis is None:
                raise ValueError(
                    f"Could not find entry for the {ix}th axis in AXES_DATA")

            shape.append(size_for_axis)
            dims.append(dim_for_axis.value)
            coordinates_shape.append(size_for_axis)
            coordinates_dimensions.append(dim_for_axis.value)
            coordinates_tick_marks[dim_for_axis.value] = list(
                range(size_for_axis))

        shape.extend(self._tile_shape)
        dims.extend([Indices.Y.value, Indices.X.value])
        coordinates_shape.append(6)
        coordinates_dimensions.append(PHYSICAL_COORDINATE_DIMENSION)
        coordinates_tick_marks[PHYSICAL_COORDINATE_DIMENSION] = [
            PhysicalCoordinateTypes.X_MIN.value,
            PhysicalCoordinateTypes.X_MAX.value,
            PhysicalCoordinateTypes.Y_MIN.value,
            PhysicalCoordinateTypes.Y_MAX.value,
            PhysicalCoordinateTypes.Z_MIN.value,
            PhysicalCoordinateTypes.Z_MAX.value,
        ]
        # now that we know the tile data type (kind and size), we can allocate the data array.
        self._data = MPDataArray.from_shape_and_dtype(
            shape=shape,
            dtype=np.float32,
            initial_value=0,
            dims=dims,
        )
        self._coordinates = xr.DataArray(
            np.empty(
                shape=coordinates_shape,
                dtype=np.float32,
            ),
            dims=coordinates_dimensions,
            coords=coordinates_tick_marks,
        )

        # iterate through the tiles and set the data.
        for tile in tileset.tiles():
            h = tile.indices[Indices.ROUND]
            c = tile.indices[Indices.CH]
            zlayer = tile.indices.get(Indices.Z, 0)
            data = tile.numpy_array

            if max_size != data.dtype.itemsize:
                warnings.warn(
                    f"Tile "
                    f"(R: {tile.indices[Indices.ROUND]} C: {tile.indices[Indices.CH]} "
                    f"Z: {tile.indices[Indices.Z]}) has "
                    f"dtype {data.dtype}.  One or more tiles is of a larger dtype "
                    f"{self._data.dtype}.", DataFormatWarning)

            data = img_as_float32(data)
            self.set_slice(indices={
                Indices.ROUND: h,
                Indices.CH: c,
                Indices.Z: zlayer
            },
                           data=data)
            coordinate_selector = {
                Indices.ROUND.value: h,
                Indices.CH.value: c,
                Indices.Z.value: zlayer,
            }
            coordinates_values = [
                tile.coordinates[Coordinates.X][0],
                tile.coordinates[Coordinates.X][1],
                tile.coordinates[Coordinates.Y][0],
                tile.coordinates[Coordinates.Y][1],
            ]
            if Coordinates.Z in tile.coordinates:
                coordinates_values.extend([
                    tile.coordinates[Coordinates.Z][0],
                    tile.coordinates[Coordinates.Z][1],
                ])
            else:
                coordinates_values.extend([np.nan, np.nan])

            self._coordinates.loc[coordinate_selector] = np.array(
                coordinates_values)