Registration Workflow#

Patient-to-template structural registration with ANTs CLI or Python FireANTs backend. Provides a swappable QC viewer abstraction (FSLeyes implemented; html reserved). FireANTs deformable runs export the affine and a composed warp as ANTs-compatible 5-D NIfTI (intent_code=1007).

thesis.workflows.registration.workflow#

Patient-to-template structural registration workflow.

thesis.workflows.registration.workflow.build_workflow(*, config, context)[source]#

Build the configured registration workflow for one patient.

Parameters:
Return type:

Workflow

thesis.workflows.registration.workflow.verify_requirements(config, context, **_)[source]#

Cross-cutting preflight checks: binaries, optional packages, GPU, viewer.

Parameters:
Return type:

List[str]

thesis.workflows.registration.paths#

Path helpers for the registration workflow.

thesis.workflows.registration.paths.DEFAULT_REGISTRATION_JOB = 'patient_to_template'#

Name of the implicit registration job synthesized when registration.jobs is empty. Its on-disk transforms use the legacy flat layout/filenames.

class thesis.workflows.registration.paths.ResolvedRegistrationJob[source]#

Bases: object

A fully-resolved registration job.

The single source of truth produced by resolve_registration_jobs(): the shared registration.* defaults merged with any per-job overrides. All scalar fields are non-optional here (overrides fall back to the shared value), and fireants is a fully-validated config (the sparse per-job block merged onto the shared one).

Variables:
  • name – The job name ("patient_to_template" for the implicit default).

  • is_default – Whether this is the implicit default job (legacy flat on-disk layout).

  • method – Resolved registration backend.

  • moving_modality – Resolved moving-image modality.

  • moving_image – Resolved explicit moving-image path override (or None).

  • fixed_image – Resolved fixed-image path override (or None).

  • interpolation – Resolved interpolation mode.

  • metric – Resolved similarity metric.

  • transform_type – Resolved transform family (Rigid/Affine/SyN).

  • use_float – Resolved float-precision flag.

  • fireants – Resolved (re-validated) FireANTs backend config.

Parameters:
name: str#
is_default: bool#
method: str#
moving_modality: str#
moving_image: str | None#
fixed_image: str | None#
interpolation: str#
metric: str#
transform_type: str#
use_float: bool#
fireants: FireantsRegistrationConfig#
property safe_name: str#

Return an identifier-safe form of the job name.

__init__(name, is_default, method, moving_modality, moving_image, fixed_image, interpolation, metric, transform_type, use_float, fireants)#
Parameters:
Return type:

None

thesis.workflows.registration.paths.get_registration_output_dir(config, context)[source]#

Return the patient-specific output directory for registration artifacts.

Parameters:
Return type:

Path

thesis.workflows.registration.paths.get_registration_transform_dir(config, context)[source]#

Return the transform output directory for the registration workflow.

Parameters:
Return type:

Path

thesis.workflows.registration.paths.get_registration_warped_image_path(config, context)[source]#

Return the output path of the patient image warped to template space.

Parameters:
Return type:

Path

thesis.workflows.registration.paths.get_registration_inverse_warped_image_path(config, context)[source]#

Return the output path of the template image warped to patient space.

Parameters:
Return type:

Path

thesis.workflows.registration.paths.get_registration_transform_prefix(config, context)[source]#

Return the ANTs output transform prefix for patient-to-template transforms.

Parameters:
Return type:

str

thesis.workflows.registration.paths.get_registration_job_dir(config, context, job)[source]#

Return the per-job output directory for registration artifacts.

The implicit default job ("patient_to_template") uses the legacy flat layout (<output>/registration) so existing on-disk paths and caches keep working. Explicit jobs nest under their (identifier-safe) name (<output>/registration/<job>).

Parameters:
Return type:

Path

thesis.workflows.registration.paths.get_registration_job_transform_dir(config, context, job)[source]#

Return the per-job transform output directory.

Parameters:
Return type:

Path

thesis.workflows.registration.paths.get_registration_job_transform_paths(config, context, job_name, direction)[source]#

Return the resolved transform chain a registration job produces.

The returned list is the same chain — in the same order, with the same filenames — the FireANTs backend emits, because both this resolver and the backend share registration_transform_filenames().

Parameters:
  • config (PipelineConfig) – The merged pipeline configuration.

  • context (ProcessingContext) – The processing context (supplies patient id + output dirs).

  • job_name (str) – The registration-job name to resolve.

  • direction (str) – "patient_to_template" selects the forward chain; "template_to_patient" selects the reverse chain.

Return type:

List[str]

Returns:

Ordered list of absolute transform path strings.

Raises:
  • KeyError – If job_name is not a resolved registration job.

  • ValueError – If direction is not a recognised value.

thesis.workflows.registration.paths.get_registration_job_warped_image_path(config, context, job)[source]#

Return the per-job moving→template warped-image output path.

Parameters:
Return type:

Path

thesis.workflows.registration.paths.get_registration_job_inverse_warped_image_path(config, context, job)[source]#

Return the per-job template→moving inverse-warped-image output path.

Parameters:
Return type:

Path

thesis.workflows.registration.paths.registration_transform_filenames(patient_id, job_name, transform_type)[source]#

Return the canonical transform filenames the FireANTs backend emits.

This is the single source of truth shared by the FireANTs backend (_run_staged) and the standalone transform resolver (get_registration_job_transform_paths). The names must never be duplicated elsewhere — both producers and consumers import this helper so the on-disk chain and the resolved chain stay in lock-step.

The returned lists are bare filenames (no directory). Callers join them onto the appropriate transform directory. The chain order matches the order the backend emits and downstream antsApplyTransforms expects.

For the legacy default job "patient_to_template" the names are the historical ones (<pid>_patient_to_template_* for the forward chain and <pid>_template_to_patient_* for the reverse chain) so existing caches and on-disk paths keep working. Other jobs use the <pid>_<job>_{forward,reverse}_* form.

Parameters:
  • patient_id (str) – Patient identifier used as the filename prefix.

  • job_name (str) – Registration job name (e.g. "patient_to_template").

  • transform_type (str) – One of "Rigid", "Affine" or "SyN".

Return type:

dict[str, list[str]]

Returns:

Mapping with two keys, "forward" (patient→template chain) and "reverse" (template→patient chain). Each value is the ordered list of transform filenames for that direction.

Raises:

ValueError – If transform_type is not a recognised value.

thesis.workflows.registration.paths.resolve_registration_jobs(config)[source]#

Resolve the registration jobs for config.

This is the single source of truth for the named-jobs model: it merges the shared registration.* defaults with each registration.jobs entry’s overrides. When registration.jobs is empty, a single implicit job named "patient_to_template" is synthesized from the top-level fields (so the existing single-registration config keeps working unchanged).

The per-job sparse fireants block is merged onto the shared registration.fireants and re-validated via FireantsRegistrationConfig.model_validate() (pydantic v2 model_copy(update=...) does not re-validate, so an invalid per-job override — e.g. a scale-length mismatch — must surface here).

Parameters:

config (PipelineConfig) – The merged pipeline configuration.

Return type:

List[ResolvedRegistrationJob]

Returns:

One ResolvedRegistrationJob per configured job (or a single implicit default when none are configured).

thesis.workflows.registration.paths.resolve_fixed_image(config, context)[source]#

Resolve the fixed template image path for the registration workflow.

Parameters:
Return type:

Path

thesis.workflows.registration.paths.resolve_fixed_image_for_job(config, context, job)[source]#

Resolve the fixed template image for a specific registration job.

Parameters:
Return type:

Path

thesis.workflows.registration.paths.resolve_moving_image(config, context)[source]#

Resolve the moving image path for the registration workflow.

Parameters:
Return type:

Path

thesis.workflows.registration.paths.resolve_moving_image_for_job(config, context, job)[source]#

Resolve the moving image for a specific registration job.

The default job reuses resolve_moving_image() verbatim (preserving the existing behaviour and tests). Explicit jobs honour their resolved moving_image / moving_modality overrides.

Parameters:
Return type:

Path

thesis.workflows.registration.viewers#

Viewer backends for registration quality control.

thesis.workflows.registration.viewers.build_fsleyes_command(template_image, warped_image, overlay_opacity=0.5)[source]#

Build an FSLeyes command for template/overlay registration review.

Parameters:
  • template_image (Path)

  • warped_image (Path)

  • overlay_opacity (float)

Return type:

list[str]

thesis.workflows.registration.viewers.describe_registration_viewer_command(template_image, warped_image, backend='fsleyes', overlay_opacity=0.5)[source]#

Return a shell-ready viewer command string for manual registration QC.

Parameters:
  • template_image (Path)

  • warped_image (Path)

  • backend (str)

  • overlay_opacity (float)

Return type:

str

thesis.workflows.registration.viewers.launch_registration_viewer(template_image, warped_image, backend='fsleyes', overlay_opacity=0.5)[source]#

Launch the configured registration QC viewer and return its command.

Parameters:
  • template_image (Path)

  • warped_image (Path)

  • backend (str)

  • overlay_opacity (float)

Return type:

list[str]

thesis.workflows.registration.fireants_backend#

FireANTs backend for patient-to-template registration.

The native staged flow mirrors FireANTs’ own reference pipeline (MomentsRegistration RigidRegistration AffineRegistration GreedyRegistration). Moments registration supplies center-of-mass and principal-axis initialization, which is what the old ANTs hack was substituting for; rigid/affine refine that initialization; and (for SyN) Greedy/SyN bakes the affine into a single composite forward warp. No ANTs subprocesses.

The reverse (template->patient) warp is produced by one of two ANTs-free routes, selected via registration.fireants.inverse_method:

  • simpleitk (default): numerically invert the high-quality forward displacement field with SimpleITK’s InvertDisplacementFieldImageFilter (explicit convergence tolerance). Works for both greedy and syn since it only needs the forward field, so it also unblocks deform_algo='syn'.

  • fireants: FireANTs’ own inverse-consistency solve (save_as_ants_transforms(save_inverse=True)); greedy only.

thesis.workflows.registration.fireants_backend.build_fireants_node(config, context, *, moving=None, fixed=None, job=None)[source]#

Build the FireANTs registration execution node.

Parameters:
  • config (PipelineConfig) – The merged pipeline configuration.

  • context (ProcessingContext) – The processing context.

  • moving (Path | None) – Optional explicit moving-image override (resolved from job otherwise).

  • fixed (Path | None) – Optional explicit fixed-image override (resolved from job otherwise).

  • job (ResolvedRegistrationJob | None) – The resolved registration job this node implements. When None the implicit default job is used (legacy behaviour).

Return type:

Node

Returns:

The configured FireANTs Nipype Function node. The default job keeps the legacy node name "fireants_registration"; explicit jobs use "fireants_<job>".

thesis.workflows.registration.fireants_backend.run_fireants_cli_task(fixed_image, moving_image, warped_image, inverse_warped_image, transform_dir, patient_id, transform_type, device, scales, affine_iterations, deformable_iterations, rigid_iterations, optimizer, affine_lr, deformable_lr, rigid_lr, cc_kernel_size, deformation_type, dtype, do_moments, do_rigid, moments_scale, moments_moments, deform_algo, job_name='patient_to_template', deformable_max_spacing_mm=None, use_gpu=True, loss_type='cc', normalize=True, inverse_method='simpleitk', inverse_max_iterations=50, inverse_tolerance=0.01)[source]#

Run staged FireANTs registration out-of-process via the CLI (Flavor 2).

Strips the _OUTPUT_PATH_SENTINEL from the output paths (added by build_fireants_node()), builds the thesis-fireants-register argv, shells out with subprocess.run(), and parses the last stdout line as the JSON result. On a non-zero exit whose stderr is the CUDA “no kernel image” failure, the helpful guidance message is re-raised so the user sees the same advice as the in-process path.

Return type:

tuple[str, str, list[str], list[str], str]

Returns:

Tuple of warped image path, inverse-warped image path, forward transforms, reverse transforms, and an informational note.

Parameters:
  • fixed_image (str)

  • moving_image (str)

  • warped_image (str)

  • inverse_warped_image (str)

  • transform_dir (str)

  • patient_id (str)

  • transform_type (str)

  • device (str)

  • scales (list[int])

  • affine_iterations (list[int])

  • deformable_iterations (list[int])

  • rigid_iterations (list[int])

  • optimizer (str)

  • affine_lr (float)

  • deformable_lr (float)

  • rigid_lr (float)

  • cc_kernel_size (int)

  • deformation_type (str)

  • dtype (str)

  • do_moments (bool)

  • do_rigid (bool)

  • moments_scale (int)

  • moments_moments (int)

  • deform_algo (str)

  • job_name (str)

  • deformable_max_spacing_mm (float | None)

  • use_gpu (bool)

  • loss_type (str)

  • normalize (bool)

  • inverse_method (str)

  • inverse_max_iterations (int)

  • inverse_tolerance (float)

thesis.workflows.registration.fireants_backend.run_fireants_registration_task(fixed_image, moving_image, warped_image, inverse_warped_image, transform_dir, patient_id, transform_type, device, scales, affine_iterations, deformable_iterations, rigid_iterations, optimizer, affine_lr, deformable_lr, rigid_lr, cc_kernel_size, deformation_type, dtype, do_moments, do_rigid, moments_scale, moments_moments, deform_algo, job_name='patient_to_template', deformable_max_spacing_mm=None, use_gpu=True, loss_type='cc', normalize=True, inverse_method='simpleitk', inverse_max_iterations=50, inverse_tolerance=0.01)[source]#

Thin Function-node wrapper around _run_staged().

Strips the _OUTPUT_PATH_SENTINEL from the output paths (the sentinel is added by build_fireants_node() to dodge Nipype’s file-content hashing) and delegates to _run_staged().

Return type:

tuple[str, str, list[str], list[str], str]

Returns:

Tuple of warped image path, inverse-warped image path, forward transforms, reverse transforms, and an informational note.

Parameters:
  • fixed_image (str)

  • moving_image (str)

  • warped_image (str)

  • inverse_warped_image (str)

  • transform_dir (str)

  • patient_id (str)

  • transform_type (str)

  • device (str)

  • scales (list[int])

  • affine_iterations (list[int])

  • deformable_iterations (list[int])

  • rigid_iterations (list[int])

  • optimizer (str)

  • affine_lr (float)

  • deformable_lr (float)

  • rigid_lr (float)

  • cc_kernel_size (int)

  • deformation_type (str)

  • dtype (str)

  • do_moments (bool)

  • do_rigid (bool)

  • moments_scale (int)

  • moments_moments (int)

  • deform_algo (str)

  • job_name (str)

  • deformable_max_spacing_mm (float | None)

  • use_gpu (bool)

  • loss_type (str)

  • normalize (bool)

  • inverse_method (str)

  • inverse_max_iterations (int)

  • inverse_tolerance (float)