From dbaf33b7d6fce644f005d49962cde4b36424b460 Mon Sep 17 00:00:00 2001 From: ravih18 Date: Thu, 24 Oct 2024 17:49:12 +0200 Subject: [PATCH] Added node to clip the image --- clinica/pipelines/pet/linear/pipeline.py | 38 +++++++++++++++++++++--- clinica/pipelines/pet/linear/tasks.py | 10 +++++++ clinica/pipelines/pet/linear/utils.py | 20 +++++++++++++ 3 files changed, 64 insertions(+), 4 deletions(-) diff --git a/clinica/pipelines/pet/linear/pipeline.py b/clinica/pipelines/pet/linear/pipeline.py index f0dd34044..b67f95640 100644 --- a/clinica/pipelines/pet/linear/pipeline.py +++ b/clinica/pipelines/pet/linear/pipeline.py @@ -259,7 +259,11 @@ def _build_core_nodes(self): from clinica.pipelines.tasks import crop_nifti_task - from .tasks import perform_suvr_normalization_task, remove_mni_background_task + from .tasks import ( + clip_task, + perform_suvr_normalization_task, + remove_mni_background_task, + ) from .utils import concatenate_transforms, init_input_node, print_end_pipeline init_node = npe.Node( @@ -281,6 +285,16 @@ def _build_core_nodes(self): # The core (processing) nodes + # 0. Optional, clipping node + clipping_node = npe.Node( + name="clipping", + interface=nutil.Function( + function=clip_task, + input_names=["input_pet"], + output_names=["output_image"], + ), + ) + # 1. `RegistrationSynQuick` by *ANTS*. It uses nipype interface. ants_registration_node = npe.Node( name="antsRegistration", interface=ants.RegistrationSynQuick() @@ -354,11 +368,12 @@ def _build_core_nodes(self): # 5. Remove background remove_background_node = npe.Node( + name="removeBackground", interface=nutil.Function( function=remove_mni_background_task, input_names=["input_image"], output_names=["output_image"], - ) + ), ) remove_background_node.mni_mask_path = self.mni_mask @@ -376,12 +391,27 @@ def _build_core_nodes(self): ) ants_applytransform_optional_node.inputs.dimension = 3 + self.connect([(self.input_node, init_node, [("pet", "pet")])]) + # STEP 0: Optional + if self.parameters.get("clip_min_0"): + self.connect( + [ + (init_node, clipping_node, ["pet", "input_pet"]), + ( + clipping_node, + ants_registration_node, + ["output_image", "moving_image"], + ), + ] + ) + else: + self.connect( + [(init_node, ants_registration_node, [("pet", "moving_image")])] + ) self.connect( [ - (self.input_node, init_node, [("pet", "pet")]), # STEP 1 (self.input_node, ants_registration_node, [("t1w", "fixed_image")]), - (init_node, ants_registration_node, [("pet", "moving_image")]), # STEP 2 ( ants_registration_node, diff --git a/clinica/pipelines/pet/linear/tasks.py b/clinica/pipelines/pet/linear/tasks.py index a7d22bf42..8c9a5fae8 100644 --- a/clinica/pipelines/pet/linear/tasks.py +++ b/clinica/pipelines/pet/linear/tasks.py @@ -32,6 +32,16 @@ def remove_mni_background_task( ) +def clip_task( + input_pet: str, +) -> str: + from pathlib import Path + + from clinica.pipelines.pet.linear.utils import clip_img + + return str(clip_img(Path(input_pet))) + + def rename_into_caps_task( pet_bids_image_filename: str, pet_preprocessed_image_filename: str, diff --git a/clinica/pipelines/pet/linear/utils.py b/clinica/pipelines/pet/linear/utils.py index 3604138a1..16644a050 100644 --- a/clinica/pipelines/pet/linear/utils.py +++ b/clinica/pipelines/pet/linear/utils.py @@ -132,6 +132,26 @@ def remove_mni_background( return output_image +def clip_img( + pet_image_path: Path, +) -> Path: + """ """ + import nibabel as nib + import numpy as np + + from clinica.utils.filemanip import get_filename_no_ext + + pet_image = nib.load(pet_image_path) + + data = np.clip(pet_image.get_fdata(dtype="float32"), a_min=0) + + output_image = Path.cwd() / f"{get_filename_no_ext(pet_image_path)}_clipped.nii.gz" + clipped_pet = nib.Nifti1Image(data, pet_image.affine, header=pet_image.header) + clipped_pet.to_filename(output_image) + + return output_image + + def rename_into_caps( pet_bids_image_filename: Path, pet_preprocessed_image_filename: Path,