|
a |
|
b/tool/Code/utilities/metrics.py |
|
|
1 |
|
|
|
2 |
# Copyright 2019 Population Health Sciences and Image Analysis, German Center for Neurodegenerative Diseases(DZNE) |
|
|
3 |
# |
|
|
4 |
# Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
5 |
# you may not use this file except in compliance with the License. |
|
|
6 |
# You may obtain a copy of the License at |
|
|
7 |
# |
|
|
8 |
# http://www.apache.org/licenses/LICENSE-2.0 |
|
|
9 |
# |
|
|
10 |
# Unless required by applicable law or agreed to in writing, software |
|
|
11 |
# distributed under the License is distributed on an "AS IS" BASIS, |
|
|
12 |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
|
13 |
# See the License for the specific language governing permissions and |
|
|
14 |
# limitations under the License. |
|
|
15 |
|
|
|
16 |
import numpy as np |
|
|
17 |
from skimage.measure import perimeter |
|
|
18 |
|
|
|
19 |
def dice(predictions, labels, num_classes): |
|
|
20 |
"""Calculates the categorical Dice similarity coefficients for each class |
|
|
21 |
between labels and predictions. |
|
|
22 |
Args: |
|
|
23 |
predictions (np.ndarray): predictions |
|
|
24 |
labels (np.ndarray): labels |
|
|
25 |
num_classes (int): number of classes to calculate the dice |
|
|
26 |
coefficient for |
|
|
27 |
Returns: |
|
|
28 |
np.ndarray: dice coefficient per class |
|
|
29 |
""" |
|
|
30 |
dice_scores = np.zeros((num_classes)) |
|
|
31 |
for i in range(num_classes): |
|
|
32 |
tmp_den = (np.sum(predictions == i) + np.sum(labels == i)) |
|
|
33 |
tmp_dice = 2. * np.sum((predictions == i) * (labels == i)) / \ |
|
|
34 |
tmp_den if tmp_den > 0 else 1. |
|
|
35 |
dice_scores[i] = tmp_dice |
|
|
36 |
return dice_scores.astype(np.dtype(float).type) |
|
|
37 |
|
|
|
38 |
|
|
|
39 |
|
|
|
40 |
def perimeter_calculation(label_mask): |
|
|
41 |
|
|
|
42 |
perimeter_val=[] |
|
|
43 |
|
|
|
44 |
for slice in range(label_mask.shape[0]): |
|
|
45 |
perimeter_val.append(perimeter(label_mask[slice,:,:])) |
|
|
46 |
|
|
|
47 |
average_perimeter = np.sum(perimeter_val)/label_mask.shape[0] |
|
|
48 |
|
|
|
49 |
return average_perimeter |
|
|
50 |
|
|
|
51 |
def calculate_areas(final_img, img_spacing,columns): |
|
|
52 |
|
|
|
53 |
if len(final_img.shape) == 2: |
|
|
54 |
final_img =np.reshape(final_img,(1,final_img.shape[0],final_img.shape[1])) |
|
|
55 |
|
|
|
56 |
|
|
|
57 |
pixel_area = (img_spacing[0] * img_spacing[1]) * 0.01 |
|
|
58 |
|
|
|
59 |
statiscs_matrix = np.zeros(( 1, columns),dtype=np.float64) |
|
|
60 |
|
|
|
61 |
abdominal_region_mask= np.zeros(final_img.shape,dtype=bool) |
|
|
62 |
abdominal_region_mask[final_img >= 1] = True |
|
|
63 |
|
|
|
64 |
# Metric Measurements |
|
|
65 |
statiscs_matrix[0,0]= final_img.shape[0] * img_spacing[2] * 0.1 # Height ROI |
|
|
66 |
statiscs_matrix[0,1]= (np.sum(abdominal_region_mask) * pixel_area) / final_img.shape[0] #Average_Area |
|
|
67 |
statiscs_matrix[0, 2] = perimeter_calculation(abdominal_region_mask) * img_spacing[0] * 0.1 # Average_perimeter |
|
|
68 |
|
|
|
69 |
return statiscs_matrix.round(decimals=4) |
|
|
70 |
|
|
|
71 |
def calculate_volumes(final_img, water_array, fat_array, img_spacing,columns,weighted=True): |
|
|
72 |
|
|
|
73 |
if len(final_img.shape) == 2: |
|
|
74 |
final_img =np.reshape(final_img,(1,final_img.shape[0],final_img.shape[1])) |
|
|
75 |
water_array = np.reshape(water_array, (1, water_array.shape[0], water_array.shape[1])) |
|
|
76 |
fat_array = np.reshape(water_array, (1, fat_array.shape[0], fat_array.shape[1])) |
|
|
77 |
|
|
|
78 |
voxel_volume = (img_spacing[0] * img_spacing[1] * img_spacing[2]) * 0.001 |
|
|
79 |
|
|
|
80 |
|
|
|
81 |
|
|
|
82 |
abdominal_region_mask= np.zeros(final_img.shape,dtype=bool) |
|
|
83 |
abdominal_region_mask[final_img >= 1] = True |
|
|
84 |
|
|
|
85 |
vat_mask = np.zeros(final_img.shape, dtype=bool) |
|
|
86 |
vat_mask[final_img == 2] = True |
|
|
87 |
|
|
|
88 |
sat_mask = np.zeros(final_img.shape, dtype=bool) |
|
|
89 |
sat_mask[final_img == 1] = True |
|
|
90 |
|
|
|
91 |
combine_array = water_array + fat_array |
|
|
92 |
fat_fraction_array = np.clip(fat_array,0.00001,None) / np.clip(combine_array,0.00001,None) |
|
|
93 |
|
|
|
94 |
if weighted: |
|
|
95 |
vat_fraction = np.sum(fat_fraction_array[vat_mask]) |
|
|
96 |
sat_fraction = np.sum(fat_fraction_array[sat_mask]) |
|
|
97 |
abdominal_region_fraction= np.sum (fat_fraction_array[abdominal_region_mask]) |
|
|
98 |
else: |
|
|
99 |
sat_fraction = np.sum(sat_mask) |
|
|
100 |
vat_fraction = np.sum(vat_mask) |
|
|
101 |
abdominal_region_fraction= np.sum (abdominal_region_mask) |
|
|
102 |
|
|
|
103 |
#print('the vat fraction values are %d, the sat fraction values are %d' % (vat_fraction, sat_fraction)) |
|
|
104 |
|
|
|
105 |
statiscs_matrix = np.zeros(( 1, columns),dtype=np.float64) |
|
|
106 |
|
|
|
107 |
# Metric Measurements |
|
|
108 |
statiscs_matrix[0,0] = abdominal_region_fraction * voxel_volume # Volume of Abdominal Region |
|
|
109 |
|
|
|
110 |
# Pixel not Weighted |
|
|
111 |
statiscs_matrix[0, 1] = sat_fraction * voxel_volume # VOL_SAT |
|
|
112 |
statiscs_matrix[0, 2] = vat_fraction * voxel_volume # VOL_VAT |
|
|
113 |
statiscs_matrix[0, 3] = statiscs_matrix[0, 1] + statiscs_matrix[0, 2] # VOL_AAT |
|
|
114 |
|
|
|
115 |
statiscs_matrix[0, 4] = statiscs_matrix[0,2] / statiscs_matrix[0, 1] # VAT/SAT |
|
|
116 |
statiscs_matrix[0, 5] = statiscs_matrix[0, 2] / statiscs_matrix[0, 3] # VAT/AAT |
|
|
117 |
statiscs_matrix[0, 6] = statiscs_matrix[0, 1] / statiscs_matrix[0, 3] # SAT/AAT |
|
|
118 |
|
|
|
119 |
#statiscs_matrix[0,17]=extreme_AAT_increase_flag(final_img,threshold=increase_thr) |
|
|
120 |
|
|
|
121 |
return statiscs_matrix.round(decimals=4) |
|
|
122 |
|
|
|
123 |
def calculate_statistics_v2(final_img, water_array, fat_array, low_idx, high_idx, columns,base_variables_len,img_spacing,comparments=0,weighted=True): |
|
|
124 |
""" |
|
|
125 |
Rhineland Stuty version |
|
|
126 |
:param final_img: |
|
|
127 |
:param water_array: |
|
|
128 |
:param fat_array: |
|
|
129 |
:param low_idx: |
|
|
130 |
:param high_idx: |
|
|
131 |
:param columns: |
|
|
132 |
:param base_variables_len: |
|
|
133 |
:param img_spacing: |
|
|
134 |
:param increase_thr: |
|
|
135 |
:param comparments: |
|
|
136 |
:param weighted: |
|
|
137 |
:return: |
|
|
138 |
""" |
|
|
139 |
|
|
|
140 |
|
|
|
141 |
statiscs_matrix = np.zeros((1, len(columns)),dtype=object) |
|
|
142 |
size_base=base_variables_len['Area']+base_variables_len['Volume']+base_variables_len['W_Volume'] |
|
|
143 |
|
|
|
144 |
|
|
|
145 |
#print('Whole Body') |
|
|
146 |
|
|
|
147 |
final_area=base_variables_len['Area'] |
|
|
148 |
statiscs_matrix[0, 0:final_area]=calculate_areas(final_img,img_spacing,base_variables_len['Area']) |
|
|
149 |
final_volume=final_area +base_variables_len['Volume'] |
|
|
150 |
statiscs_matrix[0,final_area:final_volume]=calculate_volumes(final_img,water_array,fat_array, |
|
|
151 |
img_spacing, base_variables_len['Volume'], weighted=False) |
|
|
152 |
|
|
|
153 |
|
|
|
154 |
if weighted: |
|
|
155 |
final_volume2= final_volume +base_variables_len['Volume'] |
|
|
156 |
statiscs_matrix[0,final_volume:final_volume2] = calculate_volumes(final_img,water_array,fat_array,img_spacing, |
|
|
157 |
base_variables_len['Volume'], |
|
|
158 |
weighted=True) |
|
|
159 |
|
|
|
160 |
if comparments !=0: |
|
|
161 |
|
|
|
162 |
interval = (high_idx - low_idx) |
|
|
163 |
interval_step = np.around((interval / comparments), decimals=2) |
|
|
164 |
interval_steps = np.arange(0, interval, interval_step).round(decimals=2) |
|
|
165 |
if not interval_steps[-1] == interval: |
|
|
166 |
interval_steps = np.append(interval_steps, interval) |
|
|
167 |
|
|
|
168 |
slice=0 |
|
|
169 |
|
|
|
170 |
for i in np.arange(0,comparments): |
|
|
171 |
lower_limit=np.ceil(interval_steps[i]) |
|
|
172 |
higher_limit=np.floor(interval_steps[i+1]) |
|
|
173 |
complete_slices=np.arange(lower_limit,higher_limit) |
|
|
174 |
#print (complete_slices) |
|
|
175 |
#Calculate Complete Slices |
|
|
176 |
if complete_slices.size != 0 : |
|
|
177 |
min_slice=int(np.min(complete_slices)) |
|
|
178 |
max_slice=int(np.max(complete_slices))+1 |
|
|
179 |
|
|
|
180 |
|
|
|
181 |
area_initial_len= size_base * (i+1) |
|
|
182 |
area_final_len =size_base * (i+1)+base_variables_len['Area'] |
|
|
183 |
|
|
|
184 |
#TO-DO check that is empty |
|
|
185 |
if statiscs_matrix[0, area_initial_len + 1] != 0: |
|
|
186 |
|
|
|
187 |
statiscs_matrix[0, area_initial_len:area_final_len] = statiscs_matrix[0, area_initial_len:area_final_len] + calculate_areas(final_img[min_slice:max_slice, :, :],img_spacing,base_variables_len['Area']) |
|
|
188 |
statiscs_matrix[0,area_initial_len+1] = statiscs_matrix[0,area_initial_len+1] / 2 |
|
|
189 |
statiscs_matrix[0, area_initial_len + 2] = statiscs_matrix[0, area_initial_len + 2] / 2 |
|
|
190 |
|
|
|
191 |
else: |
|
|
192 |
statiscs_matrix[0, area_initial_len:area_final_len] = statiscs_matrix[0,area_initial_len:area_final_len] + calculate_areas(final_img[min_slice:max_slice, :, :], img_spacing, base_variables_len['Area']) |
|
|
193 |
|
|
|
194 |
vol_final_len= area_final_len + base_variables_len['Volume'] |
|
|
195 |
|
|
|
196 |
statiscs_matrix[0, area_final_len:vol_final_len] = statiscs_matrix[0, area_final_len:vol_final_len] + calculate_volumes(final_img[min_slice:max_slice, :, :], water_array[min_slice:max_slice, :, :], |
|
|
197 |
fat_array[min_slice:max_slice, :, :], |
|
|
198 |
img_spacing, base_variables_len['Volume'],weighted=False) |
|
|
199 |
if weighted: |
|
|
200 |
vol2_final_len=vol_final_len +base_variables_len['W_Volume'] |
|
|
201 |
|
|
|
202 |
statiscs_matrix[0, vol_final_len:vol2_final_len] = statiscs_matrix[0,vol_final_len:vol2_final_len] + calculate_volumes(final_img[min_slice:max_slice, :, :], water_array[min_slice:max_slice, :, :], |
|
|
203 |
fat_array[min_slice:max_slice, :, :], |
|
|
204 |
img_spacing, base_variables_len['Volume'], weighted=True) |
|
|
205 |
residual=np.around(interval_steps[i+1]-int(interval_steps[i+1]),decimals=2) |
|
|
206 |
if residual !=0 : |
|
|
207 |
slice=int(np.floor(interval_steps[i+1])) |
|
|
208 |
|
|
|
209 |
area_stats= calculate_areas(final_img[slice, :, :], img_spacing, base_variables_len['Area']) |
|
|
210 |
volume_stats= calculate_volumes(final_img[slice, :, :], water_array[slice, :, :],fat_array[slice, :, :],img_spacing, base_variables_len['Volume'], weighted=False) |
|
|
211 |
weighted_volume_stats = calculate_volumes(final_img[slice, :, :], water_array[slice, :, :],fat_array[slice, :, :], img_spacing, base_variables_len['Volume'],weighted=True) |
|
|
212 |
|
|
|
213 |
area_initial_len = size_base * (i + 1) |
|
|
214 |
area_final_len = size_base * (i + 1) + base_variables_len['Area'] |
|
|
215 |
areas_residual=np.ones(base_variables_len['Area']) |
|
|
216 |
areas_residual[0]=residual |
|
|
217 |
|
|
|
218 |
if statiscs_matrix[0,area_initial_len+1] != 0: |
|
|
219 |
|
|
|
220 |
statiscs_matrix[0, area_initial_len:area_final_len] = statiscs_matrix[0,area_initial_len:area_final_len] + areas_residual * area_stats |
|
|
221 |
|
|
|
222 |
statiscs_matrix[0,area_initial_len+1] = statiscs_matrix[0,area_initial_len+1] / 2 |
|
|
223 |
statiscs_matrix[0, area_initial_len + 2] = statiscs_matrix[0, area_initial_len + 2] / 2 |
|
|
224 |
|
|
|
225 |
else: |
|
|
226 |
statiscs_matrix[0, area_initial_len:area_final_len] = statiscs_matrix[0,area_initial_len:area_final_len] + areas_residual * area_stats |
|
|
227 |
|
|
|
228 |
|
|
|
229 |
vol_final_len = area_final_len + base_variables_len['Volume'] |
|
|
230 |
|
|
|
231 |
statiscs_matrix[0, area_final_len:vol_final_len] = statiscs_matrix[0,area_final_len:vol_final_len] + residual * volume_stats |
|
|
232 |
|
|
|
233 |
if weighted: |
|
|
234 |
vol2_final_len = vol_final_len + base_variables_len['W_Volume'] |
|
|
235 |
|
|
|
236 |
statiscs_matrix[0, vol_final_len:vol2_final_len] = statiscs_matrix[0,vol_final_len:vol2_final_len] + residual * weighted_volume_stats |
|
|
237 |
|
|
|
238 |
|
|
|
239 |
residual_next_compartment=np.around(np.ceil(interval_steps[i+1])-interval_steps[i+1],decimals=2) |
|
|
240 |
|
|
|
241 |
|
|
|
242 |
area_initial_len = size_base * (i + 2) |
|
|
243 |
area_final_len = size_base * (i + 2) + base_variables_len['Area'] |
|
|
244 |
areas_residual=np.ones(base_variables_len['Area']) |
|
|
245 |
areas_residual[0]=residual_next_compartment |
|
|
246 |
|
|
|
247 |
if statiscs_matrix[0, area_initial_len + 1] != 0: |
|
|
248 |
statiscs_matrix[0, area_initial_len:area_final_len] = statiscs_matrix[0,area_initial_len:area_final_len] + areas_residual * area_stats |
|
|
249 |
|
|
|
250 |
statiscs_matrix[0,area_initial_len+1] = statiscs_matrix[0,area_initial_len+1] / 2 |
|
|
251 |
statiscs_matrix[0, area_initial_len + 2] = statiscs_matrix[0, area_initial_len + 2] / 2 |
|
|
252 |
|
|
|
253 |
else : |
|
|
254 |
statiscs_matrix[0, area_initial_len:area_final_len] = statiscs_matrix[0,area_initial_len:area_final_len] + areas_residual * area_stats |
|
|
255 |
|
|
|
256 |
vol_final_len = area_final_len + base_variables_len['Volume'] |
|
|
257 |
|
|
|
258 |
statiscs_matrix[0, area_final_len:vol_final_len] = statiscs_matrix[0,area_final_len:vol_final_len] + residual_next_compartment * volume_stats |
|
|
259 |
|
|
|
260 |
vol2_final_len = vol_final_len + base_variables_len['W_Volume'] |
|
|
261 |
|
|
|
262 |
statiscs_matrix[0, vol_final_len:vol2_final_len] = statiscs_matrix[0,vol_final_len:vol2_final_len] + residual_next_compartment * weighted_volume_stats |
|
|
263 |
|
|
|
264 |
return statiscs_matrix |
|
|
265 |
|
|
|
266 |
|
|
|
267 |
|
|
|
268 |
def calculate_statistics(final_img, water_array, fat_array, columns,base_variables_len,img_spacing,weighted=True): |
|
|
269 |
""" |
|
|
270 |
Release version |
|
|
271 |
:param final_img: |
|
|
272 |
:param water_array: |
|
|
273 |
:param fat_array: |
|
|
274 |
:param low_idx: |
|
|
275 |
:param high_idx: |
|
|
276 |
:param columns: |
|
|
277 |
:param base_variables_len: |
|
|
278 |
:param img_spacing: |
|
|
279 |
:param increase_thr: |
|
|
280 |
:param comparments: |
|
|
281 |
:param weighted: |
|
|
282 |
:return: |
|
|
283 |
""" |
|
|
284 |
print('-' * 30) |
|
|
285 |
print('Calculating Variables') |
|
|
286 |
print('-' * 30) |
|
|
287 |
|
|
|
288 |
statiscs_matrix = np.zeros((1, len(columns)),dtype=object) |
|
|
289 |
size_base=base_variables_len['Area']+base_variables_len['Volume']+base_variables_len['W_Volume'] |
|
|
290 |
|
|
|
291 |
|
|
|
292 |
#print('Whole Body') |
|
|
293 |
|
|
|
294 |
final_area=base_variables_len['Area'] |
|
|
295 |
statiscs_matrix[0, 0:final_area]=calculate_areas(final_img,img_spacing,base_variables_len['Area']) |
|
|
296 |
final_volume=final_area +base_variables_len['Volume'] |
|
|
297 |
statiscs_matrix[0,final_area:final_volume]=calculate_volumes(final_img,water_array,fat_array, |
|
|
298 |
img_spacing, base_variables_len['Volume'], weighted=False) |
|
|
299 |
|
|
|
300 |
|
|
|
301 |
if weighted: |
|
|
302 |
final_volume2= final_volume +base_variables_len['Volume'] |
|
|
303 |
statiscs_matrix[0,final_volume:final_volume2] = calculate_volumes(final_img,water_array,fat_array,img_spacing, |
|
|
304 |
base_variables_len['Volume'], |
|
|
305 |
weighted=True) |
|
|
306 |
return statiscs_matrix |