Putting everything together#
Once we have finalized the main components of the solution, it is time for integration. We now want to iterate over all the LOGO partitions of the dataset, generate a synthetic reference through the model of choice, and finally estimate the misalignment between the left-out gradient and the synthetic reference. This solution, must also abide by the API we have envisioned.
from nifreeze.data.dmri import DWI
dmri_dataset = DWI.from_filename(DATA_PATH)
dmri_dataset.dataobj = dmri_dataset.dataobj[..., :32]
dmri_dataset.gradients = dmri_dataset.gradients[..., :32]
Exercise
Complete the code snipet below to integrate the different components into the final solution to the dMRI head-motion problem.
class Estimator:
"""Estimates rigid-body head-motion and distortions derived from eddy-currents."""
@staticmethod
def fit(
dwdata,
*,
n_iter=1,
align_kwargs=None,
model="b0",
**kwargs,
):
r"""
Estimate head-motion and Eddy currents.
<please write a descriptive documentation of the function here>
"""
align_kwargs = align_kwargs or {}
for i_iter in range(1, n_iter + 1):
for i in random_iterator(len(dwdata)):
# run a original-to-synthetic affine registration
with TemporaryDirectory() as tmpdir:
# Factory creates the appropriate model and pipes arguments
dwmodel = ...
# generate a synthetic dw volume for the test gradient
predicted = dwmodel.fit_predict(i)
# Write arrays in memory to harddisk as NIfTI files
tmpdir = Path(tmpdir)
moving = tmpdir / "moving.nii.gz"
fixed = tmpdir / "fixed.nii.gz"
_to_nifti(data_test[0], moving)
_to_nifti(predicted, fixed)
# Prepare ANTs' antsRegistration via NiPype
registration = Registration(
fixed_image=str(fixed.absolute()),
moving_image=str(moving.absolute()),
**align_kwargs,
)
# execute ants command line
result = registration.run(cwd=str(tmpdir)).outputs
# read output transform
xform = nt.io.itk.ITKLinearTransform.from_filename(
result.forward_transforms[0]
)
# update
dwdata.set_transform(i, xform)
return dwdata.em_affines
Solution
The above code allows us to use our estimator as follows:
estimated_affines = Estimator.fit(dmri_dataset, model="b0")
What’s next? - Testing!#
Once we have our first implementation functional, we should think of some unit-tests for our code.
Exercise
Write a unit test for the TrivialB0Model
.
This test would just make sure that, regardless of the particular partition of the input dataset, a b=0 map is always returned.
Solution: in this solution, we are using pytest
to integrate the test into a higher-level test suite.
And after testing? - Validation!#
Once we have a sufficient portion of our code covered by unit-tests, then we would add some integration tests that give us confidence that our bullet-proof individual components also work together. Only after we have both steps secure, we can run benchmarks and evaluations from which we learn whether our solution works, and characterize its limitations.
The main strategy to validate this software would entail finding/acquiring a special dataset where motion is not present or extremely low, in which we introduce a known head-motion pattern with which we are going to challenge our estimator. Some ideas to achieve this are:
a dataset acquired with special sequences that can do prospective motion correction, or
a dataset that has been acquired under very controlled settings, with an extremely collaborative participant who was also wearing a personalized mold, or
a fully synthetic dataset such as the Fiber Box, or
a fully synthetic dataset containing a repeated b=0 image (this evaluation would be limited to work with the
TrivialB0Model
, for instance).
Please head to the GitHub repository and share your ideas with us! We are welcoming new contributors!