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,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
+ """)