From aba51261279351d7376beeca7f5b14140097197c Mon Sep 17 00:00:00 2001 From: JOULOT Matthieu Date: Mon, 9 Sep 2024 16:45:34 +0200 Subject: [PATCH 1/5] First implementation --- clinica/iotools/bids_utils.py | 27 +++++++- clinica/iotools/converters/cli.py | 2 + clinica/iotools/converters/factory.py | 4 ++ .../converters/miriad_to_bids/__init__.py | 3 + .../miriad_to_bids/miriad_to_bids.py | 64 +++++++++++++++++++ .../miriad_to_bids/miriad_to_bids_cli.py | 27 ++++++++ .../miriad_to_bids/miriad_to_bids_utils.py | 30 +++++++++ 7 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 clinica/iotools/converters/miriad_to_bids/__init__.py create mode 100644 clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py create mode 100644 clinica/iotools/converters/miriad_to_bids/miriad_to_bids_cli.py create mode 100644 clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py diff --git a/clinica/iotools/bids_utils.py b/clinica/iotools/bids_utils.py index de47302ad..60ad84293 100644 --- a/clinica/iotools/bids_utils.py +++ b/clinica/iotools/bids_utils.py @@ -26,6 +26,7 @@ class StudyName(str, Enum): OASIS3 = "OASIS3" UKB = "UKB" IXI = "IXI" + MIRIAD = "MIRIAD" BIDS_VALIDATOR_CONFIG = { @@ -93,7 +94,8 @@ def bids_id_factory(study: StudyName) -> Type[BIDSSubjectID]: return HABSBIDSSubjectID if study == StudyName.IXI: return IXIBIDSSubjectID - + if study == StudyName.MIRIAD: + return MIRIADBIDSSubjectID class ADNIBIDSSubjectID(BIDSSubjectID): """Implementation for ADNI of the BIDSSubjectIDClass, allowing to go from the source id XXX_S_XXXX @@ -319,6 +321,29 @@ def from_original_study_id(cls, study_id: str) -> str: def to_original_study_id(self) -> str: return str(self.replace("sub-", "")) +class MIRIADBIDSSubjectID(BIDSSubjectID): + """Implementation for MIRIAD of the BIDSSubjectIDClass, allowing to go from the source id MIRIAD### + to a bids id sub-MIRAD### and reciprocally.""" + + def validate(self, value: str) -> str: + if re.fullmatch(r"sub-MIRIAD\d{3}", value): + return value + raise ValueError( + f"BIDS MIRIAD subject ID {value} is not properly formatted. " + "Expecting a 'sub-MIRIAD' format." + ) + + @classmethod + def from_original_study_id(cls, study_id: str) -> str: + if re.fullmatch(r"MIRIAD\d{3}", study_id): + return f"sub-{study_id}" + raise ValueError( + f"Raw MIRIAD subject ID {study_id} is not properly formatted. " + "Expecting a 'Y' format." + ) + + def to_original_study_id(self) -> str: + return str(self.replace("sub-", "")) # -- Methods for the clinical data -- def create_participants_df( diff --git a/clinica/iotools/converters/cli.py b/clinica/iotools/converters/cli.py index 5c10c7b54..0feefa9c5 100644 --- a/clinica/iotools/converters/cli.py +++ b/clinica/iotools/converters/cli.py @@ -9,6 +9,7 @@ from .oasis3_to_bids import oasis3_to_bids_cli from .oasis_to_bids import oasis_to_bids_cli from .ukb_to_bids import ukb_to_bids_cli +from .miriad_to_bids import miriad_to_bids_cli @click.group("convert") @@ -26,6 +27,7 @@ def cli() -> None: cli.add_command(ukb_to_bids_cli.cli) cli.add_command(genfi_to_bids_cli.cli) cli.add_command(ixi_to_bids_cli.cli) +cli.add_command(miriad_to_bids_cli.cli) if __name__ == "__main__": cli() diff --git a/clinica/iotools/converters/factory.py b/clinica/iotools/converters/factory.py index d7e1baf99..5d5d85b3e 100644 --- a/clinica/iotools/converters/factory.py +++ b/clinica/iotools/converters/factory.py @@ -40,6 +40,8 @@ def get_converter_name(study: Union[str, StudyName]) -> str: return "UkbToBids" if study == StudyName.IXI: return "IxiToBids" + if study == StudyName.MIRIAD: + return "MiriadToBids" def converter_factory(study: Union[str, StudyName]) -> Callable: @@ -62,4 +64,6 @@ def converter_factory(study: Union[str, StudyName]) -> Callable: from .ukb_to_bids import convert if study == StudyName.IXI: from .ixi_to_bids import convert + if study == StudyName.MIRIAD: + from .miriad_to_bids import convert return convert diff --git a/clinica/iotools/converters/miriad_to_bids/__init__.py b/clinica/iotools/converters/miriad_to_bids/__init__.py new file mode 100644 index 000000000..798df7ea3 --- /dev/null +++ b/clinica/iotools/converters/miriad_to_bids/__init__.py @@ -0,0 +1,3 @@ +from .miriad_to_bids import convert + +__all__ = ["convert"] diff --git a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py new file mode 100644 index 000000000..36c5e9fab --- /dev/null +++ b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py @@ -0,0 +1,64 @@ +"""Convert MIRIAD dataset to BIDS.""" + +from pathlib import Path +from typing import Optional + +import os +import shutil +import csv +from clinica.utils.filemanip import UserProvidedPath + +# Paths +input_dir = 'your_input_directory' # Where the original data is located +output_dir = 'your_output_directory' # Where the BIDS data will be written +csv_file = 'metadata.csv' # Metadata CSV file to store extracted information + +def convert( + path_to_dataset: UserProvidedPath, + bids_dir: UserProvidedPath, + path_to_clinical: UserProvidedPath, + subjects: Optional[UserProvidedPath] = None, + n_procs: Optional[int] = 1, + **kwargs, +): + """_summary_ + + Args: + path_to_dataset (UserProvidedPath): _description_ + bids_dir (UserProvidedPath): _description_ + path_to_clinical (UserProvidedPath): _description_ + subjects (Optional[UserProvidedPath], optional): _description_. Defaults to None. + n_procs (Optional[int], optional): _description_. Defaults to 1. + """ + from clinica.iotools.converters.miriad_to_bids.miriad_to_bids_utils import create_bids_structure + # Prepare CSV + with open(csv_file, 'w', newline='') as csvfile: + csvwriter = csv.writer(csvfile) + csvwriter.writerow(['cohort', 'subject_id', 'diagnosis', 'gender', 'session', 'input_file', 'output_file']) + + # Traverse the input directory + for root, dirs, files in os.walk(path_to_dataset): + for file in files: + if file.endswith('.nii'): + # Example: miriad_215_AD_M_01_MR_1.nii + parts = file.split('_') + + # Extract information from filename + cohort = parts[0] # miriad + subject_id = parts[1] # 215 + diagnosis = parts[2] # AD (Alzheimer's) or HC (Healthy Control) + gender = parts[3] # M or F + session = parts[4] # Session number + + # Full path of input file + input_file = os.path.join(root, file) + + # Create BIDS structure and move the file + create_bids_structure(subject_id, session, cohort, diagnosis, gender, input_file, path_to_dataset, bids_dir, path_to_clinical) + + # Write the extracted information to CSV + bids_filename = f"sub-{subject_id}_ses-{session}_T1w.nii.gz" + output_file = os.path.join(f"sub-{subject_id}", f"ses-{session}", 'anat', bids_filename) + csvwriter.writerow([cohort, subject_id, diagnosis, gender, session, input_file, output_file]) + + print("Conversion to BIDS format and metadata extraction completed.") diff --git a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_cli.py b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_cli.py new file mode 100644 index 000000000..1f8cf5cac --- /dev/null +++ b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_cli.py @@ -0,0 +1,27 @@ +from os import PathLike +from typing import Optional + +import click + +from clinica.iotools.converters import cli_param + + +@click.command(name="miriad-to-bids") +@cli_param.dataset_directory +@cli_param.bids_directory +@cli_param.clinical_data_directory +@cli_param.subjects_list +def cli( + dataset_directory: PathLike, + bids_directory: PathLike, + clinical_data_directory: PathLike, + subjects_list: Optional[PathLike] = None, +) -> None: + """MIRIAD to BIDS converter.""" + from .miriad_to_bids import convert + + convert(dataset_directory, bids_directory, clinical_data_directory, subjects_list) + + +if __name__ == "__main__": + cli() diff --git a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py new file mode 100644 index 000000000..50b8317db --- /dev/null +++ b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py @@ -0,0 +1,30 @@ +import os +import shutil + +# Helper function to create BIDS folders and move files +def create_bids_structure(subject_id, session, cohort, diagnosis, gender, input_file, path_to_dataset, output_dir, path_to_clinical +): + + """_summary_ + + Args: + session (_type_): _description_ + cohort (_type_): _description_ + diagnosis (_type_): _description_ + gender (_type_): _description_ + input_file (_type_): _description_ + output_dir (_type_): _description_ + path_to_dataset (_type_, optional): _description_. Defaults to None, n_procs: Optional[int] = 1, **kwargs, ):#subject_id. + """ + sub_id = f"sub-{subject_id}" + ses_id = f"ses-{session}" + + # Create output directory for this subject/session + anat_dir = os.path.join(output_dir, sub_id, ses_id, 'anat') + os.makedirs(anat_dir, exist_ok=True) + + # Destination filename in BIDS format + bids_filename = f"{sub_id}_{ses_id}_T1w.nii.gz" + + # Copy and rename the file to BIDS format + shutil.copy(input_file, os.path.join(anat_dir, bids_filename)) From 2e9c3ea18491ceac7ea6eb75d4c2ebe3c0f0b5e4 Mon Sep 17 00:00:00 2001 From: JOULOT Matthieu Date: Mon, 9 Sep 2024 17:04:16 +0200 Subject: [PATCH 2/5] add MIRIAD to subject ID --- .../iotools/converters/miriad_to_bids/miriad_to_bids_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py index 50b8317db..a53cc7df2 100644 --- a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py +++ b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py @@ -16,7 +16,7 @@ def create_bids_structure(subject_id, session, cohort, diagnosis, gender, input_ output_dir (_type_): _description_ path_to_dataset (_type_, optional): _description_. Defaults to None, n_procs: Optional[int] = 1, **kwargs, ):#subject_id. """ - sub_id = f"sub-{subject_id}" + sub_id = f"sub-MIRIAD{subject_id}" ses_id = f"ses-{session}" # Create output directory for this subject/session From 13aca10baea6348e7096e43c89f9328a68c03808 Mon Sep 17 00:00:00 2001 From: JOULOT Matthieu Date: Tue, 10 Sep 2024 15:39:13 +0200 Subject: [PATCH 3/5] add clinical data --- .../miriad_to_bids/miriad_to_bids.py | 91 ++++++++++++++++--- 1 file changed, 79 insertions(+), 12 deletions(-) diff --git a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py index 36c5e9fab..d3863f235 100644 --- a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py +++ b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py @@ -6,13 +6,9 @@ import os import shutil import csv +import pandas as pd from clinica.utils.filemanip import UserProvidedPath -# Paths -input_dir = 'your_input_directory' # Where the original data is located -output_dir = 'your_output_directory' # Where the BIDS data will be written -csv_file = 'metadata.csv' # Metadata CSV file to store extracted information - def convert( path_to_dataset: UserProvidedPath, bids_dir: UserProvidedPath, @@ -31,11 +27,26 @@ def convert( n_procs (Optional[int], optional): _description_. Defaults to 1. """ from clinica.iotools.converters.miriad_to_bids.miriad_to_bids_utils import create_bids_structure + metadata_csv = 'metadata.csv' + # Load clinical data + for file in os.listdir(path_to_clinical): + if file.endswith('.csv'): + clinical_data_file = os.path.join(path_to_clinical, file) + break + + if not clinical_data_file: + raise FileNotFoundError(f"No clinical data CSV found in {path_to_clinical}") + + clinical_data = pd.read_csv(clinical_data_file) + # Prepare CSV - with open(csv_file, 'w', newline='') as csvfile: + with open(metadata_csv, 'w', newline='') as csvfile: csvwriter = csv.writer(csvfile) csvwriter.writerow(['cohort', 'subject_id', 'diagnosis', 'gender', 'session', 'input_file', 'output_file']) + participants_data = {} + sessions_data = [] + # Traverse the input directory for root, dirs, files in os.walk(path_to_dataset): for file in files: @@ -48,17 +59,73 @@ def convert( subject_id = parts[1] # 215 diagnosis = parts[2] # AD (Alzheimer's) or HC (Healthy Control) gender = parts[3] # M or F - session = parts[4] # Session number - + session = parts[4].lstrip('0') # Session number + session_alt = parts[4].lstrip('0') # Session number + scan_number = parts[6].replace('.nii', '') # Scan number from MR_1 or MR_2 + + # Extract MR ID + mr_id = f"{cohort}_{subject_id}_{session}_MR_{scan_number}" + + # Extract relevant clinical information from the clinical data + clinical_row = clinical_data[clinical_data['MR ID'] == mr_id] + if clinical_row.empty: + print(f"Clinical data not found for MR ID: {mr_id}") + continue + + age = clinical_row['Age'].values[0] + group = clinical_row['Group'].values[0] # HC or AD + gender_clinical = clinical_row['M/F'].values[0] # M or F + # Full path of input file input_file = os.path.join(root, file) # Create BIDS structure and move the file - create_bids_structure(subject_id, session, cohort, diagnosis, gender, input_file, path_to_dataset, bids_dir, path_to_clinical) + create_bids_structure(subject_id, session_alt, cohort, diagnosis, gender, input_file, path_to_dataset, bids_dir, path_to_clinical) # Write the extracted information to CSV - bids_filename = f"sub-{subject_id}_ses-{session}_T1w.nii.gz" - output_file = os.path.join(f"sub-{subject_id}", f"ses-{session}", 'anat', bids_filename) + bids_filename = f"sub-MIRIAD{subject_id}_ses-{session}_T1w.nii.gz" + output_file = os.path.join(f"sub-MIRIAD{subject_id}", f"ses-{session}", 'anat', bids_filename) csvwriter.writerow([cohort, subject_id, diagnosis, gender, session, input_file, output_file]) - print("Conversion to BIDS format and metadata extraction completed.") + # Track the minimum age for the participant for baseline + if subject_id not in participants_data or participants_data[subject_id]['age'] > age: + participants_data[subject_id] = {'participant_id': f"sub-MIRIAD{subject_id}", + 'sex': gender_clinical, + 'diagnosis': group, + 'age': age} + + # Prepare sessions data + sessions_data.append([f"sub-MIRIAD{subject_id}", f"ses-{session}", age]) + + +# Write participants.csv with baseline age (minimum age for each subject) + participants_csv = os.path.join(bids_dir, 'participants.csv') + with open(participants_csv, 'w', newline='') as participants_file: + participants_writer = csv.writer(participants_file) + participants_writer.writerow(['participant_id', 'sex', 'diagnosis', 'age']) + + # Write the baseline age (minimum age) for each subject + for participant_info in participants_data.values(): + participants_writer.writerow([participant_info['participant_id'], + participant_info['sex'], + participant_info['diagnosis'], + participant_info['age']]) + + # Write sessions.tsv for each subject + subject_sessions = {} + for session in sessions_data: + subject_id, session_id, age = session + if subject_id not in subject_sessions: + subject_sessions[subject_id] = [] + subject_sessions[subject_id].append([session_id, age]) + + for subject_id, sessions in subject_sessions.items(): + sessions_file = os.path.join(bids_dir, subject_id, 'sessions.tsv') + os.makedirs(os.path.dirname(sessions_file), exist_ok=True) + + with open(sessions_file, 'w', newline='') as session_file: + session_writer = csv.writer(session_file, delimiter='\t') + session_writer.writerow(['session_id', 'age']) + session_writer.writerows(sessions) + + print(f"BIDS conversion completed, clinical data loaded from {clinical_data_file}.") From 2c95c28d717d49966e55a2a2647905e5ffcf6e59 Mon Sep 17 00:00:00 2001 From: JOULOT Matthieu Date: Wed, 9 Oct 2024 10:25:33 +0200 Subject: [PATCH 4/5] correct run-num --- .../miriad_to_bids/miriad_to_bids.py | 7 +++++-- .../miriad_to_bids/miriad_to_bids_utils.py | 20 +++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py index d3863f235..b1815b0fb 100644 --- a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py +++ b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py @@ -26,7 +26,7 @@ def convert( subjects (Optional[UserProvidedPath], optional): _description_. Defaults to None. n_procs (Optional[int], optional): _description_. Defaults to 1. """ - from clinica.iotools.converters.miriad_to_bids.miriad_to_bids_utils import create_bids_structure + from clinica.iotools.converters.miriad_to_bids.miriad_to_bids_utils import create_bids_structure, parse_filename metadata_csv = 'metadata.csv' # Load clinical data for file in os.listdir(path_to_clinical): @@ -63,6 +63,9 @@ def convert( session_alt = parts[4].lstrip('0') # Session number scan_number = parts[6].replace('.nii', '') # Scan number from MR_1 or MR_2 + # Parse subject ID, session ID, and run ID from the filename + # subject_id, session_id, run_id = parse_filename(file) + # Extract MR ID mr_id = f"{cohort}_{subject_id}_{session}_MR_{scan_number}" @@ -80,7 +83,7 @@ def convert( input_file = os.path.join(root, file) # Create BIDS structure and move the file - create_bids_structure(subject_id, session_alt, cohort, diagnosis, gender, input_file, path_to_dataset, bids_dir, path_to_clinical) + create_bids_structure(subject_id, session_alt, scan_number, cohort, diagnosis, gender, input_file, path_to_dataset, bids_dir, path_to_clinical) # Write the extracted information to CSV bids_filename = f"sub-MIRIAD{subject_id}_ses-{session}_T1w.nii.gz" diff --git a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py index a53cc7df2..a00e990e7 100644 --- a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py +++ b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py @@ -2,7 +2,7 @@ import shutil # Helper function to create BIDS folders and move files -def create_bids_structure(subject_id, session, cohort, diagnosis, gender, input_file, path_to_dataset, output_dir, path_to_clinical +def create_bids_structure(subject_id, session, run_label, cohort, diagnosis, gender, input_file, path_to_dataset, output_dir, path_to_clinical ): """_summary_ @@ -18,13 +18,29 @@ def create_bids_structure(subject_id, session, cohort, diagnosis, gender, input_ """ sub_id = f"sub-MIRIAD{subject_id}" ses_id = f"ses-{session}" + run_id = f"run-{run_label}" # Run number (e.g., run-01) + # Create output directory for this subject/session anat_dir = os.path.join(output_dir, sub_id, ses_id, 'anat') os.makedirs(anat_dir, exist_ok=True) # Destination filename in BIDS format - bids_filename = f"{sub_id}_{ses_id}_T1w.nii.gz" + bids_filename = f"{sub_id}_{ses_id}_{run_id}_T1w.nii.gz" # Copy and rename the file to BIDS format shutil.copy(input_file, os.path.join(anat_dir, bids_filename)) + + +# Function to extract subject, session, and run info from filenames +def parse_filename(filename): + parts = filename.split('_') + cohort_name = parts[0] # "miriad" + subject_id = parts[1] # e.g., "215" + diagnosis = parts[2] # e.g., "AD" or "HC" + gender = parts[3] # "M" or "F" + session_id = parts[4] # e.g., "01" + modality = parts[5] # e.g., "MR" + run_id = parts[6] # e.g., "1" (for run-01, run-02) + + return subject_id, session_id, run_id From 22ed875f8cf6633643defdb3a6975431beb5c3e3 Mon Sep 17 00:00:00 2001 From: JOULOT Matthieu Date: Wed, 6 Nov 2024 11:36:28 +0100 Subject: [PATCH 5/5] Zip correctly niftis --- .../miriad_to_bids/miriad_to_bids.py | 74 ++++++++----------- .../miriad_to_bids/miriad_to_bids_utils.py | 36 ++++----- 2 files changed, 50 insertions(+), 60 deletions(-) diff --git a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py index b1815b0fb..104a8748f 100644 --- a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py +++ b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids.py @@ -10,25 +10,19 @@ from clinica.utils.filemanip import UserProvidedPath def convert( - path_to_dataset: UserProvidedPath, - bids_dir: UserProvidedPath, - path_to_clinical: UserProvidedPath, - subjects: Optional[UserProvidedPath] = None, + path_to_dataset: str, + bids_dir: str, + path_to_clinical: str, + subjects: Optional[str] = None, n_procs: Optional[int] = 1, **kwargs, ): - """_summary_ - - Args: - path_to_dataset (UserProvidedPath): _description_ - bids_dir (UserProvidedPath): _description_ - path_to_clinical (UserProvidedPath): _description_ - subjects (Optional[UserProvidedPath], optional): _description_. Defaults to None. - n_procs (Optional[int], optional): _description_. Defaults to 1. - """ - from clinica.iotools.converters.miriad_to_bids.miriad_to_bids_utils import create_bids_structure, parse_filename + """Convert MIRIAD data to BIDS format without removing original .nii files.""" + from clinica.iotools.converters.miriad_to_bids.miriad_to_bids_utils import create_bids_structure, parse_filename, convert_to_nii_gz metadata_csv = 'metadata.csv' + # Load clinical data + clinical_data_file = None for file in os.listdir(path_to_clinical): if file.endswith('.csv'): clinical_data_file = os.path.join(path_to_clinical, file) @@ -42,7 +36,7 @@ def convert( # Prepare CSV with open(metadata_csv, 'w', newline='') as csvfile: csvwriter = csv.writer(csvfile) - csvwriter.writerow(['cohort', 'subject_id', 'diagnosis', 'gender', 'session', 'input_file', 'output_file']) + csvwriter.writerow(['cohort', 'subject_id', 'diagnosis', 'gender', 'session', 'run', 'input_file', 'output_file']) participants_data = {} sessions_data = [] @@ -51,23 +45,23 @@ def convert( for root, dirs, files in os.walk(path_to_dataset): for file in files: if file.endswith('.nii'): - # Example: miriad_215_AD_M_01_MR_1.nii - parts = file.split('_') - # Extract information from filename + parts = file.split('_') cohort = parts[0] # miriad subject_id = parts[1] # 215 diagnosis = parts[2] # AD (Alzheimer's) or HC (Healthy Control) gender = parts[3] # M or F - session = parts[4].lstrip('0') # Session number - session_alt = parts[4].lstrip('0') # Session number - scan_number = parts[6].replace('.nii', '') # Scan number from MR_1 or MR_2 - - # Parse subject ID, session ID, and run ID from the filename - # subject_id, session_id, run_id = parse_filename(file) + session = parts[4].lstrip('0') # Session number + run_number = parts[6].replace('.nii', '') # Scan number from MR_1 or MR_2 + bids_subject_id = f"sub-{subject_id}" + bids_session_id = f"ses-{session}" + + # Original file path + original_file_path = os.path.join(root, file) + # Extract MR ID - mr_id = f"{cohort}_{subject_id}_{session}_MR_{scan_number}" + mr_id = f"{cohort}_{subject_id}_{session}_MR_{run_number}" # Extract relevant clinical information from the clinical data clinical_row = clinical_data[clinical_data['MR ID'] == mr_id] @@ -79,29 +73,25 @@ def convert( group = clinical_row['Group'].values[0] # HC or AD gender_clinical = clinical_row['M/F'].values[0] # M or F - # Full path of input file - input_file = os.path.join(root, file) - - # Create BIDS structure and move the file - create_bids_structure(subject_id, session_alt, scan_number, cohort, diagnosis, gender, input_file, path_to_dataset, bids_dir, path_to_clinical) - - # Write the extracted information to CSV - bids_filename = f"sub-MIRIAD{subject_id}_ses-{session}_T1w.nii.gz" - output_file = os.path.join(f"sub-MIRIAD{subject_id}", f"ses-{session}", 'anat', bids_filename) - csvwriter.writerow([cohort, subject_id, diagnosis, gender, session, input_file, output_file]) + # Write metadata CSV + csvwriter.writerow([cohort, subject_id, diagnosis, gender, session, run_number, original_file_path, bids_subject_id]) - # Track the minimum age for the participant for baseline + # Track baseline age (minimum age for each subject) if subject_id not in participants_data or participants_data[subject_id]['age'] > age: - participants_data[subject_id] = {'participant_id': f"sub-MIRIAD{subject_id}", - 'sex': gender_clinical, - 'diagnosis': group, - 'age': age} + participants_data[subject_id] = { + 'participant_id': f"sub-MIRIAD{subject_id}", + 'sex': gender_clinical, + 'diagnosis': group, + 'age': age + } # Prepare sessions data sessions_data.append([f"sub-MIRIAD{subject_id}", f"ses-{session}", age]) - -# Write participants.csv with baseline age (minimum age for each subject) + # Create BIDS structure and copy file with run number + create_bids_structure(subject_id, session, run_number, cohort, diagnosis, gender, original_file_path, path_to_dataset, bids_dir, path_to_clinical) + + # Write participants.csv with baseline age (minimum age for each subject) participants_csv = os.path.join(bids_dir, 'participants.csv') with open(participants_csv, 'w', newline='') as participants_file: participants_writer = csv.writer(participants_file) diff --git a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py index a00e990e7..30900123c 100644 --- a/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py +++ b/clinica/iotools/converters/miriad_to_bids/miriad_to_bids_utils.py @@ -1,35 +1,26 @@ import os import shutil +import nibabel as nib # Helper function to create BIDS folders and move files -def create_bids_structure(subject_id, session, run_label, cohort, diagnosis, gender, input_file, path_to_dataset, output_dir, path_to_clinical -): - - """_summary_ - - Args: - session (_type_): _description_ - cohort (_type_): _description_ - diagnosis (_type_): _description_ - gender (_type_): _description_ - input_file (_type_): _description_ - output_dir (_type_): _description_ - path_to_dataset (_type_, optional): _description_. Defaults to None, n_procs: Optional[int] = 1, **kwargs, ):#subject_id. - """ +def create_bids_structure(subject_id, session, run_label, cohort, diagnosis, gender, input_file, path_to_dataset, output_dir, path_to_clinical): + """Create BIDS folder structure and move files into it.""" sub_id = f"sub-MIRIAD{subject_id}" ses_id = f"ses-{session}" - run_id = f"run-{run_label}" # Run number (e.g., run-01) + run_id = f"run-{run_label}" # Run number (e.g., run-01) - # Create output directory for this subject/session anat_dir = os.path.join(output_dir, sub_id, ses_id, 'anat') os.makedirs(anat_dir, exist_ok=True) - # Destination filename in BIDS format + # Convert the input file to .nii.gz if necessary + input_file_gz = convert_to_nii_gz(input_file) + + # Destination filename in BIDS format with run number bids_filename = f"{sub_id}_{ses_id}_{run_id}_T1w.nii.gz" # Copy and rename the file to BIDS format - shutil.copy(input_file, os.path.join(anat_dir, bids_filename)) + shutil.copy(input_file_gz, os.path.join(anat_dir, bids_filename)) # Function to extract subject, session, and run info from filenames @@ -44,3 +35,12 @@ def parse_filename(filename): run_id = parts[6] # e.g., "1" (for run-01, run-02) return subject_id, session_id, run_id + +def convert_to_nii_gz(input_file): + """Convert a .nii file to .nii.gz format without deleting the original .nii file.""" + if input_file.endswith(".nii.gz"): + return input_file + img = nib.load(input_file) + output_file = input_file.replace(".nii", ".nii.gz") + nib.save(img, output_file) + return output_file \ No newline at end of file