1+ import gzip
2+ import re
3+ import shutil
4+ import os
15import subprocess
26from os import fspath
37from pathlib import Path
@@ -51,6 +55,79 @@ def get_anat_dir_paths(subj_dir_path):
5155 return anat_dirs
5256
5357
58+ def compress_to_gz (input_file , output_file ):
59+ if not output_file .exists ():
60+ with open (input_file , 'rb' ) as f_input :
61+ with gzip .open (output_file , 'wb' ) as f_output :
62+ f_output .writelines (f_input )
63+
64+
65+ def copy_over_sidecar (scan_filepath , input_anat_dir , output_anat_dir ):
66+ prefix = '_' .join ([i for i in re .split ('_|\.' , scan_filepath .name ) if i not in ['defaced' , 'nii' , 'gz' ]])
67+ filename = prefix + '.json'
68+ json_sidecar = input_anat_dir / filename
69+ shutil .copy2 (json_sidecar , output_anat_dir / filename )
70+
71+
72+ def vqcdeface_prep (bids_input_dir , defaced_anat_dir , bids_defaced_outdir ):
73+ defacing_qc_dir = bids_defaced_outdir .parent / 'QC_prep' / 'defacing_QC'
74+ interested_files = [f for f in defaced_anat_dir .rglob ('*.nii.gz' ) if
75+ 'work_dir' not in str (f ).split ('/' )]
76+ print (interested_files )
77+ for defaced_img in interested_files :
78+ entities = defaced_img .name .split ('.' )[0 ].split ('_' )
79+ vqcd_subj_dir = defacing_qc_dir / f"{ '/' .join (entities )} "
80+ vqcd_subj_dir .mkdir (parents = True , exist_ok = True )
81+
82+ defaced_link = vqcd_subj_dir / 'defaced.nii.gz'
83+ if not defaced_link .is_symlink ():
84+ defaced_link .symlink_to (defaced_img )
85+ print (list (bids_input_dir .rglob (defaced_img .name )))
86+ img = list (bids_input_dir .rglob (defaced_img .name ))[0 ]
87+ img_link = vqcd_subj_dir / 'orig.nii.gz'
88+ if not img_link .is_symlink (): img_link .symlink_to (img )
89+
90+
91+ def reorganize_into_bids (input_bids_dir , subj_dir , sess_dir , primary_t1 , bids_defaced_outdir , no_clean ):
92+ subj_id = subj_dir .name
93+ sess_id = sess_dir .name if sess_dir else None
94+
95+ if sess_id :
96+ anat_dirs = list (bids_defaced_outdir .joinpath (subj_id , sess_id ).rglob ('anat' ))
97+ else :
98+ anat_dirs = list (bids_defaced_outdir .joinpath (subj_id ).rglob ('anat' ))
99+ # make workdir for each session within anat dir
100+ for anat_dir in anat_dirs :
101+ # iterate over all nii files within an anat dir to rename all primary and "other" scans
102+ for nii_filepath in anat_dir .rglob ('*nii*' ):
103+ if nii_filepath .name .startswith ('tmp.99.result' ):
104+ # convert to nii.gz, rename and copy over to anat dir
105+ gz_file = anat_dir / Path (primary_t1 ).name
106+ compress_to_gz (nii_filepath , gz_file )
107+
108+ # copy over corresponding json sidecar
109+ copy_over_sidecar (Path (primary_t1 ), input_bids_dir / anat_dir .relative_to (bids_defaced_outdir ),
110+ anat_dir )
111+
112+ elif nii_filepath .name .endswith ('_defaced.nii.gz' ):
113+ new_filename = '_' .join (nii_filepath .name .split ('_' )[:- 1 ]) + '.nii.gz'
114+ shutil .copy2 (nii_filepath , str (anat_dir / new_filename ))
115+
116+ copy_over_sidecar (nii_filepath , input_bids_dir / anat_dir .relative_to (bids_defaced_outdir ), anat_dir )
117+
118+ # move QC images and afni intermediate files to a new directory
119+ intermediate_files_dir = anat_dir / 'work_dir'
120+ intermediate_files_dir .mkdir (parents = True , exist_ok = True )
121+ for dirpath in anat_dir .glob ('*' ):
122+ if dirpath .name .startswith ('workdir' ) or dirpath .name .endswith ('QC' ):
123+ shutil .move (str (dirpath ), str (intermediate_files_dir ))
124+
125+ vqcdeface_prep (input_bids_dir , anat_dir , bids_defaced_outdir )
126+
127+ if not no_clean :
128+ shutil .rmtree (intermediate_files_dir )
129+
130+
54131def run_afni_refacer (primary_t1 , others , subj_input_dir , sess_dir , output_dir ):
55132 # constructing afni refacer command
56133 if primary_t1 :
@@ -77,7 +154,7 @@ def run_afni_refacer(primary_t1, others, subj_input_dir, sess_dir, output_dir):
77154 refacer_cmd = f"@afni_refacer_run -input { primary_t1 } -mode_deface -no_clean -prefix { fspath (subj_outdir / prefix )} "
78155
79156 # TODO remove module load afni
80- full_cmd = f"module load afni ; { refacer_cmd } "
157+ full_cmd = f"module load afni ; export OMP_NUM_THREADS=1 ; { refacer_cmd } "
81158
82159 # TODO make log text less ugly; perhaps in a separate function
83160 log_filename = subj_outdir / 'defacing_pipeline.log'
@@ -102,6 +179,7 @@ def run_afni_refacer(primary_t1, others, subj_input_dir, sess_dir, output_dir):
102179
103180 # register other scans to the primary scan
104181 register .register_to_primary_scan (subj_input_dir , new_afni_workdir , primary_t1 , others , log_fileobj )
182+
105183 else :
106184 log_fileobj .write (
107185 f"@afni_refacer_run work directory not found. Most probably because the refacer command failed." )
@@ -110,20 +188,26 @@ def run_afni_refacer(primary_t1, others, subj_input_dir, sess_dir, output_dir):
110188 return missing_refacer_out
111189
112190
113- def deface_primary_scan (subj_input_dir , sess_dir , mapping_dict , output_dir ):
191+ def deface_primary_scan (input_bids_dir , subj_input_dir , sess_dir , mapping_dict , output_dir , no_clean ):
114192 missing_refacer_outputs = [] # list to capture missing afni refacer workdirs
115193
116- subj_id = subj_input_dir . name
117- sess_id = sess_dir . name if sess_dir else None
194+ subj_id = os . path . basename ( subj_input_dir )
195+ sess_id = os . path . basename ( sess_dir ) if sess_dir else None
118196
119197 if sess_dir :
120198 primary_t1 = mapping_dict [subj_id ][sess_id ]['primary_t1' ]
121199 others = [str (s ) for s in mapping_dict [subj_id ][sess_id ]['others' ] if s != primary_t1 ]
122200 missing_refacer_outputs .append (run_afni_refacer (primary_t1 , others , subj_input_dir , sess_dir , output_dir ))
201+ print (f"Reorganizing { sess_dir } with defaced images into BIDS tree...\n " )
202+
123203 else :
124204 primary_t1 = mapping_dict [subj_id ]['primary_t1' ]
125205 others = [str (s ) for s in mapping_dict [subj_id ]['others' ] if s != primary_t1 ]
126206 missing_refacer_outputs .append (run_afni_refacer (primary_t1 , others , subj_input_dir , "" , output_dir ))
207+ print (f"Reorganizing { subj_input_dir } with defaced images into BIDS tree...\n " )
208+
209+ # reorganizing the directory with defaced images into BIDS tree
210+ reorganize_into_bids (input_bids_dir , subj_input_dir , sess_dir , primary_t1 , output_dir , no_clean )
127211
128212 return missing_refacer_outputs
129213
0 commit comments