mediml 0.9.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- MEDiml/MEDscan.py +1696 -0
- MEDiml/__init__.py +21 -0
- MEDiml/biomarkers/BatchExtractor.py +806 -0
- MEDiml/biomarkers/BatchExtractorTexturalFilters.py +840 -0
- MEDiml/biomarkers/__init__.py +16 -0
- MEDiml/biomarkers/diagnostics.py +125 -0
- MEDiml/biomarkers/get_oriented_bound_box.py +158 -0
- MEDiml/biomarkers/glcm.py +1602 -0
- MEDiml/biomarkers/gldzm.py +523 -0
- MEDiml/biomarkers/glrlm.py +1315 -0
- MEDiml/biomarkers/glszm.py +555 -0
- MEDiml/biomarkers/int_vol_hist.py +527 -0
- MEDiml/biomarkers/intensity_histogram.py +615 -0
- MEDiml/biomarkers/local_intensity.py +89 -0
- MEDiml/biomarkers/morph.py +1756 -0
- MEDiml/biomarkers/ngldm.py +780 -0
- MEDiml/biomarkers/ngtdm.py +414 -0
- MEDiml/biomarkers/stats.py +373 -0
- MEDiml/biomarkers/utils.py +389 -0
- MEDiml/filters/TexturalFilter.py +299 -0
- MEDiml/filters/__init__.py +9 -0
- MEDiml/filters/apply_filter.py +134 -0
- MEDiml/filters/gabor.py +215 -0
- MEDiml/filters/laws.py +283 -0
- MEDiml/filters/log.py +147 -0
- MEDiml/filters/mean.py +121 -0
- MEDiml/filters/textural_filters_kernels.py +1738 -0
- MEDiml/filters/utils.py +107 -0
- MEDiml/filters/wavelet.py +237 -0
- MEDiml/learning/DataCleaner.py +198 -0
- MEDiml/learning/DesignExperiment.py +480 -0
- MEDiml/learning/FSR.py +667 -0
- MEDiml/learning/Normalization.py +112 -0
- MEDiml/learning/RadiomicsLearner.py +714 -0
- MEDiml/learning/Results.py +2237 -0
- MEDiml/learning/Stats.py +694 -0
- MEDiml/learning/__init__.py +10 -0
- MEDiml/learning/cleaning_utils.py +107 -0
- MEDiml/learning/ml_utils.py +1015 -0
- MEDiml/processing/__init__.py +6 -0
- MEDiml/processing/compute_suv_map.py +121 -0
- MEDiml/processing/discretisation.py +149 -0
- MEDiml/processing/interpolation.py +275 -0
- MEDiml/processing/resegmentation.py +66 -0
- MEDiml/processing/segmentation.py +912 -0
- MEDiml/utils/__init__.py +25 -0
- MEDiml/utils/batch_patients.py +45 -0
- MEDiml/utils/create_radiomics_table.py +131 -0
- MEDiml/utils/data_frame_export.py +42 -0
- MEDiml/utils/find_process_names.py +16 -0
- MEDiml/utils/get_file_paths.py +34 -0
- MEDiml/utils/get_full_rad_names.py +21 -0
- MEDiml/utils/get_institutions_from_ids.py +16 -0
- MEDiml/utils/get_patient_id_from_scan_name.py +22 -0
- MEDiml/utils/get_patient_names.py +26 -0
- MEDiml/utils/get_radiomic_names.py +27 -0
- MEDiml/utils/get_scan_name_from_rad_name.py +22 -0
- MEDiml/utils/image_reader_SITK.py +37 -0
- MEDiml/utils/image_volume_obj.py +22 -0
- MEDiml/utils/imref.py +340 -0
- MEDiml/utils/initialize_features_names.py +62 -0
- MEDiml/utils/inpolygon.py +159 -0
- MEDiml/utils/interp3.py +43 -0
- MEDiml/utils/json_utils.py +78 -0
- MEDiml/utils/mode.py +31 -0
- MEDiml/utils/parse_contour_string.py +58 -0
- MEDiml/utils/save_MEDscan.py +30 -0
- MEDiml/utils/strfind.py +32 -0
- MEDiml/utils/textureTools.py +188 -0
- MEDiml/utils/texture_features_names.py +115 -0
- MEDiml/utils/write_radiomics_csv.py +47 -0
- MEDiml/wrangling/DataManager.py +1724 -0
- MEDiml/wrangling/ProcessDICOM.py +512 -0
- MEDiml/wrangling/__init__.py +3 -0
- mediml-0.9.9.dist-info/LICENSE.md +674 -0
- mediml-0.9.9.dist-info/METADATA +232 -0
- mediml-0.9.9.dist-info/RECORD +78 -0
- mediml-0.9.9.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,615 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
import warnings
|
|
5
|
+
from typing import Dict, Tuple
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
from scipy.stats import scoreatpercentile, variation
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def init_IH(vol: np.ndarray) -> Tuple[np.ndarray, np.ndarray, int, np.ndarray, np.ndarray]:
|
|
12
|
+
"""Initialize Intensity Histogram Features.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
vol (ndarray): 3D volume, QUANTIZED (e.g. nBins = 100,
|
|
16
|
+
levels = [1, ..., max]), with NaNs outside the region of interest.
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
Dict: Dict of the Intensity Histogram Features.
|
|
20
|
+
"""
|
|
21
|
+
warnings.simplefilter("ignore")
|
|
22
|
+
|
|
23
|
+
# INITIALIZATION
|
|
24
|
+
|
|
25
|
+
x = vol[~np.isnan(vol[:])]
|
|
26
|
+
n_v = x.size
|
|
27
|
+
|
|
28
|
+
# CONSTRUCTION OF HISTOGRAM AND ASSOCIATED NUMBER OF GRAY-LEVELS
|
|
29
|
+
|
|
30
|
+
# Always defined from 1 to the maximum value of
|
|
31
|
+
# the volume to remove any ambiguity
|
|
32
|
+
levels = np.arange(1, np.max(x) + 100*np.finfo(float).eps)
|
|
33
|
+
n_g = levels.size # Number of gray-levels
|
|
34
|
+
h = np.zeros(n_g) # The histogram of x
|
|
35
|
+
|
|
36
|
+
for i in np.arange(0, n_g):
|
|
37
|
+
# == i or == levels(i) is equivalent since levels = 1:max(x),
|
|
38
|
+
# and n_g = numel(levels)
|
|
39
|
+
h[i] = np.sum(x == i + 1) # h[i] = sum(x == i+1)
|
|
40
|
+
|
|
41
|
+
p = (h / n_v) # Occurence probability for each grey level bin i
|
|
42
|
+
pt = p.transpose()
|
|
43
|
+
|
|
44
|
+
return x, levels, n_g, h, p, pt
|
|
45
|
+
|
|
46
|
+
def extract_all(vol: np.ndarray) -> Dict:
|
|
47
|
+
"""Computes Intensity Histogram Features.
|
|
48
|
+
These features refer to Intensity histogram family in
|
|
49
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
vol (ndarray): 3D volume, QUANTIZED (e.g. nBins = 100,
|
|
53
|
+
levels = [1, ..., max]), with NaNs outside the region of interest.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
Dict: Dict of the Intensity Histogram Features.
|
|
57
|
+
"""
|
|
58
|
+
warnings.simplefilter("ignore")
|
|
59
|
+
|
|
60
|
+
# INITIALIZATION
|
|
61
|
+
x, levels, n_g, h, p, pt = init_IH(vol)
|
|
62
|
+
|
|
63
|
+
# Initialization of final structure (Dictionary) containing all features.
|
|
64
|
+
int_hist = {'Fih_mean': [],
|
|
65
|
+
'Fih_var': [],
|
|
66
|
+
'Fih_skew': [],
|
|
67
|
+
'Fih_kurt': [],
|
|
68
|
+
'Fih_median': [],
|
|
69
|
+
'Fih_min': [],
|
|
70
|
+
'Fih_P10': [],
|
|
71
|
+
'Fih_P90': [],
|
|
72
|
+
'Fih_max': [],
|
|
73
|
+
'Fih_mode': [],
|
|
74
|
+
'Fih_iqr': [],
|
|
75
|
+
'Fih_range': [],
|
|
76
|
+
'Fih_mad': [],
|
|
77
|
+
'Fih_rmad': [],
|
|
78
|
+
'Fih_medad': [],
|
|
79
|
+
'Fih_cov': [],
|
|
80
|
+
'Fih_qcod': [],
|
|
81
|
+
'Fih_entropy': [],
|
|
82
|
+
'Fih_uniformity': [],
|
|
83
|
+
'Fih_max_grad': [],
|
|
84
|
+
'Fih_max_grad_gl': [],
|
|
85
|
+
'Fih_min_grad': [],
|
|
86
|
+
'Fih_min_grad_gl': []
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# STARTING COMPUTATION
|
|
90
|
+
# Intensity histogram mean
|
|
91
|
+
u = np.matmul(levels, pt)
|
|
92
|
+
int_hist['Fih_mean'] = u
|
|
93
|
+
|
|
94
|
+
# Intensity histogram variance
|
|
95
|
+
var = np.matmul(np.power(levels - u, 2), pt)
|
|
96
|
+
int_hist['Fih_var'] = var
|
|
97
|
+
|
|
98
|
+
# Intensity histogram skewness and kurtosis
|
|
99
|
+
skew = 0
|
|
100
|
+
kurt = 0
|
|
101
|
+
|
|
102
|
+
if var != 0:
|
|
103
|
+
skew = np.matmul(np.power(levels - u, 3), pt) / np.power(var, 3/2)
|
|
104
|
+
kurt = np.matmul(np.power(levels - u, 4), pt) / np.power(var, 2) - 3
|
|
105
|
+
|
|
106
|
+
int_hist['Fih_skew'] = skew
|
|
107
|
+
int_hist['Fih_kurt'] = kurt
|
|
108
|
+
|
|
109
|
+
# Intensity histogram median
|
|
110
|
+
int_hist['Fih_median'] = np.median(x)
|
|
111
|
+
|
|
112
|
+
# Intensity histogram minimum grey level
|
|
113
|
+
int_hist['Fih_min'] = np.min(x)
|
|
114
|
+
|
|
115
|
+
# Intensity histogram 10th percentile
|
|
116
|
+
p10 = scoreatpercentile(x, 10)
|
|
117
|
+
int_hist['Fih_P10'] = p10
|
|
118
|
+
|
|
119
|
+
# Intensity histogram 90th percentile
|
|
120
|
+
p90 = scoreatpercentile(x, 90)
|
|
121
|
+
int_hist['Fih_P90'] = p90
|
|
122
|
+
|
|
123
|
+
# Intensity histogram maximum grey level
|
|
124
|
+
int_hist['Fih_max'] = np.max(x)
|
|
125
|
+
|
|
126
|
+
# Intensity histogram mode
|
|
127
|
+
# levels = 1:max(x), so the index of the ith bin of h is the same as i
|
|
128
|
+
mh = np.max(h)
|
|
129
|
+
mode = np.where(h == mh)[0] + 1
|
|
130
|
+
|
|
131
|
+
if np.size(mode) > 1:
|
|
132
|
+
dist = np.abs(mode - u)
|
|
133
|
+
ind_min = np.argmin(dist)
|
|
134
|
+
int_hist['Fih_mode'] = mode[ind_min]
|
|
135
|
+
else:
|
|
136
|
+
int_hist['Fih_mode'] = mode[0]
|
|
137
|
+
|
|
138
|
+
# Intensity histogram interquantile range
|
|
139
|
+
# Since x goes from 1:max(x), all with integer values,
|
|
140
|
+
# the result is an integer
|
|
141
|
+
int_hist['Fih_iqr'] = scoreatpercentile(x, 75) - scoreatpercentile(x, 25)
|
|
142
|
+
|
|
143
|
+
# Intensity histogram range
|
|
144
|
+
int_hist['Fih_range'] = np.max(x) - np.min(x)
|
|
145
|
+
|
|
146
|
+
# Intensity histogram mean absolute deviation
|
|
147
|
+
int_hist['Fih_mad'] = np.mean(abs(x - u))
|
|
148
|
+
|
|
149
|
+
# Intensity histogram robust mean absolute deviation
|
|
150
|
+
x_10_90 = x[np.where((x >= p10) & (x <= p90), True, False)]
|
|
151
|
+
int_hist['Fih_rmad'] = np.mean(np.abs(x_10_90 - np.mean(x_10_90)))
|
|
152
|
+
|
|
153
|
+
# Intensity histogram median absolute deviation
|
|
154
|
+
int_hist['Fih_medad'] = np.mean(np.absolute(x - np.median(x)))
|
|
155
|
+
|
|
156
|
+
# Intensity histogram coefficient of variation
|
|
157
|
+
int_hist['Fih_cov'] = variation(x)
|
|
158
|
+
|
|
159
|
+
# Intensity histogram quartile coefficient of dispersion
|
|
160
|
+
x_75_25 = scoreatpercentile(x, 75) + scoreatpercentile(x, 25)
|
|
161
|
+
int_hist['Fih_qcod'] = int_hist['Fih_iqr'] / x_75_25
|
|
162
|
+
|
|
163
|
+
# Intensity histogram entropy
|
|
164
|
+
p = p[p > 0]
|
|
165
|
+
int_hist['Fih_entropy'] = -np.sum(p * np.log2(p))
|
|
166
|
+
|
|
167
|
+
# Intensity histogram uniformity
|
|
168
|
+
int_hist['Fih_uniformity'] = np.sum(np.power(p, 2))
|
|
169
|
+
|
|
170
|
+
# Calculation of histogram gradient
|
|
171
|
+
hist_grad = np.zeros(n_g)
|
|
172
|
+
hist_grad[0] = h[1] - h[0]
|
|
173
|
+
hist_grad[-1] = h[-1] - h[-2]
|
|
174
|
+
|
|
175
|
+
for i in np.arange(1, n_g-1):
|
|
176
|
+
hist_grad[i] = (h[i+1] - h[i-1])/2
|
|
177
|
+
|
|
178
|
+
# Maximum histogram gradient
|
|
179
|
+
int_hist['Fih_max_grad'] = np.max(hist_grad)
|
|
180
|
+
|
|
181
|
+
# Maximum histogram gradient grey level
|
|
182
|
+
ind_max = np.where(hist_grad == int_hist['Fih_max_grad'])[0][0]
|
|
183
|
+
int_hist['Fih_max_grad_gl'] = levels[ind_max]
|
|
184
|
+
|
|
185
|
+
# Minimum histogram gradient
|
|
186
|
+
int_hist['Fih_min_grad'] = np.min(hist_grad)
|
|
187
|
+
|
|
188
|
+
# Minimum histogram gradient grey level
|
|
189
|
+
ind_min = np.where(hist_grad == int_hist['Fih_min_grad'])[0][0]
|
|
190
|
+
int_hist['Fih_min_grad_gl'] = levels[ind_min]
|
|
191
|
+
|
|
192
|
+
return int_hist
|
|
193
|
+
|
|
194
|
+
def mean(vol: np.ndarray) -> float:
|
|
195
|
+
"""Compute Intensity histogram mean feature of the input dataset (3D Array).
|
|
196
|
+
This feature refers to "Fih_mean" (ID = X6K6) in
|
|
197
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
201
|
+
(continuous imaging intensity distribution)
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
float: Intensity histogram mean
|
|
205
|
+
"""
|
|
206
|
+
_, levels, _, _, _, pt = init_IH(vol) # Initialization
|
|
207
|
+
|
|
208
|
+
return np.matmul(levels, pt) # Intensity histogram mean
|
|
209
|
+
|
|
210
|
+
def var(vol: np.ndarray) -> float:
|
|
211
|
+
"""Compute Intensity histogram variance feature of the input dataset (3D Array).
|
|
212
|
+
This feature refers to "Fih_var" (ID = CH89) in
|
|
213
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
217
|
+
(continuous imaging intensity distribution)
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
float: Intensity histogram variance
|
|
221
|
+
"""
|
|
222
|
+
_, levels, _, _, _, pt = init_IH(vol) # Initialization
|
|
223
|
+
u = np.matmul(levels, pt) # Intensity histogram mean
|
|
224
|
+
|
|
225
|
+
return np.matmul(np.power(levels - u, 2), pt) # Intensity histogram variance
|
|
226
|
+
|
|
227
|
+
def skewness(vol: np.ndarray) -> float:
|
|
228
|
+
"""Compute Intensity histogram skewness feature of the input dataset (3D Array).
|
|
229
|
+
This feature refers to "Fih_skew" (ID = 88K1) in
|
|
230
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
231
|
+
|
|
232
|
+
Args:
|
|
233
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
234
|
+
(continuous imaging intensity distribution)
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
float: Intensity histogram skewness.
|
|
238
|
+
"""
|
|
239
|
+
_, levels, _, _, _, pt = init_IH(vol) # Initialization
|
|
240
|
+
u = np.matmul(levels, pt) # Intensity histogram mean
|
|
241
|
+
var = np.matmul(np.power(levels - u, 2), pt) # Intensity histogram variance
|
|
242
|
+
if var != 0:
|
|
243
|
+
skew = np.matmul(np.power(levels - u, 3), pt) / np.power(var, 3/2)
|
|
244
|
+
|
|
245
|
+
return skew # Skewness
|
|
246
|
+
|
|
247
|
+
def kurt(vol: np.ndarray) -> float:
|
|
248
|
+
"""Compute Intensity histogram kurtosis feature of the input dataset (3D Array).
|
|
249
|
+
This feature refers to "Fih_kurt" (ID = C3I7) in
|
|
250
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
254
|
+
(continuous imaging intensity distribution)
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
float: The Intensity histogram kurtosis feature
|
|
258
|
+
"""
|
|
259
|
+
_, levels, _, _, _, pt = init_IH(vol) # Initialization
|
|
260
|
+
u = np.matmul(levels, pt) # Intensity histogram mean
|
|
261
|
+
var = np.matmul(np.power(levels - u, 2), pt) # Intensity histogram variance
|
|
262
|
+
if var != 0:
|
|
263
|
+
kurt = np.matmul(np.power(levels - u, 4), pt) / np.power(var, 2) - 3
|
|
264
|
+
|
|
265
|
+
return kurt # Kurtosis
|
|
266
|
+
|
|
267
|
+
def median(vol: np.ndarray) -> float:
|
|
268
|
+
"""Compute Intensity histogram median feature along the specified axis of the input dataset (3D Array).
|
|
269
|
+
This feature refers to "Fih_median" (ID = WIFQ) in
|
|
270
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
271
|
+
|
|
272
|
+
Args:
|
|
273
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
274
|
+
(continuous imaging intensity distribution)
|
|
275
|
+
|
|
276
|
+
Returns:
|
|
277
|
+
float: Intensity histogram median feature.
|
|
278
|
+
"""
|
|
279
|
+
x = vol[~np.isnan(vol[:])] # Initialization
|
|
280
|
+
|
|
281
|
+
return np.median(x) # Median
|
|
282
|
+
|
|
283
|
+
def min(vol: np.ndarray) -> float:
|
|
284
|
+
"""Compute Intensity histogram minimum grey level feature of the input dataset (3D Array).
|
|
285
|
+
This feature refers to "Fih_min" (ID = 1PR8) in
|
|
286
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
290
|
+
(continuous imaging intensity distribution)
|
|
291
|
+
|
|
292
|
+
Returns:
|
|
293
|
+
float: Intensity histogram minimum grey level feature.
|
|
294
|
+
"""
|
|
295
|
+
x = vol[~np.isnan(vol[:])] # Initialization
|
|
296
|
+
|
|
297
|
+
return np.min(x) # Minimum grey level
|
|
298
|
+
|
|
299
|
+
def p10(vol: np.ndarray) -> float:
|
|
300
|
+
"""Compute Intensity histogram 10th percentile feature of the input dataset (3D Array).
|
|
301
|
+
This feature refers to "Fih_P10" (ID = GPMT) in
|
|
302
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
306
|
+
(continuous imaging intensity distribution)
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
float: Intensity histogram 10th percentile feature.
|
|
310
|
+
"""
|
|
311
|
+
x = vol[~np.isnan(vol[:])] # Initialization
|
|
312
|
+
|
|
313
|
+
return scoreatpercentile(x, 10) # 10th percentile
|
|
314
|
+
|
|
315
|
+
def p90(vol: np.ndarray) -> float:
|
|
316
|
+
"""Compute Intensity histogram 90th percentile feature of the input dataset (3D Array).
|
|
317
|
+
This feature refers to "Fih_P90" (ID = OZ0C) in
|
|
318
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
322
|
+
(continuous imaging intensity distribution)
|
|
323
|
+
Returns:
|
|
324
|
+
float: Intensity histogram 90th percentile feature.
|
|
325
|
+
"""
|
|
326
|
+
x = vol[~np.isnan(vol[:])] # Initialization
|
|
327
|
+
|
|
328
|
+
return scoreatpercentile(x, 90) # 90th percentile
|
|
329
|
+
|
|
330
|
+
def max(vol: np.ndarray) -> float:
|
|
331
|
+
"""Compute Intensity histogram maximum grey level feature of the input dataset (3D Array).
|
|
332
|
+
This feature refers to "Fih_max" (ID = 3NCY) in
|
|
333
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
334
|
+
|
|
335
|
+
Args:
|
|
336
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
337
|
+
(continuous imaging intensity distribution)
|
|
338
|
+
|
|
339
|
+
Returns:
|
|
340
|
+
float: Intensity histogram maximum grey level feature.
|
|
341
|
+
"""
|
|
342
|
+
x = vol[~np.isnan(vol[:])] # Initialization
|
|
343
|
+
|
|
344
|
+
return np.max(x) # Maximum grey level
|
|
345
|
+
|
|
346
|
+
def mode(vol: np.ndarray) -> int:
|
|
347
|
+
"""Compute Intensity histogram mode feature of the input dataset (3D Array).
|
|
348
|
+
This feature refers to "Fih_mode" (ID = AMMC) in
|
|
349
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
350
|
+
|
|
351
|
+
Args:
|
|
352
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
353
|
+
(continuous imaging intensity distribution)
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
integer: Intensity histogram mode.
|
|
357
|
+
levels = 1:max(x), so the index of the ith bin of h is the same as i
|
|
358
|
+
"""
|
|
359
|
+
_, levels, _, h, _, pt = init_IH(vol) # Initialization
|
|
360
|
+
u = np.matmul(levels, pt)
|
|
361
|
+
mh = np.max(h)
|
|
362
|
+
mode = np.where(h == mh)[0] + 1
|
|
363
|
+
|
|
364
|
+
if np.size(mode) > 1:
|
|
365
|
+
dist = np.abs(mode - u)
|
|
366
|
+
ind_min = np.argmin(dist)
|
|
367
|
+
|
|
368
|
+
return mode[ind_min] # Intensity histogram mode.
|
|
369
|
+
else:
|
|
370
|
+
|
|
371
|
+
return mode[0] # Intensity histogram mode.
|
|
372
|
+
|
|
373
|
+
def iqrange(vol: np.ndarray) -> float:
|
|
374
|
+
r"""Compute Intensity histogram interquantile range feature of the input dataset (3D Array).
|
|
375
|
+
This feature refers to "Fih_iqr" (ID = WR0O) in
|
|
376
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
377
|
+
|
|
378
|
+
Args:
|
|
379
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
380
|
+
(continuous imaging intensity distribution)
|
|
381
|
+
|
|
382
|
+
Returns:
|
|
383
|
+
float: Interquartile range. If :math:`axis ≠ None` , the output data-type is the same as that of the input.
|
|
384
|
+
Since x goes from :math:`1:max(x)` , all with integer values, the result is an integer.
|
|
385
|
+
"""
|
|
386
|
+
x = vol[~np.isnan(vol[:])] # Initialization
|
|
387
|
+
|
|
388
|
+
return scoreatpercentile(x, 75) - scoreatpercentile(x, 25) # Intensity histogram interquantile range
|
|
389
|
+
|
|
390
|
+
def range(vol: np.ndarray) -> float:
|
|
391
|
+
"""Compute Intensity histogram range of values (maximum - minimum) feature of the input dataset (3D Array).
|
|
392
|
+
This feature refers to "Fih_range" (ID = 5Z3W) in
|
|
393
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
394
|
+
|
|
395
|
+
Args:
|
|
396
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
397
|
+
(continuous imaging intensity distribution)
|
|
398
|
+
|
|
399
|
+
Returns:
|
|
400
|
+
float: Intensity histogram range.
|
|
401
|
+
"""
|
|
402
|
+
x = vol[~np.isnan(vol[:])] # Initialization
|
|
403
|
+
|
|
404
|
+
return np.max(x) - np.min(x) # Intensity histogram range
|
|
405
|
+
|
|
406
|
+
def mad(vol: np.ndarray) -> float:
|
|
407
|
+
"""Compute Intensity histogram mean absolute deviation feature of the input dataset (3D Array).
|
|
408
|
+
This feature refers to "Fih_mad" (ID = D2ZX) in
|
|
409
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
410
|
+
|
|
411
|
+
Args:
|
|
412
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
413
|
+
(continuous imaging intensity distribution)
|
|
414
|
+
|
|
415
|
+
Returns:
|
|
416
|
+
float : Intensity histogram mean absolute deviation feature.
|
|
417
|
+
"""
|
|
418
|
+
x, levels, _, _, _, pt = init_IH(vol) # Initialization
|
|
419
|
+
u = np.matmul(levels, pt)
|
|
420
|
+
|
|
421
|
+
return np.mean(abs(x - u)) # Intensity histogram mean absolute deviation
|
|
422
|
+
|
|
423
|
+
def rmad(vol: np.ndarray) -> float:
|
|
424
|
+
"""Compute Intensity histogram robust mean absolute deviation feature of the input dataset (3D Array).
|
|
425
|
+
This feature refers to "Fih_rmad" (ID = WRZB) in
|
|
426
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
427
|
+
|
|
428
|
+
Args:
|
|
429
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
430
|
+
(continuous imaging intensity distribution)
|
|
431
|
+
P10(ndarray): Score at 10th percentil.
|
|
432
|
+
P90(ndarray): Score at 90th percentil.
|
|
433
|
+
|
|
434
|
+
Returns:
|
|
435
|
+
float: Intensity histogram robust mean absolute deviation
|
|
436
|
+
"""
|
|
437
|
+
x = vol[~np.isnan(vol[:])] # Initialization
|
|
438
|
+
P10 = scoreatpercentile(x, 10) # 10th percentile
|
|
439
|
+
P90 = scoreatpercentile(x, 90) # 90th percentile
|
|
440
|
+
x_10_90 = x[np.where((x >= P10) &
|
|
441
|
+
(x <= P90), True, False)] # Holding x for (x >= P10) and (x<= P90)
|
|
442
|
+
|
|
443
|
+
return np.mean(np.abs(x_10_90 - np.mean(x_10_90))) # Intensity histogram robust mean absolute deviation
|
|
444
|
+
|
|
445
|
+
def medad(vol: np.ndarray) -> float:
|
|
446
|
+
"""Intensity histogram median absolute deviation feature of the input dataset (3D Array).
|
|
447
|
+
This feature refers to "Fih_medad" (ID = 4RNL) in
|
|
448
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
449
|
+
|
|
450
|
+
Args:
|
|
451
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
452
|
+
(continuous imaging intensity distribution)
|
|
453
|
+
|
|
454
|
+
Returns:
|
|
455
|
+
float: Intensity histogram median absolute deviation feature.
|
|
456
|
+
"""
|
|
457
|
+
x = vol[~np.isnan(vol[:])] # Initialization
|
|
458
|
+
|
|
459
|
+
return np.mean(np.absolute(x - np.median(x))) # Intensity histogram median absolute deviation
|
|
460
|
+
|
|
461
|
+
def cov(vol: np.ndarray) -> float:
|
|
462
|
+
"""Compute Intensity histogram coefficient of variation feature of the input dataset (3D Array).
|
|
463
|
+
This feature refers to "Fih_cov" (ID = CWYJ) in
|
|
464
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
465
|
+
|
|
466
|
+
Args:
|
|
467
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
468
|
+
(continuous imaging intensity distribution)
|
|
469
|
+
|
|
470
|
+
Returns:
|
|
471
|
+
float: Intensity histogram coefficient of variation feature.
|
|
472
|
+
"""
|
|
473
|
+
x = vol[~np.isnan(vol[:])] # Initialization
|
|
474
|
+
|
|
475
|
+
return variation(x) # Intensity histogram coefficient of variation
|
|
476
|
+
|
|
477
|
+
def qcod(vol: np.ndarray) -> float:
|
|
478
|
+
"""Compute the quartile coefficient of dispersion feature of the input dataset (3D Array).
|
|
479
|
+
This feature refers to "Fih_qcod" (ID = SLWD) in
|
|
480
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
481
|
+
|
|
482
|
+
Args:
|
|
483
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
484
|
+
(continuous imaging intensity distribution)
|
|
485
|
+
|
|
486
|
+
Returns:
|
|
487
|
+
ndarray: A new array holding the quartile coefficient of dispersion feature.
|
|
488
|
+
"""
|
|
489
|
+
x = vol[~np.isnan(vol[:])] # Initialization
|
|
490
|
+
x_75_25 = scoreatpercentile(x, 75) + scoreatpercentile(x, 25)
|
|
491
|
+
|
|
492
|
+
return iqrange(x) / x_75_25 # Quartile coefficient of dispersion
|
|
493
|
+
|
|
494
|
+
def entropy(vol: np.ndarray) -> float:
|
|
495
|
+
"""Compute Intensity histogram entropy feature of the input dataset (3D Array).
|
|
496
|
+
This feature refers to "Fih_entropy" (ID = TLU2) in
|
|
497
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
498
|
+
|
|
499
|
+
Args:
|
|
500
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
501
|
+
(continuous imaging intensity distribution)
|
|
502
|
+
|
|
503
|
+
Returns:
|
|
504
|
+
float: Intensity histogram entropy feature.
|
|
505
|
+
"""
|
|
506
|
+
x, _, _, _, p, _ = init_IH(vol) # Initialization
|
|
507
|
+
p = p[p > 0]
|
|
508
|
+
|
|
509
|
+
return -np.sum(p * np.log2(p)) # Intensity histogram entropy
|
|
510
|
+
|
|
511
|
+
def uniformity(vol: np.ndarray) -> float:
|
|
512
|
+
"""Compute Intensity histogram uniformity feature of the input dataset (3D Array).
|
|
513
|
+
This feature refers to "Fih_uniformity" (ID = BJ5W) in
|
|
514
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
515
|
+
|
|
516
|
+
Args:
|
|
517
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
518
|
+
(continuous imaging intensity distribution)
|
|
519
|
+
|
|
520
|
+
Returns:
|
|
521
|
+
float: Intensity histogram uniformity feature.
|
|
522
|
+
"""
|
|
523
|
+
x, _, _, _, p, _ = init_IH(vol) # Initialization
|
|
524
|
+
p = p[p > 0]
|
|
525
|
+
|
|
526
|
+
return np.sum(np.power(p, 2)) # Intensity histogram uniformity
|
|
527
|
+
|
|
528
|
+
def hist_grad_calc(vol: np.ndarray) -> np.ndarray:
|
|
529
|
+
"""Calculation of histogram gradient.
|
|
530
|
+
This feature refers to "Fih_hist_grad_calc" (ID = 12CE) in
|
|
531
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
532
|
+
|
|
533
|
+
Args:
|
|
534
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
535
|
+
(continuous imaging intensity distribution)
|
|
536
|
+
|
|
537
|
+
Returns:
|
|
538
|
+
ndarray: Histogram gradient
|
|
539
|
+
"""
|
|
540
|
+
_, _, n_g, h, _, _ = init_IH(vol) # Initialization
|
|
541
|
+
hist_grad = np.zeros(n_g)
|
|
542
|
+
hist_grad[0] = h[1] - h[0]
|
|
543
|
+
hist_grad[-1] = h[-1] - h[-2]
|
|
544
|
+
for i in np.arange(1, n_g-1):
|
|
545
|
+
hist_grad[i] = (h[i+1] - h[i-1])/2
|
|
546
|
+
|
|
547
|
+
return hist_grad # Intensity histogram uniformity
|
|
548
|
+
|
|
549
|
+
def max_grad(vol: np.ndarray) -> float:
|
|
550
|
+
"""Calculation of Maximum histogram gradient feature.
|
|
551
|
+
This feature refers to "Fih_max_grad" (ID = 12CE) in
|
|
552
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
553
|
+
|
|
554
|
+
Args:
|
|
555
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
556
|
+
(continuous imaging intensity distribution)
|
|
557
|
+
|
|
558
|
+
Returns:
|
|
559
|
+
float: Maximum histogram gradient feature.
|
|
560
|
+
"""
|
|
561
|
+
hist_grad = hist_grad_calc(vol) # Initialization
|
|
562
|
+
|
|
563
|
+
return np.max(hist_grad) # Maximum histogram gradient
|
|
564
|
+
|
|
565
|
+
def max_grad_gl(vol: np.ndarray) -> float:
|
|
566
|
+
"""Calculation of Maximum histogram gradient grey level feature.
|
|
567
|
+
This feature refers to "Fih_max_grad_gl" (ID = 8E6O) in
|
|
568
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
569
|
+
|
|
570
|
+
Args:
|
|
571
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
572
|
+
(continuous imaging intensity distribution)
|
|
573
|
+
|
|
574
|
+
Returns:
|
|
575
|
+
float: Maximum histogram gradient grey level feature.
|
|
576
|
+
"""
|
|
577
|
+
_, levels, _, _, _, _ = init_IH(vol) # Initialization
|
|
578
|
+
hist_grad = hist_grad_calc(vol)
|
|
579
|
+
ind_max = np.where(hist_grad == np.max(hist_grad))[0][0]
|
|
580
|
+
|
|
581
|
+
return levels[ind_max] # Maximum histogram gradient grey level
|
|
582
|
+
|
|
583
|
+
def min_grad(vol: np.ndarray) -> float:
|
|
584
|
+
"""Calculation of Minimum histogram gradient feature.
|
|
585
|
+
This feature refers to "Fih_min_grad" (ID = VQB3) in
|
|
586
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
587
|
+
|
|
588
|
+
Args:
|
|
589
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
590
|
+
(continuous imaging intensity distribution)
|
|
591
|
+
|
|
592
|
+
Returns:
|
|
593
|
+
float: Minimum histogram gradient feature.
|
|
594
|
+
"""
|
|
595
|
+
hist_grad = hist_grad_calc(vol) # Initialization
|
|
596
|
+
|
|
597
|
+
return np.min(hist_grad) # Minimum histogram gradient
|
|
598
|
+
|
|
599
|
+
def min_grad_gl(vol: np.ndarray) -> float:
|
|
600
|
+
"""Calculation of Minimum histogram gradient grey level feature.
|
|
601
|
+
This feature refers to "Fih_min_grad_gl" (ID = RHQZ) in
|
|
602
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
603
|
+
|
|
604
|
+
Args:
|
|
605
|
+
vol(ndarray): 3D volume, NON-QUANTIZED, with NaNs outside the region of interest
|
|
606
|
+
(continuous imaging intensity distribution)
|
|
607
|
+
|
|
608
|
+
Returns:
|
|
609
|
+
float: Minimum histogram gradient grey level feature.
|
|
610
|
+
"""
|
|
611
|
+
_, levels, _, _, _, _ = init_IH(vol) # Initialization
|
|
612
|
+
hist_grad = hist_grad_calc(vol)
|
|
613
|
+
ind_min = np.where(hist_grad == np.min(hist_grad))[0][0]
|
|
614
|
+
|
|
615
|
+
return levels[ind_min] # Minimum histogram gradient grey level
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
from numpy import ndarray
|
|
7
|
+
|
|
8
|
+
from ..biomarkers.utils import get_glob_peak, get_loc_peak
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def extract_all(img_obj: ndarray,
|
|
12
|
+
roi_obj: ndarray,
|
|
13
|
+
res: ndarray,
|
|
14
|
+
intensity_type: str,
|
|
15
|
+
compute_global: bool = False) -> Dict:
|
|
16
|
+
"""Compute Local Intensity Features.
|
|
17
|
+
This features refer to Local Intensity family in
|
|
18
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
img_obj (ndarray): Continuous image intensity distribution, with no NaNs
|
|
22
|
+
outside the ROI.
|
|
23
|
+
roi_obj (ndarray): Array of the mask defining the ROI.
|
|
24
|
+
res (List[float]): [a,b,c] vector specifying the resolution of the volume in mm.
|
|
25
|
+
XYZ resolution (world), or JIK resolution (intrinsic matlab).
|
|
26
|
+
intensity_type (str): Type of intensity to compute. Can be "arbitrary", "definite" or "filtered".
|
|
27
|
+
Will compute features only for "definite" intensity type.
|
|
28
|
+
compute_global (bool, optional): If True, will compute global intensity peak, we
|
|
29
|
+
recommend you don't set it to True if not necessary in your study or analysis as it
|
|
30
|
+
takes too much time for calculation. Default: False.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
Dict: Dict of the Local Intensity Features.
|
|
34
|
+
|
|
35
|
+
Raises:
|
|
36
|
+
ValueError: If `intensity_type` is not "arbitrary", "definite" or "filtered".
|
|
37
|
+
"""
|
|
38
|
+
assert intensity_type in ["arbitrary", "definite", "filtered"], \
|
|
39
|
+
"intensity_type must be 'arbitrary', 'definite' or 'filtered'"
|
|
40
|
+
|
|
41
|
+
loc_int = {'Floc_peak_local': [], 'Floc_peak_global': []}
|
|
42
|
+
|
|
43
|
+
if intensity_type == "definite":
|
|
44
|
+
loc_int['Floc_peak_local'] = (get_loc_peak(img_obj, roi_obj, res))
|
|
45
|
+
|
|
46
|
+
# NEEDS TO BE VECTORIZED FOR FASTER CALCULATION! OR
|
|
47
|
+
# SIMPLY JUST CONVOLUTE A 3D AVERAGING FILTER!
|
|
48
|
+
if compute_global:
|
|
49
|
+
loc_int['Floc_peak_global'] = (get_glob_peak(img_obj,roi_obj, res))
|
|
50
|
+
|
|
51
|
+
return loc_int
|
|
52
|
+
|
|
53
|
+
def peak_local(img_obj: ndarray,
|
|
54
|
+
roi_obj: ndarray,
|
|
55
|
+
res: ndarray) -> float:
|
|
56
|
+
"""Computes local intensity peak.
|
|
57
|
+
This feature refers to "Floc_peak_local" (ID = VJGA) in
|
|
58
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
img_obj (ndarray): Continuous image intensity distribution, with no NaNs
|
|
62
|
+
outside the ROI.
|
|
63
|
+
roi_obj (ndarray): Array of the mask defining the ROI.
|
|
64
|
+
res (List[float]): [a,b,c] vector specifying the resolution of the volume in mm.
|
|
65
|
+
XYZ resolution (world), or JIK resolution (intrinsic matlab).
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
float: Local intensity peak.
|
|
69
|
+
"""
|
|
70
|
+
return get_loc_peak(img_obj, roi_obj, res)
|
|
71
|
+
|
|
72
|
+
def peak_global(img_obj: ndarray,
|
|
73
|
+
roi_obj: ndarray,
|
|
74
|
+
res: ndarray) -> float:
|
|
75
|
+
"""Computes global intensity peak.
|
|
76
|
+
This feature refers to "Floc_peak_global" (ID = 0F91) in
|
|
77
|
+
the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
img_obj (ndarray): Continuous image intensity distribution, with no NaNs
|
|
81
|
+
outside the ROI.
|
|
82
|
+
roi_obj (ndarray): Array of the mask defining the ROI.
|
|
83
|
+
res (List[float]): [a,b,c] vector specifying the resolution of the volume in mm.
|
|
84
|
+
XYZ resolution (world), or JIK resolution (intrinsic matlab).
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
float: Global intensity peak.
|
|
88
|
+
"""
|
|
89
|
+
return get_glob_peak(img_obj, roi_obj, res)
|