示例#1
0
def test_bgr_plane_data_x(data_dir, fname, p_index, ans_file):
    ans = np.load(data_dir / ans_file)
    with open(data_dir / fname, 'rb') as fp:
        czi = CziFile(czi_filename=fp)
        img, dims = czi.read_image()
        assert img[0, p_index, :, :].shape == ans.shape
        np.testing.assert_array_almost_equal(img[0, p_index, :, :], ans)
def _read_image(
    img: Path,
    read_dims: Optional[Dict[str, int]] = None
) -> Tuple[np.ndarray, List[Tuple[str, int]]]:
    # Catch optional read dim
    if read_dims is None:
        read_dims = {}

    # Init czi
    czi = CziFile(img)

    # Read image
    log.debug(f"Reading dimensions: {read_dims}")
    data, dims = czi.read_image(**read_dims)

    # Drop dims that shouldn't be provided back
    ops = []
    real_dims = []
    for i, dim_info in enumerate(dims):
        # Expand dimension info
        dim, size = dim_info

        # If the dim was provided in the read dims we know a single plane for that
        # dimension was requested so remove it
        if dim in read_dims:
            ops.append(0)
        # Otherwise just read the full slice
        else:
            ops.append(slice(None, None, None))
            real_dims.append(dim_info)

    # Convert ops and run getitem
    return data[tuple(ops)], real_dims
示例#3
0
    def _read_immediate(self) -> da.core.Array:
        # Init temp czi
        czi = CziFile(self._file)

        # Safely construct the numpy array or catch any exception
        try:
            # Get image dims indicies
            image_dim_indices = czi.dims_shape()

            # Catch inconsistent scene dimension sizes
            if len(image_dim_indices) > 1:
                # Choose the provided scene
                log.info(
                    f"File contains variable dimensions per scene, "
                    f"selected scene: {self.specific_s_index} for data retrieval."
                )

                # Get the specific scene
                if self.specific_s_index < len(image_dim_indices):
                    data, _ = czi.read_image(
                        **{Dimensions.Scene: self.specific_s_index})
                else:
                    raise exceptions.InconsistentShapeError(
                        f"The CZI image provided has variable dimensions per scene. "
                        f"Please provide a valid index to the 'S' parameter to create "
                        f"a dask array for the index provided. "
                        f"Provided scene index: {self.specific_s_index}. "
                        f"Scene index range: 0-{len(image_dim_indices)}.")

            else:
                # If the list is length one that means that all the scenes in the image
                # have the same dimensions
                # Read all data in the image
                data, _ = czi.read_image()

                # A really bad way to close any connection to the CZI object
                czi._bytes = None
                czi.reader = None

        except Exception as e:
            # A really bad way to close any connection to the CZI object
            czi._bytes = None
            czi.reader = None

            raise e

        return data
示例#4
0
def read_nonmosaic(filename: str) -> Tuple[Union[np.ndarray, None], czimd.CziMetadata]:
    """Read CZI pixel data from non-mosaic image data
    :param filename: filename of the CZI file to be read
    :return: CZI pixel data and the CziMetadata class
    """

    # get the CZI metadata
    md = czimd.CziMetadata(filename)

    # read CZI using aicspylibczi
    aicsczi = CziFile(filename)

    if aicsczi.is_mosaic():
        # check if this CZIn is really a non-mosaic file
        print("CZI is a mosaic file. Please use the readczi_mosaic method instead")
        return None, md

    # get the shape for the 1st scene
    scene = czimd.CziScene(aicsczi, sceneindex=0)
    shape_all = scene.shape_single_scene

    # only update the shape for the scene if the CZI has an S-Dimension
    if scene.hasS:
        shape_all[scene.posS] = md.dims.SizeS

    print("Shape all Scenes : ", shape_all)
    print("DimString all Scenes : ", scene.single_scene_dimstr)

    # create an empty array with the correct dimensions
    all_scenes = np.empty(aicsczi.size, dtype=md.npdtype)

    # loop over scenes if CZI is not a mosaic image
    if md.dims.SizeS is None:
        sizeS = 1
    else:
        sizeS = md.dims.SizeS

    for s in range(sizeS):

        # read the image stack for the current scene
        current_scene, shp = aicsczi.read_image(S=s)

        # create th index lists containing the slice objects
        if scene.hasS:
            idl_scene = [slice(None, None, None)] * (len(all_scenes.shape) - 2)
            idl_scene[aicsczi.dims.index("S")] = 0
            idl_all = [slice(None, None, None)] * (len(all_scenes.shape) - 2)
            idl_all[aicsczi.dims.index("S")] = s

            # cast current stack into the stack for all scenes
            all_scenes[tuple(idl_all)] = current_scene[tuple(idl_scene)]

        # if there is no S-Dimension use the stack directly
        if not scene.hasS:
            all_scenes = current_scene

    print("Shape all scenes (no mosaic)", all_scenes.shape)

    return all_scenes, md
示例#5
0
def test_read_image_from_istream(data_dir, fname, expected_img_shape,
                                 expected_img_dims):
    with open(data_dir / fname, 'rb') as fp:
        czi = CziFile(czi_filename=fp)
        assert czi.shape_is_consistent
        data = czi.read_image()
        assert data[0].shape == expected_img_shape
        assert data[1] == expected_img_dims
示例#6
0
    def _read_image(
        img: Path,
        read_dims: Optional[Dict[str, int]] = None
    ) -> Tuple[np.ndarray, List[Tuple[str, int]]]:
        """
        Read and return the squeezed image data requested along with the dimension info
        that was read.

        Parameters
        ----------
        img: Path
            Path to the CZI file to read.
        read_dims: Optional[Dict[str, int]]
            The dimensions to read from the file as a dictionary of string to integer.
            Default: None (Read all data from the image)

        Returns
        -------
        data: np.ndarray
            The data read for the dimensions provided.
        read_dimensions: List[Tuple[str, int]]]
            The dimension sizes that were returned from the read.
        """
        # Catch optional read dim
        if read_dims is None:
            read_dims = {}

        # Init czi
        czi = CziFile(img)

        # Read image
        log.debug(f"Reading dimensions: {read_dims}")
        data, dims = czi.read_image(**read_dims)

        # Drop dims that shouldn't be provided back
        ops = []
        real_dims = []
        for i, dim_info in enumerate(dims):
            # Expand dimension info
            dim, size = dim_info

            # If the dim was provided in the read dims we know a single plane for that
            # dimension was requested so remove it
            if dim in read_dims:
                ops.append(0)
            # Otherwise just read the full slice
            else:
                ops.append(slice(None, None, None))
                real_dims.append(dim_info)

        # Convert ops and run getitem
        return data[tuple(ops)], real_dims
示例#7
0
def test_read_image_mosaic(data_dir, fname):
    czi = CziFile(str(data_dir / fname))
    czi.read_image(M=0)
    assert True
示例#8
0
def test_read_image_args(data_dir, fname, args, expected):
    czi = CziFile(data_dir / fname)
    img, shp = czi.read_image(**args)
    assert img.shape == expected
示例#9
0
def test_read_image(data_dir, fname, expected):
    czi = CziFile(str(data_dir / fname))
    img, shp = czi.read_image()
    assert img.shape == expected
示例#10
0
def load_data(filename, max_xy=512, dtype='uint8', reload=False):
    filename = Path(filename)
    cache_filename = (filename.parent / "processed" /
                      f"max_xy_{max_xy}_dtype_{dtype}" /
                      filename.with_suffix(".pkl").name)
    if not reload and cache_filename.exists():
        with cache_filename.open("rb") as fh:
            return pickle.load(fh)

    fh = CziFile(filename)

    x_pixels = float(
        fh.meta.find(
            "Metadata/Experiment/ExperimentBlocks/AcquisitionBlock/AcquisitionModeSetup/DimensionX"
        ).text)
    y_pixels = float(
        fh.meta.find(
            "Metadata/Experiment/ExperimentBlocks/AcquisitionBlock/AcquisitionModeSetup/DimensionY"
        ).text)
    z_pixels = float(
        fh.meta.find(
            "Metadata/Experiment/ExperimentBlocks/AcquisitionBlock/AcquisitionModeSetup/DimensionZ"
        ).text)

    x_scaling = float(
        fh.meta.find(
            "Metadata/Experiment/ExperimentBlocks/AcquisitionBlock/AcquisitionModeSetup/ScalingX"
        ).text)
    y_scaling = float(
        fh.meta.find(
            "Metadata/Experiment/ExperimentBlocks/AcquisitionBlock/AcquisitionModeSetup/ScalingY"
        ).text)
    z_scaling = float(
        fh.meta.find(
            "Metadata/Experiment/ExperimentBlocks/AcquisitionBlock/AcquisitionModeSetup/ScalingZ"
        ).text)

    x_offset = float(
        fh.meta.find(
            "Metadata/Experiment/ExperimentBlocks/AcquisitionBlock/AcquisitionModeSetup/OffsetX"
        ).text)
    y_offset = float(
        fh.meta.find(
            "Metadata/Experiment/ExperimentBlocks/AcquisitionBlock/AcquisitionModeSetup/OffsetY"
        ).text)
    z_offset = float(
        fh.meta.find(
            "Metadata/Experiment/ExperimentBlocks/AcquisitionBlock/AcquisitionModeSetup/OffsetZ"
        ).text)

    node = fh.meta.find(
        "Metadata/Information/Image/Dimensions/S/Scenes/Scene/Positions/Position"
    )

    info = {}
    info["offset"] = np.array([x_offset, y_offset, z_offset])
    info["pixels"] = np.array([x_pixels, y_pixels, z_pixels]).astype("i")
    info["scaling"] = np.array([x_scaling, y_scaling, z_scaling])
    info["origin"] = np.array([float(v) * 1e-6 for k, v in node.items()])
    info["lower"] = info["origin"]
    info["extent"] = info["pixels"] * info["scaling"]
    info["upper"] = info["lower"] + info["extent"]
    del info["pixels"]

    img = fh.read_image()[0][0, 0, 0]

    # First, do the zoom. This is the best time to handle it before we do
    # additional manipulations.
    zoom = max_xy / max(x_pixels, y_pixels)
    if zoom < 1:
        img = np.concatenate(
            [ndimage.zoom(i, (1, zoom, zoom))[np.newaxis] for i in img])
        info["scaling"][:2] /= zoom

    # Initial ordering is czyx
    #                     0123
    # Final ordering      xyzc
    img = img.swapaxes(0, 3).swapaxes(1, 2)

    # Add a third channel to allow for RGB images
    padding = [(0, 0)] * img.ndim
    padding[-1] = (0, 1)
    img = np.pad(img, padding, "constant")

    # Rescale to range 0 ... 1
    img = img / img.max(axis=(0, 1, 2), keepdims=True)
    if 'int' in dtype:
        img *= 255
    img = img.astype(dtype)

    cache_filename.parent.mkdir(exist_ok=True, parents=True)
    with cache_filename.open("wb") as fh:
        pickle.dump((info, img), fh, pickle.HIGHEST_PROTOCOL)

    return info, img
示例#11
0
import numpy as np
import imgfileutils as imf
from aicspylibczi import CziFile
import czifile as zis
import xmltodict

# filename = r'/datadisk1/tuxedo/temp/input/WP96_T=3_Z=4_Ch=2_3x3_A4-A5.czi'
# filename = r'/datadisk1/tuxedo/temp/input/WP96_T=3_Z=4_Ch=2_5x5_A4.czi'
filename = r'/datadisk1/tuxedo/temp/input/DTScan_ID4.czi'

print('----------czifile array ----------')
czi_czifile_array, md, addmd = imf.get_array_czi(filename, remove_HDim=False)
print('Shape czi_czifile', czi_czifile_array.shape)
czi_aics = CziFile(filename)
czi_aics_out = czi_aics.read_image(S=0)
czi_aics_array = czi_aics_out[0]
czi_aics_dims = czi_aics_out[1]

print('Shape czi_aics_array', czi_aics_array.shape)
print('Shape czi_aics_dims', czi_aics_dims)
print('CZI Mosaic', md['czi_ismosaic'])
print('SizeX', md['SizeX'])
print('SizeY', md['SizeY'])
print('SizeC', md['SizeC'])
print('SizeZ', md['SizeZ'])
print('SizeT', md['SizeT'])
print('SizeS', md['SizeS'])
print('SizeM', md['SizeM'])
print('SizeB', md['SizeB'])
print('SizeH', md['SizeH'])
def daread(img: Union[str, Path]) -> da.core.Array:
    """
    Read a CZI image file as a delayed dask array where each YX plane will be read on
    request.

    Parameters
    ----------
    img: Union[str, Path]
        The filepath to read.

    Returns
    -------
    img: dask.array.core.Array
        The constructed dask array where each YX plane is a delayed read.
    """
    # Convert pathlike to CziFile
    if isinstance(img, (str, Path)):
        # Resolve path
        img = Path(img).expanduser().resolve(strict=True)

        # Check path
        if img.is_dir():
            raise IsADirectoryError(
                f"Please provide a single file to the `img` parameter. "
                f"Received directory: {img}")

    # Check that no other type was provided
    if not isinstance(img, Path):
        raise TypeError(
            f"Please provide a path to a file as a string, or an pathlib.Path, to the "
            f"`img` parameter. "
            f"Received type: {type(img)}")

    # Init temp czi
    czi = CziFile(img)

    # Get image dims shape
    image_dims = czi.dims_shape()

    # Setup the read dimensions dictionary for reading the first plane
    first_plane_read_dims = {}
    for dim, dim_info in image_dims.items():
        # Unpack dimension info
        dim_begin_index, dim_end_index = dim_info

        # Add to read dims
        first_plane_read_dims[dim] = dim_begin_index

    # Read first plane for information used by dask.array.from_delayed
    sample, sample_dims = czi.read_image(**first_plane_read_dims)

    # The Y and X dimensions are always the last two dimensions, in that order.
    # These dimensions cannot be operated over but the shape information is used
    # in multiple places so we pull them out for easier access.
    sample_YX_shape = sample.shape[-2:]

    # Create operating shape and dim order list
    operating_shape = czi.size[:-2]
    dims = [dim for dim in czi.dims[:-2]]

    # Create empty numpy array with the operating shape so that we can iter through
    # and use the multi_index to create the readers.
    # We add empty dimensions of size one to fake being the Y and X dimensions.
    lazy_arrays = np.ndarray(operating_shape + (1, 1), dtype=object)

    # We can enumerate over the multi-indexed array and construct read_dims
    # dictionaries by simply zipping together the ordered dims list and the current
    # multi-index plus the begin index for that plane.
    # We then set the value of the array at the same multi-index to
    # the delayed reader using the constructed read_dims dictionary.
    begin_indicies = tuple(image_dims[dim][0] for dim in dims)
    for i, _ in np.ndenumerate(lazy_arrays):
        this_plane_read_indicies = (current_dim_begin_index + curr_dim_index
                                    for current_dim_begin_index, curr_dim_index
                                    in zip(begin_indicies, i))
        this_plane_read_dims = dict(zip(dims, this_plane_read_indicies))
        lazy_arrays[i] = da.from_delayed(
            delayed(_imread)(img, this_plane_read_dims),
            shape=sample_YX_shape,
            dtype=sample.dtype,
        )

    # Convert the numpy array of lazy readers into a dask array
    merged = da.block(lazy_arrays.tolist())

    # Because dimensions outside of Y and X can be in any order and present or not
    # we also return the dimension order string.
    dims = dims + ["Y", "X"]
    return merged, "".join(dims)
示例#13
0
if md['ImageType'] == 'czi':
    isCZI = True
else:
    isCZI = False

if md['czi_isRGB']:
    isRGB = True
else:
    isRGB = False

if md['czi_isMosaic']:
    isMosaic = True
else:
    isMosaic = False

output = czi.read_image(S=0, T=0, Z=0, C=0)
image = output[0]
image_dims = output[1]

#mosaic_data = czi.read_mosaic(C=0, T=0, Z=0, scale_factor=1.0)
#image2d = np.squeeze(mosaic_data)
#image2d = np.moveaxis(image2d, 0, -1)
# convert ZEN BGR into RGB
#image2d = image2d[..., ::-1]

plt.figure(figsize=(12, 12))
# plt.imshow(image2d)
plt.imshow(image)
plt.axis('off')
plt.show()
"""
示例#14
0
    def _daread(img: Path,
                czi: CziFile,
                chunk_by_dims: List[str] = [
                    Dimensions.SpatialZ, Dimensions.SpatialY,
                    Dimensions.SpatialX
                ],
                S: int = 0) -> Tuple[da.core.Array, str]:
        """
        Read a CZI image file as a delayed dask array where certain dimensions act as the chunk size.

        Parameters
        ----------
        img: Path
            The filepath to read.
        czi: CziFile
            The loaded CziFile object created from reading the filepath.
        chunk_by_dims: List[str]
            The dimensions to use as the for mapping the chunks / blocks.
            Default: [Dimensions.SpatialZ, Dimensions.SpatialY, Dimensions.SpatialX]
            Note: SpatialY and SpatialX will always be added to the list if not present.
        S: int
            If the image has different dimensions on any scene from another, the dask array construction will fail.
            In that case, use this parameter to specify a specific scene to construct a dask array for.
            Default: 0 (select the first scene)

        Returns
        -------
        img: dask.array.core.Array
            The constructed dask array where certain dimensions are chunked.
        dims: str
            The dimension order as a string.
        """
        # Get image dims indicies
        image_dim_indices = czi.dims_shape()

        # Catch inconsistent scene dimension sizes
        if len(image_dim_indices) > 1:
            # Choose the provided scene
            try:
                image_dim_indices = image_dim_indices[S]
                log.info(
                    f"File contains variable dimensions per scene, selected scene: {S} for data retrieval."
                )
            except IndexError:
                raise exceptions.InconsistentShapeError(
                    f"The CZI image provided has variable dimensions per scene. "
                    f"Please provide a valid index to the 'S' parameter to create a dask array for the index provided. "
                    f"Provided scene index: {S}. Scene index range: 0-{len(image_dim_indices)}."
                )
        else:
            # If the list is length one that means that all the scenes in the image have the same dimensions
            # Just select the first dictionary in the list
            image_dim_indices = image_dim_indices[0]

        # Uppercase dimensions provided to chunk by dims
        chunk_by_dims = [d.upper() for d in chunk_by_dims]

        # Always add Y and X dims to chunk by dims because that is how CZI files work
        if Dimensions.SpatialY not in chunk_by_dims:
            log.info(
                f"Adding the Spatial Y dimension to chunk by dimensions as it was not found."
            )
            chunk_by_dims.append(Dimensions.SpatialY)
        if Dimensions.SpatialX not in chunk_by_dims:
            log.info(
                f"Adding the Spatial X dimension to chunk by dimensions as it was not found."
            )
            chunk_by_dims.append(Dimensions.SpatialX)

        # Setup read dimensions for an example chunk
        first_chunk_read_dims = {}
        for dim, (dim_begin_index, dim_end_index) in image_dim_indices.items():
            # Only add the dimension if the dimension isn't a part of the chunk
            if dim not in chunk_by_dims:
                # Add to read dims
                first_chunk_read_dims[dim] = dim_begin_index

        # Read first chunk for information used by dask.array.from_delayed
        sample, sample_dims = czi.read_image(**first_chunk_read_dims)

        # Get the shape for the chunk and operating shape for the dask array
        # We also collect the chunk and non chunk dimension ordering so that we can swap the dimensions after we
        # block the dask array together.
        sample_chunk_shape = []
        operating_shape = []
        non_chunk_dimension_ordering = []
        chunk_dimension_ordering = []
        for i, dim_info in enumerate(sample_dims):
            # Unpack dim info
            dim, size = dim_info

            # If the dim is part of the specified chunk dims then append it to the sample, and, append the dimension
            # to the chunk dimension ordering
            if dim in chunk_by_dims:
                sample_chunk_shape.append(size)
                chunk_dimension_ordering.append(dim)

            # Otherwise, append the dimension to the non chunk dimension ordering, and, append the true size of the
            # image at that dimension
            else:
                non_chunk_dimension_ordering.append(dim)
                operating_shape.append(image_dim_indices[dim][1] -
                                       image_dim_indices[dim][0])

        # Convert shapes to tuples and combine the non and chunked dimension orders as that is the order the data will
        # actually come out of the read data as
        sample_chunk_shape = tuple(sample_chunk_shape)
        blocked_dimension_order = non_chunk_dimension_ordering + chunk_dimension_ordering

        # Fill out the rest of the operating shape with dimension sizes of 1 to match the length of the sample chunk
        # When dask.block happens it fills the dimensions from inner-most to outer-most with the chunks as long as
        # the dimension is size 1
        # Basically, we are adding empty dimensions to the operating shape that will be filled by the chunks from dask
        operating_shape = tuple(
            operating_shape) + (1, ) * len(sample_chunk_shape)

        # Create empty numpy array with the operating shape so that we can iter through and use the multi_index to
        # create the readers.
        lazy_arrays = np.ndarray(operating_shape, dtype=object)

        # We can enumerate over the multi-indexed array and construct read_dims dictionaries by simply zipping together
        # the ordered dims list and the current multi-index plus the begin index for that plane. We then set the value
        # of the array at the same multi-index to the delayed reader using the constructed read_dims dictionary.
        dims = [d for d in czi.dims]
        begin_indicies = tuple(image_dim_indices[d][0] for d in dims)
        for i, _ in np.ndenumerate(lazy_arrays):
            # Add the czi file begin index for each dimension to the array dimension index
            this_chunk_read_indicies = (
                current_dim_begin_index + curr_dim_index
                for current_dim_begin_index, curr_dim_index in zip(
                    begin_indicies, i))

            # Zip the dims with the read indices
            this_chunk_read_dims = dict(
                zip(blocked_dimension_order, this_chunk_read_indicies))

            # Remove the dimensions that we want to chunk by from the read dims
            for d in chunk_by_dims:
                if d in this_chunk_read_dims:
                    this_chunk_read_dims.pop(d)

            # Add delayed array to lazy arrays at index
            lazy_arrays[i] = da.from_delayed(
                delayed(CziReader._imread)(img, this_chunk_read_dims),
                shape=sample_chunk_shape,
                dtype=sample.dtype,
            )

        # Convert the numpy array of lazy readers into a dask array and fill the inner-most empty dimensions with chunks
        merged = da.block(lazy_arrays.tolist())

        # Because we have set certain dimensions to be chunked and others not
        # we will need to transpose back to original dimension ordering
        # Example being, if the original dimension ordering was "SZYX" and we want to chunk by "S", "Y", and "X"
        # We created an array with dimensions ordering "ZSYX"
        transpose_indices = []
        transpose_required = False
        for i, d in enumerate(czi.dims):
            new_index = blocked_dimension_order.index(d)
            if new_index != i:
                transpose_required = True
                transpose_indices.append(new_index)
            else:
                transpose_indices.append(i)

        # Only run if the transpose is actually required
        # The default case is "Z", "Y", "X", which _usually_ doesn't need to be transposed because that is _usually_
        # The normal dimension order of the CZI file anyway
        if transpose_required:
            merged = da.transpose(merged, tuple(transpose_indices))

        # Because dimensions outside of Y and X can be in any order and present or not
        # we also return the dimension order string.
        return merged, "".join(dims)