Skip to content

steinbock.classification

ilastik special

ilastik

create_and_save_ilastik_project(ilastik_crop_files, ilastik_project_file)

Source code in steinbock/classification/ilastik/ilastik.py
def create_and_save_ilastik_project(
    ilastik_crop_files: Sequence[Union[str, PathLike]],
    ilastik_project_file: Union[str, PathLike],
):
    dataset_id = str(uuid1())
    shutil.copyfile(_project_file_template, ilastik_project_file)
    with h5py.File(ilastik_project_file, mode="a", libver=_h5py_libver) as f:
        infos = f["Input Data/infos"]
        for i, ilastik_crop_file in enumerate(ilastik_crop_files):
            rel_ilastik_crop_file = Path(ilastik_crop_file).relative_to(
                Path(ilastik_project_file).parent
            )
            with h5py.File(
                ilastik_crop_file, mode="r", libver=_h5py_libver
            ) as f_crop:
                crop_shape = f_crop[_crop_dataset_path].shape
            lane = infos.create_group(f"lane{i:04d}")
            lane.create_group("Prediction Mask")
            _init_project_raw_data_group(
                lane.create_group("Raw Data"),
                dataset_id,
                str(rel_ilastik_crop_file / _crop_dataset_path),
                Path(ilastik_crop_file).stem,
                crop_shape,
            )

create_ilastik_crop(ilastik_img, crop_size, rng)

Source code in steinbock/classification/ilastik/ilastik.py
def create_ilastik_crop(
    ilastik_img: np.ndarray, crop_size: int, rng: np.random.Generator
) -> Tuple[Optional[int], Optional[int], Optional[np.ndarray]]:
    yx_shape = ilastik_img.shape[1:]
    if all(shape >= crop_size for shape in yx_shape):
        x_start = rng.integers(ilastik_img.shape[2] - crop_size)
        x_end = x_start + crop_size
        y_start = rng.integers(ilastik_img.shape[1] - crop_size)
        y_end = y_start + crop_size
        ilastik_crop = ilastik_img[:, y_start:y_end, x_start:x_end]
        return x_start, y_start, io.to_dtype(ilastik_crop, io.img_dtype)
    return None, None, None

create_ilastik_crops_from_disk(ilastik_img_files, crop_size, seed=None)

Source code in steinbock/classification/ilastik/ilastik.py
def create_ilastik_crops_from_disk(
    ilastik_img_files: Sequence[Union[str, PathLike]],
    crop_size: int,
    seed=None,
) -> Generator[
    Tuple[Path, Optional[int], Optional[int], Optional[np.ndarray]],
    None,
    None,
]:
    rng = np.random.default_rng(seed=seed)
    for ilastik_img_file in ilastik_img_files:
        x_start, y_start, ilastik_crop = create_ilastik_crop(
            read_ilastik_image(ilastik_img_file), crop_size, rng,
        )
        yield Path(ilastik_img_file), x_start, y_start, ilastik_crop
        del ilastik_crop

create_ilastik_image(img, channel_groups=None, aggr_func=<function mean at 0x7f51de7e60d0>, prepend_mean=True, mean_factor=100.0, scale_factor=1)

Source code in steinbock/classification/ilastik/ilastik.py
def create_ilastik_image(
    img: np.ndarray,
    channel_groups: Optional[np.ndarray] = None,
    aggr_func: Callable[[np.ndarray], np.ndarray] = np.mean,
    prepend_mean: bool = True,
    mean_factor: float = 100.0,
    scale_factor: int = 1,
) -> np.ndarray:
    ilastik_img = img
    if channel_groups is not None:
        ilastik_img = np.stack(
            [
                aggr_func(ilastik_img[channel_groups == channel_group], axis=0)
                for channel_group in np.unique(channel_groups)
                if not np.isnan(channel_group)
            ]
        )
    if prepend_mean:
        mean_img = ilastik_img.mean(axis=0, keepdims=True) * mean_factor
        ilastik_img = np.concatenate((mean_img, ilastik_img))
    if scale_factor > 1:
        # bilinear resizing (for compatibility with IMC Segmentation Pipeline)
        output_shape = (
            ilastik_img.shape[0],
            ilastik_img.shape[1] * scale_factor,
            ilastik_img.shape[2] * scale_factor,
        )
        ilastik_img = resize(
            ilastik_img, output_shape, order=1, mode="symmetric"
        )
    return io.to_dtype(ilastik_img, io.img_dtype)

create_ilastik_images_from_disk(img_files, channel_groups=None, aggr_func=<function mean at 0x7f51de7e60d0>, prepend_mean=True, mean_factor=100.0, scale_factor=1)

Source code in steinbock/classification/ilastik/ilastik.py
def create_ilastik_images_from_disk(
    img_files: Sequence[Union[str, PathLike]],
    channel_groups: Optional[np.ndarray] = None,
    aggr_func: Callable[[np.ndarray], np.ndarray] = np.mean,
    prepend_mean: bool = True,
    mean_factor: float = 100.0,
    scale_factor: int = 1,
) -> Generator[Tuple[Path, np.ndarray], None, None]:
    for img_file in img_files:
        ilastik_img = create_ilastik_image(
            io.read_image(img_file, ignore_dtype=True),
            channel_groups=channel_groups,
            aggr_func=aggr_func,
            prepend_mean=prepend_mean,
            mean_factor=mean_factor,
            scale_factor=scale_factor,
        )
        yield Path(img_file), ilastik_img
        del ilastik_img

fix_ilastik_crops_from_disk(ilastik_crop_files, axis_order=None)

Source code in steinbock/classification/ilastik/ilastik.py
def fix_ilastik_crops_from_disk(
    ilastik_crop_files: Sequence[Union[str, PathLike]],
    axis_order: Optional[str] = None,
) -> Generator[Tuple[Path, Tuple[int, ...], np.ndarray], None, None]:
    for ilastik_crop_file in ilastik_crop_files:
        with h5py.File(ilastik_crop_file, mode="r", libver=_h5py_libver) as f:
            ilastik_crop_dataset = None
            if _crop_dataset_path in f:
                ilastik_crop_dataset = f[_crop_dataset_path]
            elif ilastik_crop_file.stem in f:
                ilastik_crop_dataset = f[ilastik_crop_file.stem]
            elif len(f) == 1:
                ilastik_crop_dataset = next(iter(f.values()))
            else:
                raise ValueError(f"Unknown dataset name: {ilastik_crop_file}")
            if ilastik_crop_dataset.attrs.get("steinbock", False):
                continue
            ilastik_crop = ilastik_crop_dataset[()]
            orig_axis_order = None
            if axis_order is not None:
                orig_axis_order = list(axis_order)
            elif "axistags" in ilastik_crop_dataset.attrs:
                axis_tags = json.loads(ilastik_crop_dataset.attrs["axistags"])
                orig_axis_order = [item["key"] for item in axis_tags["axes"]]
            else:
                raise ValueError(f"Unknown axis order: {ilastik_crop_file}")
        if len(orig_axis_order) != ilastik_crop.ndim:
            raise ValueError(f"Incompatible axis order: {ilastik_crop_file}")
        channel_axis_index = orig_axis_order.index("c")
        size_x = ilastik_crop.shape[orig_axis_order.index("x")]
        size_y = ilastik_crop.shape[orig_axis_order.index("y")]
        num_channels = ilastik_crop.size // (size_x * size_y)
        if ilastik_crop.shape[channel_axis_index] != num_channels:
            channel_axis_indices = (
                i
                for i, a in enumerate(orig_axis_order)
                if a not in ("x", "y")
                and ilastik_crop.shape[i] == num_channels
            )
            channel_axis_index = next(channel_axis_indices, None)
        if channel_axis_index is None:
            raise ValueError(f"Unknown channel axis: {ilastik_crop_file}")
        new_axis_order = orig_axis_order.copy()
        new_axis_order.insert(0, new_axis_order.pop(channel_axis_index))
        new_axis_order.insert(1, new_axis_order.pop(new_axis_order.index("y")))
        new_axis_order.insert(2, new_axis_order.pop(new_axis_order.index("x")))
        transpose_axes = [orig_axis_order.index(a) for a in new_axis_order]
        ilastik_crop = np.transpose(ilastik_crop, axes=transpose_axes)
        ilastik_crop = np.reshape(ilastik_crop, ilastik_crop.shape[:3])
        ilastik_crop = io.to_dtype(ilastik_crop, io.img_dtype)
        yield Path(ilastik_crop_file), transpose_axes, ilastik_crop
        del ilastik_crop

fix_ilastik_project_file_inplace(ilastik_project_file, ilastik_crop_dir, ilastik_probab_dir, ilastik_crop_shapes, transpose_axes)

Source code in steinbock/classification/ilastik/ilastik.py
def fix_ilastik_project_file_inplace(
    ilastik_project_file: Union[str, PathLike],
    ilastik_crop_dir: Union[str, PathLike],
    ilastik_probab_dir: Union[str, PathLike],
    ilastik_crop_shapes: Dict[str, Tuple[int, ...]],
    transpose_axes: List[int],
):
    rel_ilastik_crop_dir = Path(ilastik_crop_dir).relative_to(
        Path(ilastik_project_file).parent
    )
    rel_ilastik_probab_dir = Path(ilastik_probab_dir).relative_to(
        Path(ilastik_project_file).parent
    )
    with h5py.File(ilastik_project_file, "a", libver=_h5py_libver) as f:
        if "Input Data" in f:
            _fix_project_input_data_inplace(
                f["Input Data"], rel_ilastik_crop_dir, ilastik_crop_shapes
            )
        if "PixelClassification" in f:
            _fix_project_pixel_classification_inplace(
                f["PixelClassification"], transpose_axes
            )
        if "Prediction Export" in f:
            _fix_project_prediction_export_inplace(
                f["Prediction Export"], rel_ilastik_probab_dir
            )

list_ilastik_crop_files(crop_dir)

Source code in steinbock/classification/ilastik/ilastik.py
def list_ilastik_crop_files(crop_dir: Union[str, PathLike]) -> List[Path]:
    return sorted(Path(crop_dir).rglob("*.h5"))

list_ilastik_image_files(img_dir)

Source code in steinbock/classification/ilastik/ilastik.py
def list_ilastik_image_files(img_dir: Union[str, PathLike]) -> List[Path]:
    return sorted(Path(img_dir).rglob("*.h5"))

read_ilastik_crop(ilastik_crop_stem)

Source code in steinbock/classification/ilastik/ilastik.py
def read_ilastik_crop(ilastik_crop_stem: Union[str, PathLike]) -> np.ndarray:
    ilastik_crop_file = io.as_path_with_suffix(ilastik_crop_stem, ".h5")
    with h5py.File(ilastik_crop_file, mode="r", libver=_h5py_libver) as f:
        return io.to_dtype(f[str(_crop_dataset_path)][()], io.img_dtype)

read_ilastik_image(ilastik_img_stem)

Source code in steinbock/classification/ilastik/ilastik.py
def read_ilastik_image(ilastik_img_stem: Union[str, PathLike]) -> np.ndarray:
    ilastik_img_file = io.as_path_with_suffix(ilastik_img_stem, ".h5")
    with h5py.File(ilastik_img_file, mode="r", libver=_h5py_libver) as f:
        return io.to_dtype(f[str(_img_dataset_path)][()], io.img_dtype)

run_pixel_classification(ilastik_binary, ilastik_project_file, ilastik_img_files, ilastik_probab_dir, num_threads=None, memory_limit=None, ilastik_env=None)

Source code in steinbock/classification/ilastik/ilastik.py
def run_pixel_classification(
    ilastik_binary: Union[str, PathLike],
    ilastik_project_file: Union[str, PathLike],
    ilastik_img_files: Sequence[Union[str, PathLike]],
    ilastik_probab_dir: Union[str, PathLike],
    num_threads: Optional[int] = None,
    memory_limit: Optional[int] = None,
    ilastik_env: Optional[Dict[str, str]] = None,
) -> subprocess.CompletedProcess:
    output_filename_format = Path(ilastik_probab_dir) / "{nickname}.tiff"
    args = [
        str(ilastik_binary),
        "--headless",
        f"--project={ilastik_project_file}",
        "--readonly",
        "--input_axes=cyx",
        "--export_source=Probabilities",
        "--output_format=tiff",
        f"--output_filename_format={output_filename_format}",
        "--export_dtype=uint16",
        "--output_axis_order=yxc",
        "--pipeline_result_drange=(0.0,1.0)",
        "--export_drange=(0,65535)",
    ]
    for ilastik_img_file in ilastik_img_files:
        args.append(str(Path(ilastik_img_file) / _img_dataset_path))
    if ilastik_env is not None:
        ilastik_env = ilastik_env.copy()
        if num_threads is not None:
            ilastik_env["LAZYFLOW_THREADS"] = num_threads
        if memory_limit is not None:
            ilastik_env["LAZYFLOW_TOTAL_RAM_MB"] = memory_limit
    result = run_captured(args, env=ilastik_env)
    ilastik_probab_files = Path(ilastik_probab_dir).rglob(
        f"*-{_img_dataset_path}.tiff"
    )
    for ilastik_probab_file in sorted(ilastik_probab_files):
        ilastik_probab_file.rename(
            ilastik_probab_file.with_name(
                ilastik_probab_file.name.replace(f"-{_img_dataset_path}", "")
            )
        )
    return result

write_ilastik_crop(ilastik_crop, ilastik_crop_stem)

Source code in steinbock/classification/ilastik/ilastik.py
def write_ilastik_crop(
    ilastik_crop: np.ndarray, ilastik_crop_stem: Union[str, PathLike]
):
    ilastik_crop = io.to_dtype(ilastik_crop, io.img_dtype)
    ilastik_crop_file = io.as_path_with_suffix(ilastik_crop_stem, ".h5")
    with h5py.File(ilastik_crop_file, mode="w", libver=_h5py_libver) as f:
        dataset = f.create_dataset(_crop_dataset_path, data=ilastik_crop)
        dataset.attrs["display_mode"] = _dataset_display_mode.encode("ascii")
        dataset.attrs["axistags"] = _dataset_axistags.encode("ascii")
        dataset.attrs["steinbock"] = True
    return ilastik_crop_file

write_ilastik_image(ilastik_img, ilastik_img_stem)

Source code in steinbock/classification/ilastik/ilastik.py
def write_ilastik_image(
    ilastik_img: np.ndarray, ilastik_img_stem: Union[str, PathLike]
) -> Path:
    ilastik_img = io.to_dtype(ilastik_img, io.img_dtype)
    ilastik_img_file = io.as_path_with_suffix(ilastik_img_stem, ".h5")
    with h5py.File(ilastik_img_file, mode="w", libver=_h5py_libver) as f:
        dataset = f.create_dataset(_img_dataset_path, data=ilastik_img)
        dataset.attrs["display_mode"] = _dataset_display_mode.encode("ascii")
        dataset.attrs["axistags"] = _dataset_axistags.encode("ascii")
        dataset.attrs["steinbock"] = True
    return ilastik_img_file
Back to top