Skip to content

steinbock.utils

matching

match_masks(mask1, mask2)

Source code in steinbock/utils/matching.py
def match_masks(mask1: np.ndarray, mask2: np.ndarray) -> pd.DataFrame:
    nz1 = mask1 != 0
    nz2 = mask2 != 0
    object_ids1 = []
    object_ids2 = []
    for object_id1 in np.unique(mask1[nz1]):
        for object_id2 in np.unique(mask2[nz2 & (mask1 == object_id1)]):
            object_ids1.append(object_id1)
            object_ids2.append(object_id2)
    for object_id2 in np.unique(mask2[nz2]):
        for object_id1 in np.unique(mask1[nz1 & (mask2 == object_id2)]):
            object_ids1.append(object_id1)
            object_ids2.append(object_id2)
    df = pd.DataFrame(data={"Object1": object_ids1, "Object2": object_ids2})
    df.drop_duplicates(inplace=True, ignore_index=True)
    return df

try_match_masks_from_disk(mask_files1, mask_files2)

Source code in steinbock/utils/matching.py
def try_match_masks_from_disk(
    mask_files1: Sequence[Union[str, PathLike]],
    mask_files2: Sequence[Union[str, PathLike]],
) -> Generator[Tuple[Path, Path, pd.DataFrame], None, None]:
    for mask_file1, mask_file2 in zip(mask_files1, mask_files2):
        try:
            df = match_masks(
                io.read_mask(mask_file1), io.read_mask(mask_file2)
            )
            yield mask_file1, mask_file2, df
            del df
        except:
            _logger.exception(f"Error matching masks {mask_file1, mask_file2}")

mosaics

try_extract_tiles_from_disk_to_disk(img_files, tile_dir, tile_size)

Source code in steinbock/utils/mosaics.py
def try_extract_tiles_from_disk_to_disk(
    img_files: Sequence[Union[str, PathLike]],
    tile_dir: Union[str, PathLike],
    tile_size: int,
) -> Generator[Tuple[Path, np.ndarray], None, None]:
    for img_file in img_files:
        try:
            img = tifffile.memmap(img_file, mode="r")
            if img.ndim == 6:
                img_width = img.shape[-2]
                img_height = img.shape[-3]
            else:
                img_width = img.shape[-1]
                img_height = img.shape[-2]
            if img_width % tile_size == 1 or img_height % tile_size == 1:
                _logger.warning(
                    "Chosen tile size yields UNSTITCHABLE tiles of 1 pixel "
                    f"width or height for image {img_file}"
                )
            for tile_x in range(0, img_width, tile_size):
                for tile_y in range(0, img_height, tile_size):
                    if img.ndim == 6:
                        tile = img[
                            :,
                            :,
                            :,
                            tile_y : (tile_y + tile_size),
                            tile_x : (tile_x + tile_size),
                            :,
                        ]
                        tile_width = tile.shape[-2]
                        tile_height = tile.shape[-3]
                    else:
                        tile = img[
                            ...,
                            tile_y : (tile_y + tile_size),
                            tile_x : (tile_x + tile_size),
                        ]
                        tile_width = tile.shape[-1]
                        tile_height = tile.shape[-2]
                    while tile.ndim < 5:
                        tile = np.expand_dims(tile, 0)
                    while tile.ndim < 6:
                        tile = np.expand_dims(tile, -1)
                    tile_file = Path(tile_dir) / (
                        f"{Path(img_file).stem}_tx{tile_x}_ty{tile_y}"
                        f"_tw{tile_width}_th{tile_height}.tiff"
                    )
                    tifffile.imwrite(tile_file, tile, imagej=True)
                    yield tile_file, tile
                    del tile
            del img
        except:
            _logger.exception(f"Error extracting tiles: {img_file}")

try_stitch_tiles_from_disk_to_disk(tile_files, img_dir)

Source code in steinbock/utils/mosaics.py
def try_stitch_tiles_from_disk_to_disk(
    tile_files: Sequence[Union[str, PathLike]],
    img_dir: Union[str, PathLike],
) -> Generator[Tuple[str, np.ndarray], None, None]:
    class TileInfo(NamedTuple):
        tile_file: Path
        x: int
        y: int
        width: int
        height: int

    tile_file_stem_pattern = re.compile(
        r"(?P<img_file_stem>.+)_tx(?P<x>\d+)_ty(?P<y>\d+)"
        r"_tw(?P<width>\d+)_th(?P<height>\d+)"
    )
    img_tile_infos = {}
    for tile_file in tile_files:
        m = tile_file_stem_pattern.fullmatch(tile_file.stem)
        if m is None:
            raise ValueError(f"Malformed tile file name: {tile_file}")
        img_file_stem = m.group("img_file_stem")
        tile_info = TileInfo(
            Path(tile_file),
            int(m.group("x")),
            int(m.group("y")),
            int(m.group("width")),
            int(m.group("height")),
        )
        if img_file_stem not in img_tile_infos:
            img_tile_infos[img_file_stem] = []
        img_tile_infos[img_file_stem].append(tile_info)
    for img_file_stem, tile_infos in img_tile_infos.items():
        img_file = Path(img_dir) / f"{img_file_stem}.tiff"
        try:
            tile = tifffile.imread(tile_infos[0].tile_file, squeeze=False)
            img_shape = list(tile.shape)
            if tile.ndim == 6:
                img_shape[-2] = max(ti.x + ti.width for ti in tile_infos)
                img_shape[-3] = max(ti.y + ti.height for ti in tile_infos)
            else:
                img_shape[-1] = max(ti.x + ti.width for ti in tile_infos)
                img_shape[-2] = max(ti.y + ti.height for ti in tile_infos)
            img = tifffile.memmap(
                img_file,
                shape=tuple(img_shape),
                dtype=tile.dtype,
                imagej=True,
            )
            for i, tile_info in enumerate(tile_infos):
                if i > 0:
                    tile = tifffile.imread(tile_info.tile_file, squeeze=False)
                if tile.ndim == 6:
                    img[
                        :,
                        :,
                        :,
                        tile_info.y : tile_info.y + tile_info.height,
                        tile_info.x : tile_info.x + tile_info.width,
                        :,
                    ] = tile
                else:
                    img[
                        :,
                        :,
                        :,
                        tile_info.y : tile_info.y + tile_info.height,
                        tile_info.x : tile_info.x + tile_info.width,
                    ] = tile
                img.flush()
            yield img_file, img
            del img
        except:
            _logger.exception(f"Error stitching tiles: {img_file}")
Back to top