aramis-lab/clinica

Remove code duplication for function `crop_nifti`

Closed this issue · 1 comments

The crop_nifti function is currently defined in two places:

def crop_nifti(input_img, ref_crop):
"""Crop input image based on the reference.
It uses nilearn `resample_to_img` function.
Args:
input_img (str): image to be processed
ref_crop (str): template used to crop the image
Returns:
output_img (NIfTI image): crop image on disk.
crop_template: (NIfTI image): output template on disk.
"""
import os
from nilearn.image import crop_img, resample_to_img
basedir = os.getcwd()
# crop_ref = crop_img(ref_img, rtol=0.5)
# crop_ref.to_filename(os.path.join(basedir, os.path.basename(input_img).split('.nii')[0] + '_cropped_template.nii.gz'))
# crop_template = os.path.join(basedir, os.path.basename(input_img).split('.nii')[0] + '_cropped_template.nii.gz')
# resample the individual MRI into the cropped template image
crop_img = resample_to_img(input_img, ref_crop, force_resample=True)
crop_img.to_filename(
os.path.join(
basedir, os.path.basename(input_img).split(".nii")[0] + "_cropped.nii.gz"
)
)
output_img = os.path.join(
basedir, os.path.basename(input_img).split(".nii")[0] + "_cropped.nii.gz"
)
crop_template = ref_crop
return output_img, crop_template

and

def crop_nifti(input_img: str, ref_img: str) -> str:
"""Crop input image based on the reference.
It uses nilearn `resample_to_img` function.
Parameters
----------
input_img : str
Path to the input image.
ref_img : str
Path to the reference image used for cropping.
Returns
-------
output_img : str
Path to the cropped image.
"""
from pathlib import Path
from nilearn.image import resample_to_img
basedir = Path.cwd()
# resample the individual MRI into the cropped template image
crop_img = resample_to_img(input_img, ref_img, force_resample=True)
crop_filename = Path(input_img.split(".nii")[0] + "_cropped.nii.gz")
output_img = basedir / crop_filename
crop_img.to_filename(str(output_img))
return str(output_img)

By a quick inspection, there are exactly the same except that the later was modernized a bit and that the first one returns both the cropped image and the reference.

It would be great to have a single function with a better signature:

def crop_nifti(input_image: Path, reference_image: Path) -> Path:
    ...

and an adapter task for Nipype:

def crop_nifti_task(input_image: str, reference_image: str) -> str:
    return str(crop_nifti(Path(input_image), Path(reference_image)))

Note: I don't think we need to return the reference as it is one of the inputs. Modifying the connections in the related pipeline should do the trick in my opinion.

I'm not sure where to put these as it will be used by PETLinear and T1Linear. Maybe we could have the function in clinica.utils.image and the adapter within a tasks.py module under clinica.pipelines which defines tasks shared by all pipelines ?

I'm reopening because we forgot to add crop_nifti here:

__all__ = [
"compute_aggregated_volume",
"get_new_image_like",
"merge_nifti_images_in_time_dimension",
"remove_dummy_dimension_from_image",
]

@AliceJoubert could you make a small follow-up PR to add it ?