h_measure.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  1. /****************************************************************************
  2. *
  3. * MODULE: r.texture
  4. * AUTHOR(S): Carmine Basco - basco@unisannio.it
  5. * with hints from:
  6. * prof. Giulio Antoniol - antoniol@ieee.org
  7. * prof. Michele Ceccarelli - ceccarelli@unisannio.it
  8. *
  9. * PURPOSE: Create map raster with textural features.
  10. *
  11. * COPYRIGHT: (C) 2003 by University of Sannio (BN) - Italy
  12. *
  13. * This program is free software under the GNU General Public
  14. * License (>=v2). Read the file COPYING that comes with GRASS
  15. * for details.
  16. *
  17. * Permission to use, copy, modify, and distribute this software and its
  18. * documentation for any purpose and without fee is hereby granted. This
  19. * software is provided "as is" without express or implied warranty.
  20. *
  21. *****************************************************************************/
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <math.h>
  25. #include <grass/gis.h>
  26. #include <grass/raster.h>
  27. #include <grass/glocale.h>
  28. #define RADIX 2.0
  29. #define EPSILON 0.000000001
  30. #define BL "Direction "
  31. #define F1 "Angular Second Moment "
  32. #define F2 "Contrast "
  33. #define F3 "Correlation "
  34. #define F4 "Variance "
  35. #define F5 "Inverse Diff Moment "
  36. #define F6 "Sum Average "
  37. #define F7 "Sum Variance "
  38. #define F8 "Sum Entropy "
  39. #define F9 "Entropy "
  40. #define F10 "Difference Variance "
  41. #define F11 "Difference Entropy "
  42. #define F12 "Measure of Correlation-1 "
  43. #define F13 "Measure of Correlation-2 "
  44. #define SIGN(x,y) ((y)<0 ? -fabs(x) : fabs(x))
  45. #define SWAP(a,b) {y=(a);(a)=(b);(b)=y;}
  46. #define PGM_MAXMAXVAL 255
  47. #define MAX_MATRIX_SIZE 512
  48. float **matrix(int nr, int nc);
  49. float *vector(int n);
  50. float f1_asm(float **P, int Ng);
  51. float f2_contrast(float **P, int Ng);
  52. float f3_corr(float **P, int Ng);
  53. float f4_var(float **P, int Ng);
  54. float f5_idm(float **P, int Ng);
  55. float f6_savg(float **P, int Ng);
  56. float f7_svar(float **P, int Ng, double S);
  57. float f8_sentropy(float **P, int Ng);
  58. float f9_entropy(float **P, int Ng);
  59. float f10_dvar(float **P, int Ng);
  60. float f11_dentropy(float **P, int Ng);
  61. float f12_icorr(float **P, int Ng);
  62. float f13_icorr(float **P, int Ng);
  63. static float **P_matrix = NULL;
  64. static float **P_matrix0 = NULL;
  65. static float **P_matrix45 = NULL;
  66. static float **P_matrix90 = NULL;
  67. static float **P_matrix135 = NULL;
  68. int tone[PGM_MAXMAXVAL + 1];
  69. static int tones = 0;
  70. static float sentropy = 0.0;
  71. static float *px, *py;
  72. static float Pxpys[2 * PGM_MAXMAXVAL + 2];
  73. static float Pxpyd[2 * PGM_MAXMAXVAL + 2];
  74. void alloc_vars(int size, int dist)
  75. {
  76. int Ng;
  77. /* Allocate memory for gray-tone spatial dependence matrix */
  78. P_matrix0 = matrix(MAX_MATRIX_SIZE + 1, MAX_MATRIX_SIZE + 1);
  79. P_matrix45 = matrix(MAX_MATRIX_SIZE + 1, MAX_MATRIX_SIZE + 1);
  80. P_matrix90 = matrix(MAX_MATRIX_SIZE + 1, MAX_MATRIX_SIZE + 1);
  81. P_matrix135 = matrix(MAX_MATRIX_SIZE + 1, MAX_MATRIX_SIZE + 1);
  82. if (size * size < 256)
  83. Ng = size * size;
  84. else
  85. Ng = 256;
  86. px = vector(Ng + 1);
  87. py = vector(Ng + 1);
  88. }
  89. int set_vars(int **grays, int curr_row, int curr_col,
  90. int size, int offset, int t_d)
  91. {
  92. int R0, R45, R90, R135, x, y;
  93. int row, col, row2, col2, rows, cols;
  94. int itone, jtone;
  95. rows = cols = size;
  96. /* Determine the number of different gray scales (not maxval) */
  97. for (row = 0; row <= PGM_MAXMAXVAL; row++)
  98. tone[row] = -1;
  99. for (row = curr_row - offset; row <= curr_row + offset; row++) {
  100. for (col = curr_col - offset; col <= curr_col + offset; col++) {
  101. if (grays[row][col] < 0) { /* No data pixel found */
  102. return 0;
  103. }
  104. if (grays[row][col] > PGM_MAXMAXVAL)
  105. G_fatal_error(_("Too many categories (found: %i, max: %i). "
  106. "Try to rescale or reclassify the map"),
  107. grays[row][col], PGM_MAXMAXVAL);
  108. tone[grays[row][col]] = grays[row][col];
  109. }
  110. }
  111. /* Collapse array, taking out all zero values */
  112. tones = 0;
  113. for (row = 0; row <= PGM_MAXMAXVAL; row++) {
  114. if (tone[row] != -1)
  115. tone[tones++] = tone[row];
  116. }
  117. /* Now array contains only the gray levels present (in ascending order) */
  118. for (row = 0; row < tones; row++)
  119. for (col = 0; col < tones; col++) {
  120. P_matrix0[row][col] = P_matrix45[row][col] = 0;
  121. P_matrix90[row][col] = P_matrix135[row][col] = 0;
  122. }
  123. /* Find gray-tone spatial dependence matrix */
  124. for (row = 0; row < rows; row++) {
  125. row2 = curr_row - offset + row;
  126. for (col = 0; col < cols; col++) {
  127. col2 = curr_col - offset + col;
  128. x = 0;
  129. while (tone[x] != grays[row2][col2])
  130. x++;
  131. if (col + t_d < cols) {
  132. y = 0;
  133. while (tone[y] != grays[row2][col2 + t_d])
  134. y++;
  135. P_matrix0[x][y]++;
  136. P_matrix0[y][x]++;
  137. }
  138. if (row + t_d < rows) {
  139. y = 0;
  140. while (tone[y] != grays[row2 + t_d][col2])
  141. y++;
  142. P_matrix90[x][y]++;
  143. P_matrix90[y][x]++;
  144. }
  145. if (row + t_d < rows && col - t_d >= 0) {
  146. y = 0;
  147. while (tone[y] != grays[row2 + t_d][col2 - t_d])
  148. y++;
  149. P_matrix45[x][y]++;
  150. P_matrix45[y][x]++;
  151. }
  152. if (row + t_d < rows && col + t_d < cols) {
  153. y = 0;
  154. while (tone[y] != grays[row2 + t_d][col2 + t_d])
  155. y++;
  156. P_matrix135[x][y]++;
  157. P_matrix135[y][x]++;
  158. }
  159. }
  160. }
  161. /* Gray-tone spatial dependence matrices are complete */
  162. /* Find normalizing constants */
  163. R0 = 2 * rows * (cols - 1);
  164. R45 = 2 * (rows - 1) * (cols - 1);
  165. R90 = 2 * (rows - 1) * cols;
  166. R135 = R45;
  167. /* Normalize gray-tone spatial dependence matrix */
  168. for (itone = 0; itone < tones; itone++) {
  169. for (jtone = 0; jtone < tones; jtone++) {
  170. P_matrix0[itone][jtone] /= R0;
  171. P_matrix45[itone][jtone] /= R45;
  172. P_matrix90[itone][jtone] /= R90;
  173. P_matrix135[itone][jtone] /= R135;
  174. }
  175. }
  176. return 1;
  177. }
  178. int set_angle_vars(int angle, int have_px, int have_py, int have_sentr,
  179. int have_pxpys, int have_pxpyd)
  180. {
  181. int i, j, Ng;
  182. float **P;
  183. switch (angle) {
  184. case 0:
  185. P_matrix = P_matrix0;
  186. break;
  187. case 1:
  188. P_matrix = P_matrix45;
  189. break;
  190. case 2:
  191. P_matrix = P_matrix90;
  192. break;
  193. case 3:
  194. P_matrix = P_matrix135;
  195. break;
  196. }
  197. if (have_sentr)
  198. sentropy = f8_sentropy(P_matrix, tones);
  199. Ng = tones;
  200. P = P_matrix;
  201. /*
  202. * px[i] is the (i-1)th entry in the marginal probability matrix obtained
  203. * by summing the rows of p[i][j]
  204. */
  205. /* Pxpy sum and difference */
  206. /* reset variabless */
  207. if (have_px || have_py || have_pxpys || have_pxpyd) {
  208. for (i = 0; i < Ng; i++) {
  209. if (have_px || have_py) {
  210. px[i] = py[i] = 0;
  211. }
  212. if (have_pxpys || have_pxpyd) {
  213. Pxpys[i] = Pxpyd[i] = 0;
  214. }
  215. }
  216. if (have_pxpys) {
  217. for (j = Ng; j < 2 * Ng; j++) {
  218. Pxpys[j] = 0;
  219. }
  220. }
  221. }
  222. if (have_pxpys || have_pxpyd || have_px || have_py) {
  223. for (i = 0; i < Ng; i++) {
  224. for (j = 0; j < Ng; j++) {
  225. if (have_px || have_py) {
  226. px[i] += P[i][j];
  227. py[j] += P[i][j];
  228. }
  229. if (have_pxpys) {
  230. Pxpys[i + j] += P[i][j];
  231. }
  232. if (have_pxpyd) {
  233. Pxpyd[abs(i - j)] += P[i][j];
  234. }
  235. }
  236. }
  237. }
  238. return 1;
  239. }
  240. float h_measure(int t_m)
  241. {
  242. switch (t_m) {
  243. /* Angular Second Moment */
  244. case 0:
  245. return (f1_asm(P_matrix, tones));
  246. break;
  247. /* Contrast */
  248. case 1:
  249. return (f2_contrast(P_matrix, tones));
  250. break;
  251. /* Correlation */
  252. case 2:
  253. return (f3_corr(P_matrix, tones));
  254. break;
  255. /* Variance */
  256. case 3:
  257. return (f4_var(P_matrix, tones));
  258. break;
  259. /* Inverse Diff Moment */
  260. case 4:
  261. return (f5_idm(P_matrix, tones));
  262. break;
  263. /* Sum Average */
  264. case 5:
  265. return (f6_savg(P_matrix, tones));
  266. break;
  267. /* Sum Entropy */
  268. case 6:
  269. return (sentropy);
  270. break;
  271. /* Sum Variance */
  272. case 7:
  273. return (f7_svar(P_matrix, tones, sentropy));
  274. break;
  275. /* Entropy */
  276. case 8:
  277. return (f9_entropy(P_matrix, tones));
  278. break;
  279. /* Difference Variance */
  280. case 9:
  281. return (f10_dvar(P_matrix, tones));
  282. break;
  283. /* Difference Entropy */
  284. case 10:
  285. return (f11_dentropy(P_matrix, tones));
  286. break;
  287. /* Measure of Correlation-1 */
  288. case 11:
  289. return (f12_icorr(P_matrix, tones));
  290. break;
  291. /* Measure of Correlation-2 */
  292. case 12:
  293. return (f13_icorr(P_matrix, tones));
  294. break;
  295. }
  296. return 0;
  297. }
  298. void MatrixDealloc(float **A, int N)
  299. {
  300. /*A is NxN */
  301. int i;
  302. for (i = 0; i < N; i++)
  303. G_free(A[i]);
  304. G_free(A);
  305. }
  306. /* Angular Second Moment */
  307. /*
  308. * The angular second-moment feature (ASM) f1 is a measure of homogeneity
  309. * of the image. In a homogeneous image, there are very few dominant
  310. * gray-tone transitions. Hence the P matrix for such an image will have
  311. * fewer entries of large magnitude.
  312. */
  313. float f1_asm(float **P, int Ng)
  314. {
  315. int i, j;
  316. float sum = 0;
  317. for (i = 0; i < Ng; i++)
  318. for (j = 0; j < Ng; j++)
  319. sum += P[i][j] * P[i][j];
  320. return sum;
  321. }
  322. /* Contrast */
  323. /*
  324. * The contrast feature is a difference moment of the P matrix and is a
  325. * measure of the contrast or the amount of local variations present in an
  326. * image.
  327. */
  328. float f2_contrast(float **P, int Ng)
  329. {
  330. int i, j, n;
  331. float sum, bigsum = 0;
  332. for (n = 0; n < Ng; n++) {
  333. sum = 0;
  334. for (i = 0; i < Ng; i++) {
  335. for (j = 0; j < Ng; j++) {
  336. if ((i - j) == n || (j - i) == n) {
  337. sum += P[i][j];
  338. }
  339. }
  340. }
  341. bigsum += n * n * sum;
  342. }
  343. return bigsum;
  344. }
  345. /* Correlation */
  346. /*
  347. * This correlation feature is a measure of gray-tone linear-dependencies
  348. * in the image.
  349. */
  350. float f3_corr(float **P, int Ng)
  351. {
  352. int i, j;
  353. float sum_sqrx = 0, sum_sqry = 0, tmp = 0;
  354. float meanx = 0, meany = 0, stddevx, stddevy;
  355. /* Now calculate the means and standard deviations of px and py */
  356. /*- fix supplied by J. Michael Christensen, 21 Jun 1991 */
  357. /*- further modified by James Darrell McCauley, 16 Aug 1991
  358. * after realizing that meanx=meany and stddevx=stddevy
  359. */
  360. for (i = 0; i < Ng; i++) {
  361. meanx += px[i] * i;
  362. sum_sqrx += px[i] * i * i;
  363. for (j = 0; j < Ng; j++)
  364. tmp += i * j * P[i][j];
  365. }
  366. meany = meanx;
  367. sum_sqry = sum_sqrx;
  368. stddevx = sqrt(sum_sqrx - (meanx * meanx));
  369. stddevy = stddevx;
  370. return (tmp - meanx * meany) / (stddevx * stddevy);
  371. }
  372. /* Sum of Squares: Variance */
  373. float f4_var(float **P, int Ng)
  374. {
  375. int i, j;
  376. float mean = 0, var = 0;
  377. /*- Corrected by James Darrell McCauley, 16 Aug 1991
  378. * calculates the mean intensity level instead of the mean of
  379. * cooccurrence matrix elements
  380. */
  381. for (i = 0; i < Ng; i++)
  382. for (j = 0; j < Ng; j++)
  383. mean += i * P[i][j];
  384. for (i = 0; i < Ng; i++)
  385. for (j = 0; j < Ng; j++)
  386. var += (i + 1 - mean) * (i + 1 - mean) * P[i][j];
  387. return var;
  388. }
  389. /* Inverse Difference Moment */
  390. float f5_idm(float **P, int Ng)
  391. {
  392. int i, j;
  393. float idm = 0;
  394. for (i = 0; i < Ng; i++)
  395. for (j = 0; j < Ng; j++)
  396. idm += P[i][j] / (1 + (i - j) * (i - j));
  397. return idm;
  398. }
  399. /* Sum Average */
  400. float f6_savg(float **P, int Ng)
  401. {
  402. int i;
  403. float savg = 0;
  404. for (i = 0; i < 2 * Ng - 1; i++)
  405. savg += (i + 2) * Pxpys[i];
  406. return savg;
  407. }
  408. /* Sum Variance */
  409. float f7_svar(float **P, int Ng, double S)
  410. {
  411. int i;
  412. float var = 0;
  413. for (i = 0; i < 2 * Ng - 1; i++)
  414. var += (i + 2 - S) * (i + 2 - S) * Pxpys[i];
  415. return var;
  416. }
  417. /* Sum Entropy */
  418. float f8_sentropy(float **P, int Ng)
  419. {
  420. int i;
  421. float sentr = 0;
  422. for (i = 0; i < 2 * Ng - 1; i++)
  423. sentr -= Pxpys[i] * log10(Pxpys[i] + EPSILON);
  424. return sentr;
  425. }
  426. /* Entropy */
  427. float f9_entropy(float **P, int Ng)
  428. {
  429. int i, j;
  430. float entropy = 0;
  431. for (i = 0; i < Ng; i++) {
  432. for (j = 0; j < Ng; j++) {
  433. entropy += P[i][j] * log10(P[i][j] + EPSILON);
  434. }
  435. }
  436. return -entropy;
  437. }
  438. /* Difference Variance */
  439. float f10_dvar(float **P, int Ng)
  440. {
  441. int i, tmp;
  442. float sum = 0, sum_sqr = 0, var = 0;
  443. /* Now calculate the variance of Pxpy (Px-y) */
  444. for (i = 0; i < Ng; i++) {
  445. sum += Pxpyd[i];
  446. sum_sqr += Pxpyd[i] * Pxpyd[i];
  447. }
  448. tmp = Ng * Ng;
  449. var = ((tmp * sum_sqr) - (sum * sum)) / (tmp * tmp);
  450. return var;
  451. }
  452. /* Difference Entropy */
  453. float f11_dentropy(float **P, int Ng)
  454. {
  455. int i;
  456. float sum = 0;
  457. for (i = 0; i < Ng; i++)
  458. sum += Pxpyd[i] * log10(Pxpyd[i] + EPSILON);
  459. return -sum;
  460. }
  461. /* Information Measures of Correlation */
  462. float f12_icorr(float **P, int Ng)
  463. {
  464. int i, j;
  465. float hx = 0, hy = 0, hxy = 0, hxy1 = 0;
  466. for (i = 0; i < Ng; i++)
  467. for (j = 0; j < Ng; j++) {
  468. hxy1 -= P[i][j] * log10(px[i] * py[j] + EPSILON);
  469. hxy -= P[i][j] * log10(P[i][j] + EPSILON);
  470. }
  471. /* Calculate entropies of px and py - is this right? */
  472. for (i = 0; i < Ng; i++) {
  473. hx -= px[i] * log10(px[i] + EPSILON);
  474. hy -= py[i] * log10(py[i] + EPSILON);
  475. }
  476. /* fprintf(stderr,"hxy1=%f\thxy=%f\thx=%f\thy=%f\n",hxy1,hxy,hx,hy); */
  477. return ((hxy - hxy1) / (hx > hy ? hx : hy));
  478. }
  479. /* Information Measures of Correlation */
  480. float f13_icorr(float **P, int Ng)
  481. {
  482. int i, j;
  483. float hxy = 0, hxy2 = 0;
  484. for (i = 0; i < Ng; i++) {
  485. for (j = 0; j < Ng; j++) {
  486. hxy2 -= px[i] * py[j] * log10(px[i] * py[j] + EPSILON);
  487. hxy -= P[i][j] * log10(P[i][j] + EPSILON);
  488. }
  489. }
  490. /* fprintf(stderr,"hx=%f\thxy2=%f\n",hx,hxy2); */
  491. return (sqrt(abs(1 - exp(-2.0 * (hxy2 - hxy)))));
  492. }
  493. float *vector(int n)
  494. {
  495. float *v;
  496. v = (float *)G_malloc(n * sizeof(float));
  497. if (!v)
  498. G_fatal_error(_("Unable to allocate memory")), exit(EXIT_FAILURE);
  499. return v;
  500. }
  501. /* Allocates a float matrix with range [nrl..nrh][ncl..nch] */
  502. float **matrix(int nr, int nc)
  503. {
  504. int i;
  505. float **m;
  506. /* allocate pointers to rows */
  507. m = (float **)G_malloc(nr * sizeof(float *));
  508. /* allocate rows */
  509. for (i = 0; i < nr; i++) {
  510. m[i] = (float *)G_malloc(nc * sizeof(float));
  511. }
  512. /* return pointer to array of pointers to rows */
  513. return m;
  514. }