123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758 |
- /****************************************************************************
- *
- * MODULE: r.texture
- * AUTHOR(S): Carmine Basco - basco@unisannio.it
- * with hints from:
- * prof. Giulio Antoniol - antoniol@ieee.org
- * prof. Michele Ceccarelli - ceccarelli@unisannio.it
- * Markus Metz (optimization and bug fixes)
- *
- * PURPOSE: Create map raster with textural features.
- *
- * COPYRIGHT: (C) 2003 by University of Sannio (BN) - Italy
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the file COPYING that comes with GRASS
- * for details.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted. This
- * software is provided "as is" without express or implied warranty.
- *
- *****************************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include <grass/gis.h>
- #include <grass/raster.h>
- #include <grass/glocale.h>
- #define BL "Direction "
- #define F1 "Angular Second Moment "
- #define F2 "Contrast "
- #define F3 "Correlation "
- #define F4 "Variance "
- #define F5 "Inverse Diff Moment "
- #define F6 "Sum Average "
- #define F7 "Sum Variance "
- #define F8 "Sum Entropy "
- #define F9 "Entropy "
- #define F10 "Difference Variance "
- #define F11 "Difference Entropy "
- #define F12 "Measure of Correlation-1 "
- #define F13 "Measure of Correlation-2 "
- #define PGM_MAXMAXVAL 255
- #define MAX_MATRIX_SIZE 512
- float **matrix(int nr, int nc);
- float *vector(int n);
- float f1_asm(void);
- float f2_contrast(void);
- float f3_corr(void);
- float f4_var(void);
- float f5_idm(void);
- float f6_savg(void);
- float f7_svar(void);
- float f8_sentropy(void);
- float f9_entropy(void);
- float f10_dvar(void);
- float f11_dentropy(void);
- float f12_icorr(void);
- float f13_icorr(void);
- static float **P_matrix = NULL;
- static float **P_matrix0 = NULL;
- static float **P_matrix45 = NULL;
- static float **P_matrix90 = NULL;
- static float **P_matrix135 = NULL;
- int tone[PGM_MAXMAXVAL + 1];
- static int Ng = 0;
- static float *px, *py;
- static float Pxpys[2 * PGM_MAXMAXVAL + 2];
- static float Pxpyd[2 * PGM_MAXMAXVAL + 2];
- void alloc_vars(int size)
- {
- int msize2;
- /* Allocate memory for gray-tone spatial dependence matrix */
- P_matrix0 = matrix(MAX_MATRIX_SIZE + 1, MAX_MATRIX_SIZE + 1);
- P_matrix45 = matrix(MAX_MATRIX_SIZE + 1, MAX_MATRIX_SIZE + 1);
- P_matrix90 = matrix(MAX_MATRIX_SIZE + 1, MAX_MATRIX_SIZE + 1);
- P_matrix135 = matrix(MAX_MATRIX_SIZE + 1, MAX_MATRIX_SIZE + 1);
- if (size * size < 256)
- msize2 = size * size;
- else
- msize2 = 256;
- px = vector(msize2 + 1);
- py = vector(msize2 + 1);
- }
- static int bsearch_gray(int *array, int n, int val)
- {
- int lo, hi, mid;
- lo = 0;
- hi = n - 1;
- while (lo <= hi) {
- mid = (lo + hi) >> 1;
-
- if (array[mid] == val)
- return mid;
- if (array[mid] > val)
- hi = mid - 1;
- else
- lo = mid + 1;
- }
- return -1;
- }
- int set_vars(int **grays, int curr_row, int curr_col,
- int size, int offset, int t_d, int with_nulls)
- {
- int R0, R45, R90, R135, x, y;
- int row, col, row2, col2, rows, cols;
- int rowmin, rowmax, colmin, colmax, wrows, wcols, rowd, cold;
- int itone, jtone;
- int cnt;
- rows = cols = size;
- wrows = Rast_window_rows();
- wcols = Rast_window_cols();
- /* Determine the number of different gray scales (not maxval) */
- for (row = 0; row <= PGM_MAXMAXVAL; row++)
- tone[row] = -1;
- cnt = 0;
- rowmin = curr_row - offset;
- if (rowmin < 0)
- rowmin = 0;
- rowmax = curr_row + offset;
- if (rowmax > wrows - 1)
- rowmax = wrows - 1;
- colmin = curr_col - offset;
- if (colmin < 0)
- colmin = 0;
- colmax = curr_col + offset;
- if (colmax > wcols - 1)
- colmax = wcols - 1;
- for (row = rowmin; row <= rowmax; row++) {
- for (col = colmin; col <= colmax; col++) {
- if (grays[row][col] < 0) { /* No data pixel found */
- continue;
- }
- if (grays[row][col] > PGM_MAXMAXVAL)
- G_fatal_error(_("Too many categories (found: %i, max: %i). "
- "Try to rescale or reclassify the map"),
- grays[row][col], PGM_MAXMAXVAL);
- tone[grays[row][col]] = grays[row][col];
- cnt++;
- }
- }
- /* what is the minimum number of pixels
- * to get reasonable texture measurements ?
- * at the very least, any of R0, R45, R90, R135 must be > 1 */
- if (cnt < size * size / 4 || (!with_nulls && cnt < size * size))
- return 0;
- /* Collapse array, taking out all zero values */
- Ng = 0;
- for (row = 0; row <= PGM_MAXMAXVAL; row++) {
- if (tone[row] != -1)
- tone[Ng++] = tone[row];
- }
- /* Now array contains only the gray levels present (in ascending order) */
- for (row = 0; row < Ng; row++)
- for (col = 0; col < Ng; col++) {
- P_matrix0[row][col] = P_matrix45[row][col] = 0;
- P_matrix90[row][col] = P_matrix135[row][col] = 0;
- }
- /* Find normalizing constants */
- /* not correct in case of NULL cells: */
- /*
- R0 = 2 * rows * (cols - t_d);
- R45 = 2 * (rows - t_d) * (cols - t_d);
- R90 = 2 * (rows - t_d) * cols;
- R135 = R45;
- */
- /* count actual cooccurrences for each angle */
- R0 = R45 = R90 = R135 = 0;
- /* Find gray-tone spatial dependence matrix */
- for (row = 0; row < rows; row++) {
- row2 = curr_row - offset + row;
- if (row2 < 0 || row2 >= wrows)
- continue;
- for (col = 0; col < cols; col++) {
- col2 = curr_col - offset + col;
- if (col2 < 0 || col2 >= wcols)
- continue;
- if (grays[row2][col2] < 0)
- continue;
- x = bsearch_gray(tone, Ng, grays[row2][col2]);
- rowd = row2;
- cold = col2 + t_d;
- if (col + t_d < cols && cold < wcols &&
- grays[rowd][cold] >= 0) {
- y = bsearch_gray(tone, Ng, grays[rowd][cold]);
- P_matrix0[x][y]++;
- P_matrix0[y][x]++;
- R0 += 2;
- }
- rowd = row2 + t_d;
- cold = col2;
- if (row + t_d < rows && rowd < wrows &&
- grays[rowd][cold] >= 0) {
- y = bsearch_gray(tone, Ng, grays[rowd][cold]);
- P_matrix90[x][y]++;
- P_matrix90[y][x]++;
- R90 += 2;
- }
- rowd = row2 + t_d;
- cold = col2 - t_d;
- if (row + t_d < rows && rowd < wrows &&
- col - t_d >= 0 && cold >= 0 &&
- grays[rowd][cold] >= 0) {
- y = bsearch_gray(tone, Ng, grays[rowd][cold]);
- P_matrix45[x][y]++;
- P_matrix45[y][x]++;
- R45 += 2;
- }
- rowd = row2 + t_d;
- cold = col2 + t_d;
- if (row + t_d < rows && rowd < wrows &&
- col + t_d < cols && cold < wcols &&
- grays[rowd][cold] >= 0) {
- y = bsearch_gray(tone, Ng, grays[rowd][cold]);
- P_matrix135[x][y]++;
- P_matrix135[y][x]++;
- R135 += 2;
- }
- }
- }
- /* Gray-tone spatial dependence matrices are complete */
- /* Normalize gray-tone spatial dependence matrix */
- for (itone = 0; itone < Ng; itone++) {
- for (jtone = 0; jtone < Ng; jtone++) {
- P_matrix0[itone][jtone] /= R0;
- P_matrix45[itone][jtone] /= R45;
- P_matrix90[itone][jtone] /= R90;
- P_matrix135[itone][jtone] /= R135;
- }
- }
- return 1;
- }
- int set_angle_vars(int angle, int have_px, int have_py,
- int have_pxpys, int have_pxpyd)
- {
- int i, j;
- float **P;
- switch (angle) {
- case 0:
- P_matrix = P_matrix0;
- break;
- case 1:
- P_matrix = P_matrix45;
- break;
- case 2:
- P_matrix = P_matrix90;
- break;
- case 3:
- P_matrix = P_matrix135;
- break;
- }
- P = P_matrix;
- /*
- * px[i] is the (i-1)th entry in the marginal probability matrix obtained
- * by summing the rows of p[i][j]
- */
- /* Pxpy sum and difference */
- /* reset variabless */
- if (have_px || have_py || have_pxpys || have_pxpyd) {
- for (i = 0; i < Ng; i++) {
- if (have_px || have_py) {
- px[i] = py[i] = 0;
- }
- if (have_pxpys || have_pxpyd) {
- Pxpys[i] = Pxpyd[i] = 0;
- }
- }
- if (have_pxpys) {
- for (j = Ng; j < 2 * Ng; j++) {
- Pxpys[j] = 0;
- }
- }
- }
- if (have_pxpys || have_pxpyd || have_px || have_py) {
- for (i = 0; i < Ng; i++) {
- for (j = 0; j < Ng; j++) {
- if (have_px || have_py) {
- px[i] += P[i][j];
- py[j] += P[i][j];
- }
- if (have_pxpys) {
- Pxpys[i + j] += P[i][j];
- }
- if (have_pxpyd) {
- Pxpyd[abs(i - j)] += P[i][j];
- }
- }
- }
- }
- return 1;
- }
- float h_measure(int t_m)
- {
- switch (t_m) {
- /* Angular Second Moment */
- case 1:
- return (f1_asm());
- break;
- /* Contrast */
- case 2:
- return (f2_contrast());
- break;
- /* Correlation */
- case 3:
- return (f3_corr());
- break;
- /* Variance */
- case 4:
- return (f4_var());
- break;
- /* Inverse Diff Moment */
- case 5:
- return (f5_idm());
- break;
- /* Sum Average */
- case 6:
- return (f6_savg());
- break;
- /* Sum Variance */
- case 7:
- return (f7_svar());
- break;
- /* Sum Entropy */
- case 8:
- return (f8_sentropy());
- break;
- /* Entropy */
- case 9:
- return (f9_entropy());
- break;
- /* Difference Variance */
- case 10:
- return (f10_dvar());
- break;
- /* Difference Entropy */
- case 11:
- return (f11_dentropy());
- break;
- /* Measure of Correlation-1 */
- case 12:
- return (f12_icorr());
- break;
- /* Measure of Correlation-2 */
- case 13:
- return (f13_icorr());
- break;
- }
- return 0;
- }
- void MatrixDealloc(float **A, int N)
- {
- /*A is NxN */
- int i;
- for (i = 0; i < N; i++)
- G_free(A[i]);
- G_free(A);
- }
- /* Angular Second Moment */
- /*
- * The angular second-moment feature (ASM) f1 is a measure of homogeneity
- * of the image. In a homogeneous image, there are very few dominant
- * gray-tone transitions. Hence the P matrix for such an image will have
- * fewer entries of large magnitude.
- */
- float f1_asm(void)
- {
- int i, j;
- float sum = 0;
- float **P = P_matrix;
- /*
- for (i = 0; i < Ng; i++)
- for (j = 0; j < Ng; j++)
- sum += P[i][j] * P[i][j];
- */
- for (i = 0; i < Ng; i++) {
- sum += P[i][i] * P[i][i];
- for (j = 0; j < i; j++)
- sum += 2 * P[i][j] * P[i][j];
- }
- return sum;
- }
- /* Contrast */
- /*
- * The contrast feature is a difference moment of the P matrix and is a
- * measure of the contrast or the amount of local variations present in an
- * image.
- */
- float f2_contrast(void)
- {
- int i, j /*, n */;
- float /* sum,*/ bigsum = 0;
- float **P = P_matrix;
- /* the three-loop version does not work
- * when gray tones that do not occur in the current window
- * have been removed in tone and P* */
- /*
- for (n = 0; n < Ng; n++) {
- sum = 0;
- for (i = 0; i < Ng; i++) {
- for (j = 0; j < Ng; j++) {
- if ((i - j) == n ||
- (j - i) == n) {
- sum += P[i][j];
- }
- }
- }
- bigsum += n * n * sum;
- }
- */
- /* two-loop version */
- for (i = 0; i < Ng; i++) {
- for (j = 0; j < i; j++) {
- bigsum += 2 * P[i][j] * (tone[i] - tone[j]) * (tone[i] - tone[j]);
- }
- }
- return bigsum;
- }
- /* Correlation */
- /*
- * This correlation feature is a measure of gray-tone linear-dependencies
- * in the image.
- */
- float f3_corr(void)
- {
- int i, j;
- float sum_sqr = 0, tmp = 0;
- float mean = 0, stddev;
- float **P = P_matrix;
- /* Now calculate the means and standard deviations of px and py */
- /*- fix supplied by J. Michael Christensen, 21 Jun 1991 */
- /*- further modified by James Darrell McCauley, 16 Aug 1991
- * after realizing that meanx=meany and stddevx=stddevy
- */
- for (i = 0; i < Ng; i++) {
- mean += px[i] * tone[i];
- sum_sqr += px[i] * tone[i] * tone[i];
- for (j = 0; j < Ng; j++)
- tmp += tone[i] * tone[j] * P[i][j];
- }
- stddev = sqrt(sum_sqr - (mean * mean));
-
- if (stddev == 0) /* stddev < GRASS_EPSILON or similar ? */
- return 0;
- return (tmp - mean * mean) / (stddev * stddev);
- }
- /* Sum of Squares: Variance */
- float f4_var(void)
- {
- int i, j;
- float mean = 0, var = 0;
- float **P = P_matrix;
- /*- Corrected by James Darrell McCauley, 16 Aug 1991
- * calculates the mean intensity level instead of the mean of
- * cooccurrence matrix elements
- */
- for (i = 0; i < Ng; i++)
- for (j = 0; j < Ng; j++)
- mean += tone[i] * P[i][j];
- for (i = 0; i < Ng; i++)
- for (j = 0; j < Ng; j++)
- var += (tone[i] - mean) * (tone[i] - mean) * P[i][j];
- return var;
- }
- /* Inverse Difference Moment */
- float f5_idm(void)
- {
- int i, j;
- float idm = 0;
- float **P = P_matrix;
- /*
- for (i = 0; i < Ng; i++)
- for (j = 0; j < Ng; j++)
- idm += P[i][j] / (1 + (tone[i] - tone[j]) * (tone[i] - tone[j]));
- */
- for (i = 0; i < Ng; i++) {
- idm += P[i][i];
- for (j = 0; j < i; j++)
- idm += 2 * P[i][j] / (1 + (tone[i] - tone[j]) * (tone[i] - tone[j]));
- }
- return idm;
- }
- /* Sum Average */
- float f6_savg(void)
- {
- int i, j, k;
- float savg = 0;
- float *P = Pxpys;
- /*
- for (i = 0; i < 2 * Ng - 1; i++)
- savg += (i + 2) * Pxpys[i];
- */
- for (i = 0; i < Ng; i++) {
- for (j = 0; j < Ng; j++) {
- k = i + j;
- savg += (tone[i] + tone[j]) * P[k];
- }
- }
- return savg;
- }
- /* Sum Variance */
- float f7_svar(void)
- {
- int i, j, k;
- float var = 0;
- float *P = Pxpys;
- float savg = f6_savg();
- float tmp;
- /*
- for (i = 0; i < 2 * Ng - 1; i++)
- var += (i + 2 - savg) * (i + 2 - savg) * Pxpys[i];
- */
- for (i = 0; i < Ng; i++) {
- for (j = 0; j < Ng; j++) {
- k = i + j;
- tmp = tone[i] + tone[j] - savg;
- var += tmp * tmp * P[k];
- }
- }
- return var;
- }
- /* Sum Entropy */
- float f8_sentropy(void)
- {
- int i;
- float sentr = 0;
- float *P = Pxpys;
- for (i = 0; i < 2 * Ng - 1; i++) {
- if (P[i] > 0)
- sentr -= P[i] * log2(P[i]);
- }
- return sentr;
- }
- /* Entropy */
- float f9_entropy(void)
- {
- int i, j;
- float entropy = 0;
- float **P = P_matrix;
- /*
- for (i = 0; i < Ng; i++) {
- for (j = 0; j < Ng; j++) {
- if (P[i][j] > 0)
- entropy += P[i][j] * log2(P[i][j]);
- }
- }
- */
- for (i = 0; i < Ng; i++) {
- if (P[i][i] > 0)
- entropy += P[i][i] * log2(P[i][i]);
- for (j = 0; j < i; j++) {
- if (P[i][j] > 0)
- entropy += 2 * P[i][j] * log2(P[i][j]);
- }
- }
- return -entropy;
- }
- /* Difference Variance */
- float f10_dvar(void)
- {
- int i, tmp;
- float sum = 0, sum_sqr = 0, var = 0;
- float *P = Pxpyd;
- /* Now calculate the variance of Pxpy (Px-y) */
- for (i = 0; i < Ng; i++) {
- sum += P[i];
- sum_sqr += P[i] * P[i];
- }
- /* tmp = Ng * Ng; */
- if (Ng > 1) {
- tmp = (tone[Ng - 1] - tone[0]) * (tone[Ng - 1] - tone[0]);
- var = ((tmp * sum_sqr) - (sum * sum)) / (tmp * tmp);
- }
- return var;
- }
- /* Difference Entropy */
- float f11_dentropy(void)
- {
- int i;
- float sum = 0;
- float *P = Pxpyd;
- for (i = 0; i < Ng; i++) {
- if (P[i] > 0)
- sum += P[i] * log2(P[i]);
- }
- return -sum;
- }
- /* Information Measures of Correlation */
- float f12_icorr(void)
- {
- int i, j;
- float hx = 0, hy = 0, hxy = 0, hxy1 = 0;
- float **P = P_matrix;
- for (i = 0; i < Ng; i++) {
- for (j = 0; j < Ng; j++) {
- if (px[i] * py[j] > 0)
- hxy1 -= P[i][j] * log2(px[i] * py[j]);
- if (P[i][j] > 0)
- hxy -= P[i][j] * log2(P[i][j]);
- }
- /* Calculate entropies of px and py - is this right? */
- if (px[i] > 0)
- hx -= px[i] * log2(px[i]);
- if (py[i] > 0)
- hy -= py[i] * log2(py[i]);
- }
- /* fprintf(stderr,"hxy1=%f\thxy=%f\thx=%f\thy=%f\n",hxy1,hxy,hx,hy); */
- if (hx == 0 && hy == 0)
- return 0;
- return ((hxy - hxy1) / (hx > hy ? hx : hy));
- }
- /* Information Measures of Correlation */
- float f13_icorr(void)
- {
- int i, j;
- float hxy = 0, hxy2 = 0;
- float **P = P_matrix;
- for (i = 0; i < Ng; i++) {
- for (j = 0; j < Ng; j++) {
- if (px[i] * py[j] > 0)
- hxy2 -= px[i] * py[j] * log2(px[i] * py[j]);
- if (P[i][j] > 0)
- hxy -= P[i][j] * log2(P[i][j]);
- }
- }
- /* fprintf(stderr,"hx=%f\thxy2=%f\n",hx,hxy2); */
- return (sqrt(fabs(1 - exp(-2.0 * (hxy2 - hxy)))));
- }
- float *vector(int n)
- {
- float *v;
- v = (float *)G_malloc(n * sizeof(float));
- if (!v)
- G_fatal_error(_("Unable to allocate memory")), exit(EXIT_FAILURE);
- return v;
- }
- /* Allocates a float matrix with range [nrl..nrh][ncl..nch] */
- float **matrix(int nr, int nc)
- {
- int i;
- float **m;
- /* allocate pointers to rows */
- m = (float **)G_malloc(nr * sizeof(float *));
- /* allocate rows */
- for (i = 0; i < nr; i++) {
- m[i] = (float *)G_malloc(nc * sizeof(float));
- }
- /* return pointer to array of pointers to rows */
- return m;
- }
|