longitudinal/REGISTRATION_BENCHMARK_DEFORMABLE.md
Furen Xiao bec0e9834f feat(benchmark): add ANTs deformable variant pipelines
Extend registration_pipelines and bench_registration with stock antspyx
ANTs presets (SyNRA, SyN, Repro sr/br, QuickRepro sr/br) plus the legacy
Rigid -> SyNOnly workflow, and update the deformable benchmark
documentation with follow-up ANTs-variant runs and results.
2026-10-03 13:26:12 +08:00

31 KiB
Raw Blame History

Registration Pipeline Benchmark — CT → T1c (M6) — Deformable

Companion to REGISTRATION_BENCHMARK_RIGID.md: the deformable variant of the same six-pipeline benchmark. The rigid benchmark asked "which toolkit aligns the head best with 6 DOF?"; this one asks "which toolkit's native deformable workflow aligns the head (and the tissue) best?" on the same 10 M6 CT→T1c test cases, the same unified contract, and the same metrics.

Run date: 2026-10-02 (main run 05:43–07:52 local; serial synthmorph re-run 09:58–10:07 local; accelerated simpleitk re-run 15:31–16:26 local). Follow-up ANTs-variant runs 2026-10-03 (08:44–09:12 local: five stock antspyx presets — direct SyNRA / SyN, Repro[sr|br], QuickRepro[sr|br]; 11:00–11:26 local: the legacy two-call Rigid → SyNOnly workflow; 12:44–12:49 local: re-run of the stock SyN preset as ants_syn, replacing the initial SyNOnly row) on the same 10 cases (see the ANTs variants section). 10 M6 test cases, 3× NVIDIA A100 80GB PCIe, 96-core host, conda env longitudinal-313. Main run: 6 workers (24 threads each, 2 workers per GPU). synthmorph was re-run serially (1 worker, one container per GPU at a time) because the concurrent run lost 6/9 cases to cuDNN scratch-space allocation failures (see the SynthMorph note under Interpretation); the re-run registered 9/9, matching the concurrent run's scores to 4 decimals on the 3 cases it completed. simpleitk was re-run after its spline grid was accelerated from 16 mm to 24 mm (see the simpleitk row of the pipeline table; the original 16 mm results are archived as simpleitk_16mm_legacy.json).

Unified contract

Identical to the rigid benchmark: the returned transform T must satisfy sitk.Resample(ct, t1c, T, ...) = CT on the T1c grid, i.e. T maps T1c → CT coordinates. fixed = T1c, moving = CT, full volumes (no head box, no mask, no crop, no pad), each toolkit's native automatic transform initialization, CT clipped to [0, 80] HU only for the pipelines where the rigid A/B showed clipping helps (niftyreg, synthmorph).

One deformable-specific change: every pipeline's output (elastix BSpline combination, ANTs warp + affine composite, NiftyReg affine + F3D spline, SimpleITK Euler + BSpline, SynthMorph joint field, IMPACT RecursiveBSpline) is rasterised to a SimpleITK DisplacementFieldTransform on the T1c grid before scoring, so all six pipelines return the same transform type and the shared scoring / GTV warping / QA code is used verbatim.

The six pipelines (deformable configurations)

Each pipeline runs its toolkit's native deformable workflow — a linear init stage + a deformable stage, or a single deformable stage where that is the toolkit's canonical setup:

pipeline deformable configuration metric
antspyx type_of_transform='SyN' (ANTs' native deformable): Affine stage (2100×1200×1200×0, shrink 4×2×2×1) + SyN[0.2,3,0] deformable stage (40×20×0, shrink 4×2×1), center-of-mass auto init Mattes MI (32 bins), both stages
elastix two-stage (the toolkit's canonical deformable workflow): EulerTransform rigid stage (2000 iters × 3 resolutions, CenterOfGravity auto init) → BSplineTransform stage (16 mm grid, spline order 3, 2000 iters × 3 resolutions) initialized from stage 1 via -t0 Mattes MI (32 bins), 5000 samples/level
impact the ImpactReg MR_CT_TS reference map in its native deformable form: RecursiveBSplineTransform (14 mm final grid, order 3) driven by the MIND + TotalSegmentator static feature combination (4 per-level scales 400/300/200/200 iters, 2000 samples) with the reference's three-metric combination: IMPACT (w 1.0) + Mattes MI (w 0.4) + TransformBendingEnergyPenalty (w 10). Two M6 adaptations, same as the rigid benchmark: CenterOfGravity auto init (the reference's GeometricalCenter start leaves the heads ~100 mm apart and aborts) and RequiredRatioOfValidSamples 0.1 IMPACT semantic (L1 + Dice) + Mattes MI + bending energy
niftyreg reg_aladin rigid init (3-level pyramid, 15 TLS iters/level) → reg_f3d non-rigid (F3D B-spline Free-Form deformation, Modat et al. 2010; NMI metric, symmetric bending/linear regularisation, 3-level pyramid, 150 iters at the final level, 8 mm final grid) NCC block matching (init) + NMI (F3D)
simpleitk two-stage (the toolkit's canonical deformable demo): Euler3D stage (2000 iters/level, pyramid [4,2,1]) → BSplineTransform3D stage (24 mm grid, 50 iters/level on pyramid [4,2]), the BSpline's control points initialised to reproduce the Euler stage exactly. The 24 mm grid (5577 parameters) is the accelerated setting (the 2026-10-02 original used 16 mm / 13005 parameters, ~61 min/case under the harness): this build's spline per-iteration cost scales ~linearly with the control-point count (~2.8 s/iter at the shrink-4 level and ~20 s/iter at shrink-2 for 24 mm vs ~6.4 / ~45.8 s for 16 mm — independent of the metric sample count, which is fixed in this SimpleITK build; LBFGS2 was tested and fails to move the transform on this noisy MI), and the full re-run keeps the 16 mm quality within 0.003–0.029 MI per case (median 0.698 vs 0.705, ImpactLoss median unchanged) while retaining simpleitk's m6_26TYQI3C MI/ImpactLoss win — see the acceleration note under Interpretation. A full-resolution polish pass (10 iters at shrink-1) was tested and dropped the achieved MI (0.6891 at 32 mm), so the pyramid stays [4,2] Mattes MI (32 bins), both stages
synthmorph joint model (affine + deformable in one symmetric network pass — the toolkit's canonical deformable; the deformable model requires a pre-existing field and would bias the comparison) anatomy-aware contrast-invariant network (pretrained)

Test cases

First 10 M6 labelled cases of m6.discover() (all with a GTV label): m6_22GD5VL2_20230724, m6_22IRRKU6_20240115, m6_23XIMO4M_20230222, m6_24V62QQM_20230223, m6_24V62QQM_20231017, m6_24V62QQM_20240820, m6_26TYQI3C_20221027, m6_2BBN5XA4_20250411, m6_2C4TKI6H_20240506, m6_2CDNN7BH_20240102.

(m6_22GD5VL2_20230724 has an incomplete CT head — a known data issue, not a pipeline failure; it is scored as ct_incomplete in every pipeline, as in the rigid benchmark.)

(Ground-truth reference transforms are not part of this benchmark — scoring is by achieved image similarity only, as in the rigid benchmark.)

Metrics (identical for every pipeline)

  • Mattes MI (nats) between the warped CT and the T1c over the MR head (largest connected component of the T1c mask) — achieved alignment, higher = better.
  • IMPACT loss (vboussot/ImpactLoss; pretrained TotalSegmentator TS/M730 deep features — weighted L1 over the two deepest layers, full volumes; the same scorer as the rigid benchmark) between the warped CT and the T1c — semantic-anatomy similarity, lower = better.
  • Registration wall time (seconds, excludes I/O + scoring).

Per-case JSONs additionally retain the production skull-ring QA (gap + concentricity, and the acceptance verdict) for reference.

Result

Alignment is scored by the achieved Mattes MI (nats, warped-CT ~ T1c over the MR head; higher = better) and the ImpactLoss semantic score (warped-CT ~ T1c over the full volumes; lower = better), on the same unclipped scoring volumes as the rigid benchmark, so all rows are comparable on the same scales and against the rigid numbers. Full volumes, no mask / crop / pad, fixed = T1c / moving = CT (shared rule). niftyreg and synthmorph clip the CT (the moving image) to [0, 80] HU before registration (per the rigid benchmark's clipping A/B); antspyx, elastix, impact and simpleitk register the CT as-is. All six transforms are deformable (each toolkit's native workflow) and are rasterised to T1c-grid displacement fields before scoring.

All six pipelines registered 9/9 cases (the 10th is the known incomplete-CT data issue, unscored in every pipeline). Bold = best for the column (MI higher is better, ImpactLoss lower is better).

pipeline toolkit registered s/reg (med) ImpactLoss (med/mean) MI (med/mean, nats)
antspyx ANTsPy 0.6.3 9 31.7 0.158 / 0.156 0.723 / 0.729
elastix ITK-Elastix 0.25.4 9 45.8 0.164 / 0.164 0.622 / 0.627
impact Docker vboussot/elastix_impact (Elastix 5.2.0 + IMPACT, deformable MIND+TS reference map) 9 273.2 0.159 / 0.159 0.553 / 0.547
niftyreg NiftyReg 2.1.1 (reg_aladin + reg_f3d, Docker + CUDA) 9 38.1 0.161 / 0.161 0.666 / 0.686
simpleitk SimpleITK 2.5.6 9 1369.9 0.158 / 0.159 0.698 / 0.704
synthmorph Docker freesurfer/synthmorph (TensorFlow, pretrained) 9 49.1 0.156 / 0.156 0.627 / 0.640

Per-case MI (nats, unclipped score; bold = best for the case). The synthmorph column is from the serial re-run (see the SynthMorph note under Interpretation):

case antspyx elastix impact niftyreg simpleitk synthmorph
m6_22GD5VL2_20230724 incomplete-CT incomplete-CT incomplete-CT incomplete-CT incomplete-CT incomplete-CT
m6_22IRRKU6_20240115 0.679 0.580 0.548 0.637 0.654 0.620
m6_23XIMO4M_20230222 0.723 0.622 0.573 0.711 0.693 0.618
m6_24V62QQM_20230223 0.789 0.570 0.635 0.729 0.738 0.701
m6_24V62QQM_20231017 0.720 0.622 0.580 0.665 0.692 0.628
m6_24V62QQM_20240820 0.738 0.674 0.462 0.707 0.700 0.666
m6_26TYQI3C_20221027 0.799 0.694 0.537 0.793 0.801 0.709
m6_2BBN5XA4_20250411 0.666 0.585 0.436 0.612 0.641 0.569
m6_2C4TKI6H_20240506 0.719 0.635 0.553 0.656 0.698 0.627
m6_2CDNN7BH_20240102 0.726 0.660 0.602 0.666 0.718 0.624

Per-case ImpactLoss (semantic, unclipped score; bold = best (lowest) for the case):

case antspyx elastix impact niftyreg simpleitk synthmorph
m6_22GD5VL2_20230724 incomplete-CT incomplete-CT incomplete-CT incomplete-CT incomplete-CT incomplete-CT
m6_22IRRKU6_20240115 0.1541 0.1595 0.1532 0.1530 0.1572 0.1512
m6_23XIMO4M_20230222 0.1581 0.1657 0.1567 0.1605 0.1603 0.1573
m6_24V62QQM_20230223 0.1473 0.1634 0.1497 0.1541 0.1502 0.1470
m6_24V62QQM_20231017 0.1518 0.1591 0.1547 0.1620 0.1548 0.1518
m6_24V62QQM_20240820 0.1545 0.1646 0.1694 0.1706 0.1584 0.1562
m6_26TYQI3C_20221027 0.1580 0.1638 0.1656 0.1672 0.1562 0.1602
m6_2BBN5XA4_20250411 0.1624 0.1663 0.1669 0.1648 0.1631 0.1616
m6_2C4TKI6H_20240506 0.1594 0.1640 0.1585 0.1552 0.1626 0.1564
m6_2CDNN7BH_20240102 0.1590 0.1662 0.1597 0.1605 0.1633 0.1583

Interpretation

  • antspyx (Affine + SyN) leads on achieved MI (median 0.723; best on 8 of 9 cases and within 0.002 of best on the other — m6_26TYQI3C, 0.799 vs simpleitk's 0.801) at the best median ImpactLoss of the gradient-based tools (0.158, within 0.002 of synthmorph's 0.156), and it is the fastest full-workflow pipeline (31.7 s/case) — the best time/quality trade of the six.
  • simpleitk is second on MI (0.698; it keeps its per-case win on m6_26TYQI3C — 0.801, still the highest MI of the whole benchmark, though now only 0.001 ahead of antspyx — and cedes its m6_2CDNN7BH win to antspyx, 0.718 vs 0.726) at a cost of ~23 min/case under the harness — ~43× the fastest pipeline after the spline-grid acceleration below (this build's BSpline per-iteration cost scales ~linearly with the control-point count, independent of the metric sample count — see the pipeline table).
  • simpleitk acceleration (2026-10-02): the original setting (16 mm spline grid, 13005 parameters) ran 3658.9 s/case (median) under the harness. The spline stage's per-iteration cost in this build scales ~linearly with the control-point count (16 mm: ~6.4 s/iter at the shrink-4 level, ~45.8 s at shrink-2; 24 mm: ~2.8 / ~20 s; 32 mm: ~1.2 / ~9.6 s), and the metric sample count is fixed in this SimpleITK build (SetMetricAsMattesMutualInformation exposes only the histogram bins); LBFGS2 was tested and its line search rejects every step on this noisy MI (the transform does not move). Switching to the 24 mm grid (5577 parameters) cut the wall to 1369.9 s median (2.7×) at a cost of −0.003…−0.029 MI on 8 of 9 cases (+0.017 on m6_2C4TKI6H; median 0.698 vs 0.705), with the median ImpactLoss unchanged (0.158) and simpleitk's m6_26TYQI3C MI/ImpactLoss wins intact. A 32 mm grid (a further ~1.9×) was rejected: it drops below antspyx's 0.7994 on m6_26TYQI3C (0.7902, and 0.7963 even with 100 fine-level iters). A full-resolution polish pass (10 iters at shrink-1) was also tested and dropped the achieved MI (0.6891 at 32 mm). The original 16 mm results are archived as simpleitk_16mm_legacy.json.
  • niftyreg's reg_f3d stage delivers the largest deformable gain of any pipeline (0.292 → 0.666 median MI, +0.374): it recovers the two gross-offset cases where the rigid block-matching locked onto local minima (m6_24V62QQM_20240820 0.118 → 0.707, m6_2BBN5XA4 0.069 → 0.612), lifts the toolkit to third on MI, and it is the most concentric of the six (median skull-ring gap 5.5 mm mid / 3.8 mm std, 6/9 accepted).
  • The deformable stage does not uniformly pay off. Against the rigid benchmark's per-case MI it improves antspyx (0.652 → 0.723 median), simpleitk (0.647 → 0.698, accelerated 24 mm setting) and niftyreg (0.292 → 0.666), but degrades elastix (0.646 → 0.622; mixed per case, worst regression m6_24V62QQM_20230223 0.698 → 0.570) and impact (0.652 → 0.553 — lower than its own rigid init on all 9 cases). The two degradations are the coarse-grid BSpline configurations (14–16 mm) with heavy bending regularisation — for impact the reference map's TransformBendingEnergyPenalty at weight 10 — so the deformable stage smooths rather than refines, and (for impact) its IMPACT-dominant objective is simply not the achieved-MI objective.
  • impact's deformable reference map is the weakest on the intensity scale (MI 0.553) even though its semantic score is competitive (ImpactLoss 0.159, within 0.003 of the best median) — a metric-objective/achieved-MI divergence the rigid benchmark did not show (there the two scores agreed, with impact in the top tier on both). At 273 s/case it is the worst time/quality trade of the six.
  • synthmorph (serial re-run, 9/9) splits the leaderboards: best on the semantic scale, mid-pack on the intensity scale. Median ImpactLoss 0.156 — the best of the six — with the per-case best on 4 of 9 (plus a 4-decimal tie with antspyx on m6_24V62QQM_20231017), while its MI (0.627) is fourth, statistically tied with elastix (0.622). The pretrained contrast-invariant network optimises learned anatomy rather than raw CT/MR intensity synchrony, so it wins where anatomy matters and loses where the intensity histogram matters. Fast (49.1 s/case) and the read-back cross-check against the tool's own resampling is NCC 1.0 on all 9 cases.
  • The two score families discriminate differently here than in the rigid benchmark. The ImpactLoss scale is nearly saturated (medians 0.156–0.164, ~5 % spread; per-case bests spread across five tools, elastix with 0/9), whereas the MI scale spans 0.553–0.723 (0.17 nats absolute) and the per-case bests go 8/9 antspyx, 1/9 simpleitk, 0/9 the rest. The deformable stage's main effect is fine intensity alignment on top of the gross anatomy the rigid stages already place — exactly what MI measures and ImpactLoss is less sensitive to. For ranking the deformable workflows, achieved MI is the more discriminative score.
  • synthmorph infrastructure note. In the main concurrent run (6 workers, 2 containers per GPU) 6 of 9 cases failed with CUDNN failed to allocate the scratch space ... [Op:Conv3D] inside the joint model's 256-channel 128³ hyperconvolution. Each case is a fresh docker run --rm container, so the failures are cuDNN scratch-space contention when two SynthMorph containers share one A100, not a pipeline fault: the serial re-run registered 9/9, reproduced the concurrent run's MI/ImpactLoss to 4 decimals on its 3 completed cases (deterministic model), and ran ~17 s/case faster without the contention (49.1 s vs 65.7 s median). The concurrent-run JSON is archived as synthmorph_concurrent_run.json.
  • Production skull-ring QA (reference only, kept in the per-case JSONs): acceptance 6/9 niftyreg, 5/9 elastix / synthmorph, 4/9 antspyx / simpleitk, 2/9 impact. Concentricity: niftyreg best (median gap 5.5 mm mid / 3.8 mm std), simpleitk (19.1 mm std, accelerated setting) and impact (18.9 mm) worst on the rotational term. The same weak correlation with perceived alignment noted in the rigid benchmark, so it is reported for reference only.

ANTs variants: direct SyNRA / SyN and the Repro / QuickRepro workflows

The current antspyx row above is antspyx's stock SyN preset (Affine 2100×1200×1200×0 + SyN[0.2,3,0] 40×20×0, Mattes MI 32, center-of-mass init). As a follow-up (2026-10-03, 6 workers as the main run) seven further ANTs configurations were benchmarked on the same 10 cases and the same contract — the question: is there a better stock ANTs deformable workflow for CT→T1c than the SyN preset?

pipeline antspyx preset stages (all COM init unless noted)
ants_rigid_synonly legacy two-call (Rigid + SyNOnly) Rigid[0.25] (Mattes 32, 500×500×200, 4×2×1, 3×2×0) → SyNOnly SyN[0.2,3,0] (Mattes 32, 100×100×0, 4×2×1, 2×1×0) initialized from the Rigid stage; Composite.h5 read-back
ants_synra SyNRA Rigid[0.25] + Affine[0.25] (each Mattes 32, 2100×1200×1200×0, 4×2×2×1, 3×2×1×0) + SyN[0.2,3,0] (Mattes 32, 40×20×0, 4×2×1)
ants_syn SyN Affine[0.25] (Mattes 32, 2100×1200×1200×0, 4×2×2×1, 3×2×1×0) + SyN[0.2,3,0] (Mattes 32, 40×20×0, 4×2×1); COM init — the stock preset, identical configuration to the existing antspyx row
ants_synreprosr antsRegistrationSyNRepro[sr] Rigid[0.1] (GC 1/1/Regular/0.25, 1000×500×250×100, 8×4×2×1, 3×2×1×0vox) + SyN[0.2,3,0] (CC 1/2, 50×20, 2×1, 1×0vox)
ants_synreprobr antsRegistrationSyNRepro[br] the Repro Rigid[0.1] stage + BSplineSyN[0.2,26,0,3] (CC 1/2, 50×20, 2×1, 1×0vox)
ants_synquickreprosr antsRegistrationSyNQuickRepro[sr] Rigid[0.1] (GC, 1000×500×250×0, 8×4×2×1) + SyN[0.2,3,0] (CC 1/2, 50×0, 2×1)
ants_synquickreprobr antsRegistrationSyNQuickRepro[br] Rigid[0.1] (GC, 1000×500×250×0, 8×4×2×1) + BSplineSyN[0.2,26,0,3] (CC 1/2, 50×0, 2×1)

sr/br select the deformable stage (SyN vs BSplineSyN, antspyx preset naming — not a brain mask); these are the same stage configurations the antsRegistrationSyNRepro*.sh / antsRegistrationSyNQuickRepro*.sh workflows use. ants_rigid_synonly is the two-call workflow that an early version of this benchmark used: a Rigid stage, then a deeper SyNOnly stage (100 iterations at every level incl. full resolution, vs the SyN preset's 40×20×0) initialized from the Rigid stage's transform. Full volumes, no CT clip, each toolkit preset's own metrics (GC/CC/Mattes as above). As for the other rows, the stage files are rasterised to the T1c-grid displacement field and scored with the shared code; the composite read-back was cross-checked per case against ANTs' own resampling (NCC 1.0 on all 63 scored cases, own_warp_ncc_head in the JSONs). One read-back subtlety: when ANTs runs Rigid + Affine as separate linear stages (SyNRA), it writes the merged linear stage as a binary 0GenericAffine.mat that SimpleITK cannot parse; the pipeline recovers it by point-probing the transform (exact for affine maps, verified to 2×10⁻⁴ mm).

All six variants registered 9/9 (the 10th is the known incomplete-CT data issue). Bold = best for the column; antspyx is the existing row, re-listed for reference.

pipeline registered s/reg (med) ImpactLoss (med/mean) MI (med/mean, nats)
ants_rigid_synonly 9 208.4 0.156 / 0.155 0.753 / 0.763
antspyx (existing) 9 31.7 0.158 / 0.156 0.723 / 0.729
ants_synra 9 43.6 0.158 / 0.156 0.722 / 0.729
ants_syn 9 33.8 0.158 / 0.156 0.722 / 0.729
ants_synreprosr 9 294.7 0.151 / 0.153 0.530 / 0.529
ants_synreprobr 9 370.3 0.156 / 0.157 0.541 / 0.537
ants_synquickreprosr 9 83.7 0.154 / 0.156 0.542 / 0.534
ants_synquickreprobr 9 96.0 0.158 / 0.158 0.549 / 0.538

Per-case MI (nats, unclipped score; bold = best for the case):

case antspyx ants_rigid_synonly ants_synra ants_syn ants_synreprosr ants_synreprobr ants_synquickreprosr ants_synquickreprobr
m6_22GD5VL2_20230724 incomplete-CT incomplete-CT incomplete-CT incomplete-CT incomplete-CT incomplete-CT incomplete-CT incomplete-CT
m6_22IRRKU6_20240115 0.679 0.741 0.681 0.681 0.623 0.646 0.630 0.627
m6_23XIMO4M_20230222 0.723 0.760 0.722 0.722 0.530 0.544 0.529 0.530
m6_24V62QQM_20230223 0.789 0.824 0.789 0.787 0.520 0.528 0.542 0.549
m6_24V62QQM_20231017 0.720 0.716 0.720 0.720 0.473 0.475 0.469 0.462
m6_24V62QQM_20240820 0.738 0.753 0.738 0.738 0.524 0.525 0.517 0.524
m6_26TYQI3C_20221027 0.799 0.857 0.798 0.799 0.557 0.541 0.599 0.632
m6_2BBN5XA4_20250411 0.665 0.696 0.665 0.666 0.230 0.303 0.235 0.297
m6_2C4TKI6H_20240506 0.719 0.751 0.719 0.719 0.672 0.649 0.654 0.621
m6_2CDNN7BH_20240102 0.726 0.765 0.726 0.725 0.629 0.622 0.631 0.599

Per-case ImpactLoss (semantic, unclipped score; bold = best (lowest) for the case):

case antspyx ants_rigid_synonly ants_synra ants_syn ants_synreprosr ants_synreprobr ants_synquickreprosr ants_synquickreprobr
m6_22GD5VL2_20230724 incomplete-CT incomplete-CT incomplete-CT incomplete-CT incomplete-CT incomplete-CT incomplete-CT incomplete-CT
m6_22IRRKU6_20240115 0.1541 0.1530 0.1542 0.1540 0.1442 0.1482 0.1474 0.1493
m6_23XIMO4M_20230222 0.1581 0.1565 0.1581 0.1581 0.1505 0.1549 0.1535 0.1585
m6_24V62QQM_20230223 0.1473 0.1464 0.1472 0.1472 0.1515 0.1553 0.1535 0.1560
m6_24V62QQM_20231017 0.1518 0.1512 0.1516 0.1519 0.1559 0.1575 0.1577 0.1581
m6_24V62QQM_20240820 0.1545 0.1545 0.1547 0.1546 0.1553 0.1578 0.1586 0.1586
m6_26TYQI3C_20221027 0.1580 0.1562 0.1578 0.1579 0.1561 0.1574 0.1602 0.1610
m6_2BBN5XA4_20250411 0.1624 0.1611 0.1624 0.1624 0.1680 0.1695 0.1690 0.1707
m6_2C4TKI6H_20240506 0.1594 0.1582 0.1594 0.1593 0.1490 0.1526 0.1517 0.1545
m6_2CDNN7BH_20240102 0.1590 0.1582 0.1589 0.1589 0.1493 0.1560 0.1538 0.1580

Interpretation (ANTs variants)

  • ants_rigid_synonly is the best ANTs configuration of the eight — the only one that beats the current antspyx row: median MI 0.753 (per-case best on 8 of 9; its 0.857 on m6_26TYQI3C is the highest MI of the whole benchmark, ahead of the previous 0.801) at ImpactLoss 0.156 (second-best median after synthmorph's 0.156). The gain over the SyN preset comes from the deeper SyN stage: 100 iterations at every level including full resolution (100×100×0 vs 40×20×0) refining the Rigid stage's pose. The cost is 208.4 s/case (~6.6× the preset) — the full-resolution SyN iterations dominate.
  • ants_synra is indistinguishable from the current antspyx row on quality (median MI 0.722 vs 0.723, ImpactLoss 0.158 vs 0.158; per-case deltas within 0.002 nats, ties on 4 of 9) at +38 % wall time (43.6 s vs 31.7 s): the explicit Rigid stage ahead of the Affine stage buys nothing — on these pairs the 12-DOF stage from the center-of-mass init already finds the gross pose, so the extra 6-DOF stage just re-solves it.
  • ants_syn reproduces the existing antspyx row (median MI 0.722 vs 0.723, ImpactLoss 0.158, s/reg 33.8 vs 31.7; per-case deltas within 0.002 nats) — as expected, since it is the same stock SyN preset (Affine + SyN[0.2,3,0], COM init) re-run in this follow-up batch: it serves as a consistency check that the shared read-back / scoring path is configuration-stable.
  • The Repro / QuickRepro family is semantically competitive but weaker on intensity: median MI 0.530–0.549 (vs 0.723 for the SyN preset), driven by the GC-based Rigid stage and the short 2-level SyN/BSplineSyN refinement (50×20 or 50×0 iters, 2×1 pyramid, CC 2-bin metric) — a workflow tuned for intra-modality T1w-T1w. ants_synreprosr still takes the best ImpactLoss median of all thirteen pipelines here (0.151; per-case wins on 4 of 9), so the semantic/intensity split of the main table carries over to the stock ANTs workflows.
  • Time tracks budget, not quality: the full Repro Rigid stage (1000×500×250×100, 8×4×2×1, GC) dominates — ants_synreprobr is the slowest ANTs configuration (370 s/case) at the same (low) MI as the 84–96 s QuickRepro variants (which drop the 4th rigid level and the 2nd SyN level, changing the MI by < 0.02). Only ants_rigid_synonly challenges the SyN preset's quality (better MI at 6.6× the time); every other variant is worse for more or for the same.
  • Production skull-ring QA (reference only): acceptance 4/9 ants_syn / ants_synra / ants_rigid_synonly (= baseline), 2/9 ants_synreprobr, 1/9 the rest; rotational dispersion worst in the Repro / QuickRepro family (24–29 mm std) vs 14–15 mm for ants_syn / ants_synra / ants_rigid_synonly — consistent with their alignment.

Transform conventions (deformable-specific)

Unlike the rigid benchmark (where the elastix-style toolkits came out in the opposite direction 8/9 cases and needed the best-of-T vs T⁻¹ orientation gate), every deformable output here is consumed in the documented fixed→moving = T1c→CT direction; the gate is replaced by an analytic read-back plus a skull-ring sanity check. Two non-obvious conventions were established empirically (validated against each tool's own resampling, NCC ≥ 0.998 on the head):

  • NiftyReg and surfa (FreeSurfer's NIfTI stack) decode RAS+ NIfTI qforms naively, i.e. they work in an x/y-mirrored world. A displacement delta (dx, dy, dz) stored by such a tool is (−dx, −dy, dz) in the true RAS world; the field grid (file indices) is unaffected. The read-back flips the x/y components of the dense field. (ANTs writes correct RAS fields — no flip needed.)
  • NiftyReg reg_f3d writes only the control-point grid (outputCPP.nii); reg_transform -disp evaluates it to a dense field on the reference grid. The reg_aladin affine is folded into the control points before optimization (reg_f3d initialises the spline with the affine's deformation field), so the dense field is the full transform — no separate composition step. (The -comp subcommand was tested and does not reproduce reg_f3d's internal transform; it is not used.)
  • SynthMorph joint: driven as register -m joint moving fixed (moving = clipped CT first, fixed = T1c second); the -t output is the displacement field on the fixed (T1c) grid — the contract transform directly. The tool's own -o resampling is written as a cross-check (per-case own_resample_ncc_head in the JSONs).
  • ANTs SyN: the two stage outputs (001Warp.nii.gz + 000GenericAffine.mat) are composed as warp-then-affine (verified to reproduce ANTs' own warpedmovout to < 0.001 MI) and rasterised.
  • Elastix / IMPACT: the combination transform (auto-init folded in) is rasterised — elastix in-process via itk.TransformToDisplacementFieldFilter (exact, machine precision on affine fields), IMPACT by evaluating the BSpline control-point file directly (SimpleITK cannot read elastix's BSpline .txt format; scipy's order-3 B-spline = ITK's kernel).

Reproducing

source /opt/conda/etc/profile.d/conda.sh && conda activate longitudinal-313
cd /mnt/b4/xfr/git26/longitudinal

# all six deformable pipelines (results go to results/bench_registration_deformable/)
# the 2026-10-02 main run used --workers 6 --threads 24 (~2 h 9 min wall,
# dominated by simpleitk's ~111 min phase)
python scripts/bench_registration.py --deformable --workers 6 --threads 24 --qa-images

# single pipeline / case subset
python scripts/bench_registration.py --deformable --pipelines simpleitk impact --n-cases 3

# the ANTs-variant follow-up (direct SyNRA / SyN + Repro / QuickRepro
# sr/br; results go to the same results/bench_registration_deformable/ dir,
# 2026-10-03 run, 6 workers, ~28 min wall; `ants_syn` is the re-run of the
# stock SyN preset that replaced the initial SyNOnly row)
python scripts/bench_registration.py --deformable --pipelines "ants_synra ants_syn ants_synreprosr ants_synreprobr ants_synquickreprosr ants_synquickreprobr" --workers 6 --threads 24 --qa-images

# the legacy two-call Rigid -> SyNOnly(100,100,100) workflow (2026-10-03,
# 6 workers, ~25 min wall; dominated by the full-resolution SyN iters)
python scripts/bench_registration.py --deformable --pipelines "ants_rigid_synonly" --workers 6 --threads 24 --qa-images

# serial SynthMorph re-run (the 2026-10-02 final numbers): one container per
# GPU at a time; two concurrent containers on one A100 hit cuDNN
# scratch-space OOM in the joint model's 256-ch 128^3 hyperconvolution
python scripts/bench_registration.py --deformable --pipelines synthmorph --workers 1 --threads 24 --qa-images

# combine the per-pipeline JSONs into summary.json / summary.md / plot
python scripts/bench_registration.py --deformable --merge

Visual QA images

--qa-images writes a checkreg-style PNG per (pipeline, case) to results/bench_registration_deformable/qa/<pipeline>__<case>.png (9 per pipeline; the incomplete-CT case is skipped) — same format as the rigid benchmark: a 3×2 grid of the mid-axial / mid-coronal / mid-sagittal slices through the head center, left column checkerboard blend of the warped CT vs the T1c (clean registration = seamless mosaic), right column additive color overlay (CT red, T1c green; agreement = yellow, misregistration = red/green fringing). CT is brain-windowed 0–80 HU, T1c 2–98 % head window; the title carries the pipeline, case key and the achieved Mattes MI.