ICP (Iterative Closest Point)

Pure Python implementation of Iterative Closest Point registration.

Class Reference

class physiomotion4d.RegisterModelsICP(fixed_model, log_level=20)[source]

Bases: PhysioMotion4DBase

Register anatomical models using Iterative Closest Point (ICP) algorithm.

This class provides ICP-based alignment of 3D surface models with support for both rigid and affine transformation modes. The registration pipeline uses centroid alignment for initialization followed by VTK’s ICP algorithm.

Registration Pipelines:
  • Rigid transform type: Centroid alignment → Rigid ICP

  • Affine transform type: Centroid alignment → Rigid ICP → Affine ICP

Transform Convention:
  • forward_point_transform: moving → fixed space transformation

    (This is the inverse of the transform used to wrap the moving image to the fixed image)

  • inverse_point_transform: moving → fixed space transformation

moving_model

Surface model to be aligned

Type:

pv.PolyData

fixed_model

Target surface model

Type:

pv.PolyData

transform_tools

Transform utility instance

Type:

TransformTools

forward_point_transform

Optimized moving→fixed transform

Type:

itk.AffineTransform

inverse_point_transform

Optimized fixed→moving transform

Type:

itk.AffineTransform

registered_model

Aligned moving model

Type:

pv.PolyData

Example

>>> # Initialize with model
>>> registrar = RegisterModelsICP(fixed_model=patient_surface)
>>>
>>> # Run rigid registration
>>> result = registrar.register(
...     transform_type='Rigid',
...     max_iterations=200,
...     moving_model=model_surface,
... )
>>>
>>> # Or run affine registration
>>> result = registrar.register(
...     transform_type='Affine',
...     max_iterations=200,
...     moving_model=model_surface,
... )
>>>
>>> # Get aligned model and transforms
>>> aligned_model = result['registered_model']
>>> forward_point_transform = result['forward_point_transform']
__init__(fixed_model, log_level=20)[source]

Initialize ICP-based model registration.

Parameters:
  • moving_model – PyVista surface model to be aligned to fixed model

  • fixed_model (PolyData) – PyVista target surface model

  • log_level (int | str) – Logging level (default: logging.INFO)

Note

The moving_model is typically extracted from a VTU model using model.extract_surface(algorithm=”dataset_surface”) before passing to this class.

register(moving_model, transform_type='Affine', max_iterations=2000)[source]

Perform ICP alignment of moving model to fixed model.

This method executes alignment with either rigid or affine transformations:

Rigid transform type:
  1. Centroid alignment: Translate moving model to align mass centers

  2. Rigid ICP: Refine with rigid-body transformation (rotation + translation)

Affine transform type:
  1. Centroid alignment: Translate moving model to align mass centers

  2. Rigid ICP: Refine with rigid-body transformation

  3. Affine ICP: Further refine with affine transformation (includes

    scaling/shearing)

Parameters:
  • moving_model (PolyData) – PyVista surface model to be aligned to fixed model

  • transform_type (str) – Registration transform type, either ‘Rigid’ or ‘Affine’. Default: ‘Affine’

  • max_iterations (int) – Maximum number of ICP iterations per stage. Default: 2000

Returns:

  • ‘registered_model’: Aligned moving model (PyVista PolyData)

  • ’forward_point_transform’: Moving→fixed transform

    (ITK AffineTransform)

  • ’inverse_point_transform’: Fixed→moving transform

    (ITK AffineTransform)

Return type:

Dictionary containing

Raises:

ValueError – If transform_type is not ‘Rigid’ or ‘Affine’

Example

>>> # Rigid registration
>>> result = registrar.register(
...     transform_type='Rigid',
...     max_iterations=5000,
...     moving_model=moving_model,
... )
>>>
>>> # Affine registration
>>> result = registrar.register(
...     transform_type='Affine',
...     max_iterations=2000,
...     moving_model=moving_model,
... )
classmethod get_log_classes()

Get the list of classes currently showing logs.

Return type:

list[str]

Returns:

List of class names that are allowed to show logs. Empty list if filter is disabled (all classes shown).

Example

>>> classes = PhysioMotion4DBase.get_log_classes()
>>> print(classes)
['RegisterModelsPCA', 'WorkflowFitStatisticalModelToPatient']
log_critical(message, *args)

Log a critical message with optional %-style formatting.

Parameters:
  • message (str) – The critical message to log (can contain %-style placeholders)

  • *args (Any) – Arguments for %-style string formatting

Return type:

None

Example

>>> self.log_critical('System failure at %s', timestamp)
>>> self.log_critical('Critical error: %(msg)s', {'msg': 'Out of memory'})
log_debug(message, *args)

Log a debug message with optional %-style formatting.

Parameters:
  • message (str) – The debug message to log (can contain %-style placeholders)

  • *args (Any) – Arguments for %-style string formatting

Return type:

None

Example

>>> self.log_debug('Processing %s with %d items', filename, count)
>>> self.log_debug('Value is %(value)d', {'value': 42})
log_error(message, *args)

Log an error message with optional %-style formatting.

Parameters:
  • message (str) – The error message to log (can contain %-style placeholders)

  • *args (Any) – Arguments for %-style string formatting

Return type:

None

Example

>>> self.log_error('Failed to load %s: %s', filename, error_msg)
>>> self.log_error('Error code: %(code)d', {'code': 404})
log_info(message, *args)

Log an info message with optional %-style formatting.

Parameters:
  • message (str) – The info message to log (can contain %-style placeholders)

  • *args (Any) – Arguments for %-style string formatting

Return type:

None

Example

>>> self.log_info('Loading file: %s', filepath)
>>> self.log_info('Iteration %(iter)d of %(total)d', {'iter': 5, 'total': 10})
log_progress(current, total, prefix='Progress')

Log progress information.

Parameters:
  • current (int) – Current step/iteration number

  • total (int) – Total number of steps/iterations

  • prefix (str) – Prefix text for the progress message. Default: ‘Progress’

Return type:

None

Example

>>> for i in range(100):
...     self.log_progress(i + 1, 100)
>>> self.log_progress(5, 10, prefix='Processing')

Note

For custom formatted progress messages, use log_info() directly: >>> self.log_info(‘Loading %s: %d/%d’, filename, current, total)

log_section(title, *args, width=70, char='=')

Log a formatted section header with optional %-style formatting.

Useful for visually separating major sections of output.

Parameters:
  • title (str) – The section title (can contain %-style placeholders)

  • *args (Any) – Arguments for %-style string formatting of title

  • width (int) – Total width of the header line. Default: 70

  • char (str) – Character to use for the header line. Default: ‘=’

Return type:

None

Example

>>> self.log_section('Stage 1: Initialization')
>>> self.log_section('Processing file: %s', filename)
>>> self.log_section('Stage %(num)d: %(name)s', {'num': 2, 'name': 'Analysis'})
# Outputs:
# ======================================================================
# Stage 2: Analysis
# ======================================================================
log_warning(message, *args)

Log a warning message with optional %-style formatting.

Parameters:
  • message (str) – The warning message to log (can contain %-style placeholders)

  • *args (Any) – Arguments for %-style string formatting

Return type:

None

Example

>>> self.log_warning('Memory usage at %d%%', usage_percent)
>>> self.log_warning('Parameter %(name)s out of range', {'name': 'threshold'})
classmethod set_log_all_classes()

Enable logging output from all PhysioMotion4D classes.

Disables the class filter so all classes show their logs.

Example

>>> PhysioMotion4DBase.set_log_all_classes()
>>> # Now all classes will show their logs
Return type:

None

classmethod set_log_classes(class_names)

Set which classes should show their logging output.

Only log messages from the specified classes will be displayed. All other classes will have their logs hidden.

Parameters:

class_names (list[str]) – List of class names to show logs from. Example: [“RegisterModelsPCA”, “WorkflowFitStatisticalModelToPatient”]

Return type:

None

Example

>>> PhysioMotion4DBase.set_log_classes(['RegisterModelsPCA'])
>>> # Now only RegisterModelsPCA logs will be shown
classmethod set_log_level(log_level)

Set the logging level for all PhysioMotion4D classes.

Parameters:

log_level (int | str) – Logging level. Can be an integer (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL) or a string (‘DEBUG’, ‘INFO’, ‘WARNING’, ‘ERROR’, ‘CRITICAL’).

Return type:

None

Example

>>> import logging
>>> PhysioMotion4DBase.set_log_level(logging.DEBUG)
>>> # or
>>> PhysioMotion4DBase.set_log_level('DEBUG')

Navigation

Model Registration Modules | ICP with ITK Backend | Distance Map Registration