Skip to content

Commit eaf6404

Browse files
committed
running generate mappings script from dsst defacing wf script
1 parent bc2837f commit eaf6404

File tree

4 files changed

+34
-164
lines changed

4 files changed

+34
-164
lines changed

deface.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ def run_afni_refacer(primary_t1, others, subj_input_dir, sess_dir, output_dir):
6868
acq = ""
6969

7070
# TODO test on hv_protocol dataset to confirm. Is this directory even necessary with the new pipeline?
71-
subj_outdir = output_dir / subj_id / sess_id / 'anat' / acq[0]
71+
subj_outdir = output_dir / subj_id / sess_id / 'anat' / acq
7272

7373
prefix = primary_t1.name.split('.')[0] # filename without the extension
7474

@@ -96,7 +96,7 @@ def run_afni_refacer(primary_t1, others, subj_input_dir, sess_dir, output_dir):
9696
# rename afni workdirs
9797
workdir_list = list(subj_outdir.glob('*work_refacer*'))
9898
if len(workdir_list) > 0:
99-
missing_refacer_out = None
99+
missing_refacer_out = ""
100100
log_fileobj.flush()
101101
new_afni_workdir = rename_afni_workdir(workdir_list[0])
102102

dsst_defacing_wf.py

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from pathlib import Path
88

99
import deface
10+
import generate_mappings
1011

1112

1213
def get_args():
@@ -19,13 +20,9 @@ def get_args():
1920
parser.add_argument('--output', '-o', action='store', type=Path, required=True, dest='output',
2021
help='Path to output BIDS dataset with defaced scan.')
2122

22-
parser.add_argument('--mapping-file', '-m', action='store', type=Path, required=True, dest='mapping',
23-
help='Path to primary to other/secondary scans mapping file.')
24-
2523
parser.add_argument('--participant-id', '-p', dest='subj_id', action='store', required=False, default=None,
2624
help="Subject ID associated with the participant. Since the input dataset is assumed to be \
2725
BIDS valid, this argument expects subject IDs with 'sub-' prefix.")
28-
# This argument is valid only if a subject ID is provided
2926
# TODO Test the session id argument
3027
parser.add_argument('--session-id', '-s', dest='sess_id', action='store', required=False, default=None,
3128
help="Session ID associated with the subject ID. If the BIDS input dataset contains sessions, \
@@ -39,7 +36,7 @@ def get_args():
3936
print("Session ID provided without a subject ID. Invalid Argument.")
4037
raise ValueError
4138

42-
return args.input.resolve(), args.output.resolve(), args.mapping.resolve(), args.subj_id, args.sess_id, args.no_clean
39+
return args.input.resolve(), args.output.resolve(), args.subj_id, args.sess_id, args.no_clean
4340

4441

4542
def run_command(cmdstr):
@@ -137,19 +134,17 @@ def vqcdeface_prep(input_dir, defacing_output_dir):
137134

138135
create_vqc_id_list(vqcdeface_dir)
139136

140-
vqcdeface_cmd = f"vqcdeface -u {vqcdeface_dir} -i {vqcdeface_dir / 'vqcdeface_id_list.txt'} \
141-
-m orig.nii.gz -d defaced.nii.gz -r defaced_render"
137+
vqcdeface_cmd = f"vqcdeface -u {vqcdeface_dir} -i {vqcdeface_dir / 'vqcdeface_id_list.txt'} -m orig.nii.gz -d defaced.nii.gz -r defaced_render"
142138

143139
return vqcdeface_cmd
144140

145141

146142
def main():
147143
# get command line arguments
148-
input_dir, output, mapping, subj_id, sess_id, no_clean = get_args()
144+
input_dir, output, subj_id, sess_id, no_clean = get_args()
149145

150-
# load primary to other scans mapping into a dict
151-
with open(mapping, 'r') as f:
152-
mapping_dict = json.load(f)
146+
# run generate mapping script
147+
mapping_dict = generate_mappings.crawl(input_dir, output)
153148

154149
# create a separate bids tree with only defaced scans
155150
defacing_outputs = output / 'bids_defaced'
@@ -176,7 +171,7 @@ def main():
176171
if missing_refacer_out is not None:
177172
afni_refacer_failures.extend(missing_refacer_out)
178173

179-
with open(output / 'logs' / 'missing_afni_refacer_output.txt', 'w') as f:
174+
with open(output / 'logs' / 'failed_afni_refacer_output.txt', 'w') as f:
180175
f.write('\n'.join(afni_refacer_failures)) # TODO Not very useful when running the pipeline in parallel
181176

182177
# reorganizing the directory with defaced images into BIDS tree

generate_mappings.py

Lines changed: 25 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -13,26 +13,13 @@
1313
visualqc T1 MRI utility : https://raamana.github.io/visualqc/cli_t1_mri.html
1414
"""
1515

16-
import argparse
1716
import json
1817
import random
1918
import subprocess
2019
from collections import defaultdict
2120
from pathlib import Path
2221

2322

24-
def get_args():
25-
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, description=__doc__)
26-
27-
parser.add_argument('-i', '--input', type=Path, action='store', dest='inputdir', metavar='INPUT_DIR',
28-
help='Path to input BIDS directory.')
29-
parser.add_argument('-o', '--output', type=Path, action='store', dest='outdir', metavar='SCRIPT_OUTPUT_DIR',
30-
default=Path('.'), help="Path to directory that'll contain this script's outputs.")
31-
args = parser.parse_args()
32-
33-
return args.inputdir.resolve(), args.outdir.resolve()
34-
35-
3623
def run_command(cmdstr, logfile):
3724
"""Runs the given command str as shell subprocess. If logfile object is provided, then the stdout and stderr of the
3825
subprocess is written to the log file.
@@ -88,9 +75,9 @@ def primary_scans_qc_prep(mapping_dict, visualqc_prep):
8875
dest.mkdir(parents=True, exist_ok=True)
8976

9077
id_list.append(dest)
91-
Path(dest / 'primary.nii.gz').symlink_to(primary)
92-
# ln_cmd = f"ln -s {primary} {}"
93-
# run_command(ln_cmd, "")
78+
primary_link = dest / 'primary.nii.gz'
79+
if not primary_link.exists():
80+
primary_link.symlink_to(primary)
9481

9582
with open(visualqc_prep / 'id_list_t1.txt', 'w') as f:
9683
f.write('\n'.join([str(i) for i in id_list]))
@@ -135,26 +122,23 @@ def get_anat_dir_paths(subj_dir_path):
135122
:param Path subj_dir_path : Absolute path to subject directory.
136123
:return: A list of absolute paths to anat directory(s) within subject tree.
137124
"""
138-
anat_dirs = []
139-
no_anat_dirs = []
140125

141126
# check if there are session directories
142-
# sess_exist, sessions = is_sessions(subj_dir_path)
143127
sessions = list(subj_dir_path.glob('ses-*'))
144128
sess_exist = True if sessions else False
145129

130+
no_anat_dirs = []
131+
anat_dirs = []
146132
if not sess_exist:
147-
anat_dir = subj_dir_path.joinpath('anat')
133+
anat_dir = subj_dir_path / 'anat'
148134
if not anat_dir.exists():
149-
# print(f'No anat directories found for {subj_dir_path.name}.\n')
150135
no_anat_dirs.append(subj_dir_path)
151136
else:
152137
anat_dirs.append(anat_dir)
153138
else:
154139
for sess in sessions:
155-
anat_dir = sess.joinpath('anat')
140+
anat_dir = sess / 'anat'
156141
if not anat_dir.exists():
157-
# print(f'No anat directories found for {subj_dir_path.name} and {sess.name}.\n')
158142
no_anat_dirs.append(sess)
159143
else:
160144
anat_dirs.append(anat_dir)
@@ -183,7 +167,7 @@ def update_mapping_dict(mapping_dict, anat_dir, is_sessions, sidecars, t1_unavai
183167
# latest T1w scan in the session based on acquisition time
184168
nifti_fname = t1_acq_time_list[0][0].name.split('.')[0] + '.nii.gz'
185169

186-
primary_t1 = t1_acq_time_list[0][0].parent.joinpath(nifti_fname)
170+
primary_t1 = t1_acq_time_list[0][0].parent / nifti_fname
187171
others = [str(s) for s in list(anat_dir.glob('*.nii*')) if s != primary_t1]
188172
t1_available.append(anat_dir.parent)
189173
else:
@@ -214,26 +198,23 @@ def summary_to_stdout(vqc_t1_cmd, sess_ct, t1s_found, t1s_not_found, no_anat_dir
214198
print(f"Sessions without a T1w scan: {len(t1s_not_found)}")
215199
print(f"List of sessions without a T1w scan:\n {readable_path_list}")
216200
print(
217-
f"\nPlease find the mapping file in JSON format at {str(output.joinpath('primary_to_others_mapping.json'))} \nand other helpful logs at {str(output.joinpath('logs'))}\n")
218-
201+
f"\nPlease find the mapping file in JSON format at {str(output / 'primary_to_others_mapping.json')} \nand other helpful logs at {str(output / 'logs')}\n")
219202

220-
def main():
221-
input, output = get_args()
222203

223-
# make a logs dir
224-
output.joinpath('logs').mkdir(parents=True, exist_ok=True)
204+
def crawl(input_dir, output):
205+
# make dir for log files and visualqc prep
206+
dir_names = ['logs', 'visualqc_prep']
207+
for dir_name in dir_names:
208+
output.joinpath(dir_name).mkdir(parents=True, exist_ok=True)
225209

226-
# make qc_prep dir
227-
output.joinpath('visualqc_prep').mkdir(parents=True, exist_ok=True)
228-
229-
# input_layout = bids.BIDSLayout(input) # taking insane amounts of time so not using pybids
230210
t1s_not_found = []
231211
t1s_found = []
232212
total_sessions = 0
233213

234214
mapping_dict = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
235215

236-
for subj_dir in list(input.glob('sub-*')):
216+
for subj_dir in list(input_dir.glob('sub-*')):
217+
# subj_id = subj_dir.name
237218
anat_dirs, no_anat_dirs, sess_exist = get_anat_dir_paths(subj_dir)
238219
for anat_dir in anat_dirs:
239220
total_sessions += 1
@@ -242,25 +223,20 @@ def main():
242223
t1_sidecars, t1s_not_found, t1s_found)
243224

244225
# write mapping dict to file
245-
with open(output.joinpath('primary_to_others_mapping.json'), 'w') as f1:
226+
with open(output / 'primary_to_others_mapping.json', 'w') as f1:
246227
json.dump(mapping_dict, f1, indent=4)
247228

248229
# write session paths without T1w scan to file
249-
with open(output.joinpath('logs', 't1_unavailable.txt'), 'w') as f2:
250-
for sess_path in t1s_not_found:
251-
f2.write(str(sess_path) + '\n')
230+
with open(output / 'logs' / 't1_unavailable.txt', 'w') as f2:
231+
f2.write('\n'.join([str(sess_path) for sess_path in t1s_not_found]))
232+
233+
with open(output / 'logs' / 'anat_unavailable.txt', 'w') as f3:
234+
f3.write('\n'.join([str(p) for p in no_anat_dirs]))
252235

253236
# write vqc command to file
254237
vqc_t1_mri_cmd = primary_scans_qc_prep(mapping_dict, output / 'visualqc_prep')
255-
with open(output / 'visualqc_prep' / 't1_mri_qc_cmd', 'w') as f3:
256-
f3.write(f"{vqc_t1_mri_cmd}\n")
257-
258-
with open(output.joinpath('logs', 'anat_unavailable.txt'), 'w') as f4:
259-
for p in no_anat_dirs:
260-
f4.write(str(p) + '\n')
238+
with open(output / 'visualqc_prep' / 't1_mri_qc_cmd', 'w') as f4:
239+
f4.write(f"{vqc_t1_mri_cmd}\n")
261240

262241
summary_to_stdout(vqc_t1_mri_cmd, total_sessions, t1s_found, t1s_not_found, no_anat_dirs, output)
263-
264-
265-
if __name__ == "__main__":
266-
main()
242+
return mapping_dict

integrate_into_bids.py

Lines changed: 0 additions & 101 deletions
This file was deleted.

0 commit comments

Comments
 (0)