Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ Version bumping: `bumpver update --patch`, `--minor`, or `--major`.
- Scripts that instantiate `SegmentChestTotalSegmentator` must guard the
top-level invocation with `if __name__ == "__main__":` on Windows
(`torch.multiprocessing` requires it).
- Single quotes for strings; double quotes for docstrings. Keep lines at or
- Double quotes for strings and docstrings. Keep lines at or
below 88 characters.
- Full type hints are required under strict mypy. Use `Optional[X]`, not
`X | None`.
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ Document via docstrings and inline comments.

## Code Style

- Single quotes for strings; double quotes for docstrings
- Double quotes for strings and docstrings
- Full type hints (`mypy` strict; `disallow_untyped_defs = true`)
- `Optional[X]` not `X | None` (ruff `UP007` suppressed)
- Breaking changes are acceptable — backward compatibility is not a priority
Expand Down
2 changes: 2 additions & 0 deletions docs/api/utilities/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Quick Links

**Utility Modules**:
* :doc:`image_tools` - Image processing utilities
* :doc:`labelmap_tools` - Labelmap to registration-mask conversion
* :doc:`transform_tools` - Transform operations
* :doc:`contour_tools` - Contour processing
* :doc:`image_conversion` - 4D image to 3D time-series utilities
Expand All @@ -34,6 +35,7 @@ Module Documentation
:maxdepth: 2

image_tools
labelmap_tools
transform_tools
contour_tools
image_conversion
Expand Down
19 changes: 19 additions & 0 deletions docs/api/utilities/labelmap_tools.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
====================================
Labelmap Tools
====================================

.. currentmodule:: physiomotion4d

Convert segmentation labelmaps into binary registration masks, with optional
label exclusion and physically isotropic dilation.

Module Reference
================

.. automodule:: physiomotion4d.labelmap_tools
:members:
:undoc-members:

.. rubric:: Navigation

:doc:`index` | :doc:`image_tools` | :doc:`transform_tools`
2 changes: 1 addition & 1 deletion docs/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ PhysioMotion4D follows strict code quality standards using modern, fast tooling.
Formatting and Linting with Ruff
---------------------------------

We use **Ruff** for all formatting and linting (line length: 88, single quotes):
We use **Ruff** for all formatting and linting (line length: 88, double quotes):

.. code-block:: bash

Expand Down
7 changes: 6 additions & 1 deletion docs/developer/registration_images.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ Basic Pattern
registered = registrar.get_registered_image()

The result dictionary contains ``forward_transform``, ``inverse_transform``,
and ``loss``.
and ``loss``. Applying the right one is critical and direction-dependent:
``forward_transform`` warps the moving image onto the fixed grid, while
``inverse_transform`` warps moving points/landmarks into fixed space (image and
point warps use opposite transforms). See
:doc:`transform_conventions` for the full rules.

Time Series
===========
Expand Down Expand Up @@ -57,5 +61,6 @@ Development Notes
See Also
========

* :doc:`transform_conventions`
* :doc:`../api/registration/index`
* :doc:`workflows`
5 changes: 5 additions & 0 deletions docs/developer/registration_models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,14 @@ Development Notes
* Convert volumetric meshes to surfaces before surface registration when needed.
* Treat ITK/PyVista coordinate transforms as high-risk and add focused tests.
* Keep synthetic test meshes small and deterministic.
* ``RegisterModelsPCA`` returns ``forward_point_transform`` /
``inverse_point_transform``. These are **point** transforms whose orientation
is opposite to the image-registration transforms; see
:doc:`transform_conventions` before applying them to images or meshes.

See Also
========

* :doc:`transform_conventions`
* :doc:`../api/model_registration/index`
* :doc:`workflows`
137 changes: 137 additions & 0 deletions docs/developer/transform_conventions.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
===============================
Transform Direction Conventions
===============================

Registration in PhysioMotion4D produces a pair of transforms, and choosing the
wrong one of the pair is the single most common registration mistake. The rules
are simple but easy to get backwards, because **warping an image and warping a
point require opposite transforms**, and because **model (PCA) registration
returns its transforms in the opposite orientation from image registration**.

Read this page before applying any transform to an image, mask, contour, or
landmark.

The two transform families
===========================

Image registration
:class:`physiomotion4d.RegisterImagesANTS`,
:class:`physiomotion4d.RegisterImagesICON`, and
:class:`physiomotion4d.RegisterImagesGreedy` register a *moving* image to a
*fixed* image and return a dict with ``forward_transform`` and
``inverse_transform``. :class:`physiomotion4d.RegisterTimeSeriesImages`
returns the list-valued ``forward_transforms`` / ``inverse_transforms``.

Model (PCA) registration
:class:`physiomotion4d.RegisterModelsPCA` deforms a *template* model toward
a *target* (patient) and, via ``compute_pca_transforms()``, returns
``forward_point_transform`` and ``inverse_point_transform``. These are
**point transforms**, oriented opposite to the image-registration transforms
(see `PCA point transforms`_ below).

Image warping vs. point warping use opposite transforms
========================================================

ITK resampling is a *pull-back* operation. To build the warped image on the
fixed grid, :func:`TransformTools.transform_image` (an ``itk.ResampleImageFilter``)
visits every fixed-grid sample ``q`` and looks up the moving image at
``transform.TransformPoint(q)``. The transform it needs therefore maps
**fixed-space coordinates to moving-space coordinates**.

Warping a *point* (landmark, contour vertex, mesh node) is a *push-forward*
operation: :func:`TransformTools.transform_pvcontour` /
:func:`TransformTools.transform_dataset` apply ``transform.TransformPoint(p)``
directly to each input point. To move a moving-space landmark to its location in
the fixed image, the transform must map **moving-space coordinates to
fixed-space coordinates** -- the inverse of the image-warp transform.

So for the **same** moving-to-fixed registration result:

.. list-table:: Image registration: which transform to apply
:header-rows: 1
:widths: 50 25 25

* - Goal
- Transform
- Helper
* - Warp the **moving image** into fixed space (onto the fixed grid)
- ``forward_transform``
- :func:`TransformTools.transform_image`
* - Warp **moving points / contours / landmarks** into fixed space
- ``inverse_transform``
- :func:`TransformTools.transform_pvcontour`
* - Warp the **fixed image** into moving space (e.g. time-series reconstruction)
- ``inverse_transform``
- :func:`TransformTools.transform_image`
* - Warp **fixed points / contours / landmarks** into moving space
- ``forward_transform``
- :func:`TransformTools.transform_pvcontour`

The first two rows are the everyday case (warping the registered moving data
into the fixed/reference frame): the **image uses** ``forward_transform``, the
**points use** ``inverse_transform``. The last two rows are the mirror image;
:meth:`physiomotion4d.RegisterTimeSeriesImages.reconstruct_time_series` is the
canonical consumer of ``inverse_transform`` for image warping (it resamples the
fixed image back onto each moving frame's grid).

.. note::

All three image-registration backends (ANTS, ICON, Greedy) follow this same
convention. ``transform_image(moving, forward_transform, fixed)`` is the
correct call to warp the moving image onto the fixed grid for every backend.

PCA point transforms
====================

:class:`physiomotion4d.RegisterModelsPCA` builds ``forward_point_transform``
directly from the template-to-target point displacement, so
``forward_point_transform.TransformPoint(template_point)`` returns the
corresponding *target* point. As a **point** map it goes template (moving) to
target (fixed) -- which is the same orientation as image registration's
``inverse_transform``, and therefore the **opposite** orientation of image
registration's ``forward_transform``.

Concretely, treating the template as the moving object and the patient/target as
the fixed object:

.. list-table:: Same goal, opposite transform names across the two families
:header-rows: 1
:widths: 50 25 25

* - Goal
- Image registration
- PCA model registration
* - Warp the **image** (moving/template space -> fixed/target grid)
- ``forward_transform``
- ``inverse_point_transform``
* - Warp **points / meshes** (moving/template -> fixed/target)
- ``inverse_transform``
- ``forward_point_transform``

In other words, ``forward_point_transform`` plays the role that
``inverse_transform`` plays for image registration, and
``inverse_point_transform`` plays the role of ``forward_transform``. Deforming
the template mesh onto the patient (the usual PCA use, performed internally by
``transform_template_model()`` and ``transform_point()``) uses
``forward_point_transform``; resampling an image with the PCA result uses
``inverse_point_transform``.

Rule of thumb
=============

* **Images pull back; points push forward.** For one registration result, the
image and the points always use the two *different* members of the transform
pair.
* **Image into the reference frame** -> ``forward_transform`` (image
registration) / ``inverse_point_transform`` (PCA).
* **Points into the reference frame** -> ``inverse_transform`` (image
registration) / ``forward_point_transform`` (PCA).
* When in doubt, warp a known landmark and a small image patch and confirm they
land in the same place before trusting a pipeline.

See Also
========

* :doc:`registration_images`
* :doc:`registration_models`
* :doc:`utilities`
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ per-tutorial implementation details.
developer/segmentation
developer/registration_images
developer/registration_models
developer/transform_conventions
developer/usd_generation
developer/utilities

Expand Down
Loading
Loading