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,16 @@
1
+ from . import *
2
+ from .BatchExtractor import *
3
+ from .BatchExtractorTexturalFilters import *
4
+ from .diagnostics import *
5
+ from .get_oriented_bound_box import *
6
+ from .glcm import *
7
+ from .gldzm import *
8
+ from .glrlm import *
9
+ from .glszm import *
10
+ from .int_vol_hist import *
11
+ from .intensity_histogram import *
12
+ from .local_intensity import *
13
+ from .morph import *
14
+ from .ngldm import *
15
+ from .ngtdm import *
16
+ from .stats import *
@@ -0,0 +1,125 @@
1
+ from typing import Dict
2
+
3
+ import numpy as np
4
+
5
+ from ..processing.segmentation import compute_bounding_box
6
+
7
+
8
+ def extract_all(vol_obj: np.ndarray,
9
+ roi_obj_int: np.ndarray,
10
+ roi_obj_morph: np.ndarray,
11
+ im_type: str) -> Dict:
12
+ """Computes diagnostic features
13
+
14
+ The diagnostic features help identify issues with
15
+ the implementation of the image processing sequence.
16
+
17
+ Args:
18
+ vol_obj (ndarray): Imaging data.
19
+ roi_obj_int (ndarray): Intensity mask data.
20
+ roi_obj_morph (ndarray): Morphological mask data.
21
+ im_type (str): Image processing step.
22
+
23
+ - 'reSeg': Computes Diagnostic features right after the re-segmentaion step.
24
+ - 'interp' or any other arg: Computes Diagnostic features for any processing step other than re-segmentation.
25
+
26
+ Returns:
27
+ Dict: Dictionnary containing the computed features.
28
+ """
29
+ diag = {}
30
+
31
+ # FOR THE IMAGE
32
+
33
+ if im_type != 'reSeg':
34
+ # Image dimension x
35
+ diag.update({'image_' + im_type + '_dimX':
36
+ vol_obj.spatialRef.ImageSize[0]})
37
+
38
+ # Image dimension y
39
+ diag.update({'image_' + im_type + '_dimY':
40
+ vol_obj.spatialRef.ImageSize[1]})
41
+
42
+ # Image dimension z
43
+ diag.update({'image_' + im_type + '_dimz':
44
+ vol_obj.spatialRef.ImageSize[2]})
45
+
46
+ # Voxel dimension x
47
+ diag.update({'image_' + im_type + '_voxDimX':
48
+ vol_obj.spatialRef.PixelExtentInWorldX})
49
+
50
+ # Voxel dimension y
51
+ diag.update({'image_' + im_type + '_voxDimY':
52
+ vol_obj.spatialRef.PixelExtentInWorldY})
53
+
54
+ # Voxel dimension z
55
+ diag.update({'image_' + im_type + '_voxDimZ':
56
+ vol_obj.spatialRef.PixelExtentInWorldZ})
57
+
58
+ # Mean intensity
59
+ diag.update({'image_' + im_type + '_meanInt': np.mean(vol_obj.data)})
60
+
61
+ # Minimum intensity
62
+ diag.update({'image_' + im_type + '_minInt': np.min(vol_obj.data)})
63
+
64
+ # Maximum intensity
65
+ diag.update({'image_' + im_type + '_maxInt': np.max(vol_obj.data)})
66
+
67
+ # FOR THE ROI
68
+ box_bound_int = compute_bounding_box(roi_obj_int.data)
69
+ box_bound_morph = compute_bounding_box(roi_obj_morph.data)
70
+
71
+ x_gl_int = vol_obj.data[roi_obj_int.data == 1]
72
+ x_gl_morph = vol_obj.data[roi_obj_morph.data == 1]
73
+
74
+ # Map dimension x
75
+ diag.update({'roi_' + im_type + '_Int_dimX':
76
+ roi_obj_int.spatialRef.ImageSize[0]})
77
+
78
+ # Map dimension y
79
+ diag.update({'roi_' + im_type + '_Int_dimY':
80
+ roi_obj_int.spatialRef.ImageSize[1]})
81
+
82
+ # Map dimension z
83
+ diag.update({'roi_' + im_type + '_Int_dimZ':
84
+ roi_obj_int.spatialRef.ImageSize[2]})
85
+
86
+ # Bounding box dimension x
87
+ diag.update({'roi_' + im_type + '_Int_boxBoundDimX':
88
+ box_bound_int[0, 1] - box_bound_int[0, 0] + 1})
89
+
90
+ # Bounding box dimension y
91
+ diag.update({'roi_' + im_type + '_Int_boxBoundDimY':
92
+ box_bound_int[1, 1] - box_bound_int[1, 0] + 1})
93
+
94
+ # Bounding box dimension z
95
+ diag.update({'roi_' + im_type + '_Int_boxBoundDimZ':
96
+ box_bound_int[2, 1] - box_bound_int[2, 0] + 1})
97
+
98
+ # Bounding box dimension x
99
+ diag.update({'roi_' + im_type + '_Morph_boxBoundDimX':
100
+ box_bound_morph[0, 1] - box_bound_morph[0, 0] + 1})
101
+
102
+ # Bounding box dimension y
103
+ diag.update({'roi_' + im_type + '_Morph_boxBoundDimY':
104
+ box_bound_morph[1, 1] - box_bound_morph[1, 0] + 1})
105
+
106
+ # Bounding box dimension z
107
+ diag.update({'roi_' + im_type + '_Morph_boxBoundDimZ':
108
+ box_bound_morph[2, 1] - box_bound_morph[2, 0] + 1})
109
+
110
+ # Voxel number
111
+ diag.update({'roi_' + im_type + '_Int_voxNumb': np.size(x_gl_int)})
112
+
113
+ # Voxel number
114
+ diag.update({'roi_' + im_type + '_Morph_voxNumb': np.size(x_gl_morph)})
115
+
116
+ # Mean intensity
117
+ diag.update({'roi_' + im_type + '_meanInt': np.mean(x_gl_int)})
118
+
119
+ # Minimum intensity
120
+ diag.update({'roi_' + im_type + '_minInt': np.min(x_gl_int)})
121
+
122
+ # Maximum intensity
123
+ diag.update({'roi_' + im_type + '_maxInt': np.max(x_gl_int)})
124
+
125
+ return diag
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+
5
+ from typing import List
6
+
7
+ import numpy as np
8
+ import pandas as pd
9
+
10
+
11
+ def rot_matrix(theta: float,
12
+ dim: int=2,
13
+ rot_axis: int=-1) -> np.ndarray:
14
+ """Creates a 2d or 3d rotation matrix
15
+
16
+ Args:
17
+ theta (float): angle in radian
18
+ dim (int, optional): dimension size. Defaults to 2.
19
+ rot_axis (int, optional): rotation axis value. Defaults to -1.
20
+
21
+ Returns:
22
+ ndarray: rotation matrix
23
+ """
24
+
25
+ if dim == 2:
26
+ rot_mat = np.array([[np.cos(theta), -np.sin(theta)],
27
+ [np.sin(theta), np.cos(theta)]])
28
+
29
+ elif dim == 3:
30
+ if rot_axis == 0:
31
+ rot_mat = np.array([[1.0, 0.0, 0.0],
32
+ [0.0, np.cos(theta), -np.sin(theta)],
33
+ [0.0, np.sin(theta), np.cos(theta)]])
34
+ elif rot_axis == 1:
35
+ rot_mat = np.array([[np.cos(theta), 0.0, np.sin(theta)],
36
+ [0.0, 1.0, 0.0],
37
+ [-np.sin(theta), 0.0, np.cos(theta)]])
38
+ elif rot_axis == 2:
39
+ rot_mat = np.array([[np.cos(theta), -np.sin(theta), 0.0],
40
+ [np.sin(theta), np.cos(theta), 0.0],
41
+ [0.0, 0.0, 1.0]])
42
+ else:
43
+ rot_mat = None
44
+ else:
45
+ rot_mat = None
46
+
47
+ return rot_mat
48
+
49
+
50
+ def sig_proc_segmentise(x: List) -> List:
51
+ """Produces a list of segments from input x with values (0,1)
52
+
53
+ Args:
54
+ x (List): list of values
55
+
56
+ Returns:
57
+ List: list of segments from input x with values (0,1)
58
+ """
59
+
60
+ # Create a difference vector
61
+ y = np.diff(x)
62
+
63
+ # Find start and end indices of sections with value 1
64
+ ind_1_start = np.array(np.where(y == 1)).flatten()
65
+ if np.shape(ind_1_start)[0] > 0:
66
+ ind_1_start += 1
67
+ ind_1_end = np.array(np.where(y == -1)).flatten()
68
+
69
+ # Check for boundary effects
70
+ if x[0] == 1:
71
+ ind_1_start = np.insert(ind_1_start, 0, 0)
72
+ if x[-1] == 1:
73
+ ind_1_end = np.append(ind_1_end, np.shape(x)[0]-1)
74
+
75
+ # Generate segment df for segments with value 1
76
+ if np.shape(ind_1_start)[0] == 0:
77
+ df_one = pd.DataFrame({"i": [],
78
+ "j": [],
79
+ "val": []})
80
+ else:
81
+ df_one = pd.DataFrame({"i": ind_1_start,
82
+ "j": ind_1_end,
83
+ "val": np.ones(np.shape(ind_1_start)[0])})
84
+
85
+ # Find start and end indices for section with value 0
86
+ if np.shape(ind_1_start)[0] == 0:
87
+ ind_0_start = np.array([0])
88
+ ind_0_end = np.array([np.shape(x)[0]-1])
89
+ else:
90
+ ind_0_end = ind_1_start - 1
91
+ ind_0_start = ind_1_end + 1
92
+
93
+ # Check for boundary effect
94
+ if x[0] == 0:
95
+ ind_0_start = np.insert(ind_0_start, 0, 0)
96
+ if x[-1] == 0:
97
+ ind_0_end = np.append(ind_0_end, np.shape(x)[0]-1)
98
+
99
+ # Check for out-of-range boundary effects
100
+ if ind_0_end[0] < 0:
101
+ ind_0_end = np.delete(ind_0_end, 0)
102
+ if ind_0_start[-1] >= np.shape(x)[0]:
103
+ ind_0_start = np.delete(ind_0_start, -1)
104
+
105
+ # Generate segment df for segments with value 0
106
+ if np.shape(ind_0_start)[0] == 0:
107
+ df_zero = pd.DataFrame({"i": [],
108
+ "j": [],
109
+ "val": []})
110
+ else:
111
+ df_zero = pd.DataFrame({"i": ind_0_start,
112
+ "j": ind_0_end,
113
+ "val": np.zeros(np.shape(ind_0_start)[0])})
114
+
115
+ df_segm = df_one.append(df_zero).sort_values(by="i").reset_index(drop=True)
116
+
117
+ return df_segm
118
+
119
+
120
+ def sig_proc_find_peaks(x: float,
121
+ ddir: str="pos") -> pd.DataFrame:
122
+ """Determines peak positions in array of values
123
+
124
+ Args:
125
+ x (float): value
126
+ ddir (str, optional): positive or negative value. Defaults to "pos".
127
+
128
+ Returns:
129
+ pd.DataFrame: peak positions in array of values
130
+ """
131
+
132
+ # Invert when looking for local minima
133
+ if ddir == "neg":
134
+ x = -x
135
+
136
+ # Generate segments where slope is negative
137
+
138
+ df_segm = sig_proc_segmentise(x=(np.diff(x) < 0.0)*1)
139
+
140
+ # Start of slope coincides with position of peak (due to index shift induced by np.diff)
141
+ ind_peak = df_segm.loc[df_segm.val == 1, "i"].values
142
+
143
+ # Check right boundary
144
+ if x[-1] > x[-2]:
145
+ ind_peak = np.append(ind_peak, np.shape(x)[0]-1)
146
+
147
+ # Construct dataframe with index and corresponding value
148
+ if np.shape(ind_peak)[0] == 0:
149
+ df_peak = pd.DataFrame({"ind": [],
150
+ "val": []})
151
+ else:
152
+ if ddir == "pos":
153
+ df_peak = pd.DataFrame({"ind": ind_peak,
154
+ "val": x[ind_peak]})
155
+ if ddir == "neg":
156
+ df_peak = pd.DataFrame({"ind": ind_peak,
157
+ "val": -x[ind_peak]})
158
+ return df_peak