main.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  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. * Markus Metz (optimization and bug fixes)
  9. *
  10. * PURPOSE: Create map raster with textural features.
  11. *
  12. * COPYRIGHT: (C) 2003 by University of Sannio (BN), Benevento, Italy
  13. *
  14. * This program is free software under the GNU General Public
  15. * License (>=v2). Read the file COPYING that comes with GRASS
  16. * for details.
  17. *
  18. * Permission to use, copy, modify, and distribute this software and its
  19. * documentation for any purpose and without fee is hereby granted. This
  20. * software is provided "as is" without express or implied warranty.
  21. *
  22. *****************************************************************************/
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <grass/gis.h>
  27. #include <grass/raster.h>
  28. #include <grass/glocale.h>
  29. #include "h_measure.h"
  30. struct menu
  31. {
  32. char *name; /* measure name */
  33. char *desc; /* menu display - full description */
  34. char *suffix; /* output suffix */
  35. char useme; /* calculate this measure if set */
  36. int idx; /* measure index */
  37. };
  38. /* modify this table to add new measures */
  39. static struct menu menu[] = {
  40. {"asm", "Angular Second Moment", "_ASM", 0, 1},
  41. {"contrast", "Contrast", "_Contr", 0, 2},
  42. {"corr", "Correlation", "_Corr", 0, 3},
  43. {"var", "Variance", "_Var", 0, 4},
  44. {"idm", "Inverse Diff Moment", "_IDM", 0, 5},
  45. {"sa", "Sum Average", "_SA", 0, 6},
  46. {"sv", "Sum Variance", "_SV", 0, 7},
  47. {"se", "Sum Entropy", "_SE", 0, 8},
  48. {"entr", "Entropy", "_Entr", 0, 9},
  49. {"dv", "Difference Variance", "_DV", 0, 10},
  50. {"de", "Difference Entropy", "_DE", 0, 11},
  51. {"moc1", "Measure of Correlation-1", "_MOC-1", 0, 12},
  52. {"moc2", "Measure of Correlation-2", "_MOC-2", 0, 13},
  53. {NULL, NULL, NULL, 0, -1}
  54. };
  55. static int find_measure(const char *measure_name)
  56. {
  57. int i;
  58. for (i = 0; menu[i].name; i++)
  59. if (strcmp(menu[i].name, measure_name) == 0)
  60. return i;
  61. G_fatal_error(_("Unknown measure <%s>"), measure_name);
  62. return -1;
  63. }
  64. int main(int argc, char *argv[])
  65. {
  66. struct Cell_head cellhd;
  67. char *name, *result;
  68. char **mapname;
  69. FCELL **fbuf;
  70. int n_measures, n_outputs, *measure_idx, overwrite;
  71. int nrows, ncols;
  72. int row, col, first_row, last_row, first_col, last_col;
  73. int i, j;
  74. CELL **data; /* Data structure containing image */
  75. DCELL *dcell_row;
  76. struct FPRange range;
  77. DCELL min, max, inscale;
  78. FCELL measure; /* Containing measure done */
  79. int dist, size; /* dist = value of distance, size = s. of moving window */
  80. int offset;
  81. int have_px, have_py, have_pxpys, have_pxpyd;
  82. int infd, *outfd;
  83. RASTER_MAP_TYPE out_data_type;
  84. struct GModule *module;
  85. struct Option *opt_input, *opt_output, *opt_size, *opt_dist, *opt_measure;
  86. struct Flag *flag_ind, *flag_all, *flag_null;
  87. struct History history;
  88. char p[1024];
  89. G_gisinit(argv[0]);
  90. module = G_define_module();
  91. G_add_keyword(_("raster"));
  92. G_add_keyword(_("algebra"));
  93. G_add_keyword(_("statistics"));
  94. G_add_keyword(_("texture"));
  95. module->description =
  96. _("Generate images with textural features from a raster map.");
  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->label = _("The distance between two samples (>= 1)");
  114. opt_dist->description = _("The distance must be smaller than the size of the moving window");
  115. opt_dist->answer = "1";
  116. for (i = 0; menu[i].name; i++) {
  117. if (i)
  118. strcat(p, ",");
  119. else
  120. *p = 0;
  121. strcat(p, menu[i].name);
  122. }
  123. opt_measure = G_define_option();
  124. opt_measure->key = "method";
  125. opt_measure->type = TYPE_STRING;
  126. opt_measure->required = NO;
  127. opt_measure->multiple = YES;
  128. opt_measure->options = p;
  129. opt_measure->description = _("Textural measurement method");
  130. flag_ind = G_define_flag();
  131. flag_ind->key = 's';
  132. flag_ind->label = _("Separate output for each angle (0, 45, 90, 135)");
  133. flag_ind->description = _("Angles are counterclockwise from east: "
  134. "0 is East to West, 45 is North-East to South-West");
  135. flag_all = G_define_flag();
  136. flag_all->key = 'a';
  137. flag_all->description = _("Calculate all textural measurements");
  138. flag_null = G_define_flag();
  139. flag_null->key = 'n';
  140. flag_null->label = _("Allow NULL cells in a moving window");
  141. flag_null->description = _("This will also avoid cropping along edges of the current region");
  142. if (G_parser(argc, argv))
  143. exit(EXIT_FAILURE);
  144. name = opt_input->answer;
  145. result = opt_output->answer;
  146. size = atoi(opt_size->answer);
  147. if (size <= 0)
  148. G_fatal_error(_("Size of the moving window must be > 0"));
  149. if (size % 2 != 1)
  150. G_fatal_error(_("Size of the moving window must be odd"));
  151. dist = atoi(opt_dist->answer);
  152. if (dist <= 0)
  153. G_fatal_error(_("The distance between two samples must be > 0"));
  154. if (dist >= size)
  155. G_fatal_error(_("The distance between two samples must be smaller than the size of the moving window"));
  156. n_measures = 0;
  157. if (flag_all->answer) {
  158. for (i = 0; menu[i].name; i++) {
  159. menu[i].useme = 1;
  160. }
  161. n_measures = i;
  162. }
  163. else {
  164. for (i = 0; opt_measure->answers[i]; i++) {
  165. if (opt_measure->answers[i]) {
  166. const char *measure_name = opt_measure->answers[i];
  167. int n = find_measure(measure_name);
  168. menu[n].useme = 1;
  169. n_measures++;
  170. }
  171. }
  172. }
  173. if (!n_measures)
  174. G_fatal_error(_("Nothing to compute. Use at least one textural measure."));
  175. measure_idx = G_malloc(n_measures * sizeof(int));
  176. j = 0;
  177. for (i = 0; menu[i].name; i++) {
  178. if (menu[i].useme == 1) {
  179. measure_idx[j] = i;
  180. j++;
  181. }
  182. }
  183. /* variables needed */
  184. if (menu[2].useme || menu[11].useme || menu[12].useme)
  185. have_px = 1;
  186. else
  187. have_px = 0;
  188. if (menu[11].useme || menu[12].useme)
  189. have_py = 1;
  190. else
  191. have_py = 0;
  192. if (menu[5].useme || menu[6].useme || menu[7].useme)
  193. have_pxpys = 1;
  194. else
  195. have_pxpys = 0;
  196. if (menu[9].useme || menu[10].useme)
  197. have_pxpyd = 1;
  198. else
  199. have_pxpyd = 0;
  200. infd = Rast_open_old(name, "");
  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. overwrite = G_check_overwrite(argc, argv);
  215. /* open output maps */
  216. outfd = G_malloc(n_outputs * sizeof(int));
  217. for (i = 0; i < n_measures; i++) {
  218. if (flag_ind->answer) {
  219. for (j = 0; j < 4; j++) {
  220. sprintf(mapname[i * 4 + j], "%s%s_%d", result,
  221. menu[measure_idx[i]].suffix, j * 45);
  222. if (!G_find_raster(mapname[i * 4 + j], G_mapset()) || overwrite) {
  223. outfd[i * 4 + j] = Rast_open_new(mapname[i * 4 + j], out_data_type);
  224. } else {
  225. G_fatal_error(_("At least one of the requested output maps exists. Use --o to overwrite."));
  226. }
  227. }
  228. }
  229. else {
  230. sprintf(mapname[i], "%s%s", result,
  231. menu[measure_idx[i]].suffix);
  232. if (!G_find_raster(mapname[i], G_mapset()) || overwrite) {
  233. outfd[i] = Rast_open_new(mapname[i], out_data_type);
  234. } else {
  235. G_fatal_error(_("At least one of the requested output maps exists. Use --o to overwrite."));
  236. }
  237. }
  238. }
  239. nrows = Rast_window_rows();
  240. ncols = Rast_window_cols();
  241. /* Load raster map. */
  242. /* allocate the space for one row of cell map data *A* */
  243. dcell_row = Rast_allocate_d_buf();
  244. /* Allocate appropriate memory for the structure containing the image */
  245. data = (int **)G_malloc(nrows * sizeof(int *));
  246. for (i = 0; i < nrows; i++) {
  247. data[i] = (int *)G_malloc(ncols * sizeof(int));
  248. }
  249. /* read input range */
  250. Rast_init_fp_range(&range);
  251. Rast_read_fp_range(name, "", &range);
  252. Rast_get_fp_range_min_max(&range, &min, &max);
  253. inscale = 0;
  254. if (min < 0 || max > 255) {
  255. inscale = 255. / (max - min);
  256. }
  257. /* input has 0 - 1 range */
  258. else if (max <= 1.) {
  259. inscale = 255. / (max - min);
  260. }
  261. /* Read in cell map values */
  262. /* TODO: use r.proj cache */
  263. G_important_message(_("Reading raster map..."));
  264. for (j = 0; j < nrows; j++) {
  265. Rast_get_row(infd, dcell_row, j, DCELL_TYPE);
  266. for (i = 0; i < ncols; i++) {
  267. if (Rast_is_d_null_value(&(dcell_row[i])))
  268. data[j][i] = -1;
  269. else if (inscale) {
  270. data[j][i] = (CELL)((dcell_row[i] - min) * inscale);
  271. }
  272. else
  273. data[j][i] = (CELL)dcell_row[i];
  274. }
  275. }
  276. /* close input cell map and release the row buffer */
  277. Rast_close(infd);
  278. G_free(dcell_row);
  279. /* Now raster map is loaded to memory. */
  280. /* *************************************************************************************************
  281. *
  282. * Compute of the matrix S.G.L.D. (Spatial Gray-Level Dependence Matrices) or co-occurrence matrix.
  283. * The image is analized for piece, every piece is naming moving window (s.w.). The s.w. must be
  284. * square with number of size's samples odd, that because we want the sample at the center of matrix.
  285. *
  286. ***************************************************************************************************/
  287. offset = size / 2;
  288. if (!flag_null->answer) {
  289. first_row = first_col = offset;
  290. last_row = nrows - offset;
  291. last_col = ncols - offset;
  292. }
  293. else {
  294. /* no cropping at window margins */
  295. first_row = first_col = 0;
  296. last_row = nrows;
  297. last_col = ncols;
  298. }
  299. Rast_set_f_null_value(fbuf[0], ncols);
  300. for (row = 0; row < first_row; row++) {
  301. for (i = 0; i < n_outputs; i++) {
  302. Rast_put_row(outfd[i], fbuf[0], out_data_type);
  303. }
  304. }
  305. if (n_measures > 1)
  306. G_message(n_("Calculating %d texture measure",
  307. "Calculating %d texture measures", n_measures), n_measures);
  308. else
  309. G_message(_("Calculating %s..."), menu[measure_idx[0]].desc);
  310. alloc_vars(size);
  311. for (row = first_row; row < last_row; row++) {
  312. G_percent(row, nrows, 2);
  313. for (i = 0; i < n_outputs; i++)
  314. Rast_set_f_null_value(fbuf[i], ncols);
  315. /*process the data */
  316. for (col = first_col; col < last_col; col++) {
  317. if (!set_vars(data, row, col, size, offset, dist, flag_null->answer)) {
  318. for (i = 0; i < n_outputs; i++)
  319. Rast_set_f_null_value(&(fbuf[i][col]), 1);
  320. continue;
  321. }
  322. /* for all angles (0, 45, 90, 135) */
  323. for (i = 0; i < 4; i++) {
  324. set_angle_vars(i, have_px, have_py, have_pxpys, have_pxpyd);
  325. /* for all requested textural measures */
  326. for (j = 0; j < n_measures; j++) {
  327. measure = (FCELL) h_measure(menu[measure_idx[j]].idx);
  328. if (flag_ind->answer) {
  329. /* output for each angle separately */
  330. fbuf[j * 4 + i][col] = measure;
  331. }
  332. else {
  333. /* use average over all angles for each measure */
  334. if (i == 0)
  335. fbuf[j][col] = measure;
  336. else if (i < 3)
  337. fbuf[j][col] += measure;
  338. else
  339. fbuf[j][col] = (fbuf[j][col] + measure) / 4.0;
  340. }
  341. }
  342. }
  343. }
  344. for (i = 0; i < n_outputs; i++) {
  345. Rast_put_row(outfd[i], fbuf[i], out_data_type);
  346. }
  347. }
  348. Rast_set_f_null_value(fbuf[0], ncols);
  349. for (row = last_row; row < nrows; row++) {
  350. for (i = 0; i < n_outputs; i++) {
  351. Rast_put_row(outfd[i], fbuf[0], out_data_type);
  352. }
  353. }
  354. G_percent(nrows, nrows, 1);
  355. for (i = 0; i < n_outputs; i++) {
  356. Rast_close(outfd[i]);
  357. Rast_short_history(mapname[i], "raster", &history);
  358. Rast_command_history(&history);
  359. Rast_write_history(mapname[i], &history);
  360. G_free(fbuf[i]);
  361. }
  362. G_free(fbuf);
  363. G_free(data);
  364. exit(EXIT_SUCCESS);
  365. }