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
MEDiml/utils/mode.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from typing import Tuple, Union
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def mode(x: np.ndarray,
|
|
11
|
+
return_counts=False) -> Union[Tuple[np.ndarray, np.ndarray],
|
|
12
|
+
np.ndarray]:
|
|
13
|
+
"""Implementation of mode that also returns counts, unlike the standard statistics.mode.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
x (ndarray): n-dimensional array of which to find mode.
|
|
17
|
+
return_counts (bool): If True, also return the number of times each unique item appears in ``x``.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
2-element tuple containing
|
|
21
|
+
|
|
22
|
+
- ndarray: Array of the modal (most common) value in the given array.
|
|
23
|
+
- ndarray: Array of the counts if ``return_counts`` is True.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
unique_values, counts = np.unique(x, return_counts=True)
|
|
27
|
+
|
|
28
|
+
if return_counts:
|
|
29
|
+
return unique_values[np.argmax(counts)], np.max(counts)
|
|
30
|
+
|
|
31
|
+
return unique_values[np.argmax(counts)]
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
from typing import List, Tuple, Union
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from ..utils.strfind import strfind
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def parse_contour_string(contour_string) -> Union[Tuple[float, List[str]],
|
|
12
|
+
Tuple[int, List[str]],
|
|
13
|
+
Tuple[List[int], List[str]]]:
|
|
14
|
+
"""Finds the delimeters (:math:`'+'` and :math:`'-'`) and the contour indexe(s) from the given string.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
contour_string (str, float or int): Index or string of indexes with
|
|
18
|
+
delimeters. For example: :math:`'3'` or :math:`'1-3+2'`.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
float, int: If ``contour_string`` is a an int or float we return ``contour_string``.
|
|
22
|
+
List[str]: List of the delimeters.
|
|
23
|
+
List[int]: List of the contour indexes.
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
>>> ``contour_string`` = '1-3+2'
|
|
27
|
+
>>> :function: parse_contour_string(contour_string)
|
|
28
|
+
[1, 2, 3], ['+', '-']
|
|
29
|
+
>>> ``contour_string`` = 1
|
|
30
|
+
>>> :function: parse_contour_string(contour_string)
|
|
31
|
+
1, []
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
if isinstance(contour_string, (int, float)):
|
|
35
|
+
return contour_string, []
|
|
36
|
+
|
|
37
|
+
ind_plus = strfind(string=contour_string, pattern='\+')
|
|
38
|
+
ind_minus = strfind(string=contour_string, pattern='\-')
|
|
39
|
+
ind_operations = np.sort(np.hstack((ind_plus, ind_minus))).astype(int)
|
|
40
|
+
|
|
41
|
+
# Parsing operations and contour numbers
|
|
42
|
+
# AZ: I assume that contour_number is an integer
|
|
43
|
+
if ind_operations.size == 0:
|
|
44
|
+
operations = []
|
|
45
|
+
contour_number = [int(contour_string)]
|
|
46
|
+
else:
|
|
47
|
+
n_op = len(ind_operations)
|
|
48
|
+
operations = [contour_string[ind_operations[i]] for i in np.arange(n_op)]
|
|
49
|
+
|
|
50
|
+
contour_number = np.zeros(n_op + 1, dtype=int)
|
|
51
|
+
contour_number[0] = int(contour_string[0:ind_operations[0]])
|
|
52
|
+
for c in np.arange(start=1, stop=n_op):
|
|
53
|
+
contour_number[c] = int(contour_string[(ind_operations[c-1]+1) : ind_operations[c]])
|
|
54
|
+
|
|
55
|
+
contour_number[-1] = int(contour_string[(ind_operations[-1]+1):])
|
|
56
|
+
contour_number.tolist()
|
|
57
|
+
|
|
58
|
+
return contour_number, operations
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import pickle
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from ..MEDscan import MEDscan
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def save_MEDscan(medscan: MEDscan,
|
|
8
|
+
path_save: Path) -> str:
|
|
9
|
+
"""Saves MEDscan class instance in a pickle object
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
medscan (MEDscan): MEDscan instance
|
|
13
|
+
path_save (Path): MEDscan instance saving paths
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
None.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
series_description = medscan.series_description.translate({ord(ch): '-' for ch in '/\\ ()&:*'})
|
|
20
|
+
name_id = medscan.patientID
|
|
21
|
+
name_id = name_id.translate({ord(ch): '-' for ch in '/\\ ()&:*'})
|
|
22
|
+
|
|
23
|
+
# final saving name
|
|
24
|
+
name_complete = name_id + '__' + series_description + '.' + medscan.type + '.npy'
|
|
25
|
+
|
|
26
|
+
# save
|
|
27
|
+
with open(path_save / name_complete,'wb') as f:
|
|
28
|
+
pickle.dump(medscan, f)
|
|
29
|
+
|
|
30
|
+
return name_complete
|
MEDiml/utils/strfind.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
from re import finditer
|
|
5
|
+
from typing import List
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def strfind(pattern: str,
|
|
9
|
+
string: str) -> List[int]:
|
|
10
|
+
"""Finds indices of ``pattern`` in ``string``. Based on regex.
|
|
11
|
+
|
|
12
|
+
Note:
|
|
13
|
+
Be careful with + and - symbols. Use :math:`\+` and :math:`\-` instead.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
pattern (str): Substring to be searched in the ``string``.
|
|
17
|
+
string (str): String used to find matches.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
List[int]: List of indexes of every occurence of ``pattern`` in the passed ``string``.
|
|
21
|
+
|
|
22
|
+
Raises:
|
|
23
|
+
ValueError: If the ``pattern`` does not use backslash with special regex symbols
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
if pattern in ('+', '-'):
|
|
27
|
+
raise ValueError(
|
|
28
|
+
"Please use a backslash with special regex symbols in findall.")
|
|
29
|
+
|
|
30
|
+
ind = [m.start() for m in finditer(pattern, string)]
|
|
31
|
+
|
|
32
|
+
return ind
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
from typing import List, Union
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_neighbour_direction(d=1.8,
|
|
11
|
+
distance="euclidian",
|
|
12
|
+
centre=False,
|
|
13
|
+
complete=False,
|
|
14
|
+
dim3=True) -> np.ndarray:
|
|
15
|
+
"""Defines transitions to neighbour voxels.
|
|
16
|
+
|
|
17
|
+
Note:
|
|
18
|
+
This code was adapted from the in-house radiomics software created at
|
|
19
|
+
OncoRay, Dresden, Germany.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
d (float, optional): Max ``distance`` between voxels.
|
|
23
|
+
distance (str, optional): Distance norm used to compute distances. must be
|
|
24
|
+
"manhattan", "l1", "l_1", "euclidian", "l2", "l_2", "chebyshev", "linf" or "l_inf".
|
|
25
|
+
centre (bool, optional): Flags whether the [0,0,0] direction should be included
|
|
26
|
+
complete(bool, optional): Flags whether all directions should be computed (True)
|
|
27
|
+
or just the primary ones (False). For example, including [0,0,1] and [0,0,-1]
|
|
28
|
+
directions may lead to redundant texture matrices.
|
|
29
|
+
dim3(bool, optional): flags whether full 3D (True) or only in-slice (2D; False)
|
|
30
|
+
directions should be considered.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
ndarray: set of k neighbour direction vectors.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
# Base transition vector
|
|
37
|
+
trans = np.arange(start=-np.ceil(d), stop=np.ceil(d)+1)
|
|
38
|
+
n = np.size(trans)
|
|
39
|
+
|
|
40
|
+
# Build transition array [x,y,z]
|
|
41
|
+
nbrs = np.array([rep(x=trans, each=n * n, times=1),
|
|
42
|
+
rep(x=trans, each=n, times=n),
|
|
43
|
+
rep(x=trans, each=1, times=n * n)], dtype=np.int32)
|
|
44
|
+
|
|
45
|
+
# Initiate maintenance index
|
|
46
|
+
index = np.zeros(np.shape(nbrs)[1], dtype=bool)
|
|
47
|
+
|
|
48
|
+
# Remove neighbours more than distance d from the center ----------------
|
|
49
|
+
|
|
50
|
+
# Manhattan distance
|
|
51
|
+
if distance.lower() in ["manhattan", "l1", "l_1"]:
|
|
52
|
+
index = np.logical_or(index, np.sum(np.abs(nbrs), axis=0) <= d)
|
|
53
|
+
# Eucldian distance
|
|
54
|
+
if distance.lower() in ["euclidian", "l2", "l_2"]:
|
|
55
|
+
index = np.logical_or(index, np.sqrt(
|
|
56
|
+
np.sum(np.multiply(nbrs, nbrs), axis=0)) <= d)
|
|
57
|
+
# Chebyshev distance
|
|
58
|
+
if distance.lower() in ["chebyshev", "linf", "l_inf"]:
|
|
59
|
+
index = np.logical_or(index, np.max(np.abs(nbrs), axis=0) <= d)
|
|
60
|
+
|
|
61
|
+
# Check if centre voxel [0,0,0] should be maintained; False indicates removal
|
|
62
|
+
if centre is False:
|
|
63
|
+
index = np.logical_and(index, (np.sum(np.abs(nbrs), axis=0)) > 0)
|
|
64
|
+
|
|
65
|
+
# Check if a complete neighbourhood should be returned
|
|
66
|
+
# False indicates that only half of the vectors are returned
|
|
67
|
+
if complete is False:
|
|
68
|
+
index[np.arange(start=0, stop=len(index)//2 + 1)] = False
|
|
69
|
+
|
|
70
|
+
# Check if neighbourhood should be 3D or 2D
|
|
71
|
+
if dim3 is False:
|
|
72
|
+
index[nbrs[2, :] != 0] = False
|
|
73
|
+
|
|
74
|
+
return nbrs[:, index]
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def rep(x: np.ndarray,
|
|
78
|
+
each=1,
|
|
79
|
+
times=1) -> np.ndarray:
|
|
80
|
+
"""Replicates the values in ``x``.
|
|
81
|
+
Replicates the :func:`"rep"` function found in R for tiling and repeating vectors.
|
|
82
|
+
|
|
83
|
+
Note:
|
|
84
|
+
Code was adapted from the in-house radiomics software created at OncoRay,
|
|
85
|
+
Dresden, Germany.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
x (ndarray): Array to replicate.
|
|
89
|
+
each (int): Integer (non-negative) giving the number of times to repeat
|
|
90
|
+
each element of the passed array.
|
|
91
|
+
times (int): Integer (non-negative). Each element of ``x`` is repeated each times.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
ndarray: Array with same values but replicated.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
each = int(each)
|
|
98
|
+
times = int(times)
|
|
99
|
+
|
|
100
|
+
if each > 1:
|
|
101
|
+
x = np.repeat(x, repeats=each)
|
|
102
|
+
|
|
103
|
+
if times > 1:
|
|
104
|
+
x = np.tile(x, reps=times)
|
|
105
|
+
|
|
106
|
+
return x
|
|
107
|
+
|
|
108
|
+
def get_value(x: np.ndarray,
|
|
109
|
+
index: int,
|
|
110
|
+
replace_invalid=True) -> np.ndarray:
|
|
111
|
+
"""Retrieves intensity values from an image intensity table used for computing
|
|
112
|
+
texture features.
|
|
113
|
+
|
|
114
|
+
Note:
|
|
115
|
+
Code was adapted from the in-house radiomics software created at OncoRay,
|
|
116
|
+
Dresden, Germany.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
x (ndarray): set of intensity values.
|
|
120
|
+
index (int): Index to the provided set of intensity values.
|
|
121
|
+
replace_invalid (bool, optional): If True, invalid indices will be replaced
|
|
122
|
+
by a placeholder "NaN" value.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
ndarray: Array of the intensity values found at the requested indices.
|
|
126
|
+
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
# Initialise placeholder
|
|
130
|
+
read_x = np.zeros(np.shape(x))
|
|
131
|
+
|
|
132
|
+
# Read variables for valid indices
|
|
133
|
+
read_x[index >= 0] = x[index[index >= 0]]
|
|
134
|
+
|
|
135
|
+
if replace_invalid:
|
|
136
|
+
# Set variables for invalid indices to nan
|
|
137
|
+
read_x[index < 0] = np.nan
|
|
138
|
+
|
|
139
|
+
# Set variables for invalid initial indices to nan
|
|
140
|
+
read_x[np.isnan(x)] = np.nan
|
|
141
|
+
|
|
142
|
+
return read_x
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def coord2index(x: np.ndarray,
|
|
146
|
+
y: np.ndarray,
|
|
147
|
+
z: np.ndarray,
|
|
148
|
+
dims: Union[List, np.ndarray]) -> Union[np.ndarray,
|
|
149
|
+
List]:
|
|
150
|
+
"""Translate requested coordinates to row indices in image intensity tables.
|
|
151
|
+
|
|
152
|
+
Note:
|
|
153
|
+
Code was adapted from the in-house radiomics software created at OncoRay,
|
|
154
|
+
Dresden, Germany.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
x (ndarray): set of discrete x-coordinates.
|
|
158
|
+
y (ndarray): set of discrete y-coordinates.
|
|
159
|
+
z (ndarray): set of discrete z-coordinates.
|
|
160
|
+
dims (ndarray or List): dimensions of the image.
|
|
161
|
+
|
|
162
|
+
Returns:
|
|
163
|
+
ndarray or List: Array or List of indexes corresponding the requested coordinates
|
|
164
|
+
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
# Translate coordinates to indices
|
|
168
|
+
index = z + y * dims[2] + x * dims[2] * dims[1]
|
|
169
|
+
|
|
170
|
+
# Mark invalid transitions
|
|
171
|
+
index[np.logical_or(x < 0, x >= dims[0])] = -99999
|
|
172
|
+
index[np.logical_or(y < 0, y >= dims[1])] = -99999
|
|
173
|
+
index[np.logical_or(z < 0, z >= dims[2])] = -99999
|
|
174
|
+
|
|
175
|
+
return index
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def is_list_all_none(x: List) -> bool:
|
|
179
|
+
"""Determines if all list elements are None.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
x (List): List of elements to check.
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
bool: True if all elemets in `x` are None.
|
|
186
|
+
|
|
187
|
+
"""
|
|
188
|
+
return all(y is None for y in x)
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
glcm_features_names = [
|
|
2
|
+
"Fcm_joint_max",
|
|
3
|
+
"Fcm_joint_avg",
|
|
4
|
+
"Fcm_joint_var",
|
|
5
|
+
"Fcm_joint_entr",
|
|
6
|
+
"Fcm_diff_avg",
|
|
7
|
+
"Fcm_diff_var",
|
|
8
|
+
"Fcm_diff_entr",
|
|
9
|
+
"Fcm_sum_avg",
|
|
10
|
+
"Fcm_sum_var",
|
|
11
|
+
"Fcm_sum_entr",
|
|
12
|
+
"Fcm_energy",
|
|
13
|
+
"Fcm_contrast",
|
|
14
|
+
"Fcm_dissimilarity",
|
|
15
|
+
"Fcm_inv_diff",
|
|
16
|
+
"Fcm_inv_diff_norm",
|
|
17
|
+
"Fcm_inv_diff_mom",
|
|
18
|
+
"Fcm_inv_diff_mom_norm",
|
|
19
|
+
"Fcm_inv_var",
|
|
20
|
+
"Fcm_corr",
|
|
21
|
+
"Fcm_auto_corr",
|
|
22
|
+
"Fcm_info_corr1",
|
|
23
|
+
"Fcm_info_corr2",
|
|
24
|
+
"Fcm_clust_tend",
|
|
25
|
+
"Fcm_clust_shade",
|
|
26
|
+
"Fcm_clust_prom"
|
|
27
|
+
]
|
|
28
|
+
glrlm_features_names = [
|
|
29
|
+
"Frlm_sre",
|
|
30
|
+
"Frlm_lre",
|
|
31
|
+
"Frlm_lgre",
|
|
32
|
+
"Frlm_hgre",
|
|
33
|
+
"Frlm_srlge",
|
|
34
|
+
"Frlm_srhge",
|
|
35
|
+
"Frlm_lrlge",
|
|
36
|
+
"Frlm_lrhge",
|
|
37
|
+
"Frlm_glnu",
|
|
38
|
+
"Frlm_glnu_norm",
|
|
39
|
+
"Frlm_rlnu",
|
|
40
|
+
"Frlm_rlnu_norm",
|
|
41
|
+
"Frlm_r_perc",
|
|
42
|
+
"Frlm_gl_var",
|
|
43
|
+
"Frlm_rl_var",
|
|
44
|
+
"Frlm_rl_entr"
|
|
45
|
+
]
|
|
46
|
+
glszm_features_names = [
|
|
47
|
+
"Fszm_sze",
|
|
48
|
+
"Fszm_lze",
|
|
49
|
+
"Fszm_lgze",
|
|
50
|
+
"Fszm_hgze",
|
|
51
|
+
"Fszm_szlge",
|
|
52
|
+
"Fszm_szhge",
|
|
53
|
+
"Fszm_lzlge",
|
|
54
|
+
"Fszm_lzhge",
|
|
55
|
+
"Fszm_glnu",
|
|
56
|
+
"Fszm_glnu_norm",
|
|
57
|
+
"Fszm_zsnu",
|
|
58
|
+
"Fszm_zsnu_norm",
|
|
59
|
+
"Fszm_z_perc",
|
|
60
|
+
"Fszm_gl_var",
|
|
61
|
+
"Fszm_zs_var",
|
|
62
|
+
"Fszm_zs_entr",
|
|
63
|
+
]
|
|
64
|
+
gldzm_features_names = [
|
|
65
|
+
"Fdzm_sde",
|
|
66
|
+
"Fdzm_lde",
|
|
67
|
+
"Fdzm_lgze",
|
|
68
|
+
"Fdzm_hgze",
|
|
69
|
+
"Fdzm_sdlge",
|
|
70
|
+
"Fdzm_sdhge",
|
|
71
|
+
"Fdzm_ldlge",
|
|
72
|
+
"Fdzm_ldhge",
|
|
73
|
+
"Fdzm_glnu",
|
|
74
|
+
"Fdzm_glnu_norm",
|
|
75
|
+
"Fdzm_zdnu",
|
|
76
|
+
"Fdzm_zdnu_norm",
|
|
77
|
+
"Fdzm_z_perc",
|
|
78
|
+
"Fdzm_gl_var",
|
|
79
|
+
"Fdzm_zd_var",
|
|
80
|
+
"Fdzm_zd_entr"
|
|
81
|
+
]
|
|
82
|
+
ngtdm_features_names = [
|
|
83
|
+
"Fngt_coarseness"
|
|
84
|
+
"Fngt_contrast"
|
|
85
|
+
"Fngt_busyness"
|
|
86
|
+
"Fngt_complexity"
|
|
87
|
+
"Fngt_strength"
|
|
88
|
+
]
|
|
89
|
+
ngldm_features_names = [
|
|
90
|
+
"Fngl_lde",
|
|
91
|
+
"Fngl_hde",
|
|
92
|
+
"Fngl_lgce",
|
|
93
|
+
"Fngl_hgce",
|
|
94
|
+
"Fngl_ldlge",
|
|
95
|
+
"Fngl_ldhge",
|
|
96
|
+
"Fngl_hdlge",
|
|
97
|
+
"Fngl_hdhge",
|
|
98
|
+
"Fngl_glnu",
|
|
99
|
+
"Fngl_glnu_norm",
|
|
100
|
+
"Fngl_dcnu",
|
|
101
|
+
"Fngl_dcnu_norm",
|
|
102
|
+
"Fngl_gl_var",
|
|
103
|
+
"Fngl_dc_var",
|
|
104
|
+
"Fngl_dc_entr",
|
|
105
|
+
"Fngl_dc_energy"
|
|
106
|
+
]
|
|
107
|
+
# PS: DO NOT CHANGE THE ORDER OF THE LISTS BELOW, CHANGING THE ORDER WILL BREAK THE CODE (RESULTS CLASS)
|
|
108
|
+
texture_features_all = [
|
|
109
|
+
glcm_features_names,
|
|
110
|
+
ngtdm_features_names,
|
|
111
|
+
ngldm_features_names,
|
|
112
|
+
glrlm_features_names,
|
|
113
|
+
gldzm_features_names,
|
|
114
|
+
glszm_features_names
|
|
115
|
+
]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Union
|
|
6
|
+
|
|
7
|
+
import numpy as np
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def write_radiomics_csv(path_radiomics_table: Union[Path, str]) -> None:
|
|
11
|
+
"""
|
|
12
|
+
Loads a radiomics structure (dict with radiomics features) to convert it to a CSV file and save it.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
path_radiomics_table(Union[Path, str]): path to the radiomics dict.
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
None.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
# INITIALIZATION
|
|
22
|
+
path_radiomics_table = Path(path_radiomics_table)
|
|
23
|
+
path_to_table = path_radiomics_table.parent
|
|
24
|
+
name_table = path_radiomics_table.stem
|
|
25
|
+
|
|
26
|
+
# LOAD RADIOMICS TABLE
|
|
27
|
+
radiomics_table_dict = np.load(path_radiomics_table, allow_pickle=True)[0]
|
|
28
|
+
|
|
29
|
+
# WRITE RADIOMICS TABLE IN CSV FORMAT
|
|
30
|
+
csv_name = name_table + '.csv'
|
|
31
|
+
csv_path = path_to_table / csv_name
|
|
32
|
+
radiomics_table_dict['Table'] = radiomics_table_dict['Table'].fillna(value='NaN')
|
|
33
|
+
radiomics_table_dict['Table'] = radiomics_table_dict['Table'].sort_index()
|
|
34
|
+
radiomics_table_dict['Table'].to_csv(csv_path,
|
|
35
|
+
sep=',',
|
|
36
|
+
encoding='utf-8',
|
|
37
|
+
index=True,
|
|
38
|
+
index_label=radiomics_table_dict['Properties']['DimensionNames'][0])
|
|
39
|
+
|
|
40
|
+
# WRITE DEFINITIONS.TXT
|
|
41
|
+
txt_name = name_table + '.txt'
|
|
42
|
+
txt_Path = path_to_table / txt_name
|
|
43
|
+
|
|
44
|
+
# WRITE THE CSV
|
|
45
|
+
fid = open(txt_Path, 'w')
|
|
46
|
+
fid.write(radiomics_table_dict['Properties']['UserData'])
|
|
47
|
+
fid.close()
|