From d3e2e8509c164812f431113378734f1df7543076 Mon Sep 17 00:00:00 2001 From: Gab-D-G Date: Mon, 2 Oct 2023 14:25:48 -0400 Subject: [PATCH] Implemented a new option for correcting oblique data --- rabies/parser.py | 9 ++++++ rabies/preprocess_pkg/main_wf.py | 47 ++++++++++++++++++++++++++++---- rabies/preprocess_pkg/utils.py | 12 ++++++++ scripts/error_check_rabies.py | 2 +- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/rabies/parser.py b/rabies/parser.py index f8e81e8..f8bc8b4 100644 --- a/rabies/parser.py +++ b/rabies/parser.py @@ -215,6 +215,15 @@ def get_parser(): "(default: %(default)s)\n" "\n" ) + preprocess.add_argument( + '--oblique2card', dest='oblique2card', action='store_true', + help= + "Applies AFNI's 3dWarp -oblique2card on all structural and functional data to \n" + "convert oblique data to cartesian (see https://github.com/CoBrALab/RABIES/issues/160). \n" + "WARNING: this is modifying the original data by resampling on a new grid, only apply if necessary. \n" + "(default: %(default)s)\n" + "\n" + ) preprocess.add_argument( '--apply_despiking', dest='apply_despiking', action='store_true', help= diff --git a/rabies/preprocess_pkg/main_wf.py b/rabies/preprocess_pkg/main_wf.py index fb6f747..cee7a09 100644 --- a/rabies/preprocess_pkg/main_wf.py +++ b/rabies/preprocess_pkg/main_wf.py @@ -8,7 +8,7 @@ from .inho_correction import init_inho_correction_wf from .commonspace_reg import init_commonspace_reg_wf from .bold_main_wf import init_bold_main_wf -from .utils import BIDSDataGraber, prep_bids_iter, convert_to_RAS, resample_template +from .utils import BIDSDataGraber, prep_bids_iter, convert_to_RAS, convert_oblique2card, resample_template from . import preprocess_visual_QC def init_main_wf(data_dir_path, output_folder, opts, name='main_wf'): @@ -171,6 +171,26 @@ def init_main_wf(data_dir_path, output_folder, opts, name='main_wf'): function=convert_to_RAS), name='bold_convert_to_RAS') + if opts.oblique2card: + bold_oblique2card_node = pe.Node(Function(input_names=['input'], + output_names=['output'], + function=convert_oblique2card), + name='bold_oblique2card') + workflow.connect([ + (bold_selectfiles, bold_oblique2card_node, [ + ('out_file', 'input'), + ]), + (bold_oblique2card_node, bold_convert_to_RAS_node, [ + ('output', 'img_file'), + ]), + ]) + else: + workflow.connect([ + (bold_selectfiles, bold_convert_to_RAS_node, [ + ('out_file', 'img_file'), + ]), + ]) + format_bold_buffer = pe.Node(niu.IdentityInterface(fields=['formatted_bold']), name="format_bold_buffer") @@ -243,9 +263,6 @@ def init_main_wf(data_dir_path, output_folder, opts, name='main_wf'): (main_split, bold_selectfiles, [ ("scan_info", "scan_info"), ]), - (bold_selectfiles, bold_convert_to_RAS_node, [ - ('out_file', 'img_file'), - ]), (bold_selectfiles, outputnode, [ ('out_file', 'input_bold'), ]), @@ -333,6 +350,26 @@ def init_main_wf(data_dir_path, output_folder, opts, name='main_wf'): function=convert_to_RAS), name='anat_convert_to_RAS') + if opts.oblique2card: + anat_oblique2card_node = pe.Node(Function(input_names=['input'], + output_names=['output'], + function=convert_oblique2card), + name='anat_oblique2card') + workflow.connect([ + (anat_selectfiles, anat_oblique2card_node, [ + ('out_file', 'input'), + ]), + (anat_oblique2card_node, anat_convert_to_RAS_node, [ + ('output', 'img_file'), + ]), + ]) + else: + workflow.connect([ + (anat_selectfiles, anat_convert_to_RAS_node, [ + ('out_file', 'img_file'), + ]), + ]) + format_anat_buffer = pe.Node(niu.IdentityInterface(fields=['formatted_anat']), name="format_anat_buffer") @@ -366,8 +403,6 @@ def init_main_wf(data_dir_path, output_folder, opts, name='main_wf'): (run_split, bold_selectfiles, [ ("run", "run"), ]), - (anat_selectfiles, anat_convert_to_RAS_node, - [("out_file", "img_file")]), (format_anat_buffer, anat_inho_cor_wf, [ ("formatted_anat", "inputnode.target_img"), ("formatted_anat", "inputnode.name_source"), diff --git a/rabies/preprocess_pkg/utils.py b/rabies/preprocess_pkg/utils.py index 7eb6c47..e694642 100644 --- a/rabies/preprocess_pkg/utils.py +++ b/rabies/preprocess_pkg/utils.py @@ -192,6 +192,18 @@ def convert_to_RAS(img_file, out_dir=None): return out_file +def convert_oblique2card(input): + import pathlib + import os + from rabies.utils import run_command + # apply AFNI's 3dWarp to convert from oblique to cartesian + split = pathlib.Path(input).name.rsplit(".nii")[0] + output = os.path.abspath(f"{split}_2card.nii.gz") + command = f'3dWarp -oblique2card -prefix {output} {input}' + rc = run_command(command) + return output + + def resample_template(template_file, mask_file, file_list, spacing='inputs_defined', rabies_data_type=8): import os import SimpleITK as sitk diff --git a/scripts/error_check_rabies.py b/scripts/error_check_rabies.py index 3d57625..026f7bb 100755 --- a/scripts/error_check_rabies.py +++ b/scripts/error_check_rabies.py @@ -104,7 +104,7 @@ def get_parser(): command = f"rabies --inclusion_ids {tmppath}/inputs/sub-token1_bold.nii.gz --verbose 1 --force preprocess {tmppath}/inputs {tmppath}/outputs --anat_inho_cor method=disable,otsu_thresh=2,multiotsu=false --bold_inho_cor method=disable,otsu_thresh=2,multiotsu=false \ --anat_template {tmppath}/inputs/sub-token1_T1w.nii.gz --brain_mask {tmppath}/inputs/token_mask.nii.gz --WM_mask {tmppath}/inputs/token_mask.nii.gz --CSF_mask {tmppath}/inputs/token_mask.nii.gz --vascular_mask {tmppath}/inputs/token_mask.nii.gz --labels {tmppath}/inputs/token_mask.nii.gz \ --bold2anat_coreg registration=no_reg,masking=true,brain_extraction=true --commonspace_reg masking=true,brain_extraction=true,fast_commonspace=true,template_registration=no_reg --data_type int16 \ - --HMC_option 0" + --HMC_option 0 --oblique2card" process = subprocess.run( command, check=True,