Fast, accurate and user-friendly Python interface for applying CMTK (Computational Morphometry Toolkit) transformations, without requiring subprocess calls to external command-line tools.
Thanks to the use of numba, we are on par for inverse transforms and ~2x faster for forward transforms compared to CMTK's streamxform tool. For smaller point sets the speed-up is even more dramatic due to eliminating overhead from process startup and file I/O. See BENCHMARK_RESULTS.md for details.
pip install cmtk-applypip install git+https://github.com/schlegelp/cmtk_applyClone the repository and run:
pip install -e ".[dev]"from cmtk_apply import load_registration
# Load a registration (directory or file path)
reg = load_registration("JFRC2_FCWB.list")
# Forward transform points
points = [[10.0, 20.0, 30.0], [40.0, 50.0, 60.0]]
forward = reg.transform_points(points)
print(forward)
# Inverse transform
inverse = reg.inverse_transform_points(forward)
print(inverse)Enable fastmath for Numba kernels by setting the environment variable:
export CMTK_APPLY_FASTMATH=1Expected impact (warp forward): ~1.5x speedup with max absolute drift around 1e-13 on typical inputs. Restart the Python process after changing the variable.
Load a CMTK registration from a .list folder or registration file.
Parameters:
path: Path to a CMTK registration directory (.listfolder) or aregistrationfile (optionally gzipped).
Returns: A Registration object.
Apply the registration transformation to points.
output = reg.transform_points(
points, # N×3 array-like of 3D points
transform="warp", # "warp" (default) or "affine"
allow_extrapolation=True, # Allow evaluation outside spline grid
fallback_to_affine=True, # Use affine if spline fails
)Parameters:
points: N×3 array or list of 3D coordinatestransform:"warp"evaluates both affine and spline;"affine"evaluates affine onlyallow_extrapolation: IfFalse, points outside the spline domain return NaNfallback_to_affine: IfTrue, points that fail spline evaluation fall back to affine
Returns: N×3 NumPy array of transformed points
Apply the inverse transformation to points.
output = reg.inverse_transform_points(
points, # N×3 array-like of 3D points
transform="warp", # "warp" (default) or "affine"
allow_extrapolation=True, # Allow evaluation outside spline grid
fallback_to_affine=True, # Use affine if spline fails
solver="auto", # "auto" (default), "analytical" or "numerical"
)Parameters:
points: N×3 array or list of 3D coordinatestransform:"warp"evaluates both affine and spline;"affine"evaluates affine onlyallow_extrapolation: IfFalse, points outside the spline domain return NaNfallback_to_affine: IfTrue, points that fail spline evaluation fall back to affinesolver: Method for solving inverse warp;"auto"uses analytical for >500 points and "numerical" otherwise
Returns: N×3 NumPy array of inverse transformed points
The library interprets the absolute flag in the spline warp configuration:
absolute yes: Coefficients represent absolute positions → final = spline(affine_transformed_point)absolute no: Coefficients represent displacements → final = affine_transformed_point + spline_displacement
CMTK affine parameters are decomposed into:
- xlate: Translation (tx, ty, tz)
- rotate: Rotation angles in degrees (rx, ry, rz)
- scale: Anisotropic scaling (sx, sy, sz)
- shear: Shear components (shx, shy, shz)
- center: Center of rotation (cx, cy, cz)
The matrix composition follows CMTK's post-2.4.0 convention. Legacy (<2.4.0) behavior is auto-detected from the TypedStream version field.
The cubic B-spline basis functions for parameter t ∈ [0,1] are:
A 4×4×4 neighborhood of control points is evaluated for each query point using tensor products of these weights.
Run tests with pytest:
pytest tests/To compare against CMTK's streamxform tool (if available):
pytest -v tests/test_cmtk_xf.py::test_affine_matches_streamxform
pytest -v tests/test_cmtk_xf.py::test_warp_matches_streamxformTests skip automatically if streamxform is not in the expected location.
The JFRC2_FCWB.list/ folder contains a pre-computed registration from the Drosophila reference brain JFRC2 to the FCWB template. This registration includes:
- An affine component (12 DOF)
- A 59×27×11 B-spline warp grid with deformation coefficients
CMTK's TypedStream format is a text-based nested structure:
! TYPEDSTREAM 2.4
registration {
reference_study "..."
floating_study "..."
affine_xform {
xlate 0 0 0
rotate 0 0 0
...
}
spline_warp {
affine_xform { ... }
absolute yes
dims 59 27 11
origin -11.36 -13.24 -16.87
domain 636.39 317.88 134.99
coefficients ...
}
}
- This library focuses on the core transformation logic; it does not reformat images (use CMTK's
reformatxfor that). - The
activefield in spline warps is parsed but not used; all control points are weighted equally (matches behavior of CMTK'sstreamxform).
MIT