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