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,1738 @@
|
|
|
1
|
+
from string import Template
|
|
2
|
+
|
|
3
|
+
glcm_kernel = Template("""
|
|
4
|
+
#include <stdio.h>
|
|
5
|
+
#include <math.h>
|
|
6
|
+
#include <iostream>
|
|
7
|
+
|
|
8
|
+
# define MAX_SIZE ${max_vol}
|
|
9
|
+
# define FILTER_SIZE ${filter_size}
|
|
10
|
+
|
|
11
|
+
// Function flatten a 3D matrix into a 1D vector
|
|
12
|
+
__device__ float * reshape(float(*matrix)[FILTER_SIZE][FILTER_SIZE]) {
|
|
13
|
+
//size of array
|
|
14
|
+
const int size = FILTER_SIZE* FILTER_SIZE* FILTER_SIZE;
|
|
15
|
+
float flattened[size];
|
|
16
|
+
int index = 0;
|
|
17
|
+
for (int i = 0; i < FILTER_SIZE; ++i) {
|
|
18
|
+
for (int j = 0; j < FILTER_SIZE; ++j) {
|
|
19
|
+
for (int k = 0; k < FILTER_SIZE; ++k) {
|
|
20
|
+
flattened[index] = matrix[i][j][k];
|
|
21
|
+
index++;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return flattened;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Function to perform histogram equalisation of the ROI imaging intensities
|
|
29
|
+
__device__ void discretize(float vol_quant_re[FILTER_SIZE][FILTER_SIZE][FILTER_SIZE],
|
|
30
|
+
float max_val, float min_val=${min_val}) {
|
|
31
|
+
|
|
32
|
+
// PARSING ARGUMENTS
|
|
33
|
+
float n_q = ${n_q};
|
|
34
|
+
const char* discr_type = "${discr_type}";
|
|
35
|
+
|
|
36
|
+
// DISCRETISATION
|
|
37
|
+
if (discr_type == "FBS") {
|
|
38
|
+
float w_b = n_q;
|
|
39
|
+
for (int i = 0; i < FILTER_SIZE; i++) {
|
|
40
|
+
for (int j = 0; j < FILTER_SIZE; j++) {
|
|
41
|
+
for (int k = 0; k < FILTER_SIZE; k++) {
|
|
42
|
+
float value = vol_quant_re[i][j][k];
|
|
43
|
+
if (!isnan(value)) {
|
|
44
|
+
vol_quant_re[i][j][k] = floorf((value - min_val) / w_b) + 1.0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
else if (discr_type == "FBN") {
|
|
51
|
+
float w_b = (max_val - min_val) / n_q;
|
|
52
|
+
for (int i = 0; i < FILTER_SIZE; i++) {
|
|
53
|
+
for (int j = 0; j < FILTER_SIZE; j++) {
|
|
54
|
+
for (int k = 0; k < FILTER_SIZE; k++) {
|
|
55
|
+
float value = vol_quant_re[i][j][k];
|
|
56
|
+
if (!isnan(value)) {
|
|
57
|
+
vol_quant_re[i][j][k] = floorf(n_q * ((value - min_val) / (max_val - min_val))) + 1.0;
|
|
58
|
+
if (value == max_val) {
|
|
59
|
+
vol_quant_re[i][j][k] = n_q;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
printf("ERROR: discretization type not supported");
|
|
68
|
+
assert(false);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Compute the diagonal probability
|
|
73
|
+
__device__ float * GLCMDiagProb(float p_ij[MAX_SIZE][MAX_SIZE], float max_vol) {
|
|
74
|
+
int valK[MAX_SIZE];
|
|
75
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
76
|
+
valK[i] = i;
|
|
77
|
+
}
|
|
78
|
+
float p_iminusj[MAX_SIZE] = { 0.0 };
|
|
79
|
+
for (int iterationK = 0; iterationK < (int)max_vol; ++iterationK) {
|
|
80
|
+
int k = valK[iterationK];
|
|
81
|
+
float p = 0.0;
|
|
82
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
83
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
84
|
+
if (k - fabsf(i - j) == 0) {
|
|
85
|
+
p += p_ij[i][j];
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
p_iminusj[iterationK] = p;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return p_iminusj;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Compute the cross-diagonal probability
|
|
97
|
+
__device__ float * GLCMCrossDiagProb(float p_ij[MAX_SIZE][MAX_SIZE], float max_vol) {
|
|
98
|
+
float valK[2 * MAX_SIZE - 1];
|
|
99
|
+
// fill valK with 2, 3, 4, ..., 2*max_vol - 1
|
|
100
|
+
for (int i = 0; i < 2 * (int)max_vol - 1; ++i) {
|
|
101
|
+
valK[i] = i + 2;
|
|
102
|
+
}
|
|
103
|
+
float p_iplusj[2*MAX_SIZE - 1] = { 0.0 };
|
|
104
|
+
|
|
105
|
+
for (int iterationK = 0; iterationK < 2*(int)max_vol - 1; ++iterationK) {
|
|
106
|
+
int k = valK[iterationK];
|
|
107
|
+
float p = 0.0;
|
|
108
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
109
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
110
|
+
if (k - (i + j + 2) == 0) {
|
|
111
|
+
p += p_ij[i][j];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
p_iplusj[iterationK] = p;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return p_iplusj;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
__device__ void getGLCMmatrix(
|
|
123
|
+
float (*ROIonly)[FILTER_SIZE][FILTER_SIZE],
|
|
124
|
+
float GLCMfinal[MAX_SIZE][MAX_SIZE],
|
|
125
|
+
float max_vol,
|
|
126
|
+
bool distCorrection = true)
|
|
127
|
+
{
|
|
128
|
+
// PARSING "distCorrection" ARGUMENT
|
|
129
|
+
|
|
130
|
+
const int Ng = MAX_SIZE;
|
|
131
|
+
float levels[Ng] = {0};
|
|
132
|
+
// initialize levels to 1, 2, 3, ..., 15
|
|
133
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
134
|
+
levels[i] = i + 1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
float levelTemp = max_vol + 1;
|
|
138
|
+
|
|
139
|
+
for (int i = 0; i < FILTER_SIZE; ++i) {
|
|
140
|
+
for (int j = 0; j < FILTER_SIZE; ++j) {
|
|
141
|
+
for (int k = 0; k < FILTER_SIZE; ++k) {
|
|
142
|
+
if (isnan(ROIonly[i][j][k])) {
|
|
143
|
+
ROIonly[i][j][k] = levelTemp;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
int dim_x = FILTER_SIZE;
|
|
150
|
+
int dim_y = FILTER_SIZE;
|
|
151
|
+
int dim_z = FILTER_SIZE;
|
|
152
|
+
|
|
153
|
+
// Reshape the 3D matrix to a 1D vector
|
|
154
|
+
float *q2;
|
|
155
|
+
q2 = reshape(ROIonly);
|
|
156
|
+
|
|
157
|
+
// Combine levels and level_temp into qs
|
|
158
|
+
float qs[Ng + 1] = {0};
|
|
159
|
+
for (int i = 0; i < (int)max_vol + 1; ++i) {
|
|
160
|
+
if (i == (int)max_vol) {
|
|
161
|
+
qs[i] = levelTemp;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
qs[i] = levels[i];
|
|
165
|
+
}
|
|
166
|
+
const int lqs = Ng + 1;
|
|
167
|
+
|
|
168
|
+
// Create a q3 matrix and assign values based on qs
|
|
169
|
+
int q3[FILTER_SIZE* FILTER_SIZE* FILTER_SIZE] = {0};
|
|
170
|
+
|
|
171
|
+
// fill q3 with 0s
|
|
172
|
+
for (int i = 0; i < FILTER_SIZE * FILTER_SIZE * FILTER_SIZE; ++i) {
|
|
173
|
+
q3[i] = 0;
|
|
174
|
+
}
|
|
175
|
+
for (int k = 0; k < (int)max_vol + 1; ++k) {
|
|
176
|
+
for (int i = 0; i < FILTER_SIZE * FILTER_SIZE * FILTER_SIZE; ++i) {
|
|
177
|
+
if (fabsf(q2[i] - qs[k]) < 1.19209e-07) {
|
|
178
|
+
q3[i] = k;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Reshape q3 back to the original dimensions (dimX, dimY, dimZ)
|
|
184
|
+
float reshaped_q3[FILTER_SIZE][FILTER_SIZE][FILTER_SIZE];
|
|
185
|
+
|
|
186
|
+
int index = 0;
|
|
187
|
+
for (int i = 0; i < dim_x; ++i) {
|
|
188
|
+
for (int j = 0; j < dim_y; ++j) {
|
|
189
|
+
for (int k = 0; k < dim_z; ++k) {
|
|
190
|
+
reshaped_q3[i][j][k] = q3[index++];
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
float GLCM[lqs][lqs] = {0};
|
|
197
|
+
|
|
198
|
+
// fill GLCM with 0s
|
|
199
|
+
for (int i = 0; i < (int)max_vol + 1; ++i) {
|
|
200
|
+
for (int j = 0; j < (int)max_vol + 1; ++j) {
|
|
201
|
+
GLCM[i][j] = 0;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
for (int i = 1; i <= dim_x; ++i) {
|
|
206
|
+
int i_min = max(1, i - 1);
|
|
207
|
+
int i_max = min(i + 1, dim_x);
|
|
208
|
+
for (int j = 1; j <= dim_y; ++j) {
|
|
209
|
+
int j_min = max(1, j - 1);
|
|
210
|
+
int j_max = min(j + 1, dim_y);
|
|
211
|
+
for (int k = 1; k <= dim_z; ++k) {
|
|
212
|
+
int k_min = max(1, k - 1);
|
|
213
|
+
int k_max = min(k + 1, dim_z);
|
|
214
|
+
int val_q3 = reshaped_q3[i - 1][j - 1][k - 1];
|
|
215
|
+
for (int I2 = i_min; I2 <= i_max; ++I2) {
|
|
216
|
+
for (int J2 = j_min; J2 <= j_max; ++J2) {
|
|
217
|
+
for (int K2 = k_min; K2 <= k_max; ++K2) {
|
|
218
|
+
if (I2 == i && J2 == j && K2 == k) {
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
int val_neighbor = reshaped_q3[I2 - 1][J2 - 1][K2 - 1];
|
|
223
|
+
if (distCorrection) {
|
|
224
|
+
// Discretization length correction
|
|
225
|
+
GLCM[val_q3][val_neighbor] +=
|
|
226
|
+
sqrtf(fabsf(I2 - i) +
|
|
227
|
+
fabsf(J2 - j) +
|
|
228
|
+
fabsf(K2 - k));
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
GLCM[val_q3][val_neighbor] += 1;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Eliminate last row and column
|
|
242
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
243
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
244
|
+
GLCMfinal[i][j] = GLCM[i][j];
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
__device__ void computeGLCMFeatures(float(*vol)[FILTER_SIZE][FILTER_SIZE], float features[25], float max_vol, bool distCorrection) {
|
|
250
|
+
|
|
251
|
+
float GLCM[MAX_SIZE][MAX_SIZE] = { 0.0 };
|
|
252
|
+
|
|
253
|
+
// Call function with specified distCorrection
|
|
254
|
+
getGLCMmatrix(vol, GLCM, max_vol, distCorrection);
|
|
255
|
+
|
|
256
|
+
// Normalize GLCM
|
|
257
|
+
float sumGLCM = 0.0;
|
|
258
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
259
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
260
|
+
sumGLCM += GLCM[i][j];
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
264
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
265
|
+
GLCM[i][j] /= sumGLCM;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Compute textures
|
|
270
|
+
// // Number of gray levels
|
|
271
|
+
const int Ng = MAX_SIZE;
|
|
272
|
+
float vectNg[Ng];
|
|
273
|
+
|
|
274
|
+
// fill vectNg with 1, 2, ..., Ng
|
|
275
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
276
|
+
vectNg[i] = i + 1;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Create meshgird of size Ng x Ng
|
|
280
|
+
float colGrid[Ng][Ng] = { 0.0 };
|
|
281
|
+
float rowGrid[Ng][Ng] = { 0.0 };
|
|
282
|
+
|
|
283
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
284
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
285
|
+
colGrid[i][j] = vectNg[j];
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
289
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
290
|
+
rowGrid[i][j] = vectNg[i];
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
int step_i = 0;
|
|
294
|
+
int step_j = 0;
|
|
295
|
+
|
|
296
|
+
// Joint maximum
|
|
297
|
+
float joint_max = 0.0;
|
|
298
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
299
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
300
|
+
joint_max = max(joint_max, GLCM[i][j]);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
features[0] = joint_max;
|
|
304
|
+
|
|
305
|
+
// Joint average
|
|
306
|
+
float u = 0.0;
|
|
307
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
308
|
+
step_i = 0;
|
|
309
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
310
|
+
u += GLCM[i][j] * rowGrid[i][j];
|
|
311
|
+
step_i++;
|
|
312
|
+
}
|
|
313
|
+
step_j++;
|
|
314
|
+
}
|
|
315
|
+
features[1] = u;
|
|
316
|
+
|
|
317
|
+
// Joint variance
|
|
318
|
+
step_j = 0;
|
|
319
|
+
float var = 0.0;
|
|
320
|
+
u = 0.0;
|
|
321
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
322
|
+
step_i = 0;
|
|
323
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
324
|
+
u += GLCM[i][j] * rowGrid[i][j];
|
|
325
|
+
step_i++;
|
|
326
|
+
}
|
|
327
|
+
step_j++;
|
|
328
|
+
}
|
|
329
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
330
|
+
step_i = 0;
|
|
331
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
332
|
+
var += GLCM[i][j] * powf(rowGrid[i][j] - u, 2);
|
|
333
|
+
step_i++;
|
|
334
|
+
}
|
|
335
|
+
step_j++;
|
|
336
|
+
}
|
|
337
|
+
features[2] = var;
|
|
338
|
+
|
|
339
|
+
// Joint entropy
|
|
340
|
+
float entropy = 0.0;
|
|
341
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
342
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
343
|
+
if (GLCM[i][j] > 0.0) {
|
|
344
|
+
entropy += GLCM[i][j] * log2f(GLCM[i][j]);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
features[3] = -entropy;
|
|
349
|
+
|
|
350
|
+
// Difference average
|
|
351
|
+
float* p_iminusj;
|
|
352
|
+
p_iminusj = GLCMDiagProb(GLCM, max_vol);
|
|
353
|
+
float diff_avg = 0.0;
|
|
354
|
+
float k[Ng];
|
|
355
|
+
// fill k with 0, 1, ..., Ng - 1
|
|
356
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
357
|
+
k[i] = i;
|
|
358
|
+
}
|
|
359
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
360
|
+
diff_avg += p_iminusj[i] * k[i];
|
|
361
|
+
}
|
|
362
|
+
features[4] = diff_avg;
|
|
363
|
+
|
|
364
|
+
// Difference variance
|
|
365
|
+
diff_avg = 0.0;
|
|
366
|
+
// fill k with 0, 1, ..., Ng - 1
|
|
367
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
368
|
+
k[i] = i;
|
|
369
|
+
}
|
|
370
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
371
|
+
diff_avg += p_iminusj[i] * k[i];
|
|
372
|
+
}
|
|
373
|
+
float diff_var = 0.0;
|
|
374
|
+
step_i = 0;
|
|
375
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
376
|
+
diff_var += p_iminusj[i] * powf(k[i] - diff_avg, 2);
|
|
377
|
+
step_i++;
|
|
378
|
+
}
|
|
379
|
+
features[5] = diff_var;
|
|
380
|
+
|
|
381
|
+
// Difference entropy
|
|
382
|
+
float diff_entropy = 0.0;
|
|
383
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
384
|
+
if (p_iminusj[i] > 0.0) {
|
|
385
|
+
diff_entropy += p_iminusj[i] * log2f(p_iminusj[i]);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
features[6] = -diff_entropy;
|
|
389
|
+
|
|
390
|
+
// Sum average
|
|
391
|
+
float k1[2 * Ng - 1];
|
|
392
|
+
// fill k with 2, 3, ..., 2 * Ng
|
|
393
|
+
for (int i = 0; i < 2 * int(max_vol) - 1; ++i) {
|
|
394
|
+
k1[i] = i + 2;
|
|
395
|
+
}
|
|
396
|
+
float sum_avg = 0.0;
|
|
397
|
+
float* p_iplusj = GLCMCrossDiagProb(GLCM, max_vol);
|
|
398
|
+
for (int i = 0; i < 2 * int(max_vol) - 1; ++i) {
|
|
399
|
+
sum_avg += p_iplusj[i] * k1[i];
|
|
400
|
+
}
|
|
401
|
+
features[7] = sum_avg;
|
|
402
|
+
|
|
403
|
+
// Sum variance
|
|
404
|
+
float sum_var = 0.0;
|
|
405
|
+
for (int i = 0; i < 2 * int(max_vol) - 1; ++i) {
|
|
406
|
+
sum_var += p_iplusj[i] * powf(k1[i] - sum_avg, 2);
|
|
407
|
+
}
|
|
408
|
+
features[8] = sum_var;
|
|
409
|
+
|
|
410
|
+
// Sum entropy
|
|
411
|
+
float sum_entr = 0.0;
|
|
412
|
+
for (int i = 0; i < 2 * int(max_vol) - 1; ++i) {
|
|
413
|
+
if (p_iplusj[i] > 0.0) {
|
|
414
|
+
sum_entr += p_iplusj[i] * log2f(p_iplusj[i]);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
features[9] = -sum_entr;
|
|
418
|
+
|
|
419
|
+
// Angular second moment (energy)
|
|
420
|
+
float energy = 0.0;
|
|
421
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
422
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
423
|
+
energy += powf(GLCM[i][j], 2);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
features[10] = energy;
|
|
427
|
+
|
|
428
|
+
// Contrast
|
|
429
|
+
float contrast = 0.0;
|
|
430
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
431
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
432
|
+
contrast += powf(rowGrid[i][j] - colGrid[i][j], 2) * GLCM[i][j];
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
features[11] = contrast;
|
|
436
|
+
|
|
437
|
+
// Dissimilarity
|
|
438
|
+
float dissimilarity = 0.0;
|
|
439
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
440
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
441
|
+
dissimilarity += fabsf(rowGrid[i][j] - colGrid[i][j]) * GLCM[i][j];
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
features[12] = dissimilarity;
|
|
445
|
+
|
|
446
|
+
// Inverse difference
|
|
447
|
+
float inv_diff = 0.0;
|
|
448
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
449
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
450
|
+
inv_diff += GLCM[i][j] / (1 + fabsf(rowGrid[i][j] - colGrid[i][j]));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
features[13] = inv_diff;
|
|
454
|
+
|
|
455
|
+
// Inverse difference normalized
|
|
456
|
+
float invDiffNorm = 0.0;
|
|
457
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
458
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
459
|
+
invDiffNorm += GLCM[i][j] / (1 + fabsf(rowGrid[i][j] - colGrid[i][j]) / int(max_vol));
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
features[14] = invDiffNorm;
|
|
463
|
+
|
|
464
|
+
// Inverse difference moment
|
|
465
|
+
float invDiffMom = 0.0;
|
|
466
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
467
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
468
|
+
invDiffMom += GLCM[i][j] / (1 + powf((rowGrid[i][j] - colGrid[i][j]), 2));
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
features[15] = invDiffMom;
|
|
472
|
+
|
|
473
|
+
// Inverse difference moment normalized
|
|
474
|
+
float invDiffMomNorm = 0.0;
|
|
475
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
476
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
477
|
+
invDiffMomNorm += GLCM[i][j] / (1 + powf((rowGrid[i][j] - colGrid[i][j]), 2) / powf(int(max_vol), 2));
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
features[16] = invDiffMomNorm;
|
|
481
|
+
|
|
482
|
+
// Inverse variance
|
|
483
|
+
float invVar = 0.0;
|
|
484
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
485
|
+
for (int j = i + 1; j < int(max_vol); j++) {
|
|
486
|
+
invVar += GLCM[i][j] / powf((i - j), 2);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
features[17] = 2*invVar;
|
|
490
|
+
|
|
491
|
+
// Correlation
|
|
492
|
+
float u_i = 0.0;
|
|
493
|
+
float u_j = 0.0;
|
|
494
|
+
float std_i = 0.0;
|
|
495
|
+
float std_j = 0.0;
|
|
496
|
+
float p_i[Ng] = { 0.0 };
|
|
497
|
+
float p_j[Ng] = { 0.0 };
|
|
498
|
+
|
|
499
|
+
// sum over rows
|
|
500
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
501
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
502
|
+
p_i[i] += GLCM[i][j];
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
// sum over columns
|
|
506
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
507
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
508
|
+
p_j[j] += GLCM[i][j];
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
512
|
+
u_i += vectNg[i] * p_i[i];
|
|
513
|
+
u_j += vectNg[i] * p_j[i];
|
|
514
|
+
}
|
|
515
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
516
|
+
std_i += powf(vectNg[i] - u_i, 2) * p_i[i];
|
|
517
|
+
std_j += powf(vectNg[i] - u_j, 2) * p_j[i];
|
|
518
|
+
}
|
|
519
|
+
std_i = sqrtf(std_i);
|
|
520
|
+
std_j = sqrtf(std_j);
|
|
521
|
+
|
|
522
|
+
float tempSum = 0.0;
|
|
523
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
524
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
525
|
+
tempSum += rowGrid[i][j] * colGrid[i][j] * GLCM[i][j];
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
float correlation = (1 / (std_i * std_j)) * (-u_i * u_j + tempSum);
|
|
529
|
+
features[18] = correlation;
|
|
530
|
+
|
|
531
|
+
// Autocorrelation
|
|
532
|
+
float autoCorr = 0.0;
|
|
533
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
534
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
535
|
+
autoCorr += rowGrid[i][j] * colGrid[i][j] * GLCM[i][j];
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
features[19] = autoCorr;
|
|
539
|
+
|
|
540
|
+
// Cluster tendency
|
|
541
|
+
float clusterTend = 0.0;
|
|
542
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
543
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
544
|
+
clusterTend += powf(rowGrid[i][j] + colGrid[i][j] - u_i - u_j, 2) * GLCM[i][j];
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
features[20] = clusterTend;
|
|
548
|
+
|
|
549
|
+
// Cluster shade
|
|
550
|
+
float clusterShade = 0.0;
|
|
551
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
552
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
553
|
+
clusterShade += powf(rowGrid[i][j] + colGrid[i][j] - u_i - u_j, 3) * GLCM[i][j];
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
features[21] = clusterShade;
|
|
557
|
+
|
|
558
|
+
// Cluster prominence
|
|
559
|
+
float clusterProm = 0.0;
|
|
560
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
561
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
562
|
+
clusterProm += powf(rowGrid[i][j] + colGrid[i][j] - u_i - u_j, 4) * GLCM[i][j];
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
features[22] = clusterProm;
|
|
566
|
+
|
|
567
|
+
// First measure of information correlation
|
|
568
|
+
float HXY = 0.0;
|
|
569
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
570
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
571
|
+
if (GLCM[i][j] > 0.0) {
|
|
572
|
+
HXY += GLCM[i][j] * log2f(GLCM[i][j]);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
HXY = -HXY;
|
|
577
|
+
|
|
578
|
+
float HX = 0.0;
|
|
579
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
580
|
+
if (p_i[i] > 0.0) {
|
|
581
|
+
HX += p_i[i] * log2f(p_i[i]);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
HX = -HX;
|
|
585
|
+
|
|
586
|
+
// Repeat p_i and p_j Ng times
|
|
587
|
+
float p_i_temp[Ng][Ng];
|
|
588
|
+
float p_j_temp[Ng][Ng];
|
|
589
|
+
float p_temp[Ng][Ng];
|
|
590
|
+
|
|
591
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
592
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
593
|
+
p_i_temp[i][j] = p_i[i];
|
|
594
|
+
p_j_temp[i][j] = p_j[j];
|
|
595
|
+
p_temp[i][j] = p_i_temp[i][j] * p_j_temp[i][j];
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
float HXY1 = 0.0;
|
|
600
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
601
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
602
|
+
if (p_temp[i][j] > 0.0) {
|
|
603
|
+
HXY1 += GLCM[i][j] * log2f(p_temp[i][j]);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
HXY1 = -HXY1;
|
|
608
|
+
features[23] = (HXY - HXY1) / HX;
|
|
609
|
+
|
|
610
|
+
// Second measure of information correlation
|
|
611
|
+
float HXY2 = 0.0;
|
|
612
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
613
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
614
|
+
if (p_temp[i][j] > 0.0) {
|
|
615
|
+
HXY2 += p_temp[i][j] * log2f(p_temp[i][j]);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
HXY2 = -HXY2;
|
|
620
|
+
if (HXY > HXY2) {
|
|
621
|
+
features[24] = 0.0;
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
features[24] = sqrtf(1 - expf(-2 * (HXY2 - HXY)));
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
extern "C"
|
|
629
|
+
__global__ void glcm_filter_global(
|
|
630
|
+
float vol[${shape_volume_0}][${shape_volume_1}][${shape_volume_2}][25],
|
|
631
|
+
float vol_copy[${shape_volume_0}][${shape_volume_1}][${shape_volume_2}],
|
|
632
|
+
bool distCorrection = false)
|
|
633
|
+
{
|
|
634
|
+
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
|
635
|
+
int j = blockIdx.y * blockDim.y + threadIdx.y;
|
|
636
|
+
int k = blockIdx.z * blockDim.z + threadIdx.z;
|
|
637
|
+
|
|
638
|
+
if (i < ${shape_volume_0} && j < ${shape_volume_1} && k < ${shape_volume_2} && i >= 0 && j >= 0 && k >= 0) {
|
|
639
|
+
// pad size
|
|
640
|
+
const int padd_size = (FILTER_SIZE - 1) / 2;
|
|
641
|
+
|
|
642
|
+
// size vol
|
|
643
|
+
const int size_x = ${shape_volume_0};
|
|
644
|
+
const int size_y = ${shape_volume_1};
|
|
645
|
+
const int size_z = ${shape_volume_2};
|
|
646
|
+
|
|
647
|
+
// skip all calculations if vol at position i,j,k is nan
|
|
648
|
+
if (!isnan(vol_copy[i][j][k])) {
|
|
649
|
+
// get submatrix
|
|
650
|
+
float sub_matrix[FILTER_SIZE][FILTER_SIZE][FILTER_SIZE] = {NAN};
|
|
651
|
+
for (int idx_i = 0; idx_i < FILTER_SIZE; ++idx_i) {
|
|
652
|
+
for (int idx_j = 0; idx_j < FILTER_SIZE; ++idx_j) {
|
|
653
|
+
for (int idx_k = 0; idx_k < FILTER_SIZE; ++idx_k) {
|
|
654
|
+
if ((i - padd_size + idx_i) >= 0 && (i - padd_size + idx_i) < size_x &&
|
|
655
|
+
(j - padd_size + idx_j) >= 0 && (j - padd_size + idx_j) < size_y &&
|
|
656
|
+
(k - padd_size + idx_k) >= 0 && (k - padd_size + idx_k) < size_z) {
|
|
657
|
+
sub_matrix[idx_i][idx_j][idx_k] = vol_copy[i - padd_size + idx_i][j - padd_size + idx_j][k - padd_size + idx_k];
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// get the maximum value of the submatrix
|
|
664
|
+
float max_vol = -3.40282e+38;
|
|
665
|
+
for (int idx_i = 0; idx_i < FILTER_SIZE; ++idx_i) {
|
|
666
|
+
for (int idx_j = 0; idx_j < FILTER_SIZE; ++idx_j) {
|
|
667
|
+
for (int idx_k = 0; idx_k < FILTER_SIZE; ++idx_k) {
|
|
668
|
+
max_vol = max(max_vol, sub_matrix[idx_i][idx_j][idx_k]);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// compute GLCM features
|
|
674
|
+
float features[25] = { 0.0 };
|
|
675
|
+
computeGLCMFeatures(sub_matrix, features, max_vol, false);
|
|
676
|
+
|
|
677
|
+
// Copy GLCM feature to voxels of the volume
|
|
678
|
+
if (i < size_x && j < size_y && k < size_z){
|
|
679
|
+
for (int idx = 0; idx < 25; ++idx) {
|
|
680
|
+
vol[i][j][k][idx] = features[idx];
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
extern "C"
|
|
688
|
+
__global__ void glcm_filter_local(
|
|
689
|
+
float vol[${shape_volume_0}][${shape_volume_1}][${shape_volume_2}][25],
|
|
690
|
+
float vol_copy[${shape_volume_0}][${shape_volume_1}][${shape_volume_2}],
|
|
691
|
+
bool distCorrection = false)
|
|
692
|
+
{
|
|
693
|
+
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
|
694
|
+
int j = blockIdx.y * blockDim.y + threadIdx.y;
|
|
695
|
+
int k = blockIdx.z * blockDim.z + threadIdx.z;
|
|
696
|
+
|
|
697
|
+
if (i < ${shape_volume_0} && j < ${shape_volume_1} && k < ${shape_volume_2} && i >= 0 && j >= 0 && k >= 0) {
|
|
698
|
+
// pad size
|
|
699
|
+
const int padd_size = (FILTER_SIZE - 1) / 2;
|
|
700
|
+
|
|
701
|
+
// size vol
|
|
702
|
+
const int size_x = ${shape_volume_0};
|
|
703
|
+
const int size_y = ${shape_volume_1};
|
|
704
|
+
const int size_z = ${shape_volume_2};
|
|
705
|
+
|
|
706
|
+
// skip all calculations if vol at position i,j,k is nan
|
|
707
|
+
if (!isnan(vol_copy[i][j][k])) {
|
|
708
|
+
// get submatrix
|
|
709
|
+
float sub_matrix[FILTER_SIZE][FILTER_SIZE][FILTER_SIZE] = {NAN};
|
|
710
|
+
for (int idx_i = 0; idx_i < FILTER_SIZE; ++idx_i) {
|
|
711
|
+
for (int idx_j = 0; idx_j < FILTER_SIZE; ++idx_j) {
|
|
712
|
+
for (int idx_k = 0; idx_k < FILTER_SIZE; ++idx_k) {
|
|
713
|
+
if ((i - padd_size + idx_i) >= 0 && (i - padd_size + idx_i) < size_x &&
|
|
714
|
+
(j - padd_size + idx_j) >= 0 && (j - padd_size + idx_j) < size_y &&
|
|
715
|
+
(k - padd_size + idx_k) >= 0 && (k - padd_size + idx_k) < size_z) {
|
|
716
|
+
sub_matrix[idx_i][idx_j][idx_k] = vol_copy[i - padd_size + idx_i][j - padd_size + idx_j][k - padd_size + idx_k];
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// get the maximum value of the submatrix
|
|
723
|
+
float max_vol = -3.40282e+38;
|
|
724
|
+
for (int idx_i = 0; idx_i < FILTER_SIZE; ++idx_i) {
|
|
725
|
+
for (int idx_j = 0; idx_j < FILTER_SIZE; ++idx_j) {
|
|
726
|
+
for (int idx_k = 0; idx_k < FILTER_SIZE; ++idx_k) {
|
|
727
|
+
max_vol = max(max_vol, sub_matrix[idx_i][idx_j][idx_k]);
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
// get the minimum value of the submatrix if discr_type is FBN
|
|
732
|
+
float min_val = 3.40282e+38;
|
|
733
|
+
if ("${discr_type}" == "FBN") {
|
|
734
|
+
for (int idx_i = 0; idx_i < FILTER_SIZE; ++idx_i) {
|
|
735
|
+
for (int idx_j = 0; idx_j < FILTER_SIZE; ++idx_j) {
|
|
736
|
+
for (int idx_k = 0; idx_k < FILTER_SIZE; ++idx_k) {
|
|
737
|
+
min_val = min(min_val, sub_matrix[idx_i][idx_j][idx_k]);
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
discretize(sub_matrix, max_vol, min_val);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// If FBS discretize the submatrix with user set minimum value
|
|
745
|
+
else{
|
|
746
|
+
discretize(sub_matrix, max_vol);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// get the maximum value of the submatrix after discretization
|
|
750
|
+
max_vol = -3.40282e+38;
|
|
751
|
+
for (int idx_i = 0; idx_i < FILTER_SIZE; ++idx_i) {
|
|
752
|
+
for (int idx_j = 0; idx_j < FILTER_SIZE; ++idx_j) {
|
|
753
|
+
for (int idx_k = 0; idx_k < FILTER_SIZE; ++idx_k) {
|
|
754
|
+
max_vol = max(max_vol, sub_matrix[idx_i][idx_j][idx_k]);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// compute GLCM features
|
|
760
|
+
float features[25] = { 0.0 };
|
|
761
|
+
computeGLCMFeatures(sub_matrix, features, max_vol, false);
|
|
762
|
+
|
|
763
|
+
// Copy GLCM feature to voxels of the volume
|
|
764
|
+
if (i < size_x && j < size_y && k < size_z){
|
|
765
|
+
for (int idx = 0; idx < 25; ++idx) {
|
|
766
|
+
vol[i][j][k][idx] = features[idx];
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
""")
|
|
773
|
+
|
|
774
|
+
# Signle-feature kernel
|
|
775
|
+
single_glcm_kernel = Template("""
|
|
776
|
+
#include <stdio.h>
|
|
777
|
+
#include <math.h>
|
|
778
|
+
#include <iostream>
|
|
779
|
+
|
|
780
|
+
# define MAX_SIZE ${max_vol}
|
|
781
|
+
# define FILTER_SIZE ${filter_size}
|
|
782
|
+
|
|
783
|
+
// Function flatten a 3D matrix into a 1D vector
|
|
784
|
+
__device__ float * reshape(float(*matrix)[FILTER_SIZE][FILTER_SIZE]) {
|
|
785
|
+
//size of array
|
|
786
|
+
const int size = FILTER_SIZE* FILTER_SIZE* FILTER_SIZE;
|
|
787
|
+
float flattened[size];
|
|
788
|
+
int index = 0;
|
|
789
|
+
for (int i = 0; i < FILTER_SIZE; ++i) {
|
|
790
|
+
for (int j = 0; j < FILTER_SIZE; ++j) {
|
|
791
|
+
for (int k = 0; k < FILTER_SIZE; ++k) {
|
|
792
|
+
flattened[index] = matrix[i][j][k];
|
|
793
|
+
index++;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
return flattened;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// Function to perform discretization on the ROI imaging intensities
|
|
801
|
+
__device__ void discretize(float vol_quant_re[FILTER_SIZE][FILTER_SIZE][FILTER_SIZE],
|
|
802
|
+
float max_val, float min_val=${min_val}) {
|
|
803
|
+
|
|
804
|
+
// PARSING ARGUMENTS
|
|
805
|
+
float n_q = ${n_q};
|
|
806
|
+
const char* discr_type = "${discr_type}";
|
|
807
|
+
|
|
808
|
+
// DISCRETISATION
|
|
809
|
+
if (discr_type == "FBS") {
|
|
810
|
+
float w_b = n_q;
|
|
811
|
+
for (int i = 0; i < FILTER_SIZE; i++) {
|
|
812
|
+
for (int j = 0; j < FILTER_SIZE; j++) {
|
|
813
|
+
for (int k = 0; k < FILTER_SIZE; k++) {
|
|
814
|
+
float value = vol_quant_re[i][j][k];
|
|
815
|
+
if (!isnan(value)) {
|
|
816
|
+
vol_quant_re[i][j][k] = floorf((value - min_val) / w_b) + 1.0;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
else if (discr_type == "FBN") {
|
|
823
|
+
float w_b = (max_val - min_val) / n_q;
|
|
824
|
+
for (int i = 0; i < FILTER_SIZE; i++) {
|
|
825
|
+
for (int j = 0; j < FILTER_SIZE; j++) {
|
|
826
|
+
for (int k = 0; k < FILTER_SIZE; k++) {
|
|
827
|
+
float value = vol_quant_re[i][j][k];
|
|
828
|
+
if (!isnan(value)) {
|
|
829
|
+
vol_quant_re[i][j][k] = floorf(n_q * ((value - min_val) / (max_val - min_val))) + 1.0;
|
|
830
|
+
if (value == max_val) {
|
|
831
|
+
vol_quant_re[i][j][k] = n_q;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
else {
|
|
839
|
+
printf("ERROR: discretization type not supported");
|
|
840
|
+
assert(false);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// Compute the diagonal probability
|
|
845
|
+
__device__ float * GLCMDiagProb(float p_ij[MAX_SIZE][MAX_SIZE], float max_vol) {
|
|
846
|
+
int valK[MAX_SIZE];
|
|
847
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
848
|
+
valK[i] = i;
|
|
849
|
+
}
|
|
850
|
+
float p_iminusj[MAX_SIZE] = { 0.0 };
|
|
851
|
+
for (int iterationK = 0; iterationK < (int)max_vol; ++iterationK) {
|
|
852
|
+
int k = valK[iterationK];
|
|
853
|
+
float p = 0.0;
|
|
854
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
855
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
856
|
+
if (k - fabsf(i - j) == 0) {
|
|
857
|
+
p += p_ij[i][j];
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
p_iminusj[iterationK] = p;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
return p_iminusj;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// Compute the cross-diagonal probability
|
|
869
|
+
__device__ float * GLCMCrossDiagProb(float p_ij[MAX_SIZE][MAX_SIZE], float max_vol) {
|
|
870
|
+
float valK[2 * MAX_SIZE - 1];
|
|
871
|
+
// fill valK with 2, 3, 4, ..., 2*max_vol - 1
|
|
872
|
+
for (int i = 0; i < 2 * (int)max_vol - 1; ++i) {
|
|
873
|
+
valK[i] = i + 2;
|
|
874
|
+
}
|
|
875
|
+
float p_iplusj[2*MAX_SIZE - 1] = { 0.0 };
|
|
876
|
+
|
|
877
|
+
for (int iterationK = 0; iterationK < 2*(int)max_vol - 1; ++iterationK) {
|
|
878
|
+
int k = valK[iterationK];
|
|
879
|
+
float p = 0.0;
|
|
880
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
881
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
882
|
+
if (k - (i + j + 2) == 0) {
|
|
883
|
+
p += p_ij[i][j];
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
p_iplusj[iterationK] = p;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
return p_iplusj;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
__device__ void getGLCMmatrix(
|
|
895
|
+
float (*ROIonly)[FILTER_SIZE][FILTER_SIZE],
|
|
896
|
+
float GLCMfinal[MAX_SIZE][MAX_SIZE],
|
|
897
|
+
float max_vol,
|
|
898
|
+
bool distCorrection = true)
|
|
899
|
+
{
|
|
900
|
+
// PARSING "distCorrection" ARGUMENT
|
|
901
|
+
|
|
902
|
+
const int Ng = MAX_SIZE;
|
|
903
|
+
float levels[Ng] = {0};
|
|
904
|
+
// initialize levels to 1, 2, 3, ..., 15
|
|
905
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
906
|
+
levels[i] = i + 1;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
float levelTemp = max_vol + 1;
|
|
910
|
+
|
|
911
|
+
for (int i = 0; i < FILTER_SIZE; ++i) {
|
|
912
|
+
for (int j = 0; j < FILTER_SIZE; ++j) {
|
|
913
|
+
for (int k = 0; k < FILTER_SIZE; ++k) {
|
|
914
|
+
if (isnan(ROIonly[i][j][k])) {
|
|
915
|
+
ROIonly[i][j][k] = levelTemp;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
int dim_x = FILTER_SIZE;
|
|
922
|
+
int dim_y = FILTER_SIZE;
|
|
923
|
+
int dim_z = FILTER_SIZE;
|
|
924
|
+
|
|
925
|
+
// Reshape the 3D matrix to a 1D vector
|
|
926
|
+
float *q2;
|
|
927
|
+
q2 = reshape(ROIonly);
|
|
928
|
+
|
|
929
|
+
// Combine levels and level_temp into qs
|
|
930
|
+
float qs[Ng + 1] = {0};
|
|
931
|
+
for (int i = 0; i < (int)max_vol + 1; ++i) {
|
|
932
|
+
if (i == (int)max_vol) {
|
|
933
|
+
qs[i] = levelTemp;
|
|
934
|
+
break;
|
|
935
|
+
}
|
|
936
|
+
qs[i] = levels[i];
|
|
937
|
+
}
|
|
938
|
+
const int lqs = Ng + 1;
|
|
939
|
+
|
|
940
|
+
// Create a q3 matrix and assign values based on qs
|
|
941
|
+
int q3[FILTER_SIZE* FILTER_SIZE* FILTER_SIZE] = {0};
|
|
942
|
+
|
|
943
|
+
// fill q3 with 0s
|
|
944
|
+
for (int i = 0; i < FILTER_SIZE * FILTER_SIZE * FILTER_SIZE; ++i) {
|
|
945
|
+
q3[i] = 0;
|
|
946
|
+
}
|
|
947
|
+
for (int k = 0; k < (int)max_vol + 1; ++k) {
|
|
948
|
+
for (int i = 0; i < FILTER_SIZE * FILTER_SIZE * FILTER_SIZE; ++i) {
|
|
949
|
+
if (fabsf(q2[i] - qs[k]) < 1.19209e-07) {
|
|
950
|
+
q3[i] = k;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// Reshape q3 back to the original dimensions (dimX, dimY, dimZ)
|
|
956
|
+
float reshaped_q3[FILTER_SIZE][FILTER_SIZE][FILTER_SIZE];
|
|
957
|
+
|
|
958
|
+
int index = 0;
|
|
959
|
+
for (int i = 0; i < dim_x; ++i) {
|
|
960
|
+
for (int j = 0; j < dim_y; ++j) {
|
|
961
|
+
for (int k = 0; k < dim_z; ++k) {
|
|
962
|
+
reshaped_q3[i][j][k] = q3[index++];
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
|
|
968
|
+
float GLCM[lqs][lqs] = {0};
|
|
969
|
+
|
|
970
|
+
// fill GLCM with 0s
|
|
971
|
+
for (int i = 0; i < (int)max_vol + 1; ++i) {
|
|
972
|
+
for (int j = 0; j < (int)max_vol + 1; ++j) {
|
|
973
|
+
GLCM[i][j] = 0;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
for (int i = 1; i <= dim_x; ++i) {
|
|
978
|
+
int i_min = max(1, i - 1);
|
|
979
|
+
int i_max = min(i + 1, dim_x);
|
|
980
|
+
for (int j = 1; j <= dim_y; ++j) {
|
|
981
|
+
int j_min = max(1, j - 1);
|
|
982
|
+
int j_max = min(j + 1, dim_y);
|
|
983
|
+
for (int k = 1; k <= dim_z; ++k) {
|
|
984
|
+
int k_min = max(1, k - 1);
|
|
985
|
+
int k_max = min(k + 1, dim_z);
|
|
986
|
+
int val_q3 = reshaped_q3[i - 1][j - 1][k - 1];
|
|
987
|
+
for (int I2 = i_min; I2 <= i_max; ++I2) {
|
|
988
|
+
for (int J2 = j_min; J2 <= j_max; ++J2) {
|
|
989
|
+
for (int K2 = k_min; K2 <= k_max; ++K2) {
|
|
990
|
+
if (I2 == i && J2 == j && K2 == k) {
|
|
991
|
+
continue;
|
|
992
|
+
}
|
|
993
|
+
else {
|
|
994
|
+
int val_neighbor = reshaped_q3[I2 - 1][J2 - 1][K2 - 1];
|
|
995
|
+
if (distCorrection) {
|
|
996
|
+
// Discretization length correction
|
|
997
|
+
GLCM[val_q3][val_neighbor] +=
|
|
998
|
+
sqrtf(fabsf(I2 - i) +
|
|
999
|
+
fabsf(J2 - j) +
|
|
1000
|
+
fabsf(K2 - k));
|
|
1001
|
+
}
|
|
1002
|
+
else {
|
|
1003
|
+
GLCM[val_q3][val_neighbor] += 1;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
// Eliminate last row and column
|
|
1014
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
1015
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
1016
|
+
GLCMfinal[i][j] = GLCM[i][j];
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
__device__ float computeGLCMFeatures(float(*vol)[FILTER_SIZE][FILTER_SIZE], int feature, float max_vol, bool distCorrection) {
|
|
1022
|
+
|
|
1023
|
+
float GLCM[MAX_SIZE][MAX_SIZE] = { 0.0 };
|
|
1024
|
+
|
|
1025
|
+
// Call function with specified distCorrection
|
|
1026
|
+
getGLCMmatrix(vol, GLCM, max_vol, distCorrection);
|
|
1027
|
+
|
|
1028
|
+
// Normalize GLCM
|
|
1029
|
+
float sumGLCM = 0.0;
|
|
1030
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
1031
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
1032
|
+
sumGLCM += GLCM[i][j];
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
1036
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
1037
|
+
GLCM[i][j] /= sumGLCM;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
// Compute textures
|
|
1042
|
+
// // Number of gray levels
|
|
1043
|
+
const int Ng = MAX_SIZE;
|
|
1044
|
+
float vectNg[Ng];
|
|
1045
|
+
|
|
1046
|
+
// fill vectNg with 1, 2, ..., Ng
|
|
1047
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
1048
|
+
vectNg[i] = i + 1;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// Create meshgird of size Ng x Ng
|
|
1052
|
+
float colGrid[Ng][Ng] = { 0.0 };
|
|
1053
|
+
float rowGrid[Ng][Ng] = { 0.0 };
|
|
1054
|
+
|
|
1055
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
1056
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
1057
|
+
colGrid[i][j] = vectNg[j];
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
1061
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1062
|
+
rowGrid[i][j] = vectNg[i];
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
int step_i = 0;
|
|
1066
|
+
int step_j = 0;
|
|
1067
|
+
|
|
1068
|
+
// Joint maximum
|
|
1069
|
+
if (feature == 0) {
|
|
1070
|
+
float joint_max = NAN;
|
|
1071
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
1072
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
1073
|
+
joint_max = max(joint_max, GLCM[i][j]);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
return joint_max;
|
|
1077
|
+
}
|
|
1078
|
+
// Joint average
|
|
1079
|
+
else if (feature == 1) {
|
|
1080
|
+
float u = 0.0;
|
|
1081
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
1082
|
+
step_i = 0;
|
|
1083
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
1084
|
+
u += GLCM[i][j] * rowGrid[i][j];
|
|
1085
|
+
step_i++;
|
|
1086
|
+
}
|
|
1087
|
+
step_j++;
|
|
1088
|
+
}
|
|
1089
|
+
return u;
|
|
1090
|
+
}
|
|
1091
|
+
// Joint variance
|
|
1092
|
+
else if (feature == 2) {
|
|
1093
|
+
step_j = 0;
|
|
1094
|
+
float var = 0.0;
|
|
1095
|
+
float u = 0.0;
|
|
1096
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
1097
|
+
step_i = 0;
|
|
1098
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
1099
|
+
u += GLCM[i][j] * rowGrid[i][j];
|
|
1100
|
+
step_i++;
|
|
1101
|
+
}
|
|
1102
|
+
step_j++;
|
|
1103
|
+
}
|
|
1104
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
1105
|
+
step_i = 0;
|
|
1106
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
1107
|
+
var += GLCM[i][j] * powf(rowGrid[i][j] - u, 2);
|
|
1108
|
+
step_i++;
|
|
1109
|
+
}
|
|
1110
|
+
step_j++;
|
|
1111
|
+
}
|
|
1112
|
+
return var;
|
|
1113
|
+
}
|
|
1114
|
+
// Joint entropy
|
|
1115
|
+
else if (feature == 3) {
|
|
1116
|
+
float entropy = 0.0;
|
|
1117
|
+
for (int i = 0; i < (int)max_vol; ++i) {
|
|
1118
|
+
for (int j = 0; j < (int)max_vol; ++j) {
|
|
1119
|
+
if (GLCM[i][j] > 0.0) {
|
|
1120
|
+
entropy += GLCM[i][j] * log2f(GLCM[i][j]);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
return -entropy;
|
|
1125
|
+
}
|
|
1126
|
+
// Difference average
|
|
1127
|
+
else if (feature == 4) {
|
|
1128
|
+
float *p_iminusj;
|
|
1129
|
+
p_iminusj = GLCMDiagProb(GLCM, max_vol);
|
|
1130
|
+
float diff_avg = 0.0;
|
|
1131
|
+
float k[Ng];
|
|
1132
|
+
// fill k with 0, 1, ..., Ng - 1
|
|
1133
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1134
|
+
k[i] = i;
|
|
1135
|
+
}
|
|
1136
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1137
|
+
diff_avg += p_iminusj[i] * k[i];
|
|
1138
|
+
}
|
|
1139
|
+
return diff_avg;
|
|
1140
|
+
}
|
|
1141
|
+
// Difference variance
|
|
1142
|
+
else if (feature == 5) {
|
|
1143
|
+
float* p_iminusj;
|
|
1144
|
+
p_iminusj = GLCMDiagProb(GLCM, max_vol);
|
|
1145
|
+
float diff_avg = 0.0;
|
|
1146
|
+
float k[Ng];
|
|
1147
|
+
// fill k with 0, 1, ..., Ng - 1
|
|
1148
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1149
|
+
k[i] = i;
|
|
1150
|
+
}
|
|
1151
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1152
|
+
diff_avg += p_iminusj[i] * k[i];
|
|
1153
|
+
}
|
|
1154
|
+
float diff_var = 0.0;
|
|
1155
|
+
step_i = 0;
|
|
1156
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1157
|
+
diff_var += p_iminusj[i] * powf(k[i] - diff_avg, 2);
|
|
1158
|
+
step_i++;
|
|
1159
|
+
}
|
|
1160
|
+
return diff_var;
|
|
1161
|
+
}
|
|
1162
|
+
// Difference entropy
|
|
1163
|
+
else if (feature == 6) {
|
|
1164
|
+
float* p_iminusj = GLCMDiagProb(GLCM, max_vol);
|
|
1165
|
+
float diff_entropy = 0.0;
|
|
1166
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1167
|
+
if (p_iminusj[i] > 0.0) {
|
|
1168
|
+
diff_entropy += p_iminusj[i] * log2f(p_iminusj[i]);
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
return -diff_entropy;
|
|
1172
|
+
}
|
|
1173
|
+
// Sum average
|
|
1174
|
+
else if (feature == 7) {
|
|
1175
|
+
float k[2 * Ng - 1];
|
|
1176
|
+
// fill k with 2, 3, ..., 2 * Ng
|
|
1177
|
+
for (int i = 0; i < 2 * int(max_vol) - 1; ++i) {
|
|
1178
|
+
k[i] = i + 2;
|
|
1179
|
+
}
|
|
1180
|
+
float sum_avg = 0.0;
|
|
1181
|
+
float* p_iplusj = GLCMCrossDiagProb(GLCM, max_vol);
|
|
1182
|
+
for (int i = 0; i < 2*int(max_vol) - 1; ++i) {
|
|
1183
|
+
sum_avg += p_iplusj[i] * k[i];
|
|
1184
|
+
}
|
|
1185
|
+
return sum_avg;
|
|
1186
|
+
}
|
|
1187
|
+
// Sum variance
|
|
1188
|
+
else if (feature == 8) {
|
|
1189
|
+
float k[2 * Ng - 1];
|
|
1190
|
+
// fill k with 2, 3, ..., 2 * Ng
|
|
1191
|
+
for (int i = 0; i < 2 * int(max_vol) - 1; ++i) {
|
|
1192
|
+
k[i] = i + 2;
|
|
1193
|
+
}
|
|
1194
|
+
float sum_avg = 0.0;
|
|
1195
|
+
float* p_iplusj = GLCMCrossDiagProb(GLCM, max_vol);
|
|
1196
|
+
for (int i = 0; i < 2 * int(max_vol) - 1; ++i) {
|
|
1197
|
+
sum_avg += p_iplusj[i] * k[i];
|
|
1198
|
+
}
|
|
1199
|
+
float sum_var = 0.0;
|
|
1200
|
+
for (int i = 0; i < 2 * int(max_vol) - 1; ++i) {
|
|
1201
|
+
sum_var += p_iplusj[i] * powf(k[i] - sum_avg, 2);
|
|
1202
|
+
}
|
|
1203
|
+
return sum_var;
|
|
1204
|
+
}
|
|
1205
|
+
// Sum entropy
|
|
1206
|
+
else if (feature == 9) {
|
|
1207
|
+
float sum_entr = 0.0;
|
|
1208
|
+
float* p_iplusj = GLCMCrossDiagProb(GLCM, max_vol);
|
|
1209
|
+
for (int i = 0; i < 2 * int(max_vol) - 1; ++i) {
|
|
1210
|
+
if (p_iplusj[i] > 0.0) {
|
|
1211
|
+
sum_entr += p_iplusj[i] * log2f(p_iplusj[i]);
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
return -sum_entr;
|
|
1215
|
+
}
|
|
1216
|
+
// Angular second moment (energy)
|
|
1217
|
+
else if (feature == 10) {
|
|
1218
|
+
float energy = 0.0;
|
|
1219
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1220
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
1221
|
+
energy += powf(GLCM[i][j], 2);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
return energy;
|
|
1225
|
+
}
|
|
1226
|
+
// Contrast
|
|
1227
|
+
else if (feature == 11) {
|
|
1228
|
+
float contrast = 0.0;
|
|
1229
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1230
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
1231
|
+
contrast += powf(rowGrid[i][j] - colGrid[i][j], 2) * GLCM[i][j];
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
return contrast;
|
|
1235
|
+
}
|
|
1236
|
+
// Dissimilarity
|
|
1237
|
+
else if (feature == 12) {
|
|
1238
|
+
float dissimilarity = 0.0;
|
|
1239
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1240
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
1241
|
+
dissimilarity += fabsf(rowGrid[i][j] - colGrid[i][j]) * GLCM[i][j];
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
return dissimilarity;
|
|
1245
|
+
}
|
|
1246
|
+
// Inverse difference
|
|
1247
|
+
else if (feature == 13) {
|
|
1248
|
+
float inv_diff = 0.0;
|
|
1249
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1250
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
1251
|
+
inv_diff += GLCM[i][j] / (1 + fabsf(rowGrid[i][j] - colGrid[i][j]));
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
return inv_diff;
|
|
1255
|
+
}
|
|
1256
|
+
// Inverse difference normalized
|
|
1257
|
+
else if (feature == 14) {
|
|
1258
|
+
float invDiffNorm = 0.0;
|
|
1259
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1260
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
1261
|
+
invDiffNorm += GLCM[i][j] / (1 + fabsf(rowGrid[i][j] - colGrid[i][j]) / int(max_vol));
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
return invDiffNorm;
|
|
1265
|
+
}
|
|
1266
|
+
// Inverse difference moment
|
|
1267
|
+
else if (feature == 15) {
|
|
1268
|
+
float invDiffMom = 0.0;
|
|
1269
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1270
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
1271
|
+
invDiffMom += GLCM[i][j] / (1 + powf((rowGrid[i][j] - colGrid[i][j]), 2));
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
return invDiffMom;
|
|
1275
|
+
}
|
|
1276
|
+
// Inverse difference moment normalized
|
|
1277
|
+
else if (feature == 16) {
|
|
1278
|
+
float invDiffMomNorm = 0.0;
|
|
1279
|
+
for (int i = 0; i < int(max_vol); ++i) {
|
|
1280
|
+
for (int j = 0; j < int(max_vol); ++j) {
|
|
1281
|
+
invDiffMomNorm += GLCM[i][j] / (1 + powf((rowGrid[i][j] - colGrid[i][j]), 2) / powf(int(max_vol), 2));
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
return invDiffMomNorm;
|
|
1285
|
+
}
|
|
1286
|
+
// Inverse variance
|
|
1287
|
+
else if (feature == 17) {
|
|
1288
|
+
float invVar = 0.0;
|
|
1289
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1290
|
+
for (int j = i + 1; j < int(max_vol); j++) {
|
|
1291
|
+
invVar += GLCM[i][j] / powf((i - j), 2);
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
return 2*invVar;
|
|
1295
|
+
}
|
|
1296
|
+
// Correlation
|
|
1297
|
+
else if (feature == 18) {
|
|
1298
|
+
float u_i = 0.0;
|
|
1299
|
+
float u_j = 0.0;
|
|
1300
|
+
float std_i = 0.0;
|
|
1301
|
+
float std_j = 0.0;
|
|
1302
|
+
float p_i[Ng] = { 0.0 };
|
|
1303
|
+
float p_j[Ng] = { 0.0 };
|
|
1304
|
+
|
|
1305
|
+
// sum over rows
|
|
1306
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1307
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1308
|
+
p_i[i] += GLCM[i][j];
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
// sum over columns
|
|
1312
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1313
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1314
|
+
p_j[j] += GLCM[i][j];
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1318
|
+
u_i += vectNg[i] * p_i[i];
|
|
1319
|
+
u_j += vectNg[i] * p_j[i];
|
|
1320
|
+
}
|
|
1321
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1322
|
+
std_i += powf(vectNg[i] - u_i, 2) * p_i[i];
|
|
1323
|
+
std_j += powf(vectNg[i] - u_j, 2) * p_j[i];
|
|
1324
|
+
}
|
|
1325
|
+
std_i = sqrtf(std_i);
|
|
1326
|
+
std_j = sqrtf(std_j);
|
|
1327
|
+
|
|
1328
|
+
float tempSum = 0.0;
|
|
1329
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1330
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1331
|
+
tempSum += rowGrid[i][j] * colGrid[i][j] * GLCM[i][j];
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
float correlation = (1 / (std_i * std_j)) * (-u_i * u_j + tempSum);
|
|
1335
|
+
return correlation;
|
|
1336
|
+
}
|
|
1337
|
+
// Autocorrelation
|
|
1338
|
+
else if (feature == 19) {
|
|
1339
|
+
float u_i = 0.0;
|
|
1340
|
+
float u_j = 0.0;
|
|
1341
|
+
float std_i = 0.0;
|
|
1342
|
+
float std_j = 0.0;
|
|
1343
|
+
float p_i[Ng] = { 0.0 };
|
|
1344
|
+
float p_j[Ng] = { 0.0 };
|
|
1345
|
+
|
|
1346
|
+
// sum over rows
|
|
1347
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1348
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1349
|
+
p_i[i] += GLCM[i][j];
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
// sum over columns
|
|
1353
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1354
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1355
|
+
p_j[j] += GLCM[i][j];
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1359
|
+
u_i += vectNg[i] * p_i[i];
|
|
1360
|
+
u_j += vectNg[i] * p_j[i];
|
|
1361
|
+
}
|
|
1362
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1363
|
+
std_i += powf(vectNg[i] - u_i, 2) * p_i[i];
|
|
1364
|
+
std_j += powf(vectNg[i] - u_j, 2) * p_j[i];
|
|
1365
|
+
}
|
|
1366
|
+
std_i = sqrtf(std_i);
|
|
1367
|
+
std_j = sqrtf(std_j);
|
|
1368
|
+
|
|
1369
|
+
float autoCorr = 0.0;
|
|
1370
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1371
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1372
|
+
autoCorr += rowGrid[i][j] * colGrid[i][j] * GLCM[i][j];
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
return autoCorr;
|
|
1377
|
+
}
|
|
1378
|
+
// Cluster tendency
|
|
1379
|
+
else if (feature == 20) {
|
|
1380
|
+
float u_i = 0.0;
|
|
1381
|
+
float u_j = 0.0;
|
|
1382
|
+
float p_i[Ng] = { 0.0 };
|
|
1383
|
+
float p_j[Ng] = { 0.0 };
|
|
1384
|
+
|
|
1385
|
+
// sum over rows
|
|
1386
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1387
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1388
|
+
p_i[i] += GLCM[i][j];
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
// sum over columns
|
|
1392
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1393
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1394
|
+
p_j[j] += GLCM[i][j];
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1398
|
+
u_i += vectNg[i] * p_i[i];
|
|
1399
|
+
u_j += vectNg[i] * p_j[i];
|
|
1400
|
+
}
|
|
1401
|
+
float clusterTend = 0.0;
|
|
1402
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1403
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1404
|
+
clusterTend += powf(rowGrid[i][j] + colGrid[i][j] - u_i - u_j, 2) * GLCM[i][j];
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
return clusterTend;
|
|
1408
|
+
}
|
|
1409
|
+
// Cluster shade
|
|
1410
|
+
else if (feature == 21) {
|
|
1411
|
+
float u_i = 0.0;
|
|
1412
|
+
float u_j = 0.0;
|
|
1413
|
+
float p_i[Ng] = { 0.0 };
|
|
1414
|
+
float p_j[Ng] = { 0.0 };
|
|
1415
|
+
|
|
1416
|
+
// sum over rows
|
|
1417
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1418
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1419
|
+
p_i[i] += GLCM[i][j];
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
// sum over columns
|
|
1423
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1424
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1425
|
+
p_j[j] += GLCM[i][j];
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1429
|
+
u_i += vectNg[i] * p_i[i];
|
|
1430
|
+
u_j += vectNg[i] * p_j[i];
|
|
1431
|
+
}
|
|
1432
|
+
float clusterShade = 0.0;
|
|
1433
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1434
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1435
|
+
clusterShade += powf(rowGrid[i][j] + colGrid[i][j] - u_i - u_j, 3) * GLCM[i][j];
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
return clusterShade;
|
|
1439
|
+
}
|
|
1440
|
+
// Cluster prominence
|
|
1441
|
+
else if (feature == 22) {
|
|
1442
|
+
float u_i = 0.0;
|
|
1443
|
+
float u_j = 0.0;
|
|
1444
|
+
float p_i[Ng] = { 0.0 };
|
|
1445
|
+
float p_j[Ng] = { 0.0 };
|
|
1446
|
+
|
|
1447
|
+
// sum over rows
|
|
1448
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1449
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1450
|
+
p_i[i] += GLCM[i][j];
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
// sum over columns
|
|
1454
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1455
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1456
|
+
p_j[j] += GLCM[i][j];
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1460
|
+
u_i += vectNg[i] * p_i[i];
|
|
1461
|
+
u_j += vectNg[i] * p_j[i];
|
|
1462
|
+
}
|
|
1463
|
+
float clusterProm = 0.0;
|
|
1464
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1465
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1466
|
+
clusterProm += powf(rowGrid[i][j] + colGrid[i][j] - u_i - u_j, 4) * GLCM[i][j];
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
return clusterProm;
|
|
1470
|
+
}
|
|
1471
|
+
// First measure of information correlation
|
|
1472
|
+
else if (feature == 23) {
|
|
1473
|
+
float p_i[Ng] = { 0.0 };
|
|
1474
|
+
float p_j[Ng] = { 0.0 };
|
|
1475
|
+
// sum over rows
|
|
1476
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1477
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1478
|
+
p_i[i] += GLCM[i][j];
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
// sum over columns
|
|
1482
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1483
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1484
|
+
p_j[j] += GLCM[i][j];
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
float HXY = 0.0;
|
|
1489
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1490
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1491
|
+
if (GLCM[i][j] > 0.0) {
|
|
1492
|
+
HXY += GLCM[i][j] * log2f(GLCM[i][j]);
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
HXY = -HXY;
|
|
1497
|
+
|
|
1498
|
+
float HX = 0.0;
|
|
1499
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1500
|
+
if (p_i[i] > 0.0) {
|
|
1501
|
+
HX += p_i[i] * log2f(p_i[i]);
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
HX = -HX;
|
|
1505
|
+
|
|
1506
|
+
// Repeat p_i and p_j Ng times
|
|
1507
|
+
float p_i_temp[Ng][Ng];
|
|
1508
|
+
float p_j_temp[Ng][Ng];
|
|
1509
|
+
float p_temp[Ng][Ng];
|
|
1510
|
+
|
|
1511
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1512
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1513
|
+
p_i_temp[i][j] = p_i[i];
|
|
1514
|
+
p_j_temp[i][j] = p_j[j];
|
|
1515
|
+
p_temp[i][j] = p_i_temp[i][j] * p_j_temp[i][j];
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
float HXY1 = 0.0;
|
|
1520
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1521
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1522
|
+
if (p_temp[i][j] > 0.0) {
|
|
1523
|
+
HXY1 += GLCM[i][j] * log2f(p_temp[i][j]);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
HXY1 = -HXY1;
|
|
1528
|
+
|
|
1529
|
+
return (HXY - HXY1) / HX;
|
|
1530
|
+
}
|
|
1531
|
+
// Second measure of information correlation
|
|
1532
|
+
else if (feature == 24) {
|
|
1533
|
+
float p_i[Ng] = { 0.0 };
|
|
1534
|
+
float p_j[Ng] = { 0.0 };
|
|
1535
|
+
// sum over rows
|
|
1536
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1537
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1538
|
+
p_i[i] += GLCM[i][j];
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
// sum over columns
|
|
1542
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1543
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1544
|
+
p_j[j] += GLCM[i][j];
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
float HXY = 0.0;
|
|
1549
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1550
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1551
|
+
if (GLCM[i][j] > 0.0) {
|
|
1552
|
+
HXY += GLCM[i][j] * log2f(GLCM[i][j]);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
HXY = -HXY;
|
|
1557
|
+
|
|
1558
|
+
// Repeat p_i and p_j Ng times
|
|
1559
|
+
float p_i_temp[Ng][Ng];
|
|
1560
|
+
float p_j_temp[Ng][Ng];
|
|
1561
|
+
float p_temp[Ng][Ng];
|
|
1562
|
+
|
|
1563
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1564
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1565
|
+
p_i_temp[i][j] = p_i[i];
|
|
1566
|
+
p_j_temp[i][j] = p_j[j];
|
|
1567
|
+
p_temp[i][j] = p_i_temp[i][j] * p_j_temp[i][j];
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
float HXY2 = 0.0;
|
|
1572
|
+
for (int i = 0; i < int(max_vol); i++) {
|
|
1573
|
+
for (int j = 0; j < int(max_vol); j++) {
|
|
1574
|
+
if (p_temp[i][j] > 0.0) {
|
|
1575
|
+
HXY2 += p_temp[i][j] * log2f(p_temp[i][j]);
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
HXY2 = -HXY2;
|
|
1580
|
+
if (HXY > HXY2) {
|
|
1581
|
+
return 0.0;
|
|
1582
|
+
}
|
|
1583
|
+
else {
|
|
1584
|
+
return sqrtf(1 - expf(-2 * (HXY2 - HXY)));
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
else {
|
|
1588
|
+
// Print error message
|
|
1589
|
+
printf("Error: feature %d not implemented\\n", feature);
|
|
1590
|
+
assert(false);
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
extern "C"
|
|
1595
|
+
__global__ void glcm_filter_global(
|
|
1596
|
+
float vol[${shape_volume_0}][${shape_volume_1}][${shape_volume_2}],
|
|
1597
|
+
float vol_copy[${shape_volume_0}][${shape_volume_1}][${shape_volume_2}],
|
|
1598
|
+
bool distCorrection = false)
|
|
1599
|
+
{
|
|
1600
|
+
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
|
1601
|
+
int j = blockIdx.y * blockDim.y + threadIdx.y;
|
|
1602
|
+
int k = blockIdx.z * blockDim.z + threadIdx.z;
|
|
1603
|
+
|
|
1604
|
+
if (i < ${shape_volume_0} && j < ${shape_volume_1} && k < ${shape_volume_2} && i >= 0 && j >= 0 && k >= 0) {
|
|
1605
|
+
// pad size
|
|
1606
|
+
const int padd_size = (FILTER_SIZE - 1) / 2;
|
|
1607
|
+
|
|
1608
|
+
// size vol
|
|
1609
|
+
const int size_x = ${shape_volume_0};
|
|
1610
|
+
const int size_y = ${shape_volume_1};
|
|
1611
|
+
const int size_z = ${shape_volume_2};
|
|
1612
|
+
|
|
1613
|
+
// skip all calculations if vol at position i,j,k is nan
|
|
1614
|
+
if (!isnan(vol_copy[i][j][k])) {
|
|
1615
|
+
// get submatrix
|
|
1616
|
+
float sub_matrix[FILTER_SIZE][FILTER_SIZE][FILTER_SIZE] = {NAN};
|
|
1617
|
+
for (int idx_i = 0; idx_i < FILTER_SIZE; ++idx_i) {
|
|
1618
|
+
for (int idx_j = 0; idx_j < FILTER_SIZE; ++idx_j) {
|
|
1619
|
+
for (int idx_k = 0; idx_k < FILTER_SIZE; ++idx_k) {
|
|
1620
|
+
if ((i - padd_size + idx_i) >= 0 && (i - padd_size + idx_i) < size_x &&
|
|
1621
|
+
(j - padd_size + idx_j) >= 0 && (j - padd_size + idx_j) < size_y &&
|
|
1622
|
+
(k - padd_size + idx_k) >= 0 && (k - padd_size + idx_k) < size_z) {
|
|
1623
|
+
sub_matrix[idx_i][idx_j][idx_k] = vol_copy[i - padd_size + idx_i][j - padd_size + idx_j][k - padd_size + idx_k];
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
// get the maximum value of the submatrix
|
|
1630
|
+
float max_vol = -3.40282e+38;
|
|
1631
|
+
for (int idx_i = 0; idx_i < FILTER_SIZE; ++idx_i) {
|
|
1632
|
+
for (int idx_j = 0; idx_j < FILTER_SIZE; ++idx_j) {
|
|
1633
|
+
for (int idx_k = 0; idx_k < FILTER_SIZE; ++idx_k) {
|
|
1634
|
+
max_vol = max(max_vol, sub_matrix[idx_i][idx_j][idx_k]);
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
// get feature index
|
|
1640
|
+
const int feature = ${feature_index};
|
|
1641
|
+
|
|
1642
|
+
// compute GLCM features
|
|
1643
|
+
float glcm_feature = computeGLCMFeatures(sub_matrix, feature, max_vol, false);
|
|
1644
|
+
|
|
1645
|
+
// Copy GLCM feature to voxels of the volume
|
|
1646
|
+
if (i < size_x && j < size_y && k < size_z){
|
|
1647
|
+
vol[i][j][k] = glcm_feature;
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
extern "C"
|
|
1654
|
+
__global__ void glcm_filter_local(
|
|
1655
|
+
float vol[${shape_volume_0}][${shape_volume_1}][${shape_volume_2}],
|
|
1656
|
+
float vol_copy[${shape_volume_0}][${shape_volume_1}][${shape_volume_2}],
|
|
1657
|
+
bool distCorrection = false)
|
|
1658
|
+
{
|
|
1659
|
+
int i = blockIdx.x * blockDim.x + threadIdx.x;
|
|
1660
|
+
int j = blockIdx.y * blockDim.y + threadIdx.y;
|
|
1661
|
+
int k = blockIdx.z * blockDim.z + threadIdx.z;
|
|
1662
|
+
|
|
1663
|
+
if (i < ${shape_volume_0} && j < ${shape_volume_1} && k < ${shape_volume_2} && i >= 0 && j >= 0 && k >= 0) {
|
|
1664
|
+
// pad size
|
|
1665
|
+
const int padd_size = (FILTER_SIZE - 1) / 2;
|
|
1666
|
+
|
|
1667
|
+
// size vol
|
|
1668
|
+
const int size_x = ${shape_volume_0};
|
|
1669
|
+
const int size_y = ${shape_volume_1};
|
|
1670
|
+
const int size_z = ${shape_volume_2};
|
|
1671
|
+
|
|
1672
|
+
// skip all calculations if vol at position i,j,k is nan
|
|
1673
|
+
if (!isnan(vol_copy[i][j][k])) {
|
|
1674
|
+
// get submatrix
|
|
1675
|
+
float sub_matrix[FILTER_SIZE][FILTER_SIZE][FILTER_SIZE] = {NAN};
|
|
1676
|
+
for (int idx_i = 0; idx_i < FILTER_SIZE; ++idx_i) {
|
|
1677
|
+
for (int idx_j = 0; idx_j < FILTER_SIZE; ++idx_j) {
|
|
1678
|
+
for (int idx_k = 0; idx_k < FILTER_SIZE; ++idx_k) {
|
|
1679
|
+
if ((i - padd_size + idx_i) >= 0 && (i - padd_size + idx_i) < size_x &&
|
|
1680
|
+
(j - padd_size + idx_j) >= 0 && (j - padd_size + idx_j) < size_y &&
|
|
1681
|
+
(k - padd_size + idx_k) >= 0 && (k - padd_size + idx_k) < size_z) {
|
|
1682
|
+
sub_matrix[idx_i][idx_j][idx_k] = vol_copy[i - padd_size + idx_i][j - padd_size + idx_j][k - padd_size + idx_k];
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
// get the maximum value of the submatrix
|
|
1689
|
+
float max_vol = -3.40282e+38;
|
|
1690
|
+
for (int idx_i = 0; idx_i < FILTER_SIZE; ++idx_i) {
|
|
1691
|
+
for (int idx_j = 0; idx_j < FILTER_SIZE; ++idx_j) {
|
|
1692
|
+
for (int idx_k = 0; idx_k < FILTER_SIZE; ++idx_k) {
|
|
1693
|
+
max_vol = max(max_vol, sub_matrix[idx_i][idx_j][idx_k]);
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
// get the minimum value of the submatrix if discr_type is FBN
|
|
1698
|
+
float min_val = 3.40282e+38;
|
|
1699
|
+
if ("${discr_type}" == "FBN") {
|
|
1700
|
+
for (int idx_i = 0; idx_i < FILTER_SIZE; ++idx_i) {
|
|
1701
|
+
for (int idx_j = 0; idx_j < FILTER_SIZE; ++idx_j) {
|
|
1702
|
+
for (int idx_k = 0; idx_k < FILTER_SIZE; ++idx_k) {
|
|
1703
|
+
min_val = min(min_val, sub_matrix[idx_i][idx_j][idx_k]);
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
discretize(sub_matrix, max_vol, min_val);
|
|
1708
|
+
}
|
|
1709
|
+
|
|
1710
|
+
// If FBS discretize the submatrix with user set minimum value
|
|
1711
|
+
else{
|
|
1712
|
+
discretize(sub_matrix, max_vol);
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
// get the maximum value of the submatrix after discretization
|
|
1716
|
+
max_vol = -3.40282e+38;
|
|
1717
|
+
for (int idx_i = 0; idx_i < FILTER_SIZE; ++idx_i) {
|
|
1718
|
+
for (int idx_j = 0; idx_j < FILTER_SIZE; ++idx_j) {
|
|
1719
|
+
for (int idx_k = 0; idx_k < FILTER_SIZE; ++idx_k) {
|
|
1720
|
+
max_vol = max(max_vol, sub_matrix[idx_i][idx_j][idx_k]);
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
// get feature index
|
|
1726
|
+
const int feature = ${feature_index};
|
|
1727
|
+
|
|
1728
|
+
// compute GLCM features
|
|
1729
|
+
float glcm_feature = computeGLCMFeatures(sub_matrix, feature, max_vol, false);
|
|
1730
|
+
|
|
1731
|
+
// Copy GLCM feature to voxels of the volume
|
|
1732
|
+
if (i < size_x && j < size_y && k < size_z){
|
|
1733
|
+
vol[i][j][k] = glcm_feature;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
""")
|