Skip to content

Commit

Permalink
Allows PETLinear to check for PET images registered on T1w image
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasGensollen committed Dec 2, 2024
1 parent 864d4c4 commit 830b4ac
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 20 deletions.
20 changes: 12 additions & 8 deletions clinica/pipelines/pet/linear/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ def get_processed_visits(self) -> list[Visit]:
The pipeline will further skip these visits and run processing only for the remaining
visits.
"""
from functools import reduce

from clinica.utils.filemanip import extract_visits
from clinica.utils.input_files import (
pet_linear_nii,
Expand All @@ -59,21 +61,23 @@ def get_processed_visits(self) -> list[Visit]:
uncropped_image=self.parameters.get("uncropped_image", False),
),
)
visits_having_pet_image = extract_visits(pet_registered_image)
visits = [set(extract_visits(pet_registered_image))]
transformation, _ = clinica_file_reader(
self.subjects,
self.sessions,
self.caps_directory,
pet_linear_transformation_matrix(tracer=self.parameters["acq_label"]),
)
visits_having_transformation = extract_visits(transformation)
return sorted(
list(
set(visits_having_pet_image).intersection(
set(visits_having_transformation)
)
visits.append(set(extract_visits(transformation)))
if self.parameters.get("save_PETinT1w", False):
pet_image_in_t1w_space, _ = clinica_file_reader(
self.subjects,
self.sessions,
self.caps_directory,
pet_linear_nii(acq_label=self.parameters["acq_label"], space="T1w"),
)
)
visits.append(set(extract_visits(pet_image_in_t1w_space)))
return sorted(list(reduce(lambda x, y: x.intersection(y), visits)))

def get_input_fields(self) -> List[str]:
"""Specify the list of possible inputs of this pipeline.
Expand Down
55 changes: 43 additions & 12 deletions clinica/utils/input_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,25 +680,56 @@ def pet_volume_normalized_suvr_pet(
return information


def _clean_pattern(pattern: str, character: str = "*") -> str:
"""Removes multiple '*' wildcards in provided pattern."""
cleaned = []
for c in pattern:
if not cleaned or not cleaned[-1] == c == character:
cleaned.append(c)
return "".join(cleaned)


def pet_linear_nii(
acq_label: Union[str, Tracer],
suvr_reference_region: Union[str, SUVRReferenceRegion],
uncropped_image: bool,
acq_label: Optional[Union[str, Tracer]] = None,
suvr_reference_region: Optional[Union[str, SUVRReferenceRegion]] = None,
uncropped_image: bool = False,
space: str = "mni",
resolution: Optional[int] = None,
) -> dict:
from pathlib import Path

acq_label = Tracer(acq_label)
region = SUVRReferenceRegion(suvr_reference_region)

if uncropped_image:
description = ""
else:
tracer_filter = "*"
tracer_description = ""
if acq_label:
acq_label = Tracer(acq_label)
tracer_filter = f"_trc-{acq_label.value}"
tracer_description = f" obtained with tracer {acq_label.value}"
region_filter = "*"
region_description = ""
if suvr_reference_region:
region = SUVRReferenceRegion(suvr_reference_region)
region_filter = f"_suvr-{region.value}"
region_description = f" for SUVR region {region.value}"
space_filer = f"_space-{'MNI152NLin2009cSym' if space == 'mni' else 'T1w'}"
space_description = f" affinely registered to the {'MNI152NLin2009cSym template' if space == 'mni' else 'associated T1w image'}"
description = "*"
if space == "mni" and not uncropped_image:
description = "_desc-Crop"

resolution_filter = "*"
resolution_description = ""
if resolution:
resolution_explicit = f"{resolution}x{resolution}x{resolution}"
resolution_filter = f"_res-{resolution_explicit}"
resolution_description = f" of resolution {resolution_explicit}"
information = {
"pattern": Path("pet_linear")
/ f"*_trc-{acq_label.value}_pet_space-MNI152NLin2009cSym{description}_res-1x1x1_suvr-{region.value}_pet.nii.gz",
"description": "",
/ _clean_pattern(
f"*{tracer_filter}_pet{space_filer}{description}{resolution_filter}{region_filter}_pet.nii.gz"
),
"description": (
f"{'Cropped ' if space == 'mni' and not uncropped_image else ''}PET nifti image{resolution_description}"
f"{tracer_description}{region_description}{space_description} resulting from the pet-linear pipeline"
),
"needed_pipeline": "pet-linear",
}
return information
Expand Down
69 changes: 69 additions & 0 deletions test/unittests/utils/test_input_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,72 @@ def test_dwi_dti_query_error():
match="'foo' is not a valid DTIBasedMeasure",
):
dwi_dti("foo")


@pytest.mark.parametrize(
"input_parameters,expected_description,expected_pattern",
[
(
{},
(
"Cropped PET nifti image affinely registered to the MNI152NLin2009cSym "
"template resulting from the pet-linear pipeline"
),
"pet_linear/*_pet_space-MNI152NLin2009cSym_desc-Crop*_pet.nii.gz",
),
(
{
"acq_label": "18FFDG",
},
(
"Cropped PET nifti image obtained with tracer 18FFDG affinely registered to the "
"MNI152NLin2009cSym template resulting from the pet-linear pipeline"
),
"pet_linear/*_trc-18FFDG_pet_space-MNI152NLin2009cSym_desc-Crop*_pet.nii.gz",
),
(
{
"acq_label": "18FAV45",
"suvr_reference_region": "pons",
"uncropped_image": True,
"resolution": 2,
},
(
"PET nifti image of resolution 2x2x2 obtained with tracer 18FAV45 for SUVR region "
"pons affinely registered to the MNI152NLin2009cSym template resulting from the pet-linear pipeline"
),
"pet_linear/*_trc-18FAV45_pet_space-MNI152NLin2009cSym*_res-2x2x2_suvr-pons_pet.nii.gz",
),
(
{
"suvr_reference_region": "pons2",
"resolution": 2,
"space": "T1w",
},
(
"PET nifti image of resolution 2x2x2 for SUVR region pons2 affinely "
"registered to the associated T1w image resulting from the pet-linear pipeline"
),
"pet_linear/*_pet_space-T1w*_res-2x2x2_suvr-pons2_pet.nii.gz",
),
(
{
"acq_label": "18FFDG",
"space": "T1w",
},
(
"PET nifti image obtained with tracer 18FFDG affinely registered to the "
"associated T1w image resulting from the pet-linear pipeline"
),
"pet_linear/*_trc-18FFDG_pet_space-T1w*_pet.nii.gz",
),
],
)
def test_pet_linear_nii(input_parameters, expected_description, expected_pattern):
from clinica.utils.input_files import pet_linear_nii

query = pet_linear_nii(**input_parameters)

assert query["description"] == expected_description
assert query["needed_pipeline"] == "pet-linear"
assert str(query["pattern"]) == expected_pattern

0 comments on commit 830b4ac

Please sign in to comment.