main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  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), Benevento, 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 <string.h>
  25. #include <grass/gis.h>
  26. #include <grass/raster.h>
  27. #include <grass/glocale.h>
  28. #include "h_measure.h"
  29. struct menu
  30. {
  31. char *name; /* measure name */
  32. char *desc; /* menu display - full description */
  33. char *suffix; /* output suffix */
  34. char useme; /* calculate this measure if set */
  35. int idx; /* measure index */
  36. };
  37. /* modify this table to add new measures */
  38. static struct menu menu[] = {
  39. {"asm", "Angular Second Moment", "_ASM", 0, 0},
  40. {"contrast", "Contrast", "_Contr", 0, 1},
  41. {"corr", "Correlation", "_Corr", 0, 2},
  42. {"var", "Variance", "_Var", 0, 3},
  43. {"idm", "Inverse Diff Moment", "_IDM", 0, 4},
  44. {"sa", "Sum Average", "_SA", 0, 5},
  45. {"se", "Sum Entropy", "_SE", 0, 6},
  46. {"sv", "Sum Variance", "_SV", 0, 7},
  47. {"entr", "Entropy", "_Entr", 0, 8},
  48. {"dv", "Difference Variance", "_DV", 0, 9},
  49. {"de", "Difference Entropy", "_DE", 0, 10},
  50. {"moc1", "Measure of Correlation-1", "_MOC-1", 0, 11},
  51. {"moc2", "Measure of Correlation-2", "_MOC-2", 0, 12},
  52. {NULL, NULL, NULL, 0, -1}
  53. };
  54. static int find_measure(const char *measure_name)
  55. {
  56. int i;
  57. for (i = 0; menu[i].name; i++)
  58. if (strcmp(menu[i].name, measure_name) == 0)
  59. return i;
  60. G_fatal_error(_("Unknown measure <%s>"), measure_name);
  61. return -1;
  62. }
  63. int main(int argc, char *argv[])
  64. {
  65. struct Cell_head cellhd;
  66. char *name, *result;
  67. char **mapname;
  68. FCELL **fbuf;
  69. int n_measures, n_outputs, *measure_idx;
  70. int nrows, ncols;
  71. int row, col, first_row, last_row, first_col, last_col;
  72. int i, j;
  73. CELL **data; /* Data structure containing image */
  74. DCELL *dcell_row;
  75. struct FPRange range;
  76. DCELL min, max, inscale;
  77. FCELL measure; /* Containing measure done */
  78. int dist, size; /* dist = value of distance, size = s. of moving window */
  79. int offset;
  80. int have_px, have_py, have_sentr, have_pxpys, have_pxpyd;
  81. int infd, *outfd;
  82. RASTER_MAP_TYPE data_type, out_data_type;
  83. struct GModule *module;
  84. struct Option *opt_input, *opt_output, *opt_size, *opt_dist, *opt_measure;
  85. struct Flag *flag_ind, *flag_all;
  86. struct History history;
  87. char p[1024];
  88. G_gisinit(argv[0]);
  89. module = G_define_module();
  90. G_add_keyword(_("raster"));
  91. G_add_keyword(_("algebra"));
  92. G_add_keyword(_("statistics"));
  93. G_add_keyword(_("texture"));
  94. module->description =
  95. _("Generate images with textural features from a raster map.");
  96. module->overwrite = 1;
  97. /* Define the different options */
  98. opt_input = G_define_standard_option(G_OPT_R_INPUT);
  99. opt_output = G_define_standard_option(G_OPT_R_BASENAME_OUTPUT);
  100. opt_size = G_define_option();
  101. opt_size->key = "size";
  102. opt_size->key_desc = "value";
  103. opt_size->type = TYPE_INTEGER;
  104. opt_size->required = NO;
  105. opt_size->description = _("The size of moving window (odd and >= 3)");
  106. opt_size->answer = "3";
  107. /* Textural character is in direct relation of the spatial size of the texture primitives. */
  108. opt_dist = G_define_option();
  109. opt_dist->key = "distance";
  110. opt_dist->key_desc = "value";
  111. opt_dist->type = TYPE_INTEGER;
  112. opt_dist->required = NO;
  113. opt_dist->description = _("The distance between two samples (>= 1)");
  114. opt_dist->answer = "1";
  115. for (i = 0; menu[i].name; i++) {
  116. if (i)
  117. strcat(p, ",");
  118. else
  119. *p = 0;
  120. strcat(p, menu[i].name);
  121. }
  122. opt_measure = G_define_option();
  123. opt_measure->key = "method";
  124. opt_measure->type = TYPE_STRING;
  125. opt_measure->required = NO;
  126. opt_measure->multiple = YES;
  127. opt_measure->options = p;
  128. opt_measure->description = _("Textural measurement method");
  129. flag_ind = G_define_flag();
  130. flag_ind->key = 's';
  131. flag_ind->description = _("Separate output for each angle (0, 45, 90, 135)");
  132. flag_all = G_define_flag();
  133. flag_all->key = 'a';
  134. flag_all->description = _("Calculate all textural measurements");
  135. if (G_parser(argc, argv))
  136. exit(EXIT_FAILURE);
  137. name = opt_input->answer;
  138. result = opt_output->answer;
  139. size = atoi(opt_size->answer);
  140. if (size <= 0)
  141. G_fatal_error(_("Size of the moving window must be > 0"));
  142. if (size % 2 != 1)
  143. G_fatal_error(_("Size of the moving window must be odd"));
  144. dist = atoi(opt_dist->answer);
  145. if (dist <= 0)
  146. G_fatal_error(_("The distance between two samples must be > 0"));
  147. n_measures = 0;
  148. if (flag_all->answer) {
  149. for (i = 0; menu[i].name; i++) {
  150. menu[i].useme = 1;
  151. }
  152. n_measures = i;
  153. }
  154. else {
  155. for (i = 0; opt_measure->answers[i]; i++) {
  156. if (opt_measure->answers[i]) {
  157. const char *measure_name = opt_measure->answers[i];
  158. int n = find_measure(measure_name);
  159. menu[n].useme = 1;
  160. n_measures++;
  161. }
  162. }
  163. }
  164. if (!n_measures)
  165. G_fatal_error(_("Nothing to compute. Use at least one textural measure."));
  166. measure_idx = G_malloc(n_measures * sizeof(int));
  167. j = 0;
  168. for (i = 0; menu[i].name; i++) {
  169. if (menu[i].useme == 1) {
  170. measure_idx[j] = menu[i].idx;
  171. j++;
  172. }
  173. }
  174. /* variables needed */
  175. if (menu[2].useme || menu[11].useme || menu[12].useme)
  176. have_px = 1;
  177. else
  178. have_px = 0;
  179. if (menu[11].useme || menu[12].useme)
  180. have_py = 1;
  181. else
  182. have_py = 0;
  183. if (menu[6].useme || menu[7].useme)
  184. have_sentr = 1;
  185. else
  186. have_sentr = 0;
  187. if (menu[5].useme || menu[6].useme || menu[7].useme)
  188. have_pxpys = 1;
  189. else
  190. have_pxpys = 0;
  191. if (menu[9].useme || menu[10].useme)
  192. have_pxpyd = 1;
  193. else
  194. have_pxpyd = 0;
  195. infd = Rast_open_old(name, "");
  196. /* determine the inputmap type (CELL/FCELL/DCELL) */
  197. data_type = Rast_get_map_type(infd);
  198. Rast_get_cellhd(name, "", &cellhd);
  199. out_data_type = FCELL_TYPE;
  200. /* Allocate output buffers, use FCELL data_type */
  201. n_outputs = n_measures;
  202. if (flag_ind->answer) {
  203. n_outputs = n_measures * 4;
  204. }
  205. fbuf = G_malloc(n_outputs * sizeof(FCELL *));
  206. mapname = G_malloc(n_outputs * sizeof(char *));
  207. for (i = 0; i < n_outputs; i++) {
  208. mapname[i] = G_malloc(GNAME_MAX * sizeof(char));
  209. fbuf[i] = Rast_allocate_buf(out_data_type);
  210. }
  211. /* open output maps */
  212. outfd = G_malloc(n_outputs * sizeof(int));
  213. for (i = 0; i < n_measures; i++) {
  214. if (flag_ind->answer) {
  215. for (j = 0; j < 4; j++) {
  216. sprintf(mapname[i * 4 + j], "%s%s_%d", result,
  217. menu[measure_idx[i]].suffix, j * 45);
  218. outfd[i * 4 + j] = Rast_open_new(mapname[i * 4 + j], out_data_type);
  219. }
  220. }
  221. else {
  222. sprintf(mapname[i], "%s%s", result,
  223. menu[measure_idx[i]].suffix);
  224. outfd[i] = Rast_open_new(mapname[i], out_data_type);
  225. }
  226. }
  227. nrows = Rast_window_rows();
  228. ncols = Rast_window_cols();
  229. /* Load raster map. */
  230. /* allocate the space for one row of cell map data *A* */
  231. dcell_row = Rast_allocate_d_buf();
  232. /* Allocate appropriate memory for the structure containing the image */
  233. data = (int **)G_malloc(nrows * sizeof(int *));
  234. for (i = 0; i < nrows; i++) {
  235. data[i] = (int *)G_malloc(ncols * sizeof(int));
  236. }
  237. /* read input range */
  238. Rast_init_fp_range(&range);
  239. Rast_read_fp_range(name, "", &range);
  240. Rast_get_fp_range_min_max(&range, &min, &max);
  241. inscale = 0;
  242. if (min < 0 || max > 255) {
  243. inscale = 255. / (max - min);
  244. }
  245. /* input has 0 - 1 range */
  246. else if (max <= 1.) {
  247. inscale = 255. / (max - min);
  248. }
  249. /* Read in cell map values */
  250. /* TODO: use r.proj cache */
  251. G_important_message(_("Reading raster map..."));
  252. for (j = 0; j < nrows; j++) {
  253. Rast_get_row(infd, dcell_row, j, DCELL_TYPE);
  254. for (i = 0; i < ncols; i++) {
  255. if (Rast_is_d_null_value(&(dcell_row[i])))
  256. data[j][i] = -1;
  257. else if (inscale) {
  258. data[j][i] = (CELL)((dcell_row[i] - min) * inscale);
  259. }
  260. else
  261. data[j][i] = (CELL)dcell_row[i];
  262. }
  263. }
  264. /* close input cell map and release the row buffer */
  265. Rast_close(infd);
  266. G_free(dcell_row);
  267. /* Now raster map is loaded to memory. */
  268. /* *************************************************************************************************
  269. *
  270. * Compute of the matrix S.G.L.D. (Spatial Gray-Level Dependence Matrices) or co-occurrence matrix.
  271. * The image is analized for piece, every piece is naming moving window (s.w.). The s.w. must be
  272. * square with number of size's samples odd, that because we want the sample at the center of matrix.
  273. *
  274. ***************************************************************************************************/
  275. offset = size / 2;
  276. first_row = first_col = offset;
  277. last_row = nrows - offset;
  278. last_col = ncols - offset;
  279. Rast_set_f_null_value(fbuf[0], ncols);
  280. for (row = 0; row < first_row; row++) {
  281. for (i = 0; i < n_outputs; i++) {
  282. Rast_put_row(outfd[i], fbuf[0], out_data_type);
  283. }
  284. }
  285. if (n_measures > 1)
  286. G_message(n_("Calculating %d texture measure",
  287. "Calculating %d texture measures", n_measures), n_measures);
  288. else
  289. G_message(_("Calculating %s"), menu[measure_idx[0]].desc);
  290. alloc_vars(size, dist);
  291. for (row = first_row; row < last_row; row++) {
  292. G_percent(row, nrows, 2);
  293. for (i = 0; i < n_outputs; i++)
  294. Rast_set_f_null_value(fbuf[i], ncols);
  295. /*process the data */
  296. for (col = first_col; col < last_col; col++) {
  297. if (!set_vars(data, row, col, size, offset, dist)) {
  298. for (i = 0; i < n_outputs; i++)
  299. Rast_set_f_null_value(&(fbuf[i][col]), 1);
  300. continue;
  301. }
  302. /* for all angles (0, 45, 90, 135) */
  303. for (i = 0; i < 4; i++) {
  304. set_angle_vars(i, have_px, have_py, have_sentr, have_pxpys, have_pxpyd);
  305. /* for all requested textural measures */
  306. for (j = 0; j < n_measures; j++) {
  307. measure = (FCELL) h_measure(measure_idx[j]);
  308. if (flag_ind->answer) {
  309. /* output for each angle separately */
  310. fbuf[j * 4 + i][col] = measure;
  311. }
  312. else {
  313. /* use average over all angles for each measure */
  314. if (i == 0)
  315. fbuf[j][col] = measure;
  316. else if (i < 3)
  317. fbuf[j][col] += measure;
  318. else
  319. fbuf[j][col] = (fbuf[j][col] + measure) / 4.0;
  320. }
  321. }
  322. }
  323. }
  324. for (i = 0; i < n_outputs; i++) {
  325. Rast_put_row(outfd[i], fbuf[i], out_data_type);
  326. }
  327. }
  328. Rast_set_f_null_value(fbuf[0], ncols);
  329. for (row = last_row; row < nrows; row++) {
  330. for (i = 0; i < n_outputs; i++) {
  331. Rast_put_row(outfd[i], fbuf[0], out_data_type);
  332. }
  333. }
  334. G_percent(nrows, nrows, 1);
  335. for (i = 0; i < n_outputs; i++) {
  336. Rast_close(outfd[i]);
  337. Rast_short_history(mapname[i], "raster", &history);
  338. Rast_command_history(&history);
  339. Rast_write_history(mapname[i], &history);
  340. G_free(fbuf[i]);
  341. }
  342. G_free(fbuf);
  343. G_free(data);
  344. exit(EXIT_SUCCESS);
  345. }