main.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  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. /* Define the different options */
  97. opt_input = G_define_standard_option(G_OPT_R_INPUT);
  98. opt_output = G_define_option();
  99. opt_output->key = "prefix";
  100. opt_output->type = TYPE_STRING;
  101. opt_output->required = YES;
  102. opt_output->description = _("Prefix for output raster map(s)");
  103. opt_size = G_define_option();
  104. opt_size->key = "size";
  105. opt_size->key_desc = "value";
  106. opt_size->type = TYPE_INTEGER;
  107. opt_size->required = NO;
  108. opt_size->description = _("The size of moving window (odd and >= 3)");
  109. opt_size->answer = "3";
  110. /* Textural character is in direct relation of the spatial size of the texture primitives. */
  111. opt_dist = G_define_option();
  112. opt_dist->key = "distance";
  113. opt_dist->key_desc = "value";
  114. opt_dist->type = TYPE_INTEGER;
  115. opt_dist->required = NO;
  116. opt_dist->description = _("The distance between two samples (>= 1)");
  117. opt_dist->answer = "1";
  118. for (i = 0; menu[i].name; i++) {
  119. if (i)
  120. strcat(p, ",");
  121. else
  122. *p = 0;
  123. strcat(p, menu[i].name);
  124. }
  125. opt_measure = G_define_option();
  126. opt_measure->key = "method";
  127. opt_measure->type = TYPE_STRING;
  128. opt_measure->required = NO;
  129. opt_measure->multiple = YES;
  130. opt_measure->options = p;
  131. opt_measure->description = _("Textural measurement method");
  132. flag_ind = G_define_flag();
  133. flag_ind->key = 's';
  134. flag_ind->description = _("Separate output for each angle (0, 45, 90, 135)");
  135. flag_all = G_define_flag();
  136. flag_all->key = 'a';
  137. flag_all->description = _("Calculate all textural measurements");
  138. if (G_parser(argc, argv))
  139. exit(EXIT_FAILURE);
  140. name = opt_input->answer;
  141. result = opt_output->answer;
  142. size = atoi(opt_size->answer);
  143. if (size <= 0)
  144. G_fatal_error(_("Size of the moving window must be > 0"));
  145. if (size % 2 != 1)
  146. G_fatal_error(_("Size of the moving window must be odd"));
  147. dist = atoi(opt_dist->answer);
  148. if (dist <= 0)
  149. G_fatal_error(_("The distance between two samples must be > 0"));
  150. n_measures = 0;
  151. if (flag_all->answer) {
  152. for (i = 0; menu[i].name; i++) {
  153. menu[i].useme = 1;
  154. }
  155. n_measures = i;
  156. }
  157. else {
  158. for (i = 0; opt_measure->answers[i]; i++) {
  159. if (opt_measure->answers[i]) {
  160. const char *measure_name = opt_measure->answers[i];
  161. int n = find_measure(measure_name);
  162. menu[n].useme = 1;
  163. n_measures++;
  164. }
  165. }
  166. }
  167. if (!n_measures)
  168. G_fatal_error(_("Nothing to compute. Use at least one textural measure."));
  169. measure_idx = G_malloc(n_measures * sizeof(int));
  170. j = 0;
  171. for (i = 0; menu[i].name; i++) {
  172. if (menu[i].useme == 1) {
  173. measure_idx[j] = menu[i].idx;
  174. j++;
  175. }
  176. }
  177. /* variables needed */
  178. if (menu[2].useme || menu[11].useme || menu[12].useme)
  179. have_px = 1;
  180. else
  181. have_px = 0;
  182. if (menu[11].useme || menu[12].useme)
  183. have_py = 1;
  184. else
  185. have_py = 0;
  186. if (menu[6].useme || menu[7].useme)
  187. have_sentr = 1;
  188. else
  189. have_sentr = 0;
  190. if (menu[5].useme || menu[6].useme || menu[7].useme)
  191. have_pxpys = 1;
  192. else
  193. have_pxpys = 0;
  194. if (menu[9].useme || menu[10].useme)
  195. have_pxpyd = 1;
  196. else
  197. have_pxpyd = 0;
  198. infd = Rast_open_old(name, "");
  199. /* determine the inputmap type (CELL/FCELL/DCELL) */
  200. data_type = Rast_get_map_type(infd);
  201. Rast_get_cellhd(name, "", &cellhd);
  202. out_data_type = FCELL_TYPE;
  203. /* Allocate output buffers, use FCELL data_type */
  204. n_outputs = n_measures;
  205. if (flag_ind->answer) {
  206. n_outputs = n_measures * 4;
  207. }
  208. fbuf = G_malloc(n_outputs * sizeof(FCELL *));
  209. mapname = G_malloc(n_outputs * sizeof(char *));
  210. for (i = 0; i < n_outputs; i++) {
  211. mapname[i] = G_malloc(GNAME_MAX * sizeof(char));
  212. fbuf[i] = Rast_allocate_buf(out_data_type);
  213. }
  214. /* open output maps */
  215. outfd = G_malloc(n_outputs * sizeof(int));
  216. for (i = 0; i < n_measures; i++) {
  217. if (flag_ind->answer) {
  218. for (j = 0; j < 4; j++) {
  219. sprintf(mapname[i * 4 + j], "%s%s_%d", result,
  220. menu[measure_idx[i]].suffix, j * 45);
  221. outfd[i * 4 + j] = Rast_open_new(mapname[i * 4 + j], out_data_type);
  222. }
  223. }
  224. else {
  225. sprintf(mapname[i], "%s%s", result,
  226. menu[measure_idx[i]].suffix);
  227. outfd[i] = Rast_open_new(mapname[i], out_data_type);
  228. }
  229. }
  230. nrows = Rast_window_rows();
  231. ncols = Rast_window_cols();
  232. /* Load raster map. */
  233. /* allocate the space for one row of cell map data *A* */
  234. dcell_row = Rast_allocate_d_buf();
  235. /* Allocate appropriate memory for the structure containing the image */
  236. data = (int **)G_malloc(nrows * sizeof(int *));
  237. for (i = 0; i < nrows; i++) {
  238. data[i] = (int *)G_malloc(ncols * sizeof(int));
  239. }
  240. /* read input range */
  241. Rast_init_fp_range(&range);
  242. Rast_read_fp_range(name, "", &range);
  243. Rast_get_fp_range_min_max(&range, &min, &max);
  244. inscale = 0;
  245. if (min < 0 || max > 255) {
  246. inscale = 255. / (max - min);
  247. }
  248. /* input has 0 - 1 range */
  249. else if (max <= 1.) {
  250. inscale = 255. / (max - min);
  251. }
  252. /* Read in cell map values */
  253. /* TODO: use r.proj cache */
  254. G_important_message(_("Reading raster map..."));
  255. for (j = 0; j < nrows; j++) {
  256. Rast_get_row(infd, dcell_row, j, DCELL_TYPE);
  257. for (i = 0; i < ncols; i++) {
  258. if (Rast_is_d_null_value(&(dcell_row[i])))
  259. data[j][i] = -1;
  260. else if (inscale) {
  261. data[j][i] = (CELL)((dcell_row[i] - min) * inscale);
  262. }
  263. else
  264. data[j][i] = (CELL)dcell_row[i];
  265. }
  266. }
  267. /* close input cell map and release the row buffer */
  268. Rast_close(infd);
  269. G_free(dcell_row);
  270. /* Now raster map is loaded to memory. */
  271. /* *************************************************************************************************
  272. *
  273. * Compute of the matrix S.G.L.D. (Spatial Gray-Level Dependence Matrices) or co-occurrence matrix.
  274. * The image is analized for piece, every piece is naming moving window (s.w.). The s.w. must be
  275. * square with number of size's samples odd, that because we want the sample at the center of matrix.
  276. *
  277. ***************************************************************************************************/
  278. offset = size / 2;
  279. first_row = first_col = offset;
  280. last_row = nrows - offset;
  281. last_col = ncols - offset;
  282. Rast_set_f_null_value(fbuf[0], ncols);
  283. for (row = 0; row < first_row; row++) {
  284. for (i = 0; i < n_outputs; i++) {
  285. Rast_put_row(outfd[i], fbuf[0], out_data_type);
  286. }
  287. }
  288. if (n_measures > 1)
  289. G_message(_("Calculating %d texture measures"), n_measures);
  290. else
  291. G_message(_("Calculating %s"), menu[measure_idx[0]].desc);
  292. alloc_vars(size, dist);
  293. for (row = first_row; row < last_row; row++) {
  294. G_percent(row, nrows, 2);
  295. for (i = 0; i < n_outputs; i++)
  296. Rast_set_f_null_value(fbuf[i], ncols);
  297. /*process the data */
  298. for (col = first_col; col < last_col; col++) {
  299. if (!set_vars(data, row, col, size, offset, dist)) {
  300. for (i = 0; i < n_outputs; i++)
  301. Rast_set_f_null_value(&(fbuf[i][col]), 1);
  302. continue;
  303. }
  304. /* for all angles (0, 45, 90, 135) */
  305. for (i = 0; i < 4; i++) {
  306. set_angle_vars(i, have_px, have_py, have_sentr, have_pxpys, have_pxpyd);
  307. /* for all requested textural measures */
  308. for (j = 0; j < n_measures; j++) {
  309. measure = (FCELL) h_measure(measure_idx[j]);
  310. if (flag_ind->answer) {
  311. /* output for each angle separately */
  312. fbuf[j * 4 + i][col] = measure;
  313. }
  314. else {
  315. /* use average over all angles for each measure */
  316. if (i == 0)
  317. fbuf[j][col] = measure;
  318. else if (i < 3)
  319. fbuf[j][col] += measure;
  320. else
  321. fbuf[j][col] = (fbuf[j][col] + measure) / 4.0;
  322. }
  323. }
  324. }
  325. }
  326. for (i = 0; i < n_outputs; i++) {
  327. Rast_put_row(outfd[i], fbuf[i], out_data_type);
  328. }
  329. }
  330. Rast_set_f_null_value(fbuf[0], ncols);
  331. for (row = last_row; row < nrows; row++) {
  332. for (i = 0; i < n_outputs; i++) {
  333. Rast_put_row(outfd[i], fbuf[0], out_data_type);
  334. }
  335. }
  336. G_percent(nrows, nrows, 1);
  337. for (i = 0; i < n_outputs; i++) {
  338. Rast_close(outfd[i]);
  339. Rast_short_history(mapname[i], "raster", &history);
  340. Rast_command_history(&history);
  341. Rast_write_history(mapname[i], &history);
  342. G_free(fbuf[i]);
  343. }
  344. G_free(fbuf);
  345. G_free(data);
  346. exit(EXIT_SUCCESS);
  347. }