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,780 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+
5
+ from copy import deepcopy
6
+ from typing import Dict, List
7
+
8
+ import numpy as np
9
+ import pandas as pd
10
+
11
+ from ..utils.textureTools import (coord2index, get_neighbour_direction,
12
+ get_value, is_list_all_none)
13
+
14
+
15
+ def get_matrix(roi_only: np.array,
16
+ levels: np.ndarray) -> float:
17
+ """Computes Neighbouring grey level dependence matrix.
18
+ This matrix refers to "Neighbouring grey level dependence based features" (ID = REK0)
19
+ in the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`_.
20
+
21
+ Args:
22
+ roi_only_int (ndarray): Smallest box containing the ROI, with the imaging data ready
23
+ for texture analysis computations. Voxels outside the ROI are
24
+ set to NaNs.
25
+ levels (ndarray or List): Vector containing the quantized gray-levels
26
+ in the tumor region (or reconstruction ``levels`` of quantization).
27
+
28
+ Returns:
29
+ ndarray: Array of neighbouring grey level dependence matrix of ``roi_only``.
30
+
31
+ """
32
+ roi_only = roi_only.copy()
33
+
34
+ # PRELIMINARY
35
+ level_temp = np.max(levels)+1
36
+ roi_only[np.isnan(roi_only)] = level_temp
37
+ levels = np.append(levels, level_temp)
38
+ dim = np.shape(roi_only)
39
+ if np.size(dim) == 2:
40
+ np.append(dim, 1)
41
+
42
+ q_2 = np.reshape(roi_only, np.prod(dim), order='F').astype("int")
43
+
44
+ # QUANTIZATION EFFECTS CORRECTION (M. Vallieres)
45
+ # In case (for example) we initially wanted to have 64 levels, but due to
46
+ # quantization, only 60 resulted.
47
+ # q_s = round(levels*adjust)/adjust;
48
+ # q_2 = round(q_2*adjust)/adjust;
49
+ q_s = levels.copy()
50
+
51
+ # EL NAQA CODE
52
+ q_3 = q_2*0
53
+ lqs = np.size(q_s)
54
+ for k in range(1, lqs+1):
55
+ q_3[q_2 == q_s[k-1]] = k
56
+
57
+ q_3 = np.reshape(q_3, dim, order='F')
58
+
59
+ # Min dependence = 0, Max dependence = 26; So 27 columns
60
+ ngldm = np.zeros((lqs, 27))
61
+ for i in range(1, dim[0]+1):
62
+ i_min = max(1, i-1)
63
+ i_max = min(i+1, dim[0])
64
+ for j in range(1, dim[1]+1):
65
+ j_min = max(1, j-1)
66
+ j_max = min(j+1, dim[1])
67
+ for k in range(1, dim[2]+1):
68
+ k_min = max(1, k-1)
69
+ k_max = min(k+1, dim[2])
70
+ val_q3 = q_3[i-1, j-1, k-1]
71
+ count = 0
72
+ for I2 in range(i_min, i_max+1):
73
+ for J2 in range(j_min, j_max+1):
74
+ for K2 in range(k_min, k_max+1):
75
+ if (I2 == i) & (J2 == j) & (K2 == k):
76
+ continue
77
+ else:
78
+ # a = 0
79
+ if (val_q3 - q_3[I2-1, J2-1, K2-1] == 0):
80
+ count += 1
81
+
82
+ ngldm[val_q3-1, count] = ngldm[val_q3-1, count] + 1
83
+
84
+ # Last column was for the NaN voxels, to be removed
85
+ ngldm = np.delete(ngldm, -1, 0)
86
+ stop = np.nonzero(np.sum(ngldm, 0))[0][-1]
87
+ ngldm = np.delete(ngldm, range(stop+1, np.shape(ngldm)[1]+1), 1)
88
+
89
+ return ngldm
90
+
91
+ def extract_all(vol: np.ndarray) -> Dict :
92
+ """Compute NGLDM features
93
+
94
+ Args:
95
+ vol (np.ndarray): volume with discretised intensities as 3D numpy array (x, y, z)
96
+ method (str, optional): Either 'old' (deprecated) or 'new' (faster) method.
97
+
98
+ Raises:
99
+ ValueError: Ngldm should either be calculated using the faster \"new\" method, or the slow \"old\" method.
100
+
101
+ Returns:
102
+ dict: Dictionary of NGTDM features.
103
+ """
104
+
105
+ ngldm = get_ngldm_features(vol=vol)
106
+
107
+ return ngldm
108
+
109
+
110
+ def get_ngldm_features(vol: np.ndarray,
111
+ ngldm_spatial_method: str="3d",
112
+ ngldm_diff_lvl: float=0.0,
113
+ ngldm_dist: float=1.0) -> Dict:
114
+ """Extract neighbouring grey level dependence matrix-based features from the intensity roi mask.
115
+ These features refer to "Neighbouring grey level dependence based features" (ID = REK0) in
116
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
117
+
118
+ Args:
119
+
120
+ vol (ndarray): volume with discretised intensities as 3D numpy array (x, y, z).
121
+ intensity_range (ndarray): range of potential discretised intensities,
122
+ provided as a list: [minimal discretised intensity, maximal discretised intensity].
123
+ If one or both values are unknown, replace the respective values with np.nan.
124
+ ngldm_spatial_method(str): spatial method which determines the way neighbouring grey level dependence
125
+ matrices are calculated and how features are determined. One of "2d", "2.5d" or "3d".
126
+ ngldm_diff_lvl (float): also called coarseness. Coarseness determines which intensity
127
+ differences are allowed for intensities to be considered similar. Typically 0, and
128
+ changing discretisation levels may have the same effect as increasing
129
+ the coarseness parameter.
130
+ ngldm_dist (float): the chebyshev distance that forms a local neighbourhood around a center voxel.
131
+
132
+ Returns:
133
+ dict: dictionary with feature values.
134
+ """
135
+ if type(ngldm_spatial_method) is not list:
136
+ ngldm_spatial_method = [ngldm_spatial_method]
137
+
138
+ if type(ngldm_diff_lvl) is not list:
139
+ ngldm_diff_lvl = [ngldm_diff_lvl]
140
+
141
+ if type(ngldm_dist) is not list:
142
+ ngldm_dist = [ngldm_dist]
143
+
144
+ # Get the roi in tabular format
145
+ img_dims = vol.shape
146
+ index_id = np.arange(start=0, stop=vol.size)
147
+ coords = np.unravel_index(indices=index_id, shape=img_dims)
148
+ df_img = pd.DataFrame({"index_id": index_id,
149
+ "g": np.ravel(vol),
150
+ "x": coords[0],
151
+ "y": coords[1],
152
+ "z": coords[2],
153
+ "roi_int_mask": np.ravel(np.isfinite(vol))})
154
+
155
+ # Generate an empty feature list
156
+ feat_list = []
157
+
158
+ # Iterate over spatial arrangements
159
+ for ii_spatial in ngldm_spatial_method:
160
+
161
+ # Iterate over difference levels
162
+ for ii_diff_lvl in ngldm_diff_lvl:
163
+
164
+ # Iterate over distances
165
+ for ii_dist in ngldm_dist:
166
+
167
+ # Initiate list of ngldm objects
168
+ ngldm_list = []
169
+
170
+ # Perform 2D analysis
171
+ if ii_spatial.lower() in ["2d", "2.5d"]:
172
+
173
+ # Iterate over slices
174
+ for ii_slice in np.arange(0, img_dims[2]):
175
+
176
+ # Add ngldm matrices to list
177
+ ngldm_list += [GreyLevelDependenceMatrix(distance=int(ii_dist), diff_lvl=ii_diff_lvl,
178
+ spatial_method=ii_spatial.lower(), img_slice=ii_slice)]
179
+
180
+ # Perform 3D analysis
181
+ elif ii_spatial.lower() == "3d":
182
+
183
+ # Add ngldm matrices to list
184
+ ngldm_list += [GreyLevelDependenceMatrix(distance=int(ii_dist), diff_lvl=ii_diff_lvl,
185
+ spatial_method=ii_spatial.lower(), img_slice=None)]
186
+ else:
187
+ raise ValueError("Spatial methods for ngldm should be \"2d\", \"2.5d\" or \"3d\".")
188
+
189
+ # Calculate ngldm matrices
190
+ for ngldm in ngldm_list:
191
+ ngldm.calculate_ngldm_matrix(df_img=df_img, img_dims=img_dims)
192
+
193
+ # Merge matrices according to the given method
194
+ upd_list = combine_ngldm_matrices(ngldm_list=ngldm_list, spatial_method=ii_spatial.lower())
195
+
196
+ # Calculate features
197
+ feat_run_list = []
198
+ for ngldm in upd_list:
199
+ feat_run_list += [ngldm.compute_ngldm_features()]
200
+
201
+ # Average feature values
202
+ feat_list += [pd.concat(feat_run_list, axis=0).mean(axis=0, skipna=True).to_frame().transpose()]
203
+
204
+ # Merge feature tables into a single dictionary
205
+ df_feat = pd.concat(feat_list, axis=1).to_dict(orient="records")[0]
206
+
207
+ return df_feat
208
+
209
+
210
+ def combine_ngldm_matrices(ngldm_list: List,
211
+ spatial_method: str) -> List:
212
+ """Function to merge neighbouring grey level dependence matrices prior to feature calculation.
213
+
214
+ Args:
215
+ ngldm_list (List): list of GreyLevelDependenceMatrix objects.
216
+ spatial_method (str): spatial method which determines the way neighbouring grey level
217
+ dependence matrices are calculated and how features are determined.
218
+ One of "2d", "2.5d" or "3d".
219
+
220
+ Returns:
221
+ List: list of one or more merged GreyLevelDependenceMatrix objects.
222
+ """
223
+ # Initiate empty list
224
+ use_list = []
225
+
226
+ if spatial_method == "2d":
227
+ # Average features over slice: maintain original ngldms
228
+
229
+ # Make copy of ngldm_list
230
+ use_list = []
231
+ for ngldm in ngldm_list:
232
+ use_list += [ngldm.copy()]
233
+
234
+ elif spatial_method in ["2.5d", "3d"]:
235
+ # Merge all ngldms into a single representation
236
+
237
+ # Select all matrices within the slice
238
+ sel_matrix_list = []
239
+ for ngldm_id in np.arange(len(ngldm_list)):
240
+ sel_matrix_list += [ngldm_list[ngldm_id].matrix]
241
+
242
+ # Check if any matrix has been created
243
+ if is_list_all_none(sel_matrix_list):
244
+ # No matrix was created
245
+ use_list += [GreyLevelDependenceMatrix(distance=ngldm_list[0].distance, diff_lvl=ngldm_list[0].diff_lvl,
246
+ spatial_method=spatial_method, img_slice=None, matrix=None, n_v=0.0)]
247
+ else:
248
+ # Merge neighbouring grey level difference matrices
249
+ merge_ngldm = pd.concat(sel_matrix_list, axis=0)
250
+ merge_ngldm = merge_ngldm.groupby(by=["i", "j"]).sum().reset_index()
251
+
252
+ # Update the number of voxels
253
+ merge_n_v = 0.0
254
+ for ngldm_id in np.arange(len(ngldm_list)):
255
+ merge_n_v += ngldm_list[ngldm_id].n_v
256
+
257
+ # Create new neighbouring grey level difference matrix
258
+ use_list += [GreyLevelDependenceMatrix(distance=ngldm_list[0].distance, diff_lvl=ngldm_list[0].diff_lvl,
259
+ spatial_method=spatial_method, img_slice=None, matrix=merge_ngldm, n_v=merge_n_v)]
260
+ else:
261
+ use_list = None
262
+
263
+ # Return to new ngldm list to calling function
264
+ return use_list
265
+
266
+
267
+ class GreyLevelDependenceMatrix:
268
+
269
+ def __init__(self,
270
+ distance: float,
271
+ diff_lvl: float,
272
+ spatial_method: str,
273
+ img_slice: np.ndarray=None,
274
+ matrix: np.ndarray=None,
275
+ n_v: float=None) -> None:
276
+ """Initialising function for a new neighbouring grey level dependence ``matrix``.
277
+
278
+ Args:
279
+ distance (float): chebyshev ``distance`` used to determine the local neighbourhood.
280
+ diff_lvl (float): coarseness parameter which determines which intensities are considered similar.
281
+ spatial_method (str): spatial method used to calculate the ngldm: 2d, 2.5d or 3d
282
+ img_slice (ndarray): corresponding slice index (only if the ngldm corresponds to a 2d image slice)
283
+ matrix (ndarray): the actual ngldm in sparse format (row, column, count)
284
+ n_v (float): the number of voxels in the volume
285
+ """
286
+
287
+ # Distance used
288
+ self.distance = distance
289
+ self.diff_lvl = diff_lvl
290
+
291
+ # Slice for which the current matrix is extracted
292
+ self.img_slice = img_slice
293
+
294
+ # Spatial analysis method (2d, 2.5d, 3d)
295
+ self.spatial_method = spatial_method
296
+
297
+ # Place holders
298
+ self.matrix = matrix
299
+ self.n_v = n_v
300
+
301
+ def copy(self):
302
+ """Returns a copy of the GreyLevelDependenceMatrix object."""
303
+ return deepcopy(self)
304
+
305
+ def set_empty(self):
306
+ """Creates an empty GreyLevelDependenceMatrix"""
307
+ self.n_v = 0
308
+ self.matrix = None
309
+
310
+ def calculate_ngldm_matrix(self,
311
+ df_img: pd.DataFrame,
312
+ img_dims: int):
313
+ """
314
+ Function that calculates an ngldm for the settings provided during initialisation and the input image.
315
+
316
+ Args:
317
+ df_img (pd.DataFrame): data table containing image intensities, x, y and z coordinates,
318
+ and mask labels corresponding to voxels in the volume.
319
+ img_dims (int): dimensions of the image volume
320
+ """
321
+
322
+ # Check if the input image and roi exist
323
+ if df_img is None:
324
+ self.set_empty()
325
+ return
326
+
327
+ # Check if the roi contains any masked voxels. If this is not the case, don't construct the ngldm.
328
+ if not np.any(df_img.roi_int_mask):
329
+ self.set_empty()
330
+ return
331
+
332
+ if self.spatial_method == "3d":
333
+ # Set up neighbour vectors
334
+ nbrs = get_neighbour_direction(d=self.distance, distance="chebyshev", centre=False, complete=True, dim3=True)
335
+
336
+ # Set up work copy
337
+ df_ngldm = deepcopy(df_img)
338
+ elif self.spatial_method in ["2d", "2.5d"]:
339
+ # Set up neighbour vectors
340
+ nbrs = get_neighbour_direction(d=self.distance, distance="chebyshev", centre=False, complete=True, dim3=False)
341
+
342
+ # Set up work copy
343
+ df_ngldm = deepcopy(df_img[df_img.z == self.img_slice])
344
+ df_ngldm["index_id"] = np.arange(0, len(df_ngldm))
345
+ df_ngldm["z"] = 0
346
+ df_ngldm = df_ngldm.reset_index(drop=True)
347
+ else:
348
+ raise ValueError("The spatial method for neighbouring grey level dependence matrices should be one of \"2d\", \"2.5d\" or \"3d\".")
349
+
350
+ # Set grey level of voxels outside ROI to NaN
351
+ df_ngldm.loc[df_ngldm.roi_int_mask == False, "g"] = np.nan
352
+
353
+ # Update number of voxels for current iteration
354
+ self.n_v = np.sum(df_ngldm.roi_int_mask.values)
355
+
356
+ # Initialise sum of grey levels and number of neighbours
357
+ df_ngldm["occur"] = 0.0
358
+ df_ngldm["n_nbrs"] = 0.0
359
+
360
+ for k in range(0, np.shape(nbrs)[1]):
361
+ # Determine potential transitions from valid voxels
362
+ df_ngldm["to_index"] = coord2index(x=df_ngldm.x.values + nbrs[2, k],
363
+ y=df_ngldm.y.values + nbrs[1, k],
364
+ z=df_ngldm.z.values + nbrs[0, k],
365
+ dims=img_dims)
366
+
367
+ # Get grey level value from transitions
368
+ df_ngldm["to_g"] = get_value(x=df_ngldm.g.values, index=df_ngldm.to_index.values)
369
+
370
+ # Determine which voxels have valid neighbours
371
+ sel_index = np.isfinite(df_ngldm.to_g)
372
+
373
+ # Determine co-occurrence within diff_lvl
374
+ df_ngldm.loc[sel_index, "occur"] += ((np.abs(df_ngldm.to_g - df_ngldm.g)[sel_index]) <= self.diff_lvl) * 1
375
+
376
+ # Work with voxels within the intensity roi
377
+ df_ngldm = df_ngldm[df_ngldm.roi_int_mask]
378
+
379
+ # Drop superfluous columns
380
+ df_ngldm = df_ngldm.drop(labels=["index_id", "x", "y", "z", "to_index", "to_g", "roi_int_mask"], axis=1)
381
+
382
+ # Sum s over voxels
383
+ df_ngldm = df_ngldm.groupby(by=["g", "occur"]).size().reset_index(name="n")
384
+
385
+ # Rename columns
386
+ df_ngldm.columns = ["i", "j", "s"]
387
+
388
+ # Add one to dependency count as features are not defined for k=0
389
+ df_ngldm.j += 1.0
390
+
391
+ # Add matrix to object
392
+ self.matrix = df_ngldm
393
+
394
+ def compute_ngldm_features(self) -> pd.DataFrame:
395
+ """Computes neighbouring grey level dependence matrix features for the current neighbouring grey level dependence matrix.
396
+
397
+ Returns:
398
+ pandas data frame: with values for each feature.
399
+ """
400
+ # Create feature table
401
+ feat_names = ["Fngl_lde",
402
+ "Fngl_hde",
403
+ "Fngl_lgce",
404
+ "Fngl_hgce",
405
+ "Fngl_ldlge",
406
+ "Fngl_ldhge",
407
+ "Fngl_hdlge",
408
+ "Fngl_hdhge",
409
+ "Fngl_glnu",
410
+ "Fngl_glnu_norm",
411
+ "Fngl_dcnu",
412
+ "Fngl_dcnu_norm",
413
+ "Fngl_gl_var",
414
+ "Fngl_dc_var",
415
+ "Fngl_dc_entr",
416
+ "Fngl_dc_energy"]
417
+ df_feat = pd.DataFrame(np.full(shape=(1, len(feat_names)), fill_value=np.nan))
418
+ df_feat.columns = feat_names
419
+
420
+ # Don't return data for empty slices or slices without a good matrix
421
+ if self.matrix is None:
422
+ # Update names
423
+ # df_feat.columns += self.parse_feature_names()
424
+ return df_feat
425
+ elif len(self.matrix) == 0:
426
+ # Update names
427
+ # df_feat.columns += self.parse_feature_names()
428
+ return df_feat
429
+
430
+ # Dependence count dataframe
431
+ df_sij = deepcopy(self.matrix)
432
+ df_sij.columns = ("i", "j", "sij")
433
+
434
+ # Sum over grey levels
435
+ df_si = df_sij.groupby(by="i")["sij"].agg(np.sum).reset_index().rename(columns={"sij": "si"})
436
+
437
+ # Sum over dependence counts
438
+ df_sj = df_sij.groupby(by="j")["sij"].agg(np.sum).reset_index().rename(columns={"sij": "sj"})
439
+
440
+ # Constant definitions
441
+ n_s = np.sum(df_sij.sij) * 1.0 # Number of neighbourhoods considered
442
+ n_v = self.n_v # Number of voxels
443
+
444
+ ###############################################
445
+ # ngldm features
446
+ ###############################################
447
+
448
+ # Low dependence emphasis
449
+ df_feat.loc[0, "Fngl_lde"] = np.sum(df_sj.sj / df_sj.j ** 2.0) / n_s
450
+
451
+ # High dependence emphasis
452
+ df_feat.loc[0, "Fngl_hde"] = np.sum(df_sj.sj * df_sj.j ** 2.0) / n_s
453
+
454
+ # Grey level non-uniformity
455
+ df_feat.loc[0, "Fngl_glnu"] = np.sum(df_si.si ** 2.0) / n_s
456
+
457
+ # Grey level non-uniformity, normalised
458
+ df_feat.loc[0, "Fngl_glnu_norm"] = np.sum(df_si.si ** 2.0) / n_s ** 2.0
459
+
460
+ # Dependence count non-uniformity
461
+ df_feat.loc[0, "Fngl_dcnu"] = np.sum(df_sj.sj ** 2.0) / n_s
462
+
463
+ # Dependence count non-uniformity, normalised
464
+ df_feat.loc[0, "Fngl_dcnu_norm"] = np.sum(df_sj.sj ** 2.0) / n_s ** 2.0
465
+
466
+ # Dependence count percentage
467
+ # df_feat.loc[0, "ngl_dc_perc"] = n_s / n_v
468
+
469
+ # Low grey level count emphasis
470
+ df_feat.loc[0, "Fngl_lgce"] = np.sum(df_si.si / df_si.i ** 2.0) / n_s
471
+
472
+ # High grey level count emphasis
473
+ df_feat.loc[0, "Fngl_hgce"] = np.sum(df_si.si * df_si.i ** 2.0) / n_s
474
+
475
+ # Low dependence low grey level emphasis
476
+ df_feat.loc[0, "Fngl_ldlge"] = np.sum(df_sij.sij / (df_sij.i * df_sij.j) ** 2.0) / n_s
477
+
478
+ # Low dependence high grey level emphasis
479
+ df_feat.loc[0, "Fngl_ldhge"] = np.sum(df_sij.sij * df_sij.i ** 2.0 / df_sij.j ** 2.0) / n_s
480
+
481
+ # High dependence low grey level emphasis
482
+ df_feat.loc[0, "Fngl_hdlge"] = np.sum(df_sij.sij * df_sij.j ** 2.0 / df_sij.i ** 2.0) / n_s
483
+
484
+ # High dependence high grey level emphasis
485
+ df_feat.loc[0, "Fngl_hdhge"] = np.sum(df_sij.sij * df_sij.i ** 2.0 * df_sij.j ** 2.0) / n_s
486
+
487
+ # Grey level variance
488
+ mu = np.sum(df_sij.sij * df_sij.i) / n_s
489
+ df_feat.loc[0, "Fngl_gl_var"] = np.sum((df_sij.i - mu) ** 2.0 * df_sij.sij) / n_s
490
+ del mu
491
+
492
+ # Dependence count variance
493
+ mu = np.sum(df_sij.sij * df_sij.j) / n_s
494
+ df_feat.loc[0, "Fngl_dc_var"] = np.sum((df_sij.j - mu) ** 2.0 * df_sij.sij) / n_s
495
+ del mu
496
+
497
+ # Dependence count entropy
498
+ df_feat.loc[0, "Fngl_dc_entr"] = - np.sum(df_sij.sij * np.log2(df_sij.sij / n_s)) / n_s
499
+
500
+ # Dependence count energy
501
+ df_feat.loc[0, "Fngl_dc_energy"] = np.sum(df_sij.sij ** 2.0) / (n_s ** 2.0)
502
+
503
+ # Update names
504
+ # df_feat.columns += self.parse_feature_names()
505
+
506
+ return df_feat
507
+
508
+ def parse_feature_names(self):
509
+ """
510
+ Adds additional settings-related identifiers to each feature.
511
+ Not used currently, as the use of different settings for the
512
+ neighbouring grey level dependence matrix is not supported.
513
+ """
514
+ parse_str = ""
515
+
516
+ # Add distance
517
+ parse_str += "_d" + str(np.round(self.distance, 1))
518
+
519
+ # Add difference level
520
+ parse_str += "_a" + str(np.round(self.diff_lvl, 0))
521
+
522
+ # Add spatial method
523
+ if self.spatial_method is not None:
524
+ parse_str += "_" + self.spatial_method
525
+
526
+ return parse_str
527
+
528
+ def get_dict(vol: np.ndarray) -> dict:
529
+ """
530
+ Extract neighbouring grey level dependence matrix-based features from the intensity roi mask.
531
+
532
+ Args:
533
+ vol (ndarray): volume with discretised intensities as 3D numpy array (x, y, z)
534
+
535
+ Returns:
536
+ dict: dictionary with feature values
537
+
538
+ """
539
+ ngldm_dict = get_ngldm_features(vol, intensity_range=[np.nan, np.nan])
540
+ return ngldm_dict
541
+
542
+ def lde(ngldm_dict: np.ndarray)-> float:
543
+ """
544
+ Computes low dependence emphasis feature.
545
+ This feature refers to "Fngl_lde" (ID = SODN) in
546
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
547
+
548
+ Args:
549
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
550
+
551
+ Returns:
552
+ float: low depence emphasis value
553
+
554
+ """
555
+ return ngldm_dict["Fngl_lde"]
556
+
557
+ def hde(ngldm_dict: np.ndarray)-> float:
558
+ """
559
+ Computes high dependence emphasis feature.
560
+ This feature refers to "Fngl_hde" (ID = IMOQ) in
561
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
562
+
563
+ Args:
564
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
565
+
566
+ Returns:
567
+ float: high depence emphasis value
568
+
569
+ """
570
+ return ngldm_dict["Fngl_hde"]
571
+
572
+ def lgce(ngldm_dict: np.ndarray)-> float:
573
+ """
574
+ Computes low grey level count emphasis feature.
575
+ This feature refers to "Fngl_lgce" (ID = TL9H) in
576
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
577
+
578
+ Args:
579
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
580
+
581
+ Returns:
582
+ float: low grey level count emphasis value
583
+
584
+ """
585
+ return ngldm_dict["Fngl_lgce"]
586
+
587
+ def hgce(ngldm_dict: np.ndarray)-> float:
588
+ """
589
+ Computes high grey level count emphasis feature.
590
+ This feature refers to "Fngl_hgce" (ID = OAE7) in
591
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
592
+
593
+ Args:
594
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
595
+
596
+ Returns:
597
+ float: high grey level count emphasis value
598
+
599
+ """
600
+ return ngldm_dict["Fngl_hgce"]
601
+
602
+ def ldlge(ngldm_dict: np.ndarray)-> float:
603
+ """
604
+ Computes low dependence low grey level emphasis feature.
605
+ This feature refers to "Fngl_ldlge" (ID = EQ3F) in
606
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
607
+
608
+ Args:
609
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
610
+
611
+ Returns:
612
+ float: low dependence low grey level emphasis value
613
+
614
+ """
615
+ return ngldm_dict["Fngl_ldlge"]
616
+
617
+ def ldhge(ngldm_dict: np.ndarray)-> float:
618
+ """
619
+ Computes low dependence high grey level emphasis feature.
620
+ This feature refers to "Fngl_ldhge" (ID = JA6D) in
621
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
622
+
623
+ Args:
624
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
625
+
626
+ Returns:
627
+ float: low dependence high grey level emphasis value
628
+
629
+ """
630
+ return ngldm_dict["Fngl_ldhge"]
631
+
632
+ def hdlge(ngldm_dict: np.ndarray)-> float:
633
+ """
634
+ Computes high dependence low grey level emphasis feature.
635
+ This feature refers to "Fngl_hdlge" (ID = NBZI) in
636
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
637
+
638
+ Args:
639
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
640
+
641
+ Returns:
642
+ float: high dependence low grey level emphasis value
643
+
644
+ """
645
+ return ngldm_dict["Fngl_hdlge"]
646
+
647
+ def hdhge(ngldm_dict: np.ndarray)-> float:
648
+ """
649
+ Computes high dependence high grey level emphasis feature.
650
+ This feature refers to "Fngl_hdhge" (ID = 9QMG) in
651
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
652
+
653
+ Args:
654
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
655
+
656
+ Returns:
657
+ float: high dependence high grey level emphasis value
658
+
659
+ """
660
+ return ngldm_dict["Fngl_hdhge"]
661
+
662
+ def glnu(ngldm_dict: np.ndarray)-> float:
663
+ """
664
+ Computes grey level non-uniformity feature.
665
+ This feature refers to "Fngl_glnu" (ID = FP8K) in
666
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
667
+
668
+ Args:
669
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
670
+
671
+ Returns:
672
+ float: grey level non-uniformity value
673
+
674
+ """
675
+ return ngldm_dict["Fngl_glnu"]
676
+
677
+ def glnu_norm(ngldm_dict: np.ndarray)-> float:
678
+ """
679
+ Computes grey level non-uniformity normalised feature.
680
+ This feature refers to "Fngl_glnu_norm" (ID = 5SPA) in
681
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
682
+
683
+ Args:
684
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
685
+
686
+ Returns:
687
+ float: grey level non-uniformity normalised value
688
+
689
+ """
690
+ return ngldm_dict["Fngl_glnu_norm"]
691
+
692
+ def dcnu(ngldm_dict: np.ndarray)-> float:
693
+ """
694
+ Computes dependence count non-uniformity feature.
695
+ This feature refers to "Fngl_dcnu" (ID = Z87G) in
696
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
697
+
698
+ Args:
699
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
700
+
701
+ Returns:
702
+ float: dependence count non-uniformity value
703
+
704
+ """
705
+ return ngldm_dict["Fngl_dcnu"]
706
+
707
+ def dcnu_norm(ngldm_dict: np.ndarray)-> float:
708
+ """
709
+ Computes dependence count non-uniformity normalised feature.
710
+ This feature refers to "Fngl_dcnu_norm" (ID = OKJI) in
711
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
712
+
713
+ Args:
714
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
715
+
716
+ Returns:
717
+ float: dependence count non-uniformity normalised value
718
+
719
+ """
720
+ return ngldm_dict["Fngl_dcnu_norm"]
721
+
722
+ def gl_var(ngldm_dict: np.ndarray)-> float:
723
+ """
724
+ Computes grey level variance feature.
725
+ This feature refers to "Fngl_gl_var" (ID = 1PFV) in
726
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
727
+
728
+ Args:
729
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
730
+
731
+ Returns:
732
+ float: grey level variance value
733
+
734
+ """
735
+ return ngldm_dict["Fngl_gl_var"]
736
+
737
+ def dc_var(ngldm_dict: np.ndarray)-> float:
738
+ """
739
+ Computes dependence count variance feature.
740
+ This feature refers to "Fngl_dc_var" (ID = DNX2) in
741
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
742
+
743
+ Args:
744
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
745
+
746
+ Returns:
747
+ float: dependence count variance value
748
+
749
+ """
750
+ return ngldm_dict["Fngl_dc_var"]
751
+
752
+ def dc_entr(ngldm_dict: np.ndarray)-> float:
753
+ """
754
+ Computes dependence count entropy feature.
755
+ This feature refers to "Fngl_dc_entr" (ID = FCBV) in
756
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
757
+
758
+ Args:
759
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
760
+
761
+ Returns:
762
+ float: dependence count entropy value
763
+
764
+ """
765
+ return ngldm_dict["Fngl_dc_entr"]
766
+
767
+ def dc_energy(ngldm_dict: np.ndarray)-> float:
768
+ """
769
+ Computes dependence count energy feature.
770
+ This feature refers to "Fngl_dc_energy" (ID = CAS9) in
771
+ the `IBSI1 reference manual <https://arxiv.org/pdf/1612.07003.pdf>`__.
772
+
773
+ Args:
774
+ ngldm (ndarray): array of neighbouring grey level dependence matrix
775
+
776
+ Returns:
777
+ float: dependence count energy value
778
+
779
+ """
780
+ return ngldm_dict["Fngl_dc_energy"]