Exemple #1
0
    def __init__(
            self,
            pixel_ticks: Union[Mapping[Axes, ArrayLike[int]], Mapping[str, ArrayLike[int]]],
            physical_ticks: Union[Mapping[Coordinates, ArrayLike[Number]],
                                  Mapping[str, ArrayLike[Number]]],
            masks: Sequence[MaskData],
            log: Optional[Log],
    ):
        self._pixel_ticks: Mapping[Axes, ArrayLike[int]] = _normalize_pixel_ticks(pixel_ticks)
        self._physical_ticks: Mapping[Coordinates, ArrayLike[Number]] = _normalize_physical_ticks(
            physical_ticks)
        self._masks: MutableMapping[int, MaskData] = {}
        self._log: Log = log or Log()

        for ix, mask_data in enumerate(masks):
            if mask_data.binary_mask.ndim not in (2, 3):
                raise TypeError(f"expected 2 or 3 dimensions; got {mask_data.binary_mask.ndim}")
            if mask_data.binary_mask.dtype != bool:
                raise ValueError(f"expected dtype of bool; got {mask_data.binary_mask.dtype}")

            self._masks[ix] = mask_data

        if len(self._pixel_ticks) != len(self._physical_ticks):
            raise ValueError(
                "pixel_ticks should have the same cardinality as physical_ticks")
        for axis, coord in zip(*_get_axes_names(len(self._pixel_ticks))):
            if axis not in self._pixel_ticks:
                raise ValueError(f"pixel ticks missing {axis.value} data")
            if coord not in self._physical_ticks:
                raise ValueError(f"physical coordinate ticks missing {coord.value} data")
            if len(self._pixel_ticks[axis]) != len(self._physical_ticks[coord]):
                raise ValueError(
                    f"pixel ticks for {axis.name} does not have the same cardinality as physical "
                    f"coordinates ticks for {coord.name}")
Exemple #2
0
 def __init__(self,
              data: xr.DataArray,
              tile_data: Optional[TileCollectionData] = None):
     self._data = data
     self._data_loaded = False
     self._tile_data = tile_data
     self._log: Log = Log()
Exemple #3
0
    def read_binary_mask(self, tf: tarfile.TarFile) -> bm.BinaryMaskCollection:
        log: Optional[Log] = None
        masks: MutableSequence[bm.MaskData] = []
        pixel_ticks: Optional[Mapping[Axes, ArrayLike[int]]] = None
        physical_ticks: Optional[Mapping[Coordinates,
                                         ArrayLike[Number]]] = None

        while True:
            tarinfo: Optional[tarfile.TarInfo] = tf.next()
            if tarinfo is None:
                break

            # wrap it in a BytesIO object to ensure we never seek backwards.
            extracted_fh = tf.extractfile(tarinfo)
            if extracted_fh is None:
                raise ValueError(f"Unable to extract file {tarinfo.name}")
            byte_stream = io.BytesIO(extracted_fh.read())

            if tarinfo.name == v0_0.LOG_FILENAME:
                string_stream = codecs.getreader("utf-8")(byte_stream)
                log = Log.decode(string_stream.read())
            elif tarinfo.name == v0_0.PIXEL_TICKS_FILE:
                pixel_ticks = pickle.load(byte_stream)
            elif tarinfo.name == v0_0.PHYSICAL_TICKS_FILE:
                physical_ticks = pickle.load(byte_stream)
            elif tarinfo.name.startswith(v0_0.MASK_PREFIX):
                mask_on_disk: v0_0.MaskOnDisk = pickle.load(byte_stream)
                if not isinstance(mask_on_disk, v0_0.MaskOnDisk):
                    raise TypeError(
                        f"mask does not conform to expected mask structure")
                masks.append(
                    bm.MaskData(mask_on_disk.binary_mask, mask_on_disk.offsets,
                                None))
            else:
                warnings.warn(
                    f"Unexpected file in binary mask collection {tarinfo.name}",
                    DataFormatWarning)

        if pixel_ticks is None:
            raise ValueError("pixel coordinates not found")
        if physical_ticks is None:
            raise ValueError("physical coordinates not found")

        return bm.BinaryMaskCollection(pixel_ticks, physical_ticks, masks, log)
Exemple #4
0
    def __init__(self, label_image: xr.DataArray):
        # verify that the data array has the required elements.
        if label_image.dtype.kind not in ("i", "u"):
            raise TypeError("label image should be an integer type")
        for axis in (Axes.X, Axes.Y):
            if axis.value not in label_image.coords:
                raise ValueError(
                    f"label image should have an {axis.value} axis")
        expected_physical_coordinates: Tuple[Coordinates, ...]
        if label_image.ndim == 5:
            expected_physical_coordinates = (Coordinates.X, Coordinates.Y,
                                             Coordinates.Z)
        else:
            expected_physical_coordinates = (Coordinates.X, Coordinates.Y)
        for coord in expected_physical_coordinates:
            if coord.value not in label_image.coords:
                raise ValueError(
                    f"label image should have a {coord.value} coordinates")

        self.label_image = label_image.copy(deep=False)
        if AttrKeys.DOCTYPE not in self.label_image.attrs:
            self.label_image.attrs[AttrKeys.DOCTYPE] = DOCTYPE_STRING
        if AttrKeys.LOG not in self.label_image.attrs:
            self.label_image.attrs[AttrKeys.LOG] = Log().encode()
Exemple #5
0
    def from_label_array_and_ticks(
        cls,
        array: np.ndarray,
        pixel_ticks: Optional[Union[Mapping[Axes, ArrayLike[int]],
                                    Mapping[str, ArrayLike[int]]]],
        physical_ticks: Union[Mapping[Coordinates, ArrayLike[Number]],
                              Mapping[str, ArrayLike[Number]]],
        log: Optional[Log],
    ) -> "LabelImage":
        """Constructs a LabelImage from an array containing the labels, a set of physical
        coordinates, and an optional log of how this label image came to be.

        Parameters
        ----------
        array : np.ndarray
            A 2D or 3D array containing the labels.  The ordering of the axes must be Y, X for 2D
            images and ZPLANE, Y, X for 3D images.
        pixel_ticks : Optional[Union[Mapping[Axes, ArrayLike[int]], Mapping[str, ArrayLike[int]]]]
            A map from the axis to the values for that axis.  For any axis that exist in the array
            but not in pixel_coordinates, the pixel coordinates are assigned from 0..N-1, where N is
            the size along that axis.
        physical_ticks : Union[Mapping[Coordinates, ArrayLike[Number]], Mapping[str,
        ArrayLike[Number]]]
            A map from the physical coordinate type to the values for axis.  For 2D label images,
            X and Y physical coordinates must be provided.  For 3D label images, Z physical
            coordinates must also be provided.
        log : Optional[Log]
            A log of how this label image came to be.
        """
        # normalize the pixel coordinates to Mapping[Axes, ArrayLike[int]]
        pixel_ticks = _normalize_pixel_ticks(pixel_ticks)
        # normalize the physical coordinates to Mapping[Coordinates, ArrayLike[Number]]
        physical_ticks = _normalize_physical_ticks(physical_ticks)

        img_axes, img_coords = _get_axes_names(array.ndim)
        xr_axes = [axis.value for axis in img_axes]
        try:
            xr_coords: MutableMapping[Hashable, Any] = {
                coord.value: (axis.value, physical_ticks[coord])
                for axis, coord in zip(img_axes, img_coords)
            }
        except KeyError as ex:
            raise KeyError(
                f"missing physical coordinates {ex.args[0]}") from ex

        for ix, axis in enumerate(img_axes):
            xr_coords[axis.value] = pixel_ticks.get(
                axis, np.arange(0, array.shape[ix]))

        dataarray = xr.DataArray(
            array,
            dims=xr_axes,
            coords=xr_coords,
        )
        dataarray.attrs.update({
            AttrKeys.LOG: (log or Log()).encode(),
            AttrKeys.DOCTYPE: DOCTYPE_STRING,
            AttrKeys.VERSION: str(CURRENT_VERSION),
        })

        return LabelImage(dataarray)
Exemple #6
0
 def log(self) -> Log:
     """Returns a copy of the provenance data.  Modifications to this copy will not affect the
     log stored on this label image."""
     return Log.decode(self.label_image.attrs[AttrKeys.LOG])