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