Skip to content

Commit

Permalink
Merge branch 'master' into correct_oblique
Browse files Browse the repository at this point in the history
  • Loading branch information
Gab-D-G authored Oct 3, 2023
2 parents 01165af + 8fa3c7b commit 8d4899b
Show file tree
Hide file tree
Showing 22 changed files with 378 additions and 165 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
# Install a few minimal AFNI components
RUN curl -L -O https://afni.nimh.nih.gov/pub/dist/tgz/linux_ubuntu_16_64.tgz && \
mkdir -p /opt/afni && \
tar xzvf linux_ubuntu_16_64.tgz -C /opt/afni linux_ubuntu_16_64/{libmri.so,libf2c.so,3dDespike,3dTshift,3dWarp} --strip-components=1 && \
tar xzvf linux_ubuntu_16_64.tgz -C /opt/afni linux_ubuntu_16_64/{libmri.so,libf2c.so,3dDespike,3dTshift,3dWarp,3dAutobox} --strip-components=1 && \
rm -f linux_ubuntu_16_64.tgz
ENV PATH=/opt/afni${PATH:+:$PATH}

Expand Down
4 changes: 2 additions & 2 deletions rabies/analysis_pkg/analysis_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def seed_based_FC(dict_file, seed_dict, seed_name):
seed_file = seed_dict[seed_name]
resampled = os.path.abspath('resampled.nii.gz')
command=f'antsApplyTransforms -i {seed_file} -r {mask_file} -o {resampled} -n GenericLabel'
rc = run_command(command)
rc,c_out = run_command(command)
roi_mask = sitk.GetArrayFromImage(sitk.ReadImage(resampled))[volume_indices].astype(bool)

# extract the voxel timeseries within the mask, and take the mean ROI timeseries
Expand Down Expand Up @@ -139,7 +139,7 @@ def run_group_ICA(bold_file_list, mask_file, dim, random_seed):
from rabies.utils import run_command
out_dir = os.path.abspath('group_melodic.ica')
command = f'melodic -i {file_path} -m {mask_file} -o {out_dir} -d {dim} --report --seed={str(random_seed)}'
rc = run_command(command)
rc,c_out = run_command(command)
IC_file = out_dir+'/melodic_IC.nii.gz'
return out_dir, IC_file

Expand Down
2 changes: 1 addition & 1 deletion rabies/analysis_pkg/diagnosis_pkg/diagnosis_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def resample_mask(in_file, ref_file):
transform_string += f"-t {transform} "

command = f'antsApplyTransforms -i {in_file} {transform_string}-n GenericLabel -r {ref_file} -o {out_file}'
rc = run_command(command)
rc,c_out = run_command(command)
return out_file


Expand Down
21 changes: 0 additions & 21 deletions rabies/analysis_pkg/main_wf.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,27 +393,6 @@ def read_confound_workflow(conf_output, nativespace=False):
return split_dict, split_name, target_list


def get_iterable_scan_list(scan_list, split_name):
# prep the subset of scans on which the analysis will be run
import numpy as np
import pandas as pd
if os.path.isfile(os.path.abspath(scan_list[0])):
updated_split_name=[]
if '.nii' in pathlib.Path(scan_list[0]).name:
for scan in scan_list:
updated_split_name.append(find_split(scan, split_name))
else:
# read the file as a .txt
scan_list = np.array(pd.read_csv(os.path.abspath(scan_list[0]), header=None)).flatten()
for scan in scan_list:
updated_split_name.append(find_split(scan, split_name))
elif scan_list[0]=='all':
updated_split_name = split_name
else:
raise ValueError(f"The --scan_list {scan_list} input had improper format. It must the full path to a .txt or .nii files, or 'all' to keep all scans.")
return updated_split_name


def find_split(scan, split_name):
for split in split_name:
if split in scan:
Expand Down
157 changes: 101 additions & 56 deletions rabies/confound_correction_pkg/mod_ICA_AROMA/ICA_AROMA_functions.py

Large diffs are not rendered by default.

13 changes: 0 additions & 13 deletions rabies/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -774,19 +774,6 @@ def get_parser():
"path for analysis outputs.\n"
"\n"
)
analysis.add_argument(
'--scan_list', type=str,
nargs="*", # 0 or more values expected => creates a list
default=['all'],
help=
"This option offers to run the analysis on a subset of the scans. The scans are selected by\n"
"providing the full path to the corresponding EPI file in the input BIDS folder. The list \n"
"of scan can be specified manually as a list of file name '--scan_list scan1.nii.gz \n"
"scan2.nii.gz ...' or the files can be imbedded into a .txt file with one filename per row.\n"
"By default, 'all' will use all the scans previously processed.\n"
"(default: %(default)s)\n"
"\n"
)
analysis.add_argument(
'--prior_maps', action='store', type=Path,
default=f"{rabies_path}/melodic_IC.nii.gz",
Expand Down
11 changes: 6 additions & 5 deletions rabies/preprocess_pkg/bold_main_wf.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from nipype.pipeline import engine as pe
from nipype.interfaces import utility as niu, afni
from nipype.interfaces import utility as niu

from .hmc import init_bold_hmc_wf,EstimateMotionParams
from .bold_ref import init_bold_reference_wf
Expand All @@ -8,7 +8,7 @@
from .inho_correction import init_inho_correction_wf
from .registration import init_cross_modal_reg_wf
from nipype.interfaces.utility import Function

from .utils import apply_despike

def init_bold_main_wf(opts, output_folder, number_functional_scans, inho_cor_only=False, name='bold_main_wf'):
"""
Expand Down Expand Up @@ -193,9 +193,10 @@ def resample_isotropic(bold_file, rabies_data_type):
])

if opts.apply_despiking:
despike = pe.Node(
afni.Despike(outputtype='NIFTI_GZ'),
name='despike')
despike = pe.Node(Function(input_names=['in_file'],
output_names=['out_file'],
function=apply_despike),
name='despike')
workflow.connect([
(inputnode, despike, [('bold', 'in_file')]),
(despike, boldbuffer, [('out_file', 'bold_file')]),
Expand Down
2 changes: 1 addition & 1 deletion rabies/preprocess_pkg/bold_ref.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def _run_interface(self, runtime):
# denoise the resulting reference image through non-local mean denoising
# Denoising reference image.
command = f'DenoiseImage -d 3 -i {out_ref_fname} -o {out_ref_fname}'
rc = run_command(command)
rc,c_out = run_command(command)

setattr(self, 'ref_image', out_ref_fname)

Expand Down
6 changes: 3 additions & 3 deletions rabies/preprocess_pkg/commonspace_reg.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ def _run_interface(self, runtime):
template_folder = self.inputs.output_folder

command = f'mkdir -p {template_folder}'
rc = run_command(command)
rc,c_out = run_command(command)

merged = flatten_list(list(self.inputs.moving_image_list))
# create a csv file of the input image list
Expand Down Expand Up @@ -580,13 +580,13 @@ def _run_interface(self, runtime):
# for an intermediate modelbuild step and include --close and --initial-transform to the registration.
# To avoid this, the template file is renamed to another generic filename.
command = f'cp {self.inputs.template_anat} {template_folder}/modelbuild_starting_target.nii.gz'
rc = run_command(command)
rc,c_out = run_command(command)
log.debug(f"The --starting-target template original file is {self.inputs.template_anat}, and was renamed to {template_folder}/modelbuild_starting_target.nii.gz.")

command = f'QBATCH_SYSTEM={cluster_type} QBATCH_CORES={num_threads} modelbuild.sh \
--float --average-type median --gradient-step 0.25 --iterations 2 --starting-target {template_folder}/modelbuild_starting_target.nii.gz --stages rigid,affine,nlin \
--output-dir {template_folder} --sharpen-type unsharp --block --debug {masks} {csv_path}'
rc = run_command(command)
rc,c_out = run_command(command)


unbiased_template = template_folder + \
Expand Down
8 changes: 4 additions & 4 deletions rabies/preprocess_pkg/hmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def _run_interface(self, runtime):
# change the name of the first iteration directory to prevent overlap of files with second iteration
if self.inputs.second:
command = 'mv ants_mc_tmp first_ants_mc_tmp'
rc = run_command(command)
rc,c_out = run_command(command)

# make a tmp directory to store the files
os.makedirs('ants_mc_tmp', exist_ok=True)
Expand Down Expand Up @@ -212,7 +212,7 @@ def _run_interface(self, runtime):
raise ValueError("No smoothing coefficient was found.")
else:
raise ValueError("Wrong moreaccurate provided.")
rc = run_command(command)
rc,c_out = run_command(command)

setattr(self, 'csv_params', os.path.abspath('ants_mc_tmp/motcorrMOCOparams.csv'))
setattr(self, 'mc_corrected_bold', os.path.abspath('ants_mc_tmp/motcorr.nii.gz'))
Expand Down Expand Up @@ -395,14 +395,14 @@ def _run_interface(self, runtime):
# first the voxelwise positioning map
command = f'antsMotionCorrStats -m {self.inputs.motcorr_params} -o {filename_split[0]}_pos_file.csv -x {self.inputs.raw_brain_mask} \
-d {self.inputs.raw_bold}'
rc = run_command(command)
rc,c_out = run_command(command)
pos_voxelwise = os.path.abspath(
f"{filename_split[0]}_pos_file.nii.gz")

# then the voxelwise framewise displacement map
command = f'antsMotionCorrStats -m {self.inputs.motcorr_params} -o {filename_split[0]}_FD_file.csv -x {self.inputs.raw_brain_mask} \
-d {self.inputs.raw_bold} -f 1'
rc = run_command(command)
rc,c_out = run_command(command)

FD_csv = os.path.abspath(f"{filename_split[0]}_FD_file.csv")
FD_voxelwise = os.path.abspath(f"{filename_split[0]}_FD_file.nii.gz")
Expand Down
32 changes: 16 additions & 16 deletions rabies/preprocess_pkg/inho_correction.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ def _run_interface(self, runtime):
else:
raise ValueError(f"Image type must be 'EPI' or 'structural', {self.inputs.image_type}")
command = f'{processing_script} {target_img} {corrected} {self.inputs.anat_ref} {self.inputs.anat_mask} {self.inputs.inho_cor_method} {self.inputs.multistage_otsu} {str(self.inputs.otsu_threshold)}'
rc = run_command(command)
rc,c_out = run_command(command)

resampled_mask = corrected.split('.nii.gz')[0]+'_mask.nii.gz'
init_denoise = corrected.split('.nii.gz')[0]+'_init_denoise.nii.gz'
Expand All @@ -297,25 +297,25 @@ def _run_interface(self, runtime):
input_anat = target_img

command = 'ImageMath 3 null_mask.nii.gz ThresholdAtMean %s 0' % (input_anat)
rc = run_command(command)
rc,c_out = run_command(command)
command = 'ImageMath 3 thresh_mask.nii.gz ThresholdAtMean %s 1.2' % (input_anat)
rc = run_command(command)
rc,c_out = run_command(command)

command = 'N4BiasFieldCorrection -d 3 -s 4 -i %s -b [20] -c [200x200x200,0.0] -w thresh_mask.nii.gz -x null_mask.nii.gz -o N4.nii.gz' % (input_anat)
rc = run_command(command)
rc,c_out = run_command(command)
command = 'DenoiseImage -d 3 -i N4.nii.gz -o denoise.nii.gz'
rc = run_command(command)
rc,c_out = run_command(command)

from rabies.preprocess_pkg.registration import run_antsRegistration
[affine, warp, inverse_warp, warped_image] = run_antsRegistration(reg_method='Affine', moving_image=input_anat, fixed_image=self.inputs.anat_ref, fixed_mask=self.inputs.anat_mask)

command = 'antsApplyTransforms -d 3 -i %s -t [%s,1] -r %s -o resampled_mask.nii.gz -n GenericLabel' % (self.inputs.anat_mask, affine, input_anat)
rc = run_command(command)
rc,c_out = run_command(command)

command = 'N4BiasFieldCorrection -d 3 -s 2 -i %s -b [20] -c [200x200x200x200,0.0] -w resampled_mask.nii.gz -r 1 -x null_mask.nii.gz -o N4.nii.gz' % (input_anat)
rc = run_command(command)
rc,c_out = run_command(command)
command = 'DenoiseImage -d 3 -i N4.nii.gz -o %s' % (corrected)
rc = run_command(command)
rc,c_out = run_command(command)

# resample image to specified data format
sitk.WriteImage(sitk.ReadImage(corrected, self.inputs.rabies_data_type), corrected)
Expand Down Expand Up @@ -412,7 +412,7 @@ def _run_interface(self, runtime):
[affine, warp, inverse_warp, warped_image] = run_antsRegistration(reg_method='Rigid', moving_image=cwd+'/corrected_iter2.nii.gz', fixed_image=self.inputs.anat, fixed_mask=self.inputs.anat_mask)

command = 'antsApplyTransforms -d 3 -i %s -t [%s,1] -r %s -o %s -n GenericLabel' % (self.inputs.anat_mask, affine, cwd+'/corrected_iter2.nii.gz',resampled_mask)
rc = run_command(command)
rc,c_out = run_command(command)

otsu_bias_cor(target=bias_cor_input, otsu_ref=cwd+'/corrected_iter2.nii.gz', out_name=cwd+'/final_otsu.nii.gz', b_value=b_value, mask=resampled_mask)

Expand Down Expand Up @@ -444,9 +444,9 @@ def otsu_bias_cor(target, otsu_ref, out_name, b_value, mask=None, n_iter=200):
import SimpleITK as sitk
from rabies.utils import run_command
command = 'ImageMath 3 null_mask.nii.gz ThresholdAtMean %s 0' % (otsu_ref)
rc = run_command(command)
rc,c_out = run_command(command)
command = 'ThresholdImage 3 %s otsu_weight.nii.gz Otsu 4' % (otsu_ref)
rc = run_command(command)
rc,c_out = run_command(command)

otsu_img = sitk.ReadImage(
'otsu_weight.nii.gz', sitk.sitkUInt8)
Expand Down Expand Up @@ -485,16 +485,16 @@ def otsu_bias_cor(target, otsu_ref, out_name, b_value, mask=None, n_iter=200):
sitk.WriteImage(mask_img, 'mask1234.nii.gz')

command = 'N4BiasFieldCorrection -d 3 -i %s -b %s -s 1 -c [%sx%sx%s,1e-4] -w mask12.nii.gz -x null_mask.nii.gz -o corrected1.nii.gz' % (target, str(b_value), str(n_iter),str(n_iter),str(n_iter),)
rc = run_command(command)
rc,c_out = run_command(command)

command = 'N4BiasFieldCorrection -d 3 -i corrected1.nii.gz -b %s -s 1 -c [%sx%sx%s,1e-4] -w mask34.nii.gz -x null_mask.nii.gz -o corrected2.nii.gz' % (str(b_value), str(n_iter),str(n_iter),str(n_iter),)
rc = run_command(command)
rc,c_out = run_command(command)

command = 'N4BiasFieldCorrection -d 3 -i corrected2.nii.gz -b %s -s 1 -c [%sx%sx%s,1e-4] -w mask123.nii.gz -x null_mask.nii.gz -o corrected3.nii.gz' % (str(b_value), str(n_iter),str(n_iter),str(n_iter),)
rc = run_command(command)
rc,c_out = run_command(command)

command = 'N4BiasFieldCorrection -d 3 -i corrected3.nii.gz -b %s -s 1 -c [%sx%sx%s,1e-4] -w mask234.nii.gz -x null_mask.nii.gz -o corrected4.nii.gz' % (str(b_value), str(n_iter),str(n_iter),str(n_iter),)
rc = run_command(command)
rc,c_out = run_command(command)

command = 'N4BiasFieldCorrection -d 3 -i corrected4.nii.gz -b %s -s 1 -c [%sx%sx%s,1e-4] -w mask1234.nii.gz -x null_mask.nii.gz -o %s' % (str(b_value), str(n_iter),str(n_iter),str(n_iter),out_name,)
rc = run_command(command)
rc,c_out = run_command(command)
15 changes: 9 additions & 6 deletions rabies/preprocess_pkg/main_wf.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
from nipype.interfaces import utility as niu
from nipype.interfaces.io import DataSink
from nipype.interfaces.utility import Function
from nipype.interfaces.afni import Autobox
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, convert_oblique2card, resample_template
from .utils import BIDSDataGraber, prep_bids_iter, convert_to_RAS, convert_oblique2card, apply_autobox, resample_template
from . import preprocess_visual_QC

def init_main_wf(data_dir_path, output_folder, opts, name='main_wf'):
Expand Down Expand Up @@ -195,8 +194,10 @@ def init_main_wf(data_dir_path, output_folder, opts, name='main_wf'):
name="format_bold_buffer")

if opts.bold_autobox: # apply AFNI's 3dAutobox
bold_autobox = pe.Node(Autobox(padding=1, outputtype='NIFTI_GZ'),
name="bold_autobox")
bold_autobox = pe.Node(Function(input_names=['in_file'],
output_names=['out_file'],
function=apply_autobox),
name='bold_autobox')
workflow.connect([
(bold_convert_to_RAS_node, bold_autobox, [
('RAS_file', 'in_file'),
Expand Down Expand Up @@ -374,8 +375,10 @@ def init_main_wf(data_dir_path, output_folder, opts, name='main_wf'):
name="format_anat_buffer")

if opts.anat_autobox: # apply AFNI's 3dAutobox
anat_autobox = pe.Node(Autobox(padding=1, outputtype='NIFTI_GZ'),
name="anat_autobox")
anat_autobox = pe.Node(Function(input_names=['in_file'],
output_names=['out_file'],
function=apply_autobox),
name='anat_autobox')
workflow.connect([
(anat_convert_to_RAS_node, anat_autobox, [
('RAS_file', 'in_file'),
Expand Down
2 changes: 1 addition & 1 deletion rabies/preprocess_pkg/preprocess_visual_QC.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def _run_interface(self, runtime):
filename_template+f'_registration.png'

command = f'{script_path} {self.inputs.moving} {self.inputs.fixed} {out_name}'
rc = run_command(command)
rc,c_out = run_command(command)

setattr(self, 'out_figure', out_name)
return runtime
Expand Down
2 changes: 1 addition & 1 deletion rabies/preprocess_pkg/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def run_antsRegistration(reg_method, brain_extraction=False, moving_image='NULL'
else:
command = f'{reg_call} {moving_image} {moving_mask} {fixed_image} {fixed_mask} {filename_split[0]}'
from rabies.utils import run_command
rc = run_command(command)
rc,c_out = run_command(command)

cwd = os.getcwd()
warped_image = f'{cwd}/{filename_split[0]}_output_warped_image.nii.gz'
Expand Down
2 changes: 1 addition & 1 deletion rabies/preprocess_pkg/stc.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def slice_timing_correction(in_file, tr='auto', tpattern='alt-z', stc_axis='Y',

command = f'3dTshift -{interp_method} -prefix temp_tshift.nii.gz -tpattern {tpattern} -TR {tr} {target_file}'
from rabies.utils import run_command
rc = run_command(command)
rc,c_out = run_command(command)

tshift_img = sitk.ReadImage(
'temp_tshift.nii.gz', rabies_data_type)
Expand Down
25 changes: 24 additions & 1 deletion rabies/preprocess_pkg/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,29 @@ def _list_outputs(self):
return {'out_file': getattr(self, 'out_file')}


###WRAPPERS FOR AFNI'S FUNCTIONS; NECESSARY TO PREVENT ISSUES WHEN READING INPUTS/OUTPUTS FROM WORKFLOW GRAPH

def apply_despike(in_file):
import pathlib
import os
from rabies.utils import run_command
split = pathlib.Path(in_file).name.rsplit(".nii")[0]
out_file = os.path.abspath(f"{split}_despike.nii.gz")
command = f'3dDespike -prefix {out_file} {in_file}'
rc,c_out = run_command(command)
return out_file

def apply_autobox(in_file):
import pathlib
import os
from rabies.utils import run_command
split = pathlib.Path(in_file).name.rsplit(".nii")[0]
out_file = os.path.abspath(f"{split}_autobox.nii.gz")
command = f'3dAutobox -input {in_file} -prefix {out_file} -npad 1'
rc,c_out = run_command(command)
return out_file


def convert_to_RAS(img_file, out_dir=None):
# convert the input image to the RAS orientation convention
import os
Expand Down Expand Up @@ -241,7 +264,7 @@ def resample_template(template_file, mask_file, file_list, spacing='inputs_defin
# also resample the brain mask to ensure stable registrations further down
resampled_mask = os.path.abspath("resampled_mask.nii.gz")
command = f'antsApplyTransforms -d 3 -i {mask_file} -r {resampled_template} -o {resampled_mask} --verbose -n GenericLabel'
rc = run_command(command)
rc,c_out = run_command(command)

return resampled_template, resampled_mask

2 changes: 1 addition & 1 deletion rabies/run_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ def install_DSURQE(log):
from rabies.preprocess_pkg.utils import run_command
log.info(
"SOME FILES FROM THE DEFAULT TEMPLATE ARE MISSING. THEY WILL BE INSTALLED BEFORE FURTHER PROCESSING.")
rc = run_command(f'install_DSURQE.sh {rabies_path}', verbose=True)
rc,c_out = run_command(f'install_DSURQE.sh {rabies_path}', verbose=True)


def check_binary_masks(mask):
Expand Down
Loading

0 comments on commit 8d4899b

Please sign in to comment.