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.
Files changed (78) hide show
  1. MEDiml/MEDscan.py +1696 -0
  2. MEDiml/__init__.py +21 -0
  3. MEDiml/biomarkers/BatchExtractor.py +806 -0
  4. MEDiml/biomarkers/BatchExtractorTexturalFilters.py +840 -0
  5. MEDiml/biomarkers/__init__.py +16 -0
  6. MEDiml/biomarkers/diagnostics.py +125 -0
  7. MEDiml/biomarkers/get_oriented_bound_box.py +158 -0
  8. MEDiml/biomarkers/glcm.py +1602 -0
  9. MEDiml/biomarkers/gldzm.py +523 -0
  10. MEDiml/biomarkers/glrlm.py +1315 -0
  11. MEDiml/biomarkers/glszm.py +555 -0
  12. MEDiml/biomarkers/int_vol_hist.py +527 -0
  13. MEDiml/biomarkers/intensity_histogram.py +615 -0
  14. MEDiml/biomarkers/local_intensity.py +89 -0
  15. MEDiml/biomarkers/morph.py +1756 -0
  16. MEDiml/biomarkers/ngldm.py +780 -0
  17. MEDiml/biomarkers/ngtdm.py +414 -0
  18. MEDiml/biomarkers/stats.py +373 -0
  19. MEDiml/biomarkers/utils.py +389 -0
  20. MEDiml/filters/TexturalFilter.py +299 -0
  21. MEDiml/filters/__init__.py +9 -0
  22. MEDiml/filters/apply_filter.py +134 -0
  23. MEDiml/filters/gabor.py +215 -0
  24. MEDiml/filters/laws.py +283 -0
  25. MEDiml/filters/log.py +147 -0
  26. MEDiml/filters/mean.py +121 -0
  27. MEDiml/filters/textural_filters_kernels.py +1738 -0
  28. MEDiml/filters/utils.py +107 -0
  29. MEDiml/filters/wavelet.py +237 -0
  30. MEDiml/learning/DataCleaner.py +198 -0
  31. MEDiml/learning/DesignExperiment.py +480 -0
  32. MEDiml/learning/FSR.py +667 -0
  33. MEDiml/learning/Normalization.py +112 -0
  34. MEDiml/learning/RadiomicsLearner.py +714 -0
  35. MEDiml/learning/Results.py +2237 -0
  36. MEDiml/learning/Stats.py +694 -0
  37. MEDiml/learning/__init__.py +10 -0
  38. MEDiml/learning/cleaning_utils.py +107 -0
  39. MEDiml/learning/ml_utils.py +1015 -0
  40. MEDiml/processing/__init__.py +6 -0
  41. MEDiml/processing/compute_suv_map.py +121 -0
  42. MEDiml/processing/discretisation.py +149 -0
  43. MEDiml/processing/interpolation.py +275 -0
  44. MEDiml/processing/resegmentation.py +66 -0
  45. MEDiml/processing/segmentation.py +912 -0
  46. MEDiml/utils/__init__.py +25 -0
  47. MEDiml/utils/batch_patients.py +45 -0
  48. MEDiml/utils/create_radiomics_table.py +131 -0
  49. MEDiml/utils/data_frame_export.py +42 -0
  50. MEDiml/utils/find_process_names.py +16 -0
  51. MEDiml/utils/get_file_paths.py +34 -0
  52. MEDiml/utils/get_full_rad_names.py +21 -0
  53. MEDiml/utils/get_institutions_from_ids.py +16 -0
  54. MEDiml/utils/get_patient_id_from_scan_name.py +22 -0
  55. MEDiml/utils/get_patient_names.py +26 -0
  56. MEDiml/utils/get_radiomic_names.py +27 -0
  57. MEDiml/utils/get_scan_name_from_rad_name.py +22 -0
  58. MEDiml/utils/image_reader_SITK.py +37 -0
  59. MEDiml/utils/image_volume_obj.py +22 -0
  60. MEDiml/utils/imref.py +340 -0
  61. MEDiml/utils/initialize_features_names.py +62 -0
  62. MEDiml/utils/inpolygon.py +159 -0
  63. MEDiml/utils/interp3.py +43 -0
  64. MEDiml/utils/json_utils.py +78 -0
  65. MEDiml/utils/mode.py +31 -0
  66. MEDiml/utils/parse_contour_string.py +58 -0
  67. MEDiml/utils/save_MEDscan.py +30 -0
  68. MEDiml/utils/strfind.py +32 -0
  69. MEDiml/utils/textureTools.py +188 -0
  70. MEDiml/utils/texture_features_names.py +115 -0
  71. MEDiml/utils/write_radiomics_csv.py +47 -0
  72. MEDiml/wrangling/DataManager.py +1724 -0
  73. MEDiml/wrangling/ProcessDICOM.py +512 -0
  74. MEDiml/wrangling/__init__.py +3 -0
  75. mediml-0.9.9.dist-info/LICENSE.md +674 -0
  76. mediml-0.9.9.dist-info/METADATA +232 -0
  77. mediml-0.9.9.dist-info/RECORD +78 -0
  78. mediml-0.9.9.dist-info/WHEEL +4 -0
@@ -0,0 +1,527 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ import logging
5
+ from typing import Dict, Tuple
6
+
7
+ import numpy as np
8
+
9
+ from ..biomarkers.utils import find_i_x, find_v_x
10
+ from ..MEDscan import MEDscan
11
+
12
+
13
+ def init_ivh(
14
+ vol: np.ndarray,
15
+ vol_int_re: np.ndarray,
16
+ wd: int,
17
+ ivh: Dict = None,
18
+ im_range: np.ndarray = None,
19
+ medscan: MEDscan = None
20
+ ) -> Tuple[np.ndarray, np.ndarray, int, int]:
21
+ """Computes Intensity-volume Histogram Features.
22
+
23
+ Note:
24
+ For the input volume:
25
+
26
+ - Naturally discretised volume can be kept as it is (e.g. HU values of CT scans)
27
+ - All other volumes with continuous intensity distribution should be \
28
+ quantized (e.g., nBins = 100), with levels = [min, ..., max]
29
+
30
+ Args:
31
+ vol (ndarray): 3D volume, QUANTIZED, with NaNs outside the region of interest
32
+ vol_int_re (ndarray): 3D volume, with NaNs outside the region of interest
33
+ wd (int): Discretisation width.
34
+ ivh (Dict, optional): Dict of the Intensity-volume Histogram parameters (Discretization algo and value).
35
+ im_range (ndarray, optional): The intensity range.
36
+ medscan (MEDscan, optional): MEDscan instance containing processing parameters.
37
+
38
+ Returns:
39
+ Dict: Dict of the Intensity Histogram Features.
40
+ """
41
+ try:
42
+ # Retrieve relevant parameters from MEDscan instance.
43
+ if medscan is not None:
44
+ ivh = medscan.params.process.ivh
45
+ im_range = medscan.params.process.im_range
46
+ elif ivh is None or im_range is None:
47
+ raise ValueError('MEDscan instance or ivh and im_range must be provided.')
48
+
49
+ # Initialize relevant parameters.
50
+ user_set_range = []
51
+ if ivh and 'type' in ivh:
52
+ # PET example case (definite intensity units -- continuous case)
53
+ if ivh['type'] == 'FBS' or ivh['type'] == 'FBSequal':
54
+ range_fbs = [0, 0]
55
+ if not im_range:
56
+ range_fbs[0] = np.nanmin(vol_int_re)
57
+ range_fbs[1] = np.nanmax(vol_int_re)
58
+ else:
59
+ if im_range[0] == -np.inf:
60
+ range_fbs[0] = np.nanmin(vol_int_re)
61
+ else:
62
+ range_fbs[0] = im_range[0]
63
+ if im_range[1] == np.inf:
64
+ range_fbs[1] = np.nanmax(vol_int_re)
65
+ else:
66
+ range_fbs[1] = im_range[1]
67
+ # In this case, wd = wb (see discretisation.m)
68
+ range_fbs[0] = range_fbs[0] + 0.5*wd
69
+ # In this case, wd = wb (see discretisation.m)
70
+ range_fbs[1] = range_fbs[1] - 0.5*wd
71
+ user_set_range = range_fbs
72
+
73
+ else: # MRI example case (arbitrary intensity units)
74
+ user_set_range = None
75
+
76
+ else: # CT example case (definite intensity units -- discrete case)
77
+ user_set_range = im_range
78
+
79
+ # INITIALIZATION
80
+ X = vol[~np.isnan(vol[:])]
81
+
82
+ if (vol is not None) & (wd is not None) & (user_set_range is not None):
83
+ if user_set_range:
84
+ min_val = user_set_range[0]
85
+ max_val = user_set_range[1]
86
+ else:
87
+ min_val = np.min(X)
88
+ max_val = np.max(X)
89
+ else:
90
+ min_val = np.min(X)
91
+ max_val = np.max(X)
92
+
93
+ if max_val == np.inf:
94
+ max_val = np.max(X)
95
+
96
+ if min_val == -np.inf:
97
+ min_val = np.min(X)
98
+
99
+ # Vector of grey-levels.
100
+ # Values are generated within the half-open interval [min_val,max_val+wd)
101
+ levels = np.arange(min_val, max_val + wd, wd)
102
+ n_g = levels.size
103
+ n_v = X.size
104
+
105
+ except Exception as e:
106
+ print('PROBLEM WITH INITIALIZATION OF INTENSITY-VOLUME HISTOGRAM PARAMETERS \n {e}')
107
+
108
+ return X, levels, n_g, n_v
109
+
110
+ def extract_all(
111
+ vol: np.ndarray,
112
+ vol_int_re: np.ndarray,
113
+ wd: int,
114
+ ivh: Dict = None,
115
+ im_range: np.ndarray = None,
116
+ medscan: MEDscan = None
117
+ ) -> Dict:
118
+ """Computes Intensity-volume Histogram Features.
119
+ This features refer to Intensity-volume histogram family in
120
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
121
+
122
+ Note:
123
+ For the input volume, naturally discretised volume can be kept as it is (e.g. HU values of CT scans).
124
+ All other volumes with continuous intensity distribution should be
125
+ quantized (e.g., nBins = 100), with levels = [min, ..., max]
126
+
127
+ Args:
128
+ vol (ndarray): 3D volume, QUANTIZED, with NaNs outside the region of interest
129
+ vol_int_re (ndarray): 3D volume, with NaNs outside the region of interest
130
+ wd (int): Discretisation width.
131
+ ivh (Dict, optional): Dict of the Intensity-volume Histogram parameters (Discretization algo and value).
132
+ im_range (ndarray, optional): The intensity range.
133
+ medscan (MEDscan, optional): MEDscan instance containing processing parameters.
134
+
135
+ Returns:
136
+ Dict: Dict of the Intensity Histogram Features.
137
+ """
138
+ try:
139
+ # Initialization of final structure (Dictionary) containing all features.
140
+ int_vol_hist = {
141
+ 'Fivh_V10': [],
142
+ 'Fivh_V90': [],
143
+ 'Fivh_I10': [],
144
+ 'Fivh_I90': [],
145
+ 'Fivh_V10minusV90': [],
146
+ 'Fivh_I10minusI90': [],
147
+ 'Fivh_auc': []
148
+ }
149
+
150
+ # Retrieve relevant parameters
151
+ X, levels, n_g, n_v = init_ivh(vol, vol_int_re, wd, ivh, im_range, medscan)
152
+
153
+ # Calculating fractional volume
154
+ fract_vol = np.zeros(n_g)
155
+ for i in range(0, n_g):
156
+ fract_vol[i] = 1 - np.sum(X < levels[i])/n_v
157
+
158
+ # Calculating intensity fraction
159
+ fract_int = (levels - np.min(levels)) / (np.max(levels) - np.min(levels))
160
+
161
+ # Volume at intensity fraction 10
162
+ v10 = find_v_x(fract_int, fract_vol, 10)
163
+ int_vol_hist['Fivh_V10'] = v10
164
+
165
+ # Volume at intensity fraction 90
166
+ v90 = find_v_x(fract_int, fract_vol, 90)
167
+ int_vol_hist['Fivh_V90'] = v90
168
+
169
+ # Intensity at volume fraction 10
170
+ # For initial arbitrary intensities,
171
+ # we will always be discretising (1000 bins).
172
+ # So intensities are definite here.
173
+ i10 = find_i_x(levels, fract_vol, 10)
174
+ int_vol_hist['Fivh_I10'] = i10
175
+
176
+ # Intensity at volume fraction 90
177
+ # For initial arbitrary intensities,
178
+ # we will always be discretising (1000 bins).
179
+ # So intensities are definite here.
180
+ i90 = find_i_x(levels, fract_vol, 90)
181
+ int_vol_hist['Fivh_I90'] = i90
182
+
183
+ # Volume at intensity fraction difference v10-v90
184
+ int_vol_hist['Fivh_V10minusV90'] = v10 - v90
185
+
186
+ # Intensity at volume fraction difference i10-i90
187
+ # For initial arbitrary intensities,
188
+ # we will always be discretising (1000 bins).
189
+ # So intensities are definite here.
190
+ int_vol_hist['Fivh_I10minusI90'] = i10 - i90
191
+
192
+ # Area under IVH curve
193
+ int_vol_hist['Fivh_auc'] = np.trapz(fract_vol) / (n_g - 1)
194
+
195
+ except Exception as e:
196
+ message = f'PROBLEM WITH COMPUTATION OF INTENSITY-VOLUME HISTOGRAM FEATURES \n {e}'
197
+ if medscan is not None:
198
+ medscan.radiomics.image['intVolHist_3D'][medscan.params.radiomics.ivh_name].update(
199
+ {'error': 'ERROR_COMPUTATION'})
200
+ logging.error(message)
201
+ print(message)
202
+
203
+ return int_vol_hist
204
+
205
+ return int_vol_hist
206
+
207
+ def v10(
208
+ vol: np.ndarray,
209
+ vol_int_re: np.ndarray,
210
+ wd: int,
211
+ ivh: Dict = None,
212
+ im_range: np.ndarray = None,
213
+ medscan: MEDscan = None
214
+ ) -> float:
215
+ """Computes Volume at intensity fraction 10 feature.
216
+ This feature refers to "Fivh_V10" (ID = BC2M) in
217
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
218
+
219
+ Args:
220
+ vol (ndarray): 3D volume, QUANTIZED, with NaNs outside the region of interest
221
+ vol_int_re (ndarray): 3D volume, with NaNs outside the region of interest
222
+ wd (int): Discretisation width.
223
+ ivh (Dict, optional): Dict of the Intensity-volume Histogram parameters (Discretization algo and value).
224
+ im_range (ndarray, optional): The intensity range.
225
+ medscan (MEDscan, optional): MEDscan instance containing processing parameters.
226
+
227
+ Returns:
228
+ float: Volume at intensity fraction 10 feature.
229
+ """
230
+ try:
231
+ # Retrieve relevant parameters from init_ivh() method.
232
+ X, levels, n_g, n_v = init_ivh(vol, vol_int_re, wd, ivh, im_range, medscan)
233
+
234
+ # Calculating fractional volume
235
+ fract_vol = np.zeros(n_g)
236
+ for i in range(0, n_g):
237
+ fract_vol[i] = 1 - np.sum(X < levels[i]) / n_v
238
+
239
+ # Calculating intensity fraction
240
+ fract_int = (levels - np.min(levels))/(np.max(levels) - np.min(levels))
241
+
242
+ # Volume at intensity fraction 10
243
+ v10 = find_v_x(fract_int, fract_vol, 10)
244
+
245
+ except Exception as e:
246
+ print(f'PROBLEM WITH COMPUTATION OF V10 FEATURE \n {e}')
247
+ return None
248
+
249
+ return v10
250
+
251
+ def v90(
252
+ vol: np.ndarray,
253
+ vol_int_re: np.ndarray,
254
+ wd: int,
255
+ ivh: Dict = None,
256
+ im_range: np.ndarray = None,
257
+ medscan: MEDscan = None
258
+ ) -> float:
259
+ """Computes Volume at intensity fraction 90 feature.
260
+ This feature refers to "Fivh_V90" (ID = BC2M) in
261
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
262
+
263
+ Args:
264
+ vol (ndarray): 3D volume, QUANTIZED, with NaNs outside the region of interest
265
+ vol_int_re (ndarray): 3D volume, with NaNs outside the region of interest
266
+ wd (int): Discretisation width.
267
+ ivh (Dict, optional): Dict of the Intensity-volume Histogram parameters (Discretization algo and value).
268
+ im_range (ndarray, optional): The intensity range.
269
+ medscan (MEDscan, optional): MEDscan instance containing processing parameters.
270
+
271
+ Returns:
272
+ float: Volume at intensity fraction 90 feature.
273
+ """
274
+ try:
275
+ # Retrieve relevant parameters from init_ivh() method.
276
+ X, levels, n_g, n_v = init_ivh(vol, vol_int_re, wd, ivh, im_range, medscan)
277
+
278
+ # Calculating fractional volume
279
+ fract_vol = np.zeros(n_g)
280
+ for i in range(0, n_g):
281
+ fract_vol[i] = 1 - np.sum(X < levels[i]) / n_v
282
+
283
+ # Calculating intensity fraction
284
+ fract_int = (levels - np.min(levels)) / (np.max(levels) - np.min(levels))
285
+
286
+ # Volume at intensity fraction 90
287
+ v90 = find_v_x(fract_int, fract_vol, 90)
288
+
289
+ except Exception as e:
290
+ print(f'PROBLEM WITH COMPUTATION OF V90 FEATURE \n {e}')
291
+ return None
292
+
293
+ return v90
294
+
295
+ def i10(
296
+ vol: np.ndarray,
297
+ vol_int_re: np.ndarray,
298
+ wd: int,
299
+ ivh: Dict = None,
300
+ im_range: np.ndarray = None,
301
+ medscan: MEDscan = None
302
+ ) -> float:
303
+ """Computes Intensity at volume fraction 10 feature.
304
+ This feature refers to "Fivh_I10" (ID = GBPN) in
305
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
306
+
307
+ Args:
308
+ vol (ndarray): 3D volume, QUANTIZED, with NaNs outside the region of interest
309
+ vol_int_re (ndarray): 3D volume, with NaNs outside the region of interest
310
+ wd (int): Discretisation width.
311
+ ivh (Dict, optional): Dict of the Intensity-volume Histogram parameters (Discretization algo and value).
312
+ im_range (ndarray, optional): The intensity range.
313
+ medscan (MEDscan, optional): MEDscan instance containing processing parameters.
314
+
315
+ Returns:
316
+ float: Intensity at volume fraction 10 feature.
317
+ """
318
+ try:
319
+ # Retrieve relevant parameters from init_ivh() method.
320
+ X, levels, n_g, n_v = init_ivh(vol, vol_int_re, wd, ivh, im_range, medscan)
321
+
322
+ # Calculating fractional volume
323
+ fract_vol = np.zeros(n_g)
324
+ for i in range(0, n_g):
325
+ fract_vol[i] = 1 - np.sum(X < levels[i]) / n_v
326
+
327
+ # Intensity at volume fraction 10
328
+ # For initial arbitrary intensities,
329
+ # we will always be discretising (1000 bins).
330
+ # So intensities are definite here.
331
+ i10 = find_i_x(levels, fract_vol, 10)
332
+
333
+ except Exception as e:
334
+ print(f'PROBLEM WITH COMPUTATION OF I10 FEATURE \n {e}')
335
+ return None
336
+
337
+ return i10
338
+
339
+ def i90(
340
+ vol: np.ndarray,
341
+ vol_int_re: np.ndarray,
342
+ wd: int,
343
+ ivh: Dict = None,
344
+ im_range: np.ndarray = None,
345
+ medscan: MEDscan = None
346
+ ) -> float:
347
+ """Computes Intensity at volume fraction 90 feature.
348
+ This feature refers to "Fivh_I90" (ID = GBPN) in
349
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
350
+
351
+ Args:
352
+ vol (ndarray): 3D volume, QUANTIZED, with NaNs outside the region of interest
353
+ vol_int_re (ndarray): 3D volume, with NaNs outside the region of interest
354
+ wd (int): Discretisation width.
355
+ ivh (Dict, optional): Dict of the Intensity-volume Histogram parameters (Discretization algo and value).
356
+ im_range (ndarray, optional): The intensity range.
357
+ medscan (MEDscan, optional): MEDscan instance containing processing parameters.
358
+
359
+ Returns:
360
+ float: Intensity at volume fraction 90 feature.
361
+ """
362
+ try:
363
+ # Retrieve relevant parameters from init_ivh() method.
364
+ X, levels, n_g, n_v = init_ivh(vol, vol_int_re, wd, ivh, im_range, medscan)
365
+
366
+ # Calculating fractional volume
367
+ fract_vol = np.zeros(n_g)
368
+ for i in range(0, n_g):
369
+ fract_vol[i] = 1 - np.sum(X < levels[i]) / n_v
370
+
371
+ # Intensity at volume fraction 90
372
+ # For initial arbitrary intensities,
373
+ # we will always be discretising (1000 bins).
374
+ # So intensities are definite here.
375
+ i90 = find_i_x(levels, fract_vol, 90)
376
+
377
+ except Exception as e:
378
+ print(f'PROBLEM WITH COMPUTATION OF I90 FEATURE \n {e}')
379
+ return None
380
+
381
+ return i90
382
+
383
+ def v10_minus_v90(
384
+ vol: np.ndarray,
385
+ vol_int_re: np.ndarray,
386
+ wd: int,
387
+ ivh: Dict = None,
388
+ im_range: np.ndarray = None,
389
+ medscan: MEDscan = None
390
+ ) -> float:
391
+ """Computes Volume at intensity fraction difference v10-v90
392
+ This feature refers to "Fivh_V10minusV90" (ID = DDTU) in
393
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
394
+
395
+ Args:
396
+ vol (ndarray): 3D volume, QUANTIZED, with NaNs outside the region of interest
397
+ vol_int_re (ndarray): 3D volume, with NaNs outside the region of interest
398
+ wd (int): Discretisation width.
399
+ ivh (Dict, optional): Dict of the Intensity-volume Histogram parameters (Discretization algo and value).
400
+ im_range (ndarray, optional): The intensity range.
401
+ medscan (MEDscan, optional): MEDscan instance containing processing parameters.
402
+
403
+ Returns:
404
+ float: Volume at intensity fraction difference v10-v90 feature.
405
+ """
406
+ try:
407
+ # Retrieve relevant parameters from init_ivh() method.
408
+ X, levels, n_g, n_v = init_ivh(vol, vol_int_re, wd, ivh, im_range, medscan)
409
+
410
+ # Calculating fractional volume
411
+ fract_vol = np.zeros(n_g)
412
+ for i in range(0, n_g):
413
+ fract_vol[i] = 1 - np.sum(X < levels[i]) / n_v
414
+
415
+ # Calculating intensity fraction
416
+ fract_int = (levels - np.min(levels)) / (np.max(levels) - np.min(levels))
417
+
418
+ # Volume at intensity fraction 10
419
+ v10 = find_v_x(fract_int, fract_vol, 10)
420
+
421
+ # Volume at intensity fraction 90
422
+ v90 = find_v_x(fract_int, fract_vol, 90)
423
+
424
+ except Exception as e:
425
+ print(f'PROBLEM WITH COMPUTATION OF V10minusV90 FEATURE \n {e}')
426
+ return None
427
+
428
+ return v10 - v90
429
+
430
+ def i10_minus_i90(
431
+ vol: np.ndarray,
432
+ vol_int_re: np.ndarray,
433
+ wd: int,
434
+ ivh: Dict = None,
435
+ im_range: np.ndarray = None,
436
+ medscan: MEDscan = None
437
+ ) -> float:
438
+ """Computes Intensity at volume fraction difference i10-i90
439
+ This feature refers to "Fivh_I10minusI90" (ID = CNV2) in
440
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
441
+
442
+ Args:
443
+ vol (ndarray): 3D volume, QUANTIZED, with NaNs outside the region of interest
444
+ vol_int_re (ndarray): 3D volume, with NaNs outside the region of interest
445
+ wd (int): Discretisation width.
446
+ ivh (Dict, optional): Dict of the Intensity-volume Histogram parameters (Discretization algo and value).
447
+ im_range (ndarray, optional): The intensity range.
448
+ medscan (MEDscan, optional): MEDscan instance containing processing parameters.
449
+
450
+ Returns:
451
+ float: Intensity at volume fraction difference i10-i90 feature.
452
+ """
453
+ try:
454
+ # Retrieve relevant parameters from init_ivh() method.
455
+ X, levels, n_g, n_v = init_ivh(vol, vol_int_re, wd, ivh, im_range, medscan)
456
+
457
+ # Calculating fractional volume
458
+ fract_vol = np.zeros(n_g)
459
+ for i in range(0, n_g):
460
+ fract_vol[i] = 1 - np.sum(X < levels[i]) / n_v
461
+
462
+ # Intensity at volume fraction 10
463
+ # For initial arbitrary intensities,
464
+ # we will always be discretising (1000 bins).
465
+ # So intensities are definite here.
466
+ i10 = find_i_x(levels, fract_vol, 10)
467
+
468
+ # Intensity at volume fraction 90
469
+ # For initial arbitrary intensities,
470
+ # we will always be discretising (1000 bins).
471
+ # So intensities are definite here.
472
+ i90 = find_i_x(levels, fract_vol, 90)
473
+
474
+ except Exception as e:
475
+ print(f'PROBLEM WITH COMPUTATION OF I10minusI90 FEATURE \n {e}')
476
+ return None
477
+
478
+ return i10 - i90
479
+
480
+ def auc(
481
+ vol: np.ndarray,
482
+ vol_int_re: np.ndarray,
483
+ wd: int,
484
+ ivh: Dict = None,
485
+ im_range: np.ndarray = None,
486
+ medscan: MEDscan = None
487
+ ) -> float:
488
+ """
489
+ Computes Area under IVH curve.
490
+ This feature refers to "Fivh_auc" (ID = 9CMM) in
491
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
492
+
493
+ Note:
494
+ For the input volume:
495
+
496
+ * Naturally discretised volume can be kept as it is (e.g. HU values of CT scans)
497
+ * All other volumes with continuous intensity distribution should be \
498
+ quantized (e.g., nBins = 100), with levels = [min, ..., max]
499
+
500
+ Args:
501
+ vol(ndarray): 3D volume, QUANTIZED, with NaNs outside the region of interest
502
+ vol_int_re(ndarray): 3D volume, with NaNs outside the region of interest
503
+ wd(int): Discretisation width.
504
+ ivh (Dict, optional): Dict of the Intensity-volume Histogram parameters (Discretization algo and value).
505
+ im_range (ndarray, optional): The intensity range.
506
+ medscan (MEDscan, optional): MEDscan instance containing processing parameters.
507
+
508
+ Returns:
509
+ float: Area under IVH curve feature.
510
+ """
511
+ try:
512
+ # Retrieve relevant parameters from init_ivh() method.
513
+ X, levels, n_g, n_v = init_ivh(vol, vol_int_re, wd, ivh, im_range, medscan)
514
+
515
+ # Calculating fractional volume
516
+ fract_vol = np.zeros(n_g)
517
+ for i in range(0, n_g):
518
+ fract_vol[i] = 1 - np.sum(X < levels[i]) / n_v
519
+
520
+ # Area under IVH curve
521
+ auc = np.trapz(fract_vol) / (n_g - 1)
522
+
523
+ except Exception as e:
524
+ print(f'PROBLEM WITH COMPUTATION OF AUC FEATURE \n {e}')
525
+ return None
526
+
527
+ return auc