-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathresection.py
More file actions
190 lines (127 loc) · 4.84 KB
/
resection.py
File metadata and controls
190 lines (127 loc) · 4.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Oct 21 16:03:45 2024
@author: Leela Srinivasan
Functions for spatial cluster/resection volume clinical validation
"""
import os
import glob
import shutil
import subprocess
import pandas as pd
from general import euclidean_distance
def import_resection(SUBJECT, config):
"""
Parameters
----------
config : dict
configuration dictionary describing user paths.
Returns
-------
None.
"""
if not os.path.isfile('rsxn_al.nii'):
path=os.path.join(config['resection_dir'], SUBJECT, 'rsxn_msk', 'rsxn.msk.nii')
if os.path.isfile(path):
shutil.copyfile(path,'rsxn.msk.nii')
return 1
print('rsxn.msk.nii not found in provided directory path. Please look in alternative location.')
return 0
def align_resection_to_surfvol(SUBJECT, SESSION, f):
"""
Align the resection mask to the SurfVol by translating the relationship between the preoperative t1 and the SurfVol
Parameters
----------
SUBJECT : string
p***.
SESSION : string
clinical/altclinical.
f : string
resection mask filename.
Returns
-------
None. Outputs aligned resection to the working directory.
"""
if not os.path.exists('rsxn_al.nii'):
cmd1="3dAllineate -base sub-{}_{}_SurfVol.nii -source resection_t1.nii -prefix aligned+orig -1Dmatrix_save anat_to_fs"
cmd1=cmd1.format(SUBJECT,SESSION)
subprocess.run(cmd1,shell=True)
cmd2="3dAllineate -base sub-{}_{}_SurfVol.nii -source rsxn.msk.nii -1Dmatrix_apply anat_to_fs.aff12.1D -prefix tmp_rsxn+orig"
cmd2=cmd2.format(SUBJECT,SESSION)
subprocess.run(cmd2,shell=True)
cmd3="3dcalc -a tmp_rsxn+orig -expr 'ispositive(a-0.1)' -prefix tmp2_rsxn.nii"
subprocess.run(cmd3,shell=True)
cmd4="3dmask_tool -input tmp2_rsxn.nii -prefix rsxn_al.nii -fill_holes"
subprocess.run(cmd4,shell=True)
for file in os.listdir(os.getcwd()):
if 'tmp_rsxn+orig' in file or 'tmp2_rsxn' in file:
os.remove(file)
def get_resection_cm(f):
"""
Parameters
----------
f : string
filename of aligned resection mask.
Returns
-------
rsxn_cm : int
Center of mass of the resection mask
"""
#Calculate CM
cmd1="3dcm {}"
cmd1=cmd1.format(f)
result=subprocess.run(cmd1,shell=True,capture_output=True,text = True)
#Read and return CM
rsxn_cm_str = result.stdout.split('\n')[0].split(' ')
rsxn_cm = [eval(coord) for coord in rsxn_cm_str]
return rsxn_cm
def get_resection_cluster_overlap(SUBJECT, rsxn_cm):
"""
Parameters
----------
SUBJECT : string
p***.
rsxn_cm : int
Center of mass of the resection mask
Returns
-------
output_list : array
array of 3-element arrays containing (1) cluster number/hemisphere, (2) percentage overlap with the resection,
and (3) the distance between the COM of the cluster and the resection.
"""
#Find cluster files projected into the volume
output_list = []
for nifti in glob.glob("*_auc.nii"):
#Pipe overlap
f_pref = nifti.split('_auc')[0]
cmd1="3dABoverlap rsxn_al.nii {} > overlap.txt"
cmd1=cmd1.format(nifti)
subprocess.run(cmd1,shell=True)
#Get % of the resection contained in the cluster
overlap_df = pd.read_csv('overlap.txt', sep='\s+', skiprows=1)
percentage_overlap = (overlap_df.values[0][3]/overlap_df.values[0][0])*100
print('Overlap for subject {}, {}: {}'.format(SUBJECT, f_pref, percentage_overlap))
#Get cluster COM
cmd2="3dcm {}"
cmd2=cmd2.format(nifti)
result=subprocess.run(cmd2,shell=True,capture_output=True,text = True)
cluster_cm_str = result.stdout.split('\n')[0].split(' ')
cluster_cm = [eval(coord) for coord in cluster_cm_str]
# Calculate euclidean distance between COMs
com_dist = euclidean_distance(cluster_cm, rsxn_cm)
print('Distance from {} resection COM to {} COM: {}'.format(SUBJECT, f_pref, com_dist))
output_list.append([f_pref, percentage_overlap, com_dist])
return output_list
def print_overlap_results(output_list):
"""
Parameters
----------
output_list : array
list of lists from get_resection_cluster_overlap with overlap information per cluster
Returns
-------
None.
"""
for cluster in output_list:
print('{} has overlap percentage {} and has inter-CM distance of {}'.format(cluster[0], cluster[1], cluster[2]))