From 2e5bfa013298e66b285560a14d1706e318b8f258 Mon Sep 17 00:00:00 2001 From: camillebrianceau <57992134+camillebrianceau@users.noreply.github.com> Date: Mon, 24 Jun 2024 10:39:12 +0200 Subject: [PATCH] Change file_type dict for a class (#627) create a FileType class instead of having a dictionary --- clinicadl/caps_dataset/caps_dataset_config.py | 67 ++++++- clinicadl/caps_dataset/caps_dataset_utils.py | 65 +++---- clinicadl/caps_dataset/data.py | 30 ++-- clinicadl/caps_dataset/data_utils.py | 47 +++-- clinicadl/caps_dataset/extraction/config.py | 10 +- .../caps_dataset/preprocessing/config.py | 5 + .../commandline/modules_options/extraction.py | 8 - .../modules_options/preprocessing.py | 6 + .../pipelines/generate/artifacts/cli.py | 4 +- .../pipelines/generate/hypometabolic/cli.py | 8 +- .../pipelines/generate/random/cli.py | 7 +- .../pipelines/generate/shepplogan/cli.py | 12 +- .../pipelines/generate/trivial/cli.py | 4 +- .../prepare_data/prepare_data_cli.py | 8 +- .../prepare_data_from_bids_cli.py | 8 +- clinicadl/generate/generate_utils.py | 11 +- clinicadl/prepare_data/prepare_data.py | 12 +- clinicadl/quality_check/pet_linear/cli.py | 19 +- .../quality_check/pet_linear/quality_check.py | 26 +-- clinicadl/quality_check/t1_linear/utils.py | 14 +- clinicadl/utils/clinica_utils.py | 164 +++++++++--------- clinicadl/utils/maps_manager/__init__.py | 1 - clinicadl/utils/maps_manager/iotools.py | 132 -------------- .../utils/maps_manager/maps_manager_utils.py | 20 ++- clinicadl/utils/read_utils.py | 10 +- clinicadl/utils/seed.py | 7 +- .../utils/split_manager/split_manager.py | 2 +- .../utils/task_manager/classification.py | 2 +- tests/test_prepare_data.py | 8 +- tests/unittests/utils/test_clinica_utils.py | 18 +- 30 files changed, 329 insertions(+), 406 deletions(-) diff --git a/clinicadl/caps_dataset/caps_dataset_config.py b/clinicadl/caps_dataset/caps_dataset_config.py index 6545dc263..3eec87c54 100644 --- a/clinicadl/caps_dataset/caps_dataset_config.py +++ b/clinicadl/caps_dataset/caps_dataset_config.py @@ -1,12 +1,27 @@ -from typing import Optional, Union +from pathlib import Path +from typing import Optional, Tuple, Union from pydantic import BaseModel, ConfigDict from clinicadl.caps_dataset.data_config import DataConfig from clinicadl.caps_dataset.dataloader_config import DataLoaderConfig from clinicadl.caps_dataset.extraction import config as extraction -from clinicadl.caps_dataset.preprocessing import config as preprocessing +from clinicadl.caps_dataset.preprocessing.config import ( + CustomPreprocessingConfig, + DTIPreprocessingConfig, + FlairPreprocessingConfig, + PETPreprocessingConfig, + PreprocessingConfig, + T1PreprocessingConfig, +) from clinicadl.transforms.config import TransformsConfig +from clinicadl.utils.clinica_utils import ( + FileType, + bids_nii, + dwi_dti, + linear_nii, + pet_linear_nii, +) from clinicadl.utils.enum import ExtractionMethod, Preprocessing @@ -25,15 +40,15 @@ def get_extraction(extract_method: ExtractionMethod): def get_preprocessing(preprocessing_type: Preprocessing): if preprocessing_type == Preprocessing.T1_LINEAR: - return preprocessing.T1PreprocessingConfig + return T1PreprocessingConfig elif preprocessing_type == Preprocessing.PET_LINEAR: - return preprocessing.PETPreprocessingConfig + return PETPreprocessingConfig elif preprocessing_type == Preprocessing.FLAIR_LINEAR: - return preprocessing.FlairPreprocessingConfig + return FlairPreprocessingConfig elif preprocessing_type == Preprocessing.CUSTOM: - return preprocessing.CustomPreprocessingConfig + return CustomPreprocessingConfig elif preprocessing_type == Preprocessing.DWI_DTI: - return preprocessing.DTIPreprocessingConfig + return DTIPreprocessingConfig else: raise ValueError( f"Preprocessing {preprocessing_type.value} is not implemented." @@ -52,7 +67,7 @@ class CapsDatasetConfig(BaseModel): data: DataConfig dataloader: DataLoaderConfig extraction: extraction.ExtractionConfig - preprocessing: preprocessing.PreprocessingConfig + preprocessing: PreprocessingConfig transforms: TransformsConfig # pydantic config @@ -74,3 +89,39 @@ def from_preprocessing_and_extraction_method( extraction=get_extraction(ExtractionMethod(extraction))(**kwargs), transforms=TransformsConfig(**kwargs), ) + + def compute_folder_and_file_type( + self, from_bids: Optional[Path] = None + ) -> Tuple[str, FileType]: + preprocessing = self.preprocessing.preprocessing + if from_bids is not None: + if isinstance(self.preprocessing, CustomPreprocessingConfig): + mod_subfolder = Preprocessing.CUSTOM.value + file_type = FileType( + pattern=f"*{self.preprocessing.custom_suffix}", + description="Custom suffix", + ) + else: + mod_subfolder = preprocessing + file_type = bids_nii(self.preprocessing) + + elif preprocessing not in Preprocessing: + raise NotImplementedError( + f"Extraction of preprocessing {preprocessing} is not implemented from CAPS directory." + ) + else: + mod_subfolder = preprocessing.value.replace("-", "_") + if isinstance(self.preprocessing, T1PreprocessingConfig) or isinstance( + self.preprocessing, FlairPreprocessingConfig + ): + file_type = linear_nii(self.preprocessing) + elif isinstance(self.preprocessing, PETPreprocessingConfig): + file_type = pet_linear_nii(self.preprocessing) + elif isinstance(self.preprocessing, DTIPreprocessingConfig): + file_type = dwi_dti(self.preprocessing) + elif isinstance(self.preprocessing, CustomPreprocessingConfig): + file_type = FileType( + pattern=f"*{self.preprocessing.custom_suffix}", + description="Custom suffix", + ) + return mod_subfolder, file_type diff --git a/clinicadl/caps_dataset/caps_dataset_utils.py b/clinicadl/caps_dataset/caps_dataset_utils.py index 665acf814..d5244332c 100644 --- a/clinicadl/caps_dataset/caps_dataset_utils.py +++ b/clinicadl/caps_dataset/caps_dataset_utils.py @@ -1,5 +1,5 @@ from pathlib import Path -from typing import Dict, Optional, Tuple +from typing import Optional, Tuple from clinicadl.caps_dataset.caps_dataset_config import CapsDatasetConfig from clinicadl.caps_dataset.preprocessing.config import ( @@ -9,30 +9,30 @@ PETPreprocessingConfig, T1PreprocessingConfig, ) -from clinicadl.utils.enum import LinearModality, Preprocessing +from clinicadl.utils.clinica_utils import ( + FileType, + bids_nii, + dwi_dti, + linear_nii, + pet_linear_nii, +) +from clinicadl.utils.enum import Preprocessing def compute_folder_and_file_type( config: CapsDatasetConfig, from_bids: Optional[Path] = None -) -> Tuple[str, Dict[str, str]]: - from clinicadl.utils.clinica_utils import ( - bids_nii, - dwi_dti, - linear_nii, - pet_linear_nii, - ) - +) -> Tuple[str, FileType]: preprocessing = config.preprocessing.preprocessing if from_bids is not None: if isinstance(config.preprocessing, CustomPreprocessingConfig): mod_subfolder = Preprocessing.CUSTOM.value - file_type = { - "pattern": f"*{config.preprocessing.custom_suffix}", - "description": "Custom suffix", - } + file_type = FileType( + pattern=f"*{config.preprocessing.custom_suffix}", + description="Custom suffix", + ) else: mod_subfolder = preprocessing - file_type = bids_nii(preprocessing) + file_type = bids_nii(config.preprocessing) elif preprocessing not in Preprocessing: raise NotImplementedError( @@ -40,32 +40,17 @@ def compute_folder_and_file_type( ) else: mod_subfolder = preprocessing.value.replace("-", "_") - if isinstance(config.preprocessing, T1PreprocessingConfig): - file_type = linear_nii( - LinearModality.T1W, config.extraction.use_uncropped_image - ) - - elif isinstance(config.preprocessing, FlairPreprocessingConfig): - file_type = linear_nii( - LinearModality.FLAIR, config.extraction.use_uncropped_image - ) - + if isinstance(config.preprocessing, T1PreprocessingConfig) or isinstance( + config.preprocessing, FlairPreprocessingConfig + ): + file_type = linear_nii(config.preprocessing) elif isinstance(config.preprocessing, PETPreprocessingConfig): - file_type = pet_linear_nii( - config.preprocessing.tracer, - config.preprocessing.suvr_reference_region, - config.extraction.use_uncropped_image, - ) + file_type = pet_linear_nii(config.preprocessing) elif isinstance(config.preprocessing, DTIPreprocessingConfig): - file_type = dwi_dti( - config.preprocessing.dti_measure, - config.preprocessing.dti_space, - ) + file_type = dwi_dti(config.preprocessing) elif isinstance(config.preprocessing, CustomPreprocessingConfig): - file_type = { - "pattern": f"*{config.preprocessing.custom_suffix}", - "description": "Custom suffix", - } - # custom_suffix["use_uncropped_image"] = None - + file_type = FileType( + pattern=f"*{config.preprocessing.custom_suffix}", + description="Custom suffix", + ) return mod_subfolder, file_type diff --git a/clinicadl/caps_dataset/data.py b/clinicadl/caps_dataset/data.py index 470171916..884d184a1 100644 --- a/clinicadl/caps_dataset/data.py +++ b/clinicadl/caps_dataset/data.py @@ -137,15 +137,18 @@ def _get_image_path(self, participant: str, session: str, cohort: str) -> Path: # Try to find .nii.gz file try: - file_type = self.preprocessing_dict["file_type"] + folder, file_type = self.config.compute_folder_and_file_type() + results = clinicadl_file_reader( - [participant], [session], self.config.data.caps_dict[cohort], file_type + [participant], + [session], + self.config.data.caps_dict[cohort], + file_type.model_dump(), ) logger.debug(f"clinicadl_file_reader output: {results}") filepath = Path(results[0][0]) image_filename = filepath.name.replace(".nii.gz", ".pt") - folder, _ = compute_folder_and_file_type(self.config) image_dir = ( self.config.data.caps_dict[cohort] / "subjects" @@ -158,10 +161,13 @@ def _get_image_path(self, participant: str, session: str, cohort: str) -> Path: image_path = image_dir / image_filename # Try to find .pt file except ClinicaDLCAPSError: - file_type = self.preprocessing_dict["file_type"] - file_type["pattern"] = file_type["pattern"].replace(".nii.gz", ".pt") + folder, file_type = self.config.compute_folder_and_file_type() + file_type.pattern = file_type.pattern.replace(".nii.gz", ".pt") results = clinicadl_file_reader( - [participant], [session], self.config.data.caps_dict[cohort], file_type + [participant], + [session], + self.config.data.caps_dict[cohort], + file_type.model_dump(), ) filepath = results[0] image_path = Path(filepath[0]) @@ -225,12 +231,12 @@ def _get_full_image(self) -> torch.Tensor: image_path = self._get_image_path(participant_id, session_id, cohort) image = torch.load(image_path) except IndexError: - file_type = self.preprocessing_dict["file_type"] + file_type = self.config.extraction.file_type results = clinicadl_file_reader( [participant_id], [session_id], self.config.data.caps_dict[cohort], - file_type, + file_type.model_dump(), ) image_nii = nib.loadsave.load(results[0]) image_np = image_nii.get_fdata() @@ -741,7 +747,7 @@ def return_dataset( if preprocessing_dict["mode"] == "image": config.extraction.save_features = preprocessing_dict["prepare_dl"] - config.extraction.use_uncropped_image = preprocessing_dict[ + config.preprocessing.use_uncropped_image = preprocessing_dict[ "use_uncropped_image" ] return CapsDatasetImage( @@ -755,7 +761,7 @@ def return_dataset( config.extraction.patch_size = preprocessing_dict["patch_size"] config.extraction.stride_size = preprocessing_dict["stride_size"] config.extraction.save_features = preprocessing_dict["prepare_dl"] - config.extraction.use_uncropped_image = preprocessing_dict[ + config.preprocessing.use_uncropped_image = preprocessing_dict[ "use_uncropped_image" ] return CapsDatasetPatch( @@ -770,7 +776,7 @@ def return_dataset( config.extraction.roi_list = preprocessing_dict["roi_list"] config.extraction.roi_uncrop_output = preprocessing_dict["uncropped_roi"] config.extraction.save_features = preprocessing_dict["prepare_dl"] - config.extraction.use_uncropped_image = preprocessing_dict[ + config.preprocessing.use_uncropped_image = preprocessing_dict[ "use_uncropped_image" ] return CapsDatasetRoi( @@ -795,7 +801,7 @@ def return_dataset( else preprocessing_dict["num_slices"] ) config.extraction.save_features = preprocessing_dict["prepare_dl"] - config.extraction.use_uncropped_image = preprocessing_dict[ + config.preprocessing.use_uncropped_image = preprocessing_dict[ "use_uncropped_image" ] return CapsDatasetSlice( diff --git a/clinicadl/caps_dataset/data_utils.py b/clinicadl/caps_dataset/data_utils.py index 4cd514079..66ea5d8a0 100644 --- a/clinicadl/caps_dataset/data_utils.py +++ b/clinicadl/caps_dataset/data_utils.py @@ -31,7 +31,7 @@ def load_data_test(test_path: Path, diagnoses_list, baseline=True, multi_cohort= # TODO: computes baseline sessions on-the-fly to manager TSV file case if multi_cohort: - if not test_path.suffix == ".tsv": + if test_path.suffix != ".tsv": raise ClinicaDLArgumentError( "If multi_cohort is given, the TSV_DIRECTORY argument should be a path to a TSV file." ) @@ -77,6 +77,27 @@ def load_data_test(test_path: Path, diagnoses_list, baseline=True, multi_cohort= return test_df +def check_test_path(test_path: Path, baseline: bool = True) -> Path: + if baseline: + train_filename = "train_baseline.tsv" + label_filename = "labels_baseline.tsv" + else: + train_filename = "train.tsv" + label_filename = "labels.tsv" + + if not (test_path.parent / train_filename).is_file(): + if not (test_path.parent / label_filename).is_file(): + raise ClinicaDLTSVError( + f"There is no {train_filename} nor {label_filename} in your folder {test_path.parents[0]} " + ) + else: + test_path = test_path.parent / label_filename + else: + test_path = test_path.parent / train_filename + + return test_path + + def load_data_test_single(test_path: Path, diagnoses_list, baseline=True): if test_path.suffix == ".tsv": test_df = pd.read_csv(test_path, sep="\t") @@ -91,29 +112,7 @@ def load_data_test_single(test_path: Path, diagnoses_list, baseline=True): ) return test_df - test_df = pd.DataFrame() - - if baseline: - if not (test_path.parent / "train_baseline.tsv").is_file(): - if not (test_path.parent / "labels_baseline.tsv").is_file(): - raise ClinicaDLTSVError( - f"There is no train_baseline.tsv nor labels_baseline.tsv in your folder {test_path.parents[0]} " - ) - else: - test_path = test_path.parent / "labels_baseline.tsv" - else: - test_path = test_path.parent / "train_baseline.tsv" - else: - if not (test_path.parent / "train.tsv").is_file(): - if not (test_path.parent / "labels.tsv").is_file(): - raise ClinicaDLTSVError( - f"There is no train.tsv or labels.tsv in your folder {test_path.parent} " - ) - else: - test_path = test_path.parent / "labels.tsv" - else: - test_path = test_path.parent / "train.tsv" - + test_path = check_test_path(test_path=test_path, baseline=baseline) test_df = pd.read_csv(test_path, sep="\t") test_df = test_df[test_df.diagnosis.isin(diagnoses_list)] test_df.reset_index(inplace=True, drop=True) diff --git a/clinicadl/caps_dataset/extraction/config.py b/clinicadl/caps_dataset/extraction/config.py index 816966063..5a88ca4fd 100644 --- a/clinicadl/caps_dataset/extraction/config.py +++ b/clinicadl/caps_dataset/extraction/config.py @@ -1,14 +1,13 @@ from logging import getLogger -from pathlib import Path from time import time from typing import List, Optional, Tuple from pydantic import BaseModel, ConfigDict, field_validator from pydantic.types import NonNegativeInt +from clinicadl.utils.clinica_utils import FileType from clinicadl.utils.enum import ( ExtractionMethod, - Preprocessing, SliceDirection, SliceMode, ) @@ -18,14 +17,11 @@ class ExtractionConfig(BaseModel): """ - Abstract config class for the validation procedure. - - + Abstract config class for the Extraction procedure. """ - use_uncropped_image: bool = False extract_method: ExtractionMethod - file_type: Optional[str] = None # Optional ?? + file_type: Optional[FileType] = None save_features: bool = False extract_json: Optional[str] = None diff --git a/clinicadl/caps_dataset/preprocessing/config.py b/clinicadl/caps_dataset/preprocessing/config.py index 9d3ca863b..ad8db765e 100644 --- a/clinicadl/caps_dataset/preprocessing/config.py +++ b/clinicadl/caps_dataset/preprocessing/config.py @@ -22,6 +22,7 @@ class PreprocessingConfig(BaseModel): tsv_file: Optional[Path] = None preprocessing: Preprocessing + use_uncropped_image: bool = False # pydantic config model_config = ConfigDict(validate_assignment=True) @@ -50,3 +51,7 @@ class T1PreprocessingConfig(PreprocessingConfig): class FlairPreprocessingConfig(PreprocessingConfig): preprocessing: Preprocessing = Preprocessing.FLAIR_LINEAR + + +class T2PreprocessingConfig(PreprocessingConfig): + preprocessing: Preprocessing = Preprocessing.T2_LINEAR diff --git a/clinicadl/commandline/modules_options/extraction.py b/clinicadl/commandline/modules_options/extraction.py index 8e09f9db7..fc0db1f98 100644 --- a/clinicadl/commandline/modules_options/extraction.py +++ b/clinicadl/commandline/modules_options/extraction.py @@ -27,14 +27,6 @@ is done when images are loaded in the train.""", ) - -use_uncropped_image = click.option( - "-uui", - "--use_uncropped_image", - is_flag=True, - help="Use the uncropped image instead of the cropped image generated by t1-linear or pet-linear.", -) - patch_size = click.option( "-ps", "--patch_size", diff --git a/clinicadl/commandline/modules_options/preprocessing.py b/clinicadl/commandline/modules_options/preprocessing.py index bb3d78d0f..641e91518 100644 --- a/clinicadl/commandline/modules_options/preprocessing.py +++ b/clinicadl/commandline/modules_options/preprocessing.py @@ -65,3 +65,9 @@ help="Extraction used to generate synthetic data.", show_default=True, ) +use_uncropped_image = click.option( + "-uui", + "--use_uncropped_image", + is_flag=True, + help="Use the uncropped image instead of the cropped image generated by t1-linear or pet-linear.", +) diff --git a/clinicadl/commandline/pipelines/generate/artifacts/cli.py b/clinicadl/commandline/pipelines/generate/artifacts/cli.py index b0fc9683c..1c89d4979 100644 --- a/clinicadl/commandline/pipelines/generate/artifacts/cli.py +++ b/clinicadl/commandline/pipelines/generate/artifacts/cli.py @@ -35,7 +35,7 @@ @arguments.generated_caps_directory @dataloader.n_proc @preprocessing.preprocessing -@extraction.use_uncropped_image +@preprocessing.use_uncropped_image @data.participants_tsv @preprocessing.tracer @preprocessing.suvr_reference_region @@ -100,7 +100,7 @@ def create_artifacts_image(data_idx: int) -> pd.DataFrame: [participant_id], [session_id], caps_config.data.caps_dict[cohort], - file_type, + file_type.model_dump(), )[0][0] ) from clinicadl.utils.read_utils import get_info_from_filename diff --git a/clinicadl/commandline/pipelines/generate/hypometabolic/cli.py b/clinicadl/commandline/pipelines/generate/hypometabolic/cli.py index 2d7b5b5fc..b374d58a5 100644 --- a/clinicadl/commandline/pipelines/generate/hypometabolic/cli.py +++ b/clinicadl/commandline/pipelines/generate/hypometabolic/cli.py @@ -9,7 +9,7 @@ from clinicadl.caps_dataset.caps_dataset_config import CapsDatasetConfig from clinicadl.commandline import arguments -from clinicadl.commandline.modules_options import data, dataloader, extraction +from clinicadl.commandline.modules_options import data, dataloader, preprocessing from clinicadl.commandline.pipelines.generate.hypometabolic import ( options as hypometabolic, ) @@ -38,7 +38,7 @@ @dataloader.n_proc @data.participants_tsv @data.n_subjects -@extraction.use_uncropped_image +@preprocessing.use_uncropped_image @hypometabolic.sigma @hypometabolic.anomaly_degree @hypometabolic.pathology @@ -97,7 +97,9 @@ def cli(generated_caps_directory, **kwargs): sessions = [data_df.at[i, "session_id"] for i in range(caps_config.data.n_subjects)] cohort = caps_config.data.caps_directory - images_paths = clinicadl_file_reader(participants, sessions, cohort, file_type)[0] + images_paths = clinicadl_file_reader( + participants, sessions, cohort, file_type.model_dump() + )[0] image_nii = nib.loadsave.load(images_paths[0]) mask_resample_nii = resample_to_img(mask_nii, image_nii, interpolation="nearest") mask = mask_resample_nii.get_fdata() diff --git a/clinicadl/commandline/pipelines/generate/random/cli.py b/clinicadl/commandline/pipelines/generate/random/cli.py index 2247c2149..b4c33a503 100644 --- a/clinicadl/commandline/pipelines/generate/random/cli.py +++ b/clinicadl/commandline/pipelines/generate/random/cli.py @@ -37,7 +37,7 @@ @data.participants_tsv @data.n_subjects @dataloader.n_proc -@extraction.use_uncropped_image +@preprocessing.use_uncropped_image @preprocessing.tracer @preprocessing.suvr_reference_region @random.mean @@ -97,7 +97,10 @@ def cli(generated_caps_directory, n_proc, **kwargs): session_id = data_df.at[0, "session_id"] cohort = data_df.at[0, "cohort"] image_paths = clinicadl_file_reader( - [participant_id], [session_id], caps_config.data.caps_dict[cohort], file_type + [participant_id], + [session_id], + caps_config.data.caps_dict[cohort], + file_type.model_dump(), ) image_nii = nib.loadsave.load(image_paths[0][0]) # assert isinstance(image_nii, nib.nifti1.Nifti1Image) diff --git a/clinicadl/commandline/pipelines/generate/shepplogan/cli.py b/clinicadl/commandline/pipelines/generate/shepplogan/cli.py index 87dde5e4c..42595d35a 100644 --- a/clinicadl/commandline/pipelines/generate/shepplogan/cli.py +++ b/clinicadl/commandline/pipelines/generate/shepplogan/cli.py @@ -1,4 +1,5 @@ from logging import getLogger +from pathlib import Path import click import numpy as np @@ -15,6 +16,7 @@ generate_shepplogan_phantom, write_missing_mods, ) +from clinicadl.utils.clinica_utils import FileType from clinicadl.utils.maps_manager.iotools import check_and_clean, commandline_to_json logger = getLogger("clinicadl.generate.shepplogan") @@ -129,11 +131,11 @@ def create_shepplogan_image( "slice_mode": "single", "discarded_slices": 0, "num_slices": 1, - "file_type": { - "pattern": f"*_space-SheppLogan_phantom.nii.gz", - "description": "Custom suffix", - "needed_pipeline": "shepplogan", - }, + "file_type": FileType( + pattern="*_space-SheppLogan_phantom.nii.gz", + description="Custom suffix", + needed_pipeline="shepplogan", + ).model_dump(), } write_preprocessing(preprocessing_dict, generated_caps_directory) write_missing_mods(generated_caps_directory, data_df) diff --git a/clinicadl/commandline/pipelines/generate/trivial/cli.py b/clinicadl/commandline/pipelines/generate/trivial/cli.py index 0a989f747..580de1626 100644 --- a/clinicadl/commandline/pipelines/generate/trivial/cli.py +++ b/clinicadl/commandline/pipelines/generate/trivial/cli.py @@ -38,7 +38,7 @@ @data.participants_tsv @data.n_subjects @dataloader.n_proc -@extraction.use_uncropped_image +@preprocessing.use_uncropped_image @preprocessing.tracer @preprocessing.suvr_reference_region @trivial.atrophy_percent @@ -96,7 +96,7 @@ def create_trivial_image(subject_id: int) -> pd.DataFrame: [participant_id], [session_id], caps_config.data.caps_dict[cohort], - file_type, + file_type.model_dump(), )[0][0] ) diff --git a/clinicadl/commandline/pipelines/prepare_data/prepare_data_cli.py b/clinicadl/commandline/pipelines/prepare_data/prepare_data_cli.py index c374ab5dc..35d6db73c 100644 --- a/clinicadl/commandline/pipelines/prepare_data/prepare_data_cli.py +++ b/clinicadl/commandline/pipelines/prepare_data/prepare_data_cli.py @@ -20,7 +20,7 @@ @dataloader.n_proc @data.participants_tsv @extraction.extract_json -@extraction.use_uncropped_image +@preprocessing.use_uncropped_image @preprocessing.tracer @preprocessing.suvr_reference_region @preprocessing.custom_suffix @@ -50,7 +50,7 @@ def image_cli(**kwargs): @extraction.save_features @data.participants_tsv @extraction.extract_json -@extraction.use_uncropped_image +@preprocessing.use_uncropped_image @preprocessing.tracer @preprocessing.suvr_reference_region @preprocessing.custom_suffix @@ -82,7 +82,7 @@ def patch_cli(**kwargs): @extraction.save_features @data.participants_tsv @extraction.extract_json -@extraction.use_uncropped_image +@preprocessing.use_uncropped_image @preprocessing.tracer @preprocessing.suvr_reference_region @preprocessing.custom_suffix @@ -114,7 +114,7 @@ def slice_cli(**kwargs): @extraction.save_features @data.participants_tsv @extraction.extract_json -@extraction.use_uncropped_image +@preprocessing.use_uncropped_image @preprocessing.tracer @preprocessing.suvr_reference_region @preprocessing.custom_suffix diff --git a/clinicadl/commandline/pipelines/prepare_data/prepare_data_from_bids_cli.py b/clinicadl/commandline/pipelines/prepare_data/prepare_data_from_bids_cli.py index 4f014e361..4c43df851 100644 --- a/clinicadl/commandline/pipelines/prepare_data/prepare_data_from_bids_cli.py +++ b/clinicadl/commandline/pipelines/prepare_data/prepare_data_from_bids_cli.py @@ -18,7 +18,7 @@ @arguments.modality_bids @dataloader.n_proc @extraction.extract_json -@extraction.use_uncropped_image +@preprocessing.use_uncropped_image @preprocessing.tracer @preprocessing.suvr_reference_region @preprocessing.custom_suffix @@ -41,7 +41,7 @@ def image_bids_cli(kwargs): @extraction.save_features @data.participants_tsv @extraction.extract_json -@extraction.use_uncropped_image +@preprocessing.use_uncropped_image @extraction.patch_size @extraction.stride_size @preprocessing.tracer @@ -69,7 +69,7 @@ def patch_bids_cli(kwargs): @extraction.save_features @data.participants_tsv @extraction.extract_json -@extraction.use_uncropped_image +@preprocessing.use_uncropped_image @extraction.slice_direction @extraction.slice_mode @extraction.discarded_slices @@ -99,7 +99,7 @@ def slice_bids_cli(kwargs): @extraction.save_features @data.participants_tsv @extraction.extract_json -@extraction.use_uncropped_image +@preprocessing.use_uncropped_image @extraction.roi_custom_mask_pattern @extraction.roi_custom_template @extraction.roi_list diff --git a/clinicadl/generate/generate_utils.py b/clinicadl/generate/generate_utils.py index d367cb6b8..3e65b5949 100755 --- a/clinicadl/generate/generate_utils.py +++ b/clinicadl/generate/generate_utils.py @@ -17,6 +17,7 @@ T1PreprocessingConfig, ) from clinicadl.utils.clinica_utils import ( + FileType, create_subs_sess_list, linear_nii, pet_linear_nii, @@ -34,9 +35,7 @@ def find_file_type(config: CapsDatasetConfig) -> Dict[str, str]: if isinstance(config.preprocessing, T1PreprocessingConfig): - file_type = linear_nii( - LinearModality.T1W, config.extraction.use_uncropped_image - ) + file_type = linear_nii(config.preprocessing) elif isinstance(config.preprocessing, PETPreprocessingConfig): if ( config.preprocessing.tracer is None @@ -46,11 +45,7 @@ def find_file_type(config: CapsDatasetConfig) -> Dict[str, str]: "`tracer` and `suvr_reference_region` must be defined " "when using `pet-linear` preprocessing." ) - file_type = pet_linear_nii( - config.preprocessing.tracer, - config.preprocessing.suvr_reference_region, - config.extraction.use_uncropped_image, - ) + file_type = pet_linear_nii(config.preprocessing) else: raise NotImplementedError( f"Generation of synthetic data is not implemented for preprocessing {config.preprocessing.preprocessing.value}" diff --git a/clinicadl/prepare_data/prepare_data.py b/clinicadl/prepare_data/prepare_data.py index 24057e544..262d178e2 100644 --- a/clinicadl/prepare_data/prepare_data.py +++ b/clinicadl/prepare_data/prepare_data.py @@ -19,6 +19,7 @@ check_caps_folder, clinicadl_file_reader, container_from_filename, + determine_caps_or_bids, get_subject_session_list, ) from clinicadl.utils.enum import ExtractionMethod, Pattern, Preprocessing, Template @@ -71,12 +72,11 @@ def DeepLearningPrepareData( ) mod_subfolder, file_type = compute_folder_and_file_type(config, from_bids) - # parameters["file_type"] = file_type # Input file: - input_files = clinicadl_file_reader(subjects, sessions, input_directory, file_type)[ - 0 - ] + input_files = clinicadl_file_reader( + subjects, sessions, input_directory, file_type.model_dump() + )[0] logger.debug(f"Selected image file name list: {input_files}.") def write_output_imgs(output_mode, container, subfolder): @@ -200,14 +200,14 @@ def prepare_roi(file): masks_location, config.extraction.roi_list, roi_mask_pattern, - config.extraction.use_uncropped_image, + config.preprocessing.use_uncropped_image, ) output_mode = extract_roi( Path(file), masks_location=masks_location, mask_pattern=roi_mask_pattern, - cropped_input=not config.extraction.use_uncropped_image, + cropped_input=not config.preprocessing.use_uncropped_image, roi_names=config.extraction.roi_list, uncrop_output=config.extraction.roi_uncrop_output, ) diff --git a/clinicadl/quality_check/pet_linear/cli.py b/clinicadl/quality_check/pet_linear/cli.py index 5673df778..c47226a20 100644 --- a/clinicadl/quality_check/pet_linear/cli.py +++ b/clinicadl/quality_check/pet_linear/cli.py @@ -7,6 +7,7 @@ extraction, preprocessing, ) +from clinicadl.utils.enum import ExtractionMethod, Preprocessing @click.command(name="pet-linear", no_args_is_help=True) @@ -14,7 +15,7 @@ @arguments.results_tsv @preprocessing.tracer @preprocessing.suvr_reference_region -@extraction.use_uncropped_image +@preprocessing.use_uncropped_image @data.participants_tsv @dataloader.n_proc @click.option( @@ -44,15 +45,19 @@ def cli( SUVR_REFERENCE_REGION is the reference region used to perform intensity normalization {pons|cerebellumPons|pons2|cerebellumPons2}. """ + from clinicadl.caps_dataset.caps_dataset_config import CapsDatasetConfig + from .quality_check import quality_check as pet_linear_qc - pet_linear_qc( - caps_directory, - output_tsv=results_tsv, + config = CapsDatasetConfig.from_preprocessing_and_extraction_method( + caps_directory=caps_directory, tracer=tracer, - ref_region=suvr_reference_region, + suvr_reference_region=suvr_reference_region, use_uncropped_image=use_uncropped_image, - participants_tsv=participants_tsv, - threshold=threshold, + data_tsv=participants_tsv, n_proc=n_proc, + preprocessing_type=Preprocessing.PET_LINEAR, + extraction=ExtractionMethod.IMAGE, ) + + pet_linear_qc(config, output_tsv=results_tsv, threshold=threshold) diff --git a/clinicadl/quality_check/pet_linear/quality_check.py b/clinicadl/quality_check/pet_linear/quality_check.py index 177f3dfa1..1b4e9d2a9 100644 --- a/clinicadl/quality_check/pet_linear/quality_check.py +++ b/clinicadl/quality_check/pet_linear/quality_check.py @@ -6,13 +6,13 @@ from logging import getLogger from pathlib import Path -from typing import Optional, Union import nibabel as nib import numpy as np import pandas as pd from joblib import Parallel, delayed +from clinicadl.caps_dataset.caps_dataset_config import CapsDatasetConfig from clinicadl.utils.clinica_utils import ( RemoteFileStructure, clinicadl_file_reader, @@ -26,14 +26,9 @@ def quality_check( - caps_dir: Path, + config: CapsDatasetConfig, output_tsv: Path, - tracer: Union[Tracer, str], - ref_region: Union[SUVRReferenceRegions, str], - use_uncropped_image: bool, - participants_tsv: Optional[Path], threshold: float = 0.8, - n_proc: int = 1, ): """ Performs quality check on pet-linear pipeline. @@ -61,9 +56,6 @@ def quality_check( """ logger = getLogger("clinicadl.quality_check") - tracer = Tracer(tracer) - ref_region = SUVRReferenceRegions(ref_region) - if Path(output_tsv).is_file(): raise NameError("this file already exists please chose another name") @@ -102,14 +94,12 @@ def quality_check( results_df = pd.DataFrame(columns=columns) subjects, sessions = get_subject_session_list( - caps_dir, participants_tsv, False, False, None - ) - file_type = pet_linear_nii( - tracer, - ref_region, - use_uncropped_image, + config.data.caps_directory, config.data.data_tsv, False, False, None ) - input_files = clinicadl_file_reader(subjects, sessions, caps_dir, file_type)[0] + file_type = pet_linear_nii(config.preprocessing) + input_files = clinicadl_file_reader( + subjects, sessions, config.data.caps_directory, file_type.model_dump() + )[0] def write_output_data(file): file = Path(file) @@ -136,7 +126,7 @@ def write_output_data(file): return row_df - results_df = Parallel(n_jobs=n_proc)( + results_df = Parallel(n_jobs=config.dataloader.n_proc)( delayed(write_output_data)(file) for file in input_files ) diff --git a/clinicadl/quality_check/t1_linear/utils.py b/clinicadl/quality_check/t1_linear/utils.py index 0a4a19157..d368bd2e4 100755 --- a/clinicadl/quality_check/t1_linear/utils.py +++ b/clinicadl/quality_check/t1_linear/utils.py @@ -34,7 +34,7 @@ def __init__( self.img_dir = config.data.caps_directory self.df = config.data.data_df self.use_extracted_tensors = use_extracted_tensors - self.use_uncropped_image = config.extraction.use_uncropped_image + self.use_uncropped_image = config.preprocessing.use_uncropped_image self.config = config if ("session_id" not in list(self.df.columns.values)) or ( @@ -51,7 +51,7 @@ def __init__( "preprocessing": Preprocessing.T1_LINEAR.value, "mode": "image", "use_uncropped_image": self.use_uncropped_image, - "file_type": linear_nii(LinearModality.T1W, self.use_uncropped_image), + "file_type": linear_nii(config.preprocessing).model_dump(), "use_tensor": self.use_extracted_tensors, } @@ -63,14 +63,14 @@ def __getitem__(self, idx): session = self.df.loc[idx, "session_id"] if self.use_extracted_tensors: - file_type = self.preprocessing_dict["file_type"] - file_type["pattern"] = file_type["pattern"].replace(".nii.gz", ".pt") + file_type = self.config.extraction.file_type + file_type.pattern = Path(str(file_type.pattern).replace(".nii.gz", ".pt")) image_output = clinicadl_file_reader( - [subject], [session], self.img_dir, file_type + [subject], [session], self.img_dir, file_type.model_dump() )[0] image_path = Path(image_output[0]) image_filename = image_path.name - folder, file_type = compute_folder_and_file_type(config=self.config) + folder, _ = compute_folder_and_file_type(config=self.config) image_dir = ( self.img_dir / "subjects" @@ -89,7 +89,7 @@ def __getitem__(self, idx): [subject], [session], self.img_dir, - linear_nii(LinearModality.T1W, self.use_uncropped_image), + linear_nii(self.config.preprocessing).model_dump(), )[0] image = nib.loadsave.load(image_path[0]) image = self.nii_transform(image) diff --git a/clinicadl/utils/clinica_utils.py b/clinicadl/utils/clinica_utils.py index 65012bcef..463a305ab 100644 --- a/clinicadl/utils/clinica_utils.py +++ b/clinicadl/utils/clinica_utils.py @@ -13,7 +13,9 @@ from urllib.request import Request, urlopen import pandas as pd +from pydantic import BaseModel +from clinicadl.caps_dataset.preprocessing import config as preprocessing_config from clinicadl.utils.enum import ( DTIMeasure, DTISpace, @@ -33,11 +35,16 @@ RemoteFileStructure = namedtuple("RemoteFileStructure", ["filename", "url", "checksum"]) +class FileType(BaseModel): + pattern: str + description: str + needed_pipeline: Optional[str] = None + + def bids_nii( - modality: Union[str, ImageModality] = ImageModality.T1, - tracer: Optional[Union[str, Tracer]] = None, + config: preprocessing_config.PreprocessingConfig, reconstruction: Optional[str] = None, -) -> dict: +) -> FileType: """Return the query dict required to capture PET scans. Parameters @@ -60,124 +67,115 @@ def bids_nii( The query dictionary to get PET scans. """ - try: - modality = ImageModality(modality) - except ClinicaDLArgumentError: - print( - f"ClinicaDL is Unable to read this modality ({modality}) of images, please chose one from this list: {list[Modality]}" + if config.preprocessing not in Preprocessing: + raise ClinicaDLArgumentError( + f"ClinicaDL is Unable to read this modality ({config.preprocessing}) of images, please chose one from this list: {list[Preprocessing]}" ) - if modality == ImageModality.PET: - if tracer is not None: - tracer = Tracer(tracer) - trc = "" if tracer is None else f"_trc-{tracer.value}" + if isinstance(config, preprocessing_config.PETPreprocessingConfig): + trc = "" if config.tracer is None else f"_trc-{Tracer(config.tracer).value}" rec = "" if reconstruction is None else f"_rec-{reconstruction}" description = "PET data" - if tracer: - description += f" with {tracer.value} tracer" + + if config.tracer: + description += f" with {config.tracer.value} tracer" if reconstruction: description += f" and reconstruction method {reconstruction}" - return { - "pattern": os.path.join("pet", f"*{trc}{rec}_pet.nii*"), - "description": description, - } - elif modality == ImageModality.T1: - return {"pattern": "anat/sub-*_ses-*_T1w.nii*", "description": "T1w MRI"} - elif modality == ImageModality.FLAIR: - return { - "pattern": "sub-*_ses-*_flair.nii*", - "description": "FLAIR T2w MRI", - } - elif modality == ImageModality.DWI: - return { - "pattern": "dwi/sub-*_ses-*_dwi.nii*", - "description": "DWI NIfTI", - } - - -def linear_nii(modality: Union[LinearModality, str], uncropped_image: bool) -> dict: - try: - modality = LinearModality(modality) - except ClinicaDLArgumentError: - print(f"ClinicaDL is Unable to read this modality ({modality}) of images") + file_type = FileType( + pattern=f"pet/*{trc}{rec}_pet.nii*", description=description + ) + return file_type + + elif isinstance(config, preprocessing_config.T1PreprocessingConfig): + return FileType(pattern="anat/sub-*_ses-*_T1w.nii*", description="T1w MRI") + + elif isinstance(config, preprocessing_config.FlairPreprocessingConfig): + return FileType(pattern="sub-*_ses-*_flair.nii*", description="FLAIR T2w MRI") + + elif isinstance(config, preprocessing_config.DTIPreprocessingConfig): + return FileType(pattern="dwi/sub-*_ses-*_dwi.nii*", description="DWI NIfTI") + + else: + raise ClinicaDLArgumentError("Invalid preprocessing") - if modality == LinearModality.T1W: + +def linear_nii( + config: preprocessing_config.PreprocessingConfig, +) -> FileType: + if isinstance(config, preprocessing_config.T1PreprocessingConfig): needed_pipeline = Preprocessing.T1_LINEAR - elif modality == LinearModality.T2W: + modality = LinearModality.T1W + elif isinstance(config, preprocessing_config.T2PreprocessingConfig): needed_pipeline = Preprocessing.T2_LINEAR - elif modality == LinearModality.FLAIR: + modality = LinearModality.T2W + elif isinstance(config, preprocessing_config.FlairPreprocessingConfig): needed_pipeline = Preprocessing.FLAIR_LINEAR + modality = LinearModality.FLAIR + else: + raise ClinicaDLArgumentError("Invalid configuration") - if uncropped_image: + if config.use_uncropped_image: desc_crop = "" else: desc_crop = "_desc-Crop" - information = { - "pattern": f"*space-MNI152NLin2009cSym{desc_crop}_res-1x1x1_{modality.value}.nii.gz", - "description": f"{modality.value} Image registered in MNI152NLin2009cSym space using {needed_pipeline.value} pipeline " + file_type = FileType( + pattern=f"*space-MNI152NLin2009cSym{desc_crop}_res-1x1x1_{modality.value}.nii.gz", + description=f"{modality.value} Image registered in MNI152NLin2009cSym space using {needed_pipeline.value} pipeline " + ( "" - if uncropped_image + if config.use_uncropped_image else "and cropped (matrix size 169×208×179, 1 mm isotropic voxels)" ), - "needed_pipeline": needed_pipeline, - } - return information + needed_pipeline=needed_pipeline, + ) + return file_type -def dwi_dti( - measure: Union[str, DTIMeasure], space: Union[str, DTISpace] = None -) -> dict: +def dwi_dti(config: preprocessing_config.DTIPreprocessingConfig) -> FileType: """Return the query dict required to capture DWI DTI images. Parameters ---------- - measure : DTIBasedMeasure or str - The DTI based measure to consider. - - space : str, optional - The space to consider. - By default, all spaces are considered (i.e. '*' is used in regexp). + config: DTIPreprocessingConfig Returns ------- - dict : - The query dictionary to get DWI DTI images. + FileType : """ - measure = DTIMeasure(measure) - space = DTISpace(space) + if isinstance(config, preprocessing_config.DTIPreprocessingConfig): + measure = config.dti_measure + space = config.dti_space + else: + raise ClinicaDLArgumentError( + f"PreprocessingConfig is of type {config} but should be of type{preprocessing_config.DTIPreprocessingConfig}" + ) - return { - "pattern": f"dwi/dti_based_processing/*/*_space-{space}_{measure.value}.nii.gz", - "description": f"DTI-based {measure.value} in space {space}.", - "needed_pipeline": "dwi_dti", - } + return FileType( + pattern=f"dwi/dti_based_processing/*/*_space-{space}_{measure.value}.nii.gz", + description=f"DTI-based {measure.value} in space {space}.", + needed_pipeline="dwi_dti", + ) -def pet_linear_nii( - tracer: Union[str, Tracer], - suvr_reference_region: Union[str, SUVRReferenceRegions], - uncropped_image: bool, -) -> dict: - tracer = Tracer(tracer) - suvr_reference_region = SUVRReferenceRegions(suvr_reference_region) +def pet_linear_nii(config: preprocessing_config.PETPreprocessingConfig) -> FileType: + if not isinstance(config, preprocessing_config.PETPreprocessingConfig): + raise ClinicaDLArgumentError( + f"PreprocessingConfig is of type {config} but should be of type{preprocessing_config.PETPreprocessingConfig}" + ) - if uncropped_image: + if config.use_uncropped_image: description = "" else: description = "_desc-Crop" - information = { - "pattern": str( - Path("pet_linear") - / f"*_trc-{tracer.value}_space-MNI152NLin2009cSym{description}_res-1x1x1_suvr-{suvr_reference_region.value}_pet.nii.gz" - ), - "description": "", - "needed_pipeline": "pet-linear", - } - return information + file_type = FileType( + pattern=f"pet_linear/*_trc-{config.tracer.value}_space-MNI152NLin2009cSym{description}_res-1x1x1_suvr-{config.suvr_reference_region.value}_pet.nii.gz", + description="", + needed_pipeline="pet-linear", + ) + return file_type def container_from_filename(bids_or_caps_filename: Path) -> Path: diff --git a/clinicadl/utils/maps_manager/__init__.py b/clinicadl/utils/maps_manager/__init__.py index ebaff788e..92fbfae72 100644 --- a/clinicadl/utils/maps_manager/__init__.py +++ b/clinicadl/utils/maps_manager/__init__.py @@ -1,7 +1,6 @@ from .iotools import ( check_and_complete, commandline_to_json, - read_json, write_requirements_version, ) from .logwriter import LogWriter diff --git a/clinicadl/utils/maps_manager/iotools.py b/clinicadl/utils/maps_manager/iotools.py index ed012c614..1833979ec 100644 --- a/clinicadl/utils/maps_manager/iotools.py +++ b/clinicadl/utils/maps_manager/iotools.py @@ -77,138 +77,6 @@ def commandline_to_json(commandline, logger=None, filename="commandline.json"): f.close() -def read_json( - options=None, json_path: Path = None, test=False, read_computational=False -): - """ - Read a json file to update options dictionary. - Ensures retro-compatibility with previous namings in clinicadl. - - Args: - options: (dict) options of the model. - json_path: (str) If given path to the json file, else found with options.model_path. - test: (bool) If given the reader will ignore some options specific to data. - read_computational: (bool) if set to True, the computational arguments are also read. - Returns: - options (dict) options of the model updated - """ - import json - - if options is None: - options = {} - - evaluation_parameters = ["diagnosis_path", "input_dir", "diagnoses"] - prep_compatibility_dict = {"mni": "t1-extensive", "linear": "t1-linear"} - if json_path is None: - json_path = options["model_path"] / "commandline.json" - - with json_path.open(mode="r") as f: - json_data = json.load(f) - - for key, item in json_data.items(): - # We do not change computational options - if key in computational_list and not read_computational: - pass - # If used for evaluation, some parameters were already given - if test and key in evaluation_parameters: - pass - else: - options[key] = item - - # Retro-compatibility with runs of previous versions - if "network" in options: - options["model"] = options["network"] - del options["network"] - - if "discarded_slices" not in options: - options["discarded_slices"] = 20 - - if isinstance(options["preprocessing"], str): - if options["preprocessing"] in prep_compatibility_dict.keys(): - options["preprocessing"] = prep_compatibility_dict[options["preprocessing"]] - - if "mri_plane" in options: - options["slice_direction"] = options["mri_plane"] - del options["mri_plane"] - - if "hippocampus_roi" in options: - if options["hippocampus_roi"]: - options["mode"] = "roi" - del options["hippocampus_roi"] - - if "pretrained_path" in options: - options["transfer_learning_path"] = options["pretrained_path"] - del options["pretrained_path"] - - if "pretrained_difference" in options: - options["transfer_learning_difference"] = options["pretrained_difference"] - del options["pretrained_difference"] - - if "patch_stride" in options: - options["stride_size"] = options["patch_stride"] - - if "use_gpu" in options: - options["gpu"] = options["use_gpu"] - - if "mode" in options: - if options["mode"] == "subject": - options["mode"] = "image" - if options["mode"] == "slice" and "network_type" not in options: - options["network_type"] = "cnn" - if options["mode"] == "patch" and "network_type" in options: - if options["network_type"] == "multi": - options["network_type"] = "multicnn" - - if "network_type" not in options: - if "mode_task" in options: - options["network_type"] = options["mode_task"] - elif "train_autoencoder" in options: - options["network_type"] = "autoencoder" - else: - options["network_type"] = "cnn" - - if "selection" in options: - options["transfer_learning_selection"] = options["selection"] - - if "loss" not in options: - options["loss"] = "default" - - if "dropout" not in options or options["dropout"] is None: - options["dropout"] = 0 - - if "uncropped_roi" not in options: - options["uncropped_roi"] = False - - if "roi_list" not in options: - options["roi_list"] = None - - if "multi_cohort" not in options: - options["multi_cohort"] = False - - if "predict_atlas_intensities" not in options: - options["predict_atlas_intensities"] = None - - if "merged_tsv_path" not in options: - options["merged_tsv_path"] = None - - if "atlas_weight" not in options: - options["atlas_weight"] = 1 - - if "n_splits" in options and options["n_splits"] is None: - options["n_splits"] = 0 - - if not hasattr(options, "seed"): - options.seed = None - - if not hasattr(options, "deterministic"): - options.deterministic = False - - if not hasattr(options, "compensation"): - options.compensation = "memory" - - return options - - def check_and_complete(options, random_search=False): """ This function initializes missing fields with missing values. diff --git a/clinicadl/utils/maps_manager/maps_manager_utils.py b/clinicadl/utils/maps_manager/maps_manager_utils.py index 176f7aa4d..acb34df7a 100644 --- a/clinicadl/utils/maps_manager/maps_manager_utils.py +++ b/clinicadl/utils/maps_manager/maps_manager_utils.py @@ -72,6 +72,7 @@ def read_json(json_path: Path) -> Dict[str, Any]: "multi": "multi_network", "minmaxnormalization": "normalize", "num_workers": "n_proc", + "mode": "extract_method", } retro_add = { @@ -88,6 +89,8 @@ def read_json(json_path: Path) -> Dict[str, Any]: if name not in parameters: parameters[name] = value + if "extract_method" in parameters: + parameters["mode"] = parameters["extract_method"] # Value changes if "use_cpu" in parameters: parameters["gpu"] = not parameters["use_cpu"] @@ -102,7 +105,8 @@ def read_json(json_path: Path) -> Dict[str, Any]: preprocessing_options = [ "preprocessing", "use_uncropped_image", - "prepare_dl" "custom_suffix", + "prepare_dl", + "custom_suffix", "tracer", "suvr_reference_region", "patch_size", @@ -139,9 +143,19 @@ def read_json(json_path: Path) -> Dict[str, Any]: ): parameters["preprocessing_dict"]["slice_mode"] = "rgb" + if "preprocessing" not in parameters: + parameters["preprocessing"] = parameters["preprocessing_dict"]["preprocessing"] + + from clinicadl.caps_dataset.caps_dataset_config import CapsDatasetConfig + + config = CapsDatasetConfig.from_preprocessing_and_extraction_method( + extraction=parameters["mode"], + preprocessing_type=parameters["preprocessing"], + **parameters, + ) if "file_type" not in parameters["preprocessing_dict"]: - _, file_type = compute_folder_and_file_type(parameters["preprocessing_dict"]) - parameters["preprocessing_dict"]["file_type"] = file_type + _, file_type = compute_folder_and_file_type(config) + parameters["preprocessing_dict"]["file_type"] = file_type.model_dump() return parameters diff --git a/clinicadl/utils/read_utils.py b/clinicadl/utils/read_utils.py index c852f2fd1..b57bda2b8 100644 --- a/clinicadl/utils/read_utils.py +++ b/clinicadl/utils/read_utils.py @@ -52,22 +52,22 @@ def get_mask_checksum_and_filename( def get_mask_path(pathology: Optional[Pathology] = None) -> Path: + cache_clinicadl_home = Path.home() / ".cache" / "clinicadl" / "ressources" if pathology is None: - cache_clinicadl = Path.home() / ".cache" / "clinicadl" / "ressources" / "masks" # noqa (typo in resources) + cache_clinicadl = cache_clinicadl_home / "masks" # noqa (typo in resources) url_aramis = "https://aramislab.paris.inria.fr/files/data/masks/" else: - cache_clinicadl = ( - Path.home() / ".cache" / "clinicadl" / "ressources" / "masks_hypo" - ) # noqa (typo in resources) + cache_clinicadl = cache_clinicadl_home / "masks_hypo" # noqa (typo in resources) url_aramis = "https://aramislab.paris.inria.fr/files/data/masks/hypo/" checksum, filename = get_mask_checksum_and_filename(pathology) + cache_clinicadl.mkdir(parents=True, exist_ok=True) + FILE1 = RemoteFileStructure( filename=filename, url=url_aramis, checksum=checksum.value, ) - cache_clinicadl.mkdir(parents=True, exist_ok=True) if not ((cache_clinicadl / "AAL2").is_dir()) and not ( (cache_clinicadl / filename).is_file() ): diff --git a/clinicadl/utils/seed.py b/clinicadl/utils/seed.py index 6351b24e0..5c4cbeeef 100644 --- a/clinicadl/utils/seed.py +++ b/clinicadl/utils/seed.py @@ -1,5 +1,6 @@ import os import random +from typing import Optional import numpy as np import torch @@ -44,7 +45,7 @@ def pl_worker_init_function(worker_id: int) -> None: # pragma: no cover random.seed(stdlib_seed) -def get_seed(seed: int = None) -> int: +def get_seed(seed: Optional[int] = None) -> int: max_seed_value = np.iinfo(np.uint32).max min_seed_value = np.iinfo(np.uint32).min @@ -94,7 +95,7 @@ def seed_everything(seed, deterministic=False, compensation="memory") -> None: os.environ["CUBLAS_WORKSPACE_CONFIG"] = ":16:8" else: raise ClinicaDLConfigurationError( - f"The compensation for a deterministic CUDA setting " - f"must be chosen between 'time' and 'memory'." + "The compensation for a deterministic CUDA setting " + "must be chosen between 'time' and 'memory'." ) torch.use_deterministic_algorithms(True) diff --git a/clinicadl/utils/split_manager/split_manager.py b/clinicadl/utils/split_manager/split_manager.py index af05a4b31..7ddd06161 100644 --- a/clinicadl/utils/split_manager/split_manager.py +++ b/clinicadl/utils/split_manager/split_manager.py @@ -258,7 +258,7 @@ def _create_caps_dict(caps_directory: Path, multi_cohort): @staticmethod def _check_tsv_path(tsv_path, multi_cohort): if multi_cohort: - if not tsv_path.suffix == ".tsv": + if tsv_path.suffix != ".tsv": raise ClinicaDLArgumentError( "If multi_cohort is given, the TSV_DIRECTORY argument should be a path to a TSV file." ) diff --git a/clinicadl/utils/task_manager/classification.py b/clinicadl/utils/task_manager/classification.py index 6d7ebbd8a..abaeb4985 100644 --- a/clinicadl/utils/task_manager/classification.py +++ b/clinicadl/utils/task_manager/classification.py @@ -72,7 +72,7 @@ def generate_test_row(self, idx, data, outputs): + [normalized_output[i].item() for i in range(self.n_classes)] ] - def compute_metrics(self, results_df, report_ci): + def compute_metrics(self, results_df, report_ci: bool = False): return self.metrics_module.apply( results_df.true_label.values, results_df.predicted_label.values, diff --git a/tests/test_prepare_data.py b/tests/test_prepare_data.py index 560f50ea3..b6dda43d1 100644 --- a/tests/test_prepare_data.py +++ b/tests/test_prepare_data.py @@ -143,7 +143,7 @@ def run_test_prepare_data( config.preprocessing.suvr_reference_region = SUVRReferenceRegions( "pons2" ) - config.extraction.use_uncropped_image = False + config.preprocessing.use_uncropped_image = False config.extraction.extract_json = ( f"{modality}-{acq}_mode-{test_name}.json" ) @@ -153,7 +153,7 @@ def run_test_prepare_data( elif modality == "custom": assert isinstance(config.preprocessing, CustomPreprocessingConfig) - config.extraction.use_uncropped_image = True + config.preprocessing.use_uncropped_image = True config.preprocessing.custom_suffix = ( "graymatter_space-Ixi549Space_modulated-off_probability.nii.gz" ) @@ -166,7 +166,7 @@ def run_test_prepare_data( elif modality == "t1-linear": for flag in uncropped_image: - config.extraction.use_uncropped_image = flag + config.preprocessing.use_uncropped_image = flag config.extraction.extract_json = ( f"{modality}_crop-{not flag}_mode-{test_name}.json" ) @@ -179,7 +179,7 @@ def run_test_prepare_data( ) config.extraction.save_features = False for flag in uncropped_image: - config.extraction.use_uncropped_image = flag + config.preprocessing.use_uncropped_image = flag config.extraction.extract_json = ( f"{modality}_crop-{not flag}_mode-{test_name}.json" ) diff --git a/tests/unittests/utils/test_clinica_utils.py b/tests/unittests/utils/test_clinica_utils.py index 8bafc3b78..8f08ff24c 100644 --- a/tests/unittests/utils/test_clinica_utils.py +++ b/tests/unittests/utils/test_clinica_utils.py @@ -21,10 +21,16 @@ def test_pet_linear_nii( tracer, suvr_reference_region, uncropped_image, expected_pattern ): - from clinicadl.utils.clinica_utils import pet_linear_nii + from clinicadl.caps_dataset.preprocessing.config import PETPreprocessingConfig + from clinicadl.utils.clinica_utils import FileType, pet_linear_nii - assert pet_linear_nii(tracer, suvr_reference_region, uncropped_image) == { - "description": "", - "needed_pipeline": "pet-linear", - "pattern": expected_pattern, - } + config = PETPreprocessingConfig( + tracer=tracer, + suvr_reference_region=suvr_reference_region, + use_uncropped_image=uncropped_image, + ) + assert pet_linear_nii(config) == FileType( + description="", + needed_pipeline="pet-linear", + pattern=expected_pattern, + )