pub fn estimate_motion(
series: &[SeriesVolume<'_>],
mask: Option<&[u8]>,
params: &MotionParams,
) -> Option<MotionSeries>Expand description
Estimate where every volume of a series was, relative to a reference volume.
mask is optional and lives on the reference volume’s grid. Passing a brain mask is worth
it twice over: it keeps air, neck and the receive-field falloff out of the correlation, and it
is the domain VolumeMotion::max_displacement_mm is measured over.
Returns None if the series is empty, if MotionParams::reference does not name a volume,
if any volume’s data length disagrees with its dimensions, if the mask length disagrees with
the reference volume, or if any pairwise registration could not be evaluated at all. A
per-volume failure fails the whole call rather than quietly substituting the identity, because
an identity transform for a volume that moved is indistinguishable downstream from a volume
that did not move.
§Echoes are harder than repeats
Repeats and runs are the easy case: same contrast, and NCC absorbs the gain difference
between them. Echoes are not — T2* decay changes contrast spatially, far more in
iron-rich grey matter and vein than in white matter, so a late echo is not a scaled copy of
the first one. NCC still finds the alignment, because the anatomy’s edges stay where they
are, but its value falls: on the four-echo 7 T phantom, echoes at TE 12, 20 and 28 ms
registered to a 4 ms reference scored 0.84, 0.68 and 0.55 while recovering a known 2.5-7.5
degree rotation to 0.04 degrees. A low NCC on an echo series is therefore the contrast and
not a failure; MotionParams::min_ncc is defaulted for that case and should be raised
for repeats. The same caveat applies, for the same reason, to receive-field shading that
rotates with the coil rather than the head — see crate::registration on what NCC does
and does not absorb.