fidopt Interactive view

About

What this benchmark is for, who keeps it, and the rules it follows.

Purpose

To be the place where a registration, segmentation or synthesis method is compared with the others on equal terms: the same datasets, the same rules, baselines run as their authors run them, and every result open to inspection.

The aim is a reference that authors and reviewers can point to, instead of a new private comparison in every paper.

Commitments

  • The rules are public and versioned. A change of rule is a change of version.
  • Every number names its method version, its machine and its date.
  • Each dataset says who or what made the annotations its results are checked against.
  • Failures, and results worse than doing nothing, are shown, not hidden.

Why a standing benchmark

Papers compare a new method with baselines that the same authors configured, on cases they chose. Jena et al. showed how much the conclusion depends on that set-up: baselines under-run, rankings that reverse from one evaluation set to another.

A one-off evaluation cannot settle it for the next method. This benchmark is the standing answer: the same datasets and the same rules every time, and every number traceable to a method version, a machine and a date.

Jena, Sethi, Chaudhari, Gee. Deep Learning in Medical Image Registration: Magic or Mirage? NeurIPS 2024.

The rules, in short

  • Test cases follow each challenge's official list where there is one, and a published random draw elsewhere. No image is in two datasets.
  • Each dataset says who or what made the annotations its results are checked against. Datasets a program annotated are ranked apart.
  • A method states what it was trained and tuned on. One tuned on a dataset's test cases is not ranked there.

The rules in full · submit a method

Who keeps it

The benchmark is developed by Valentin Boussot at Fideus Labs.

A stated interest. The maintainers also develop IMPACT-Reg, one of the methods on the leaderboards. This is why the datasets, the scoring, the apps and every result are meant to be public and reproducible by anyone, and why outside submissions are scored by the same code.

The details

The rules in full: the datasets, the scoring, how each method is run. The machines that produced the results.

Preview, fidopt 0.1.0, generated on 2026-11-05. The results can still change; the repository opens with the paper that describes the benchmark.

Machines

Every result names the machine that produced it. Times compare within one machine only, and none of these is a timing reference yet.

Laptop, RTX PRO 5000 24 GB

GPU
NVIDIA RTX PRO 5000 Blackwell Generation Laptop GPU, 24 GB
CPU
Intel Core Ultra 9 275HX, 24 cores
System
Ubuntu 26.04, Linux 7.0
Jobs
GPU methods alone on the GPU; CPU work on 8 to 16 threads
  • The reference machine of the 2026-10 campaign for the methods whose result depends on the memory at hand (PROTOCOL.md).
  • Not a timing reference: the machine was in use, and the times are those of an accuracy campaign.
  • The 2026-10-14 ConvexAdam and new segmentation runs compute predictions on GPU; their KonfAI metrics are evaluated on CPU because the corpus environment uses a CPU-only PyTorch build. Reported method runtime and memory come from GPU inference, not metric evaluation.

Rented instance, RTX 3090 24 GB

GPU
NVIDIA RTX 3090, 24 GB
CPU
24 usable cores (model not recorded)
System
Ubuntu 26.04 container
Jobs
GPU methods alone on the GPU
  • A Vast.ai instance rented for the campaign (2026-10-05 to 2026-10-06), since destroyed: its CPU model and RAM were not recorded.
  • Not a timing reference.

Rented instance, RTX 3090 24 GB, Ryzen 9 5900X

GPU
NVIDIA RTX 3090, 24 GB, driver 595.84
CPU
AMD Ryzen 9 5900X, 23 usable threads, 62 GB of memory
System
Ubuntu 26.04 container
Jobs
GPU methods alone on the GPU; ANTs on 12 threads, NiftyReg and deeds on 8, the three at once
  • A Vast.ai instance rented from 2026-10-09 to finish corpus v1 when the laptop was needed for other work.
  • Not a timing reference: the GPU queue and two CPU queues share the machine.

Workstation, RTX 3080 10 GB

GPU
NVIDIA RTX 3080, 10 GB
CPU
20 cores (model not recorded)
System
Arch Linux
Jobs
CPU methods on 8 threads, capped at 32 GB; GPU methods alone on the GPU
  • Ran the CPU methods of the campaign and the IMPACT-Reg presets on the small-volume datasets.
  • Not a timing reference: shared with other work.

Protocol

The rules behind every number: what is in the corpus, how a field is scored, how each method runs and how results
are ranked.

## 1. The corpus

**Three tasks, test cases only.** Each dataset (`datasets/<name>/dataset.json`) is a list of test cases for one task:
a registration pair (fixed and moving image), a segmentation image, or a synthesis pair (source and target). Each case
has a ground truth. A dataset also names development cases for tuning, never scored. Training data is not part of the
benchmark. CT is in Hounsfield units, masks are binary on their image's grid, and landmarks are `x,y,z` in
millimetres in the world (ITK, LPS) frame.

**What a method reads and what scores it are kept apart.** A method gets the images, the modalities and the masks,
never `truth/`. A label map that is scored is never handed over as a mask.

**Built, then checked.** `datasets/<name>/prepare.py` turns the provider's files into one folder a case and changes
nothing else. `fidopt build` writes the cases, and `fidopt verify` compares every file with the checksums in the
repository. Two results are comparable only on the same checksums.

**One storage format.** Every image, mask and label map is an OME-Zarr store (NGFF 0.5, Zarr v3, sharded, lossless),
named after what it holds (`fixed.ome.zarr`, `truth/fixed_labels.ome.zarr`). Landmarks stay CSV.

- Level 0 is the image as built: its voxels, type and channels untouched, a channel axis first when there are
  several.
- Coarser levels halve each axis, down to one chunk (64 voxels a side in 3D, 512 in 2D): the mean of each block for
  an image, the most frequent label for a mask or a label map. They are for viewing; nothing is scored on them,
  except on a large dataset.
- NGFF 0.5 has scale and translation but no rotation, and half the corpus has axes that are not the world's. The
  store therefore also keeps the full geometry (direction, origin, spacing) in its `konfai` attribute.

A store reads back as the image it was written from, voxel for voxel and to the last digit of its geometry: the build
checks it. Methods are handed NIfTI (section 2).

**2D datasets** (`"dimension": 2`) keep their images as delivered, colour included, with `x,y` landmarks. Their unit
is the provider's pixel size (micrometres for a slide, metres for a satellite image) or the pixel when none is given
(`"px"`), and every distance is in that unit. The landmark error is also given relative to the fixed image's diagonal
(rTRE, section 3), so that datasets of different units compare. A method runs on them when its `method.json` lists 2D.

**Images too large for memory** (`"large": true`: whole slides, light-sheet volumes) are built, aligned, warped and
downsampled block by block, their axes the world axes.

**The split.** A dataset's test cases are 10% of its independent subjects, at least 10 and at most 30, drawn by
sorting the eligible cases on `sha256("<seed>:<dataset>:<case>")` and taking the first ones from each stratum in
proportion (`"draw"` in the descriptor; `fidopt draw` reproduces it). When the provider releases a test split with its
truth, that split is taken whole, even past 30 (each `L2R_*` dataset holds all of its task's validation pairs). The
development cases are 10% of what is left, 10 to 30: the last ones of the same seeded order, or the provider's
training split. Cases left out of a pool are named in the draw's `held_out`, so the draw stays reproducible. A
dataset whose split grew kept the cases drawn first. Where subjects must be paired (Mindboggle-101, AFIDs), they are
sorted the same way and paired two by two. Development checksums are recorded too (`checksums_development.json`), and
`fidopt tune` compares settings on them across a family of datasets (`datasets/families.json`).

**No image twice.** No subject is in two datasets, across all three tasks, nor in both the test and development cases
of one. When another task needs the same images, the dataset is derived (`"from"`) instead of copied: it takes its
source's cases and split. One overlap is kept on purpose: the ten `L2R_NLST` pairs are also in `Lung250M`, on another
grid and with manual landmarks; the lung track ranks on `Lung250M`, and `L2R_NLST` stays in the Learn2Reg track next
to the challenge's own table.

**Where the truth comes from** is in each descriptor (`"truth"`), graded `expert`, `semi-automatic`, `automatic`,
`synthetic` or `provider`, with its limits. The corpus says who made a truth and what it does not measure, but never
publishes what would let a method learn it (the generator of a synthetic deformation). When reading a leaderboard:

- Labels from a segmentation network are not manual annotations. Where a dataset also has landmarks placed by people
  (POPI, Lung-DIR-QA), its label metrics are `unranked`: shown, not used to rank.
- The DIR-QA landmarks were found by a program, carried to the other image by a registration and checked by people
  (`semi-automatic`): methods close to that registration may be favoured.
- Automatic keypoints are not a truth (`L2R_NLST`). When a metric is a method's own output, `results/notes.json`
  takes it out of that method's line.

**What a main leaderboard needs.** The truth is made or checked by people on both images (`expert` or
`semi-automatic`), dense enough to separate methods (a median of ten landmark pairs a case, or labels covering the
anatomy), and leaves room (no registration under a Dice of 0.8, or a landmark error several times the truth's own).
A dataset that misses a check is ranked apart, never dropped: the corpus makes it a truth instead and grades it.

- Labels from a public segmentation network run on the images: graded `automatic`.
- A known deformation (`"warp"`) for two images aligned by construction, such as two contrasts of one session: the
  moving side goes through a smooth, one-to-one deformation drawn once per case; labels follow it and landmark pairs
  are drawn inside the body. The truth is exact but the deformation is ours: graded `synthetic`. How it is drawn is
  not published.

The datasets examined and left out are listed with their reasons in the screening lists (`datasets/screening*.json`).

**Other label sets.** A case may carry a second label map (`"other_labels"`: tumours under treatment, a network's
organs next to expert landmarks). It is scored under the set's name (`dice_<set>`) and never ranked.

### Alignment

**Native images, one start for every method.** Nothing is resampled: a method gets the provider's voxels. A pair its
provider does not deliver aligned gets a start, computed once and written into the moving image's header alone (its
origin and direction moved; its mask, labels and landmarks follow). A header holds a translation or a rotation, never
an affine: every deformation, breathing included, is left to the methods.

**The least start that works, from the intensities, never the truth** (`"alignment"` in the descriptor):

- as delivered (`"aligned": true`), when the images already sit together: 62 of the 127 registration datasets, the
  Learn2Reg tasks and the SynthRAD sets among them;
- `"image-centres"`, the two images' centres put together, nothing optimised: 3 datasets, ultrasound or images
  centred on their organ by their acquisition;
- `"elastix-translation"`: 45 datasets;
- `"elastix-rigid"`, only when a rotation is needed: 16 datasets, one of them `-centred` (one image is a part cut out
  of the other) and one `-oriented` (`OpenEar`, two specimens in arbitrary orientation: run from each of the 24
  axis-aligned rotations, the run kept whose densest tenth of each body overlaps most).

elastix runs on Mattes mutual information inside each image's body (above -500 HU for a CT, above half of Otsu's
threshold otherwise), from a few starts (the bodies' centres of mass, the images' centres, the ends of the bodies, the
peak of the cross-correlation), on images reduced to at most 512 voxels an axis, and keeps the run with the best
overlap of the bodies weighted by their normalised mutual information. A start computed from annotations would leak
the truth into the pair.

Two datasets differ, and say why in their descriptor: `PelvisLandmarksMRCT` keeps the provider's ANTs rigid
start, and `SpineUSCT` is a rigid task (`"registration": "rigid"`):
spine phantoms whose CT and ultrasound do not overlap as delivered, so aligning them would leave nothing to measure;
only methods that can run a rigid stage alone are run, in a track of its own.

**Frames and headers.** Where a provider's files carry a wrong header or an intensity offset, `prepare.py` fixes it
and says so.

## 2. The field and its convention

A method returns `OUTDIR/DVF.nii.gz`: a float32 image on the fixed grid with one component per dimension (3, or 2 on a
2D dataset), the displacement `u` in millimetres (in the dataset's unit on a 2D dataset) along the world (ITK, LPS)
axes, such that the fixed point `x` matches `x + u(x)` in the moving image.
`fidopt score` also reads Learn2Reg displacements (voxels along the index axes, `--voxels`).

On a large dataset a method reads the level of the images it can hold and returns its field on a grid of its choice,
coarser, along the fixed image's axes, that covers the fixed image: every fixed voxel centre has a nearest voxel in the
field. A method that reads no OME-Zarr is given each image and mask at its finest level within the method's
`"max_voxels"` (2^24 voxels unless its `method.json` says otherwise) and `"max_side"` (NiftyReg smooths no axis longer
than 2048 voxels), as NIfTI, and returns its field on that level's grid. The zero field is on the coarsest level.

A wrong sign or axis order gives a plausible wrong score, so the convention is checked for every method:

- `fidopt check <method>` registers a synthetic volume shifted by a known translation, on an oblique, axis-permuted,
  anisotropic grid, with the moving image once on the fixed grid and once on another. The field as written must
  recover the translation within 1 mm; read with a wrong sign, component order, frame, direction or spacing, it must
  miss it by more than 2.5 mm. A method that takes 2D is also checked on a 2D colour image, three 8-bit components a
  pixel, on a grid of 0.7 by 2.5 mm whose index axes are turned by 215 degrees: the method's conversion to one value
  a pixel, where it makes one, is checked with it.
- `fidopt check <method> --on <dataset> <case>` uses the real scorer on a corpus case: only the field as written
  may beat the zero field. This is the check for networks trained on anatomy. uniGradICON and multiGradICON pass the
  synthetic check on one grid only, since they read each image in its own voxel frame.

## 3. Scoring

One evaluation for every method, run by KonfAI's evaluator. `evaluation/<task>.yml` holds it, one block per kind of
truth; a dataset takes the blocks its truth has, filled with the values of its descriptor, and the file KonfAI
resolves from them is kept with the rows it scored (`scores/evaluations.parquet`, below). Where
Learn2Reg defines a metric, it is computed like the organisers' code
([MDL-UzL/L2R](https://github.com/MDL-UzL/L2R), `evaluation/`), except the TRE: KonfAI reads the field at a landmark
linearly, as ITK does, where that code takes a cubic B-spline.

| metric | definition |
|---|---|
| Dice | Moving labels warped by nearest neighbour, as ITK resamples: a point mapped more than half a voxel outside the moving image is background. Mean over the labels present in both the fixed and the moving map, as the organisers' code scores. **A label the warp erased counts 0**, otherwise a field that loses structures would be rewarded (`labels_lost` counts them). |
| HD95 | 95th percentile of the surface distances (DeepMind `surface-distance`), in mm (the dataset's unit on a 2D dataset), mean over the labels the warp kept. |
| TRE | `‖x + u(x) − y‖` in mm (the dataset's unit on a 2D dataset) over the landmark pairs `(x, y)`, with `u` read at `x` as ITK's `DisplacementFieldTransform` reads it (linear, from the voxels around `x`). Mean and 95th percentile. |
| rTRE | The TRE over the length of the fixed image's diagonal, as ANHIR relates its landmark errors, without a unit: it compares datasets of other units and sizes. Shown, never ranked: it is the TRE again. |
| SDlogJ | Standard deviation of `log(clip(det J + 3, 1e-9, 1e9))`, `J` the Jacobian of `x + u(x)`, 2 voxels cropped on each side (the `+ 3` is Learn2Reg's). Also inside the body and inside the fixed mask when there is one. |
| folds | Fraction of voxels with `det J ≤ 0`, over the whole field and inside the body (the Otsu foreground of the fixed image). |
| time, memory | Wall time of the method's run including model loading, peak RAM of its process tree, peak GPU memory of its processes. An app's first run on a machine, which fetches its code, weights and environment, is run once untimed before the timed cases. A case run while another process used the GPU says so (`gpu_shared`): its memory is its own, but its time is left out of the line's mean. |

**On a large dataset** the landmarks are scored at full resolution: the field is read at each fixed landmark from its
world coordinates, keeping its edge values out to the edges of its voxels as ITK reads it. The labels are scored at a
reduced level, the same for every method whatever its grid: the finest level of the label maps within 2^26 voxels,
recorded in the row (`labels_level`), the moving labels warped through the field read at each voxel of that level. The
regularity is that of the field on its own grid, with the fixed image's body and mask brought onto it.

**What is kept.** One row per test case: the metrics, time and memory,
the method's version, fidopt's version, the date, and `built`, the digest of the case as it was built. A row whose
`built` is missing or differs from the case's digest is stale: the case was rebuilt since, and the next `fidopt run`
runs it again. The rows' one copy is the Hugging Face dataset
[fideus-labs/fidopt-results](https://huggingface.co/datasets/fideus-labs/fidopt-results), a Parquet table per task
(`scores/<task>.parquet`), at the revision `results/published.json` pins: a commit of the repository always gives the
same boards. A run's rows stay in `results/<machine>/<method>/<dataset>.json`, read over the published ones, until
`fidopt publish` sends them. The result itself is kept small, for the site's viewer (`docs/results-format.md`): a registration's
field sampled at most 128 points a side (512 in 2D) as float16, a label map or a synthetic image whole, as a
multiscale store; nothing on a large dataset.

**A failure is a row.** A case with no field, an invalid field, or a timeout is recorded with its error and counts as
the unregistered pair, as a challenge scores a missing submission.

**Two boards.** Every dataset is built and scored the same way; the licence decides which board ranks it. The
official board, a public release of the corpus and a paid service hold only the datasets whose licence is open and
allows commercial use (`"spdx"` in the descriptor, every part of it one of `LICENCES` in `fidopt/corpus.py`), as the
methods carry only open licences. The research board ranks every dataset, each shown with its terms, including
those under non-commercial, no-derivatives or research-only terms or with no licence stated: their truth is no
weaker, their terms are.

**The partition follows the image.** One image may serve several tasks (a segmentation or a synthesis dataset takes
its cases from a registration dataset's pairs); an image of a test pair is a test case in every task, an image of a
development pair a development case, never the reverse.

**A segmentation is scored by structure, by name.** The dataset names its labels; the method writes its own
labels and their names; the two meet through `datasets/structures.json` (one name for `oesophagus` and
`esophagus`; `kidneys` made of `kidney_left` and `kidney_right`). Dice, HD95 and the surface Dice (at the descriptor's
`truth.tolerance_mm`, one for all or one a structure, 1 mm unless it says otherwise) are computed for every structure the dataset names, with
KonfAI's criteria as for registration. A structure the case's truth holds and the method
does not produce scores a Dice of 0 and no distance; one the truth lacks is left out of the case's mean, unless the
method writes it there, a false positive that scores 0 (Metrics Reloaded's rule). A method is scored on the
structures it writes, as its method.json names them (`structures`): the dataset's structures it never writes (a
sub-task that writes the glands of a head and neck set, not its 24 other structures) are left out of its score, not
counted at 0, and its line says its coverage, how many of the dataset's structures it writes. The line's Dice is the
mean over the structures so scored, and the line says how many of the truth's structures the method produced. A
failed case is an empty map.

**A synthesis is scored inside the body.** The synthetic image against the real image of the target modality,
where the dataset's mask (or the real image's body) is: the mean absolute error in the target's units, the PSNR and
the SSIM at the descriptor's dynamic range, with KonfAI's criteria. How the real image was brought onto the source
image's grid is the dataset's own business, and is not described here (a method could learn it). No image stands in
for a failed case: the line is incomplete, shown and not ranked, until the case is produced. Where the source and the
target are one modality (a denoising, a change of contrast), `identity`, the source as given, is the reference line, as
the zero field is in registration: a method has to beat it. A dataset whose target is a CT may ask
for the anatomy kept (`truth.geometry`): TotalSegmentator's KonfAI port segments the synthetic and the real image,
and the Dice and HD95 of its structures are shown beside the line, never ranked, the reference being a program's
reading of the real image.

**Parity with Learn2Reg.** `fidopt table --parity` compares the zero field on each `L2R_*` dataset with the
organisers' own zero-displacement submission (`datasets/<name>/official_zero.json`). Every listed metric matches
within 1e-4. Two leaderboards cannot be fully reproduced from public data, as their descriptors state: ThoraxCBCT
scores 15 labels, of which 13 are public, and NLST scores landmarks that were not released (the public keypoint TRE
is reproduced).

**Next to the challenge's table.** `datasets/<name>/published.json` holds the rows the organisers published, with
their source. They come from the hidden test set, not the validation pairs scored here, and from entries tuned on the
task. The website shows them under the leaderboard as the level of the challenge, never ranked with it.

## 4. How methods run

**The authors' code with the authors' defaults.** Each method runs its authors' code at a pinned version, through its
command-line tool or the function that tool calls, with every setting at its default. A protocol the authors document
for one modality or anatomy is a method of its own (`unigradicon_lungmask`). The KonfAI app people run is held to a
private reference that runs the authors' code untouched, outside KonfAI: same pin, same settings, the same result
within the tool's run-to-run spread.

**Two tiers.** Tier 1 compares each tool's defaults. Tier 2 holds settings chosen for a task, by a challenge's
organisers, by the authors for their entry, or by anyone who names the cases they tuned on. A tier 2 line is a
variant (`<method>@<configuration>`, declared in `method.json` with its datasets and source), shown next to those
datasets' leaderboards and never ranked with tier 1. A variant tuned on a dataset's test cases is not shown on that
dataset.

**Deformable stage only, from the same alignment.** Since every pair is aligned (section 1), no tool runs its own
rigid or affine stage: ANTs runs SyN alone, NiftyReg runs `reg_f3d` alone, deeds runs `deedsBCV` alone, as the
literature runs them on aligned pairs. The IMPACT-Reg 1.8.7 rows are the one exception: each preset ran as shipped,
and `FireANTs_SyN` and `Generic_Rigid_BSpline` kept their linear stages. The next presets are deformable only.

**Same inputs.** The pair, the modality of each image (`ct`, `cbct`, `mr`, `us`) and the dataset's masks. A method
is not run on a modality it does not take (`"modalities"` in `method.json`), nor on a 2D dataset unless it names 2D in
`"dimensions"`. A 2D colour image is given as it is: a method whose tool reads one value a pixel converts it (ANTs
and Demons take the mean of its components), one whose tool reads several passes them on (greedy weighs the components
itself, NiftyReg registers them as the channels of one image), and its description says so.

**One job at a time.** A GPU method runs alone on its GPU; CPU methods run on a stated number of threads
(`results/<machine>/machine.json`). A machine's rows are written to its folder of `results/`: the one whose `machine.json`
lists the host in `"hostnames"`, unless `$FIDOPT_MACHINE` or `--machine` names another. A method that runs out of
GPU memory fails the case, never falls back to the CPU; the voxel budgets of corrField, ConvexAdam and anatomix
(below) are sized for 24 GB GPUs.

### Each baseline against its official configuration

Each baseline was compared with the published script, not with a description of it.

| method | official reference | what runs here | |
|---|---|---|---|
| `ants` | the Learn2Reg 2024 organisers' LUMIR baseline, `ants.registration(..., 'antsRegistrationSyN[so]')` ([script](https://github.com/JHU-MedImage-Reg/LUMIR_L2R/tree/main/SyN%20(ATNs))) | the `antsRegistration` command ANTsPy builds for it | the same since 2026-10-09; earlier rows ran `antsRegistrationSyN.sh -t so`, equal within ANTs' run-to-run spread |
| `unigradicon`, `multigradicon` | the authors' `unigradicon-register` with its defaults | the same command | the same |
| `anatomix_convexadam` | the commands of the authors' README | the same settings | the same |
| `corrfield` | the Learn2Reg organisers' NLST baseline ([script](https://github.com/MDL-UzL/L2R/tree/main/examples/basic_docker_examples/corrfield)) | the Lung250M-4B authors' copy with its defaults: MIND sigma 1 instead of 0.8, stages added where the organisers compose them | close; `corrfield@l2r` is the organisers' copy, called as their script calls it |
| `convexadam_mind` | one script per task in the authors' repository, their Learn2Reg entries | the repository's generic defaults | different; `convexadam_mind@l2r2021-lungct` is their LungCT entry |
| `deeds` | `-G 6x5x4x3x2 -L 6x5x4x3x2 -Q 5x4x3x2x1` on LUMIR, a task not in this corpus; the ThoraxCBCT settings are not published | the tool's defaults, `8x7x6x5x4` | different |
| `niftyreg` | the organisers describe MIND with bending and Jacobian penalties and fewer levels, without values | `reg_f3d` defaults: NMI, no Jacobian penalty | different, not reproducible from what is published |

Where the official settings are published, the benchmark gives the challenge's numbers. On the three Learn2Reg
LungCT validation pairs:

| line | landmark error | SDlogJ in the lungs | the challenge's row, on its test set |
|---|---|---|---|
| `convexadam_mind`, defaults | 3.68 mm | 0.086 | |
| `convexadam_mind@l2r2021-lungct` | 2.01 mm | 0.065 | ConvexAdam 1.79 mm, 0.06 |
| `corrfield`, defaults | 2.14 mm | 0.056 | corrField 1.75 mm, 0.05 |
| `corrfield@l2r` | 2.12 mm | 0.055 | |

The validation pairs start further apart than the test pairs (14.6 mm against 10.2). On the NLST validation pairs,
`corrfield@l2r` lands on the task's public keypoints within 0.006 mm: those keypoints are that baseline's own output,
which is why no TRE on them counts for corrField (`results/notes.json`).

Not reproduced: the ConvexAdam entries on OASIS, Hippocampus and AbdomenCTCT register the output of segmentation
networks trained on the task's labels, which are not published, and its AbdomenMRCT script runs on the authors' own
cropped and resized images. The organisers' NiftyReg and deeds settings would have to be asked for.

### The methods

| method | version | device | similarity | settings |
|---|---|---|---|---|
| `ants` | ANTs 2.6.5 release binaries | CPU | CC radius 2 | the Learn2Reg organisers' `antsRegistrationSyN[so]` call |
| `niftyreg` | NiftyReg v2.0.0 | CPU | NMI, 64 bins | `reg_f3d` defaults |
| `deeds` | deedsBCV `00b4653` | CPU | MIND-SSC | `deedsBCV` defaults |
| `convexadam_mind` | convexAdam `b229e52` | GPU | MIND-SSC, SSD | repository defaults |
| `anatomix_convexadam` | anatomix `4c86aee`, weights `842cfe9` | GPU | anatomix and MIND-SSC features, SSD | command-line defaults, CT window of the README |
| `unigradicon`, `multigradicon` | `unigradicon` 1.0.5, weights 1.0 | GPU | LNCC in the instance optimisation | command-line defaults |
| `unigradicon_lungmask`, `multigradicon_lungmask` | same | GPU | same | the authors' lung protocol: images multiplied by their lung masks; lung CT only |
| `corrfield` | Lung250M-4B `53598ca` | GPU | MIND-SSC, SSD | command-line defaults; lung datasets only |
| `impact_reg@<preset>` | impact-reg-konfai 1.8.7 | GPU | the preset's | the preset's defaults |
| `identity` | | | | the zero field: the "no registration" line; in a synthesis within one modality, the source as given |

`fireants` (the FireANTs library with its tutorial settings) is there for cost comparisons, not as a baseline.
DINO-Reg is not run: its repository has no licence.

- **ANTs.** SyN[0.2, 3, 0] from the identity, cross-correlation of radius 2, 100x70x50x20 iterations at shrink factors
  8x4x2x1, smoothing 3x2x1x0 voxels, single precision, then `antsApplyTransforms` writes the field. The run sets
  the thread count and a fixed random seed. Not applied: a mutual information stage for multimodal pairs.
- **NiftyReg.** `reg_f3d`: cubic B-spline with control points every 5 voxels, NMI with 64 bins, bending energy 0.001,
  first-order penalty 0.01, no Jacobian penalty, 3 levels, 150 iterations at the last one, CPU build. Version 2.0.0,
  not the later 2.1: commit bd9ffd65 (first released in 2.1.0) scaled the bending and first-order gradients down to
  about two thirds and one third without changing the default weights, so the same defaults regularise far less (brain
  MR to CT: Dice 0.64 with 2.0.0, 0.35 with 2.1.2).
- **deeds.** `deedsBCV`: 5 levels, grid 8x7x6x5x4, search radius 8x7x6x5x4, quantisation 5x4x3x2x1, regularisation
  1.6, symmetric. deeds counts all of these in voxels and reads two arrays of one size without geometry: a pair whose
  voxels are not cubic is first resampled onto a cubic grid of as many voxels, as its README asks for thick slices,
  and the field is brought back to the fixed grid.
- **ConvexAdam (MIND).** `convex_adam_pt(fixed, moving)` with no argument: MIND-SSC radius 1, dilation 2; convex stage
  on a 6-voxel grid with search half-width 4 and inverse consistency; Adam stage on a 2-voxel grid, 80 iterations,
  learning rate 1, diffusion weight 1.25; half precision. The capture range is in voxels: 24 voxels are 48 mm on a
  2 mm grid and 14 mm on a 0.57 mm grid. Not applied: the per-task settings of the Learn2Reg scripts, self-configuring
  ConvexAdam, and the nnU-Net features behind most published ConvexAdam Dice scores. The function holds about 0.25 GB
  of GPU memory a million fixed voxels: a fixed image above 95 million voxels is coarsened evenly to 75 million (same
  origin, direction and extent) and the field comes back to the fixed grid.
- **anatomix + ConvexAdam.** The pipeline of the anatomix paper: diffusion weight 0.75, convex grid 2, search
  half-width 1, 80 Adam iterations on a grid of 2; 16 anatomix channels and 12 MIND-SSC channels compared by SSD;
  features on a 128³ sliding window with 0.8 overlap; CT clipped to [-450, 450] HU, as in the README. Not applied:
  the per-dataset grid search the paper describes. The pipeline holds about 0.8 GB of GPU memory a million fixed
  voxels: a fixed image above 29 million voxels is coarsened evenly to 26 million and the field comes back to the
  fixed grid.
- **uniGradICON and multiGradICON.** `unigradicon-register` with its defaults: the network's prediction, then 50 steps
  of instance optimisation with LNCC. The tool knows `ct` (also used for `cbct`), clamped to [-1000, 1000] HU, and
  `mri`, clamped to [minimum, 99th percentile]. With the lung protocol each image is multiplied by its lung mask, as in
  the authors' Learn2Reg lung submissions; the field then means nothing outside the lungs, so the masked and unmasked
  versions are two lines.
- **corrField.** `corrfield.py` with its defaults: regularisation 2.5, two non-rigid stages, Foerstner keypoints inside
  the fixed lung mask, thin-plate spline interpolation. Lung datasets only. It runs on the authors' grid: an axis finer
  than 1 mm is brought to 1 mm, as they resample their scans, and a volume still above 50 million voxels is coarsened
  evenly (LungDIRQA case30 at 1.16 mm); the field comes back to the fixed grid.
- **IMPACT-Reg.** `impact-reg-konfai register <preset>` as a user runs it, with the preset's defaults and, since
  2026-10-09, the masks the dataset allows (the 1.8.7 rows ran without them). Both images are first clipped to their
  0.5th and 99.5th percentiles, as ANTs winsorizes by default: a PET in Bq/ml otherwise crushes the presets' 32-bin
  mutual information into one bin. Its result depends on the machine's
  memory: a pair that fits is registered whole, a larger one by a coarse pass then tiles, and the two paths do not give
  the same field. A line is the result on its machine.

## 5. Leaderboards

- **A dataset's leaderboard** has one line per method and machine: the mean of each metric over the test cases, with
  failures counted as unregistered, the number of failures, the mean time and the peak GPU memory.
- **Rank.** A complete line is ranked on every metric all complete lines share (Dice and HD95, TRE, SDlogJ; higher
  Dice and lower everything else is better), except those the dataset lists as `unranked`. Its rank is the mean of
  those ranks. A line that misses cases is shown but not ranked. The zero field is the reference and is not ranked,
  since its perfect smoothness would put it above methods that actually register; nor is a line that failed on every
  case, which amounts to the zero field. A method measured on several machines is ranked once, on its latest
  complete line.
- **Uncertainty.** A dataset has ten test cases, so many ranks are noise, and the boards say so instead of hiding it.
  Each mean carries its 95% t interval over the cases. Two neighbouring lines are tied when a paired Wilcoxon
  signed-rank test on their cases (two-sided, 5%) does not find the upper one better on the dataset's main measure
  (the first of Dice, TRE, HD95, MAE, PSNR and SSIM it ranks); a tied line is shown with the places it could hold,
  those of the lines it is tied with. On the results of October 2026, two thirds of neighbouring lines are tied, and
  so are the first two lines of most datasets. A leaderboard of several datasets shows beside each mean rank the
  mean of those places, low and high, in the spirit of challengeR's rank ranges (Wiesenfarth et al., 2021) without
  its bootstrap.
- **Methods under a licence that is not open.** A method is ranked when its code and its weights are under MIT,
  Apache-2.0, BSD, ISC, Zlib, CC0 or Unlicense. A method under another licence (non-commercial, share-alike,
  copyleft, custom) is run and shown after the ranked lines, under its licence, ranked nowhere.
- **A track's leaderboard** (`datasets/tracks.json`) ranks the methods ranked on every dataset of the track by their
  mean rank. There is no ranking across tracks, and a track names its task (`"task"`, registration unless it says
  otherwise). Tracks marked `"truth": "automatic"` hold datasets whose labels come from a network, and are shown
  apart; so is a track marked `"apart"` with its reason (`"four point pairs a pair, from two blocks"`), its truth
  keeping its grade. On the official board a track ranks on the datasets whose licence admits them (`spdx`: every part an
  open licence that allows commercial use), the others shown after them, "research only"; on the research board it
  ranks on all its datasets, each one not admitted showing its `use`.
- **Worse than no registration.** Each score is shown with its change from the unregistered pair, and a baseline is
  expected to improve on it. A baseline below that pair is looked into before its line is trusted: a wrong reading of
  the field, a wrong input or a missing step of the authors' preprocessing is fixed and the cases run again (the
  IMPACT-Reg presets on PET in Bq/ml, now clipped). What remains is a real result, the method's own moved image
  matching the scorer's reading of its field, and the dataset's notes say why when the cause is known. On the SynthRAD
  pairs, which come rigidly aligned, a single-modality similarity on an MR/CT pair, a network outside its training
  data or a weakly regularised deformation can break what was already right; lung-only methods are below it on
  whole-thorax labels (POPI); on autoPET's PET to CT the PET shows uptake, not anatomy, and the deformable baselines
  pull the uptake onto the CT's structures (AutoPETCT).
- **Off the leaderboards.** A method whose `method.json` sets `"board": false` is run and its rows are kept, but it
  is not shown. IMPACT-Reg is in that case while its presets are being retuned: the leaderboards hold the baselines.
- **Notes** (`results/notes.json`) flag a result that needs a look, or remove a metric from a line when its ground
  truth is the method's own output.
- **Time is not ranked yet.** The rows come from machines that were not timing references, so times compare within
  one machine only. A timing table needs every method on one idle reference machine.