Source code for itasc.cellpose.shape
"""Layout-free input canonicalisation for the standalone tool.
The standalone Cellpose tool supports neither stitching-as-a-mode nor true 3D
segmentation, so it never needs the 4-way ``2D/2D+t/3D/3D+t`` layout: it segments
every plane individually. The only place axis *identity* matters is tracking,
which links the **z** axis by spatial overlap (stitch) and the **t** axis by
motion (laptrack). By convention the shorter of the two leading axes is ``z``
(few z-slices, many timepoints is the common case) and the longer is ``t``.
:func:`to_canonical_tzyx` applies that convention so the rest of the pipeline can
keep working in canonical ``(T, Z, Y, X)`` without the user declaring a layout.
"""
from __future__ import annotations
import numpy as np
__all__ = ["to_canonical_tzyx", "describe_axes"]
[docs]
def to_canonical_tzyx(arr: np.ndarray) -> np.ndarray:
"""Coerce any 2-D..4-D input to canonical ``(T, Z, Y, X)`` without a layout.
- 2-D ``(Y, X)`` → ``(1, 1, Y, X)``.
- 3-D → one leading axis, read as **time** (the common 2D+t case); ``Z`` is a
singleton: ``(T, 1, Y, X)``.
- 4-D → two leading axes; the **shorter** is ``Z`` and the longer is ``T``, so
the result is reordered to ``(T, Z, Y, X)`` (a no-op when already so).
"""
arr = np.asarray(arr)
if arr.ndim == 2:
return arr[np.newaxis, np.newaxis]
if arr.ndim == 3:
return arr[:, np.newaxis]
if arr.ndim == 4:
if arr.shape[0] < arr.shape[1]:
# leading axis 0 is the shorter one → it is Z; swap to (T, Z, Y, X).
arr = np.swapaxes(arr, 0, 1)
return arr
raise ValueError(f"expected a 2-D..4-D array, got shape {arr.shape}")
[docs]
def describe_axes(shape: tuple[int, ...]) -> str:
"""Human-readable summary of how an input shape is interpreted.
Used for widget status so the user can see the inferred ``T``/``Z`` without a
picker, e.g. ``"6×512×512 → T=6, Z=1"`` or ``"40×5×512×512 → T=40, Z=5"``.
"""
canon = to_canonical_tzyx(np.empty(shape, dtype=np.uint8))
T, Z = int(canon.shape[0]), int(canon.shape[1])
dims = "×".join(str(s) for s in shape)
return f"{dims} → T={T}, Z={Z}"