main.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /****************************************************************************
  2. *
  3. * MODULE: r.stats.zonal
  4. *
  5. * AUTHOR(S): Glynn Clements; loosely based upon r.statistics, by
  6. * Martin Schroeder, Geographisches Institut Heidelberg, Germany
  7. *
  8. * PURPOSE: Category or object oriented statistics
  9. *
  10. * COPYRIGHT: (C) 2007,2008 Martin Schroeder, Glynn Clements
  11. * and the GRASS Development Team
  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. *****************************************************************************/
  18. #include <string.h>
  19. #include <stdlib.h>
  20. #include <math.h>
  21. #include <grass/gis.h>
  22. #include <grass/raster.h>
  23. #include <grass/spawn.h>
  24. #include <grass/glocale.h>
  25. #define COUNT 1 /* Count */
  26. #define SUM 2 /* Sum */
  27. #define MIN 3 /* Minimum */
  28. #define MAX 4 /* Maximum */
  29. #define RANGE 5 /* Range */
  30. #define AVERAGE 6 /* Average (mean) */
  31. #define ADEV 7 /* Average deviation */
  32. #define VARIANCE1 8 /* Variance */
  33. #define STDDEV1 9 /* Standard deviation */
  34. #define SKEWNESS1 10 /* Skewness */
  35. #define KURTOSIS1 11 /* Kurtosis */
  36. #define VARIANCE2 12 /* Variance */
  37. #define STDDEV2 13 /* Standard deviation */
  38. #define SKEWNESS2 14 /* Skewness */
  39. #define KURTOSIS2 15 /* Kurtosis */
  40. struct menu
  41. {
  42. const char *name; /* method name */
  43. int val; /* number of function */
  44. const char *text; /* menu display - full description */
  45. };
  46. extern struct menu menu[];
  47. /* modify this table to add new methods */
  48. struct menu menu[] = {
  49. {"count", COUNT, "Count of values in specified objects"},
  50. {"sum", SUM, "Sum of values in specified objects"},
  51. {"min", MIN, "Minimum of values in specified objects"},
  52. {"max", MAX, "Maximum of values in specified objects"},
  53. {"range", RANGE, "Range of values (max - min) in specified objects"},
  54. {"average", AVERAGE, "Average of values in specified objects"},
  55. {"avedev", ADEV, "Average deviation of values in specified objects"},
  56. {"variance", VARIANCE1, "Variance of values in specified objects"},
  57. {"stddev", STDDEV1, "Standard deviation of values in specified objects"},
  58. {"skewness", SKEWNESS1, "Skewness of values in specified objects"},
  59. {"kurtosis", KURTOSIS1, "Kurtosis of values in specified objects"},
  60. {"variance2", VARIANCE2, "(2-pass) Variance of values in specified objects"},
  61. {"stddev2", STDDEV2, "(2-pass) Standard deviation of values in specified objects"},
  62. {"skewness2", SKEWNESS2, "(2-pass) Skewness of values in specified objects"},
  63. {"kurtosis2", KURTOSIS2, "(2-pass) Kurtosis of values in specified objects"},
  64. {0, 0, 0}
  65. };
  66. int main(int argc, char **argv)
  67. {
  68. static DCELL *count, *sum, *mean, *sumu, *sum2, *sum3, *sum4, *min, *max;
  69. DCELL *result;
  70. struct GModule *module;
  71. struct {
  72. struct Option *method, *basemap, *covermap, *output;
  73. } opt;
  74. struct {
  75. struct Flag *c, *r;
  76. } flag;
  77. char methods[2048];
  78. const char *basemap, *covermap, *output;
  79. int usecats;
  80. int reclass;
  81. int base_fd, cover_fd;
  82. struct Categories cats;
  83. CELL *base_buf;
  84. DCELL *cover_buf;
  85. struct Range range;
  86. CELL mincat, ncats;
  87. int method;
  88. int rows, cols;
  89. int row, col, i;
  90. G_gisinit(argv[0]);
  91. module = G_define_module();
  92. G_add_keyword(_("raster"));
  93. G_add_keyword(_("statistics"));
  94. G_add_keyword(_("zonal statistics"));
  95. module->description =
  96. _("Calculates category or object oriented statistics (accumulator-based statistics).");
  97. opt.basemap = G_define_standard_option(G_OPT_R_BASE);
  98. opt.covermap = G_define_standard_option(G_OPT_R_COVER);
  99. opt.method = G_define_option();
  100. opt.method->key = "method";
  101. opt.method->type = TYPE_STRING;
  102. opt.method->required = YES;
  103. opt.method->description = _("Method of object-based statistic");
  104. for (i = 0; menu[i].name; i++) {
  105. if (i)
  106. strcat(methods, ",");
  107. else
  108. *(methods) = 0;
  109. strcat(methods, menu[i].name);
  110. }
  111. opt.method->options = G_store(methods);
  112. for (i = 0; menu[i].name; i++) {
  113. if (i)
  114. strcat(methods, ";");
  115. else
  116. *(methods) = 0;
  117. strcat(methods, menu[i].name);
  118. strcat(methods, ";");
  119. strcat(methods, menu[i].text);
  120. }
  121. opt.method->descriptions = G_store(methods);
  122. opt.output = G_define_standard_option(G_OPT_R_OUTPUT);
  123. opt.output->description = _("Resultant raster map");
  124. opt.output->required = YES;
  125. flag.c = G_define_flag();
  126. flag.c->key = 'c';
  127. flag.c->description =
  128. _("Cover values extracted from the category labels of the cover map");
  129. flag.r = G_define_flag();
  130. flag.r->key = 'r';
  131. flag.r->description =
  132. _("Create reclass map with statistics as category labels");
  133. if (G_parser(argc, argv))
  134. exit(EXIT_FAILURE);
  135. basemap = opt.basemap->answer;
  136. covermap = opt.covermap->answer;
  137. output = opt.output->answer;
  138. usecats = flag.c->answer;
  139. reclass = flag.r->answer;
  140. for (i = 0; menu[i].name; i++)
  141. if (strcmp(menu[i].name, opt.method->answer) == 0)
  142. break;
  143. if (!menu[i].name) {
  144. G_warning(_("<%s=%s> unknown %s"), opt.method->key, opt.method->answer,
  145. opt.method->key);
  146. G_usage();
  147. exit(EXIT_FAILURE);
  148. }
  149. method = menu[i].val;
  150. base_fd = Rast_open_old(basemap, "");
  151. cover_fd = Rast_open_old(covermap, "");
  152. if (usecats && Rast_read_cats(covermap, "", &cats) < 0)
  153. G_fatal_error(_("Unable to read category file of cover map <%s>"), covermap);
  154. if (Rast_map_is_fp(basemap, "") != 0)
  155. G_fatal_error(_("The base map must be an integer (CELL) map"));
  156. if (Rast_read_range(basemap, "", &range) < 0)
  157. G_fatal_error(_("Unable to read range of base map <%s>"), basemap);
  158. mincat = range.min;
  159. ncats = range.max - range.min + 1;
  160. rows = Rast_window_rows();
  161. cols = Rast_window_cols();
  162. switch (method) {
  163. case COUNT:
  164. count = G_calloc(ncats, sizeof(DCELL));
  165. break;
  166. case SUM:
  167. sum = G_calloc(ncats, sizeof(DCELL));
  168. break;
  169. case MIN:
  170. min = G_malloc(ncats * sizeof(DCELL));
  171. break;
  172. case MAX:
  173. max = G_malloc(ncats * sizeof(DCELL));
  174. break;
  175. case RANGE:
  176. min = G_malloc(ncats * sizeof(DCELL));
  177. max = G_malloc(ncats * sizeof(DCELL));
  178. break;
  179. case AVERAGE:
  180. case ADEV:
  181. case VARIANCE2:
  182. case STDDEV2:
  183. case SKEWNESS2:
  184. case KURTOSIS2:
  185. count = G_calloc(ncats, sizeof(DCELL));
  186. sum = G_calloc(ncats, sizeof(DCELL));
  187. break;
  188. case VARIANCE1:
  189. case STDDEV1:
  190. count = G_calloc(ncats, sizeof(DCELL));
  191. sum = G_calloc(ncats, sizeof(DCELL));
  192. sum2 = G_calloc(ncats, sizeof(DCELL));
  193. break;
  194. case SKEWNESS1:
  195. count = G_calloc(ncats, sizeof(DCELL));
  196. sum = G_calloc(ncats, sizeof(DCELL));
  197. sum2 = G_calloc(ncats, sizeof(DCELL));
  198. sum3 = G_calloc(ncats, sizeof(DCELL));
  199. break;
  200. case KURTOSIS1:
  201. count = G_calloc(ncats, sizeof(DCELL));
  202. sum = G_calloc(ncats, sizeof(DCELL));
  203. sum2 = G_calloc(ncats, sizeof(DCELL));
  204. sum4 = G_calloc(ncats, sizeof(DCELL));
  205. break;
  206. }
  207. if (min)
  208. for (i = 0; i < ncats; i++)
  209. min[i] = 1e300;
  210. if (max)
  211. for (i = 0; i < ncats; i++)
  212. max[i] = -1e300;
  213. base_buf = Rast_allocate_c_buf();
  214. cover_buf = Rast_allocate_d_buf();
  215. G_message(_("First pass"));
  216. for (row = 0; row < rows; row++) {
  217. Rast_get_c_row(base_fd, base_buf, row);
  218. Rast_get_d_row(cover_fd, cover_buf, row);
  219. for (col = 0; col < cols; col++) {
  220. int n;
  221. DCELL v;
  222. if (Rast_is_c_null_value(&base_buf[col]))
  223. continue;
  224. if (Rast_is_d_null_value(&cover_buf[col]))
  225. continue;
  226. n = base_buf[col] - mincat;
  227. if (n < 0 || n >= ncats)
  228. continue;
  229. v = cover_buf[col];
  230. if (usecats)
  231. sscanf(Rast_get_c_cat((CELL *) &v, &cats), "%lf", &v);
  232. if (count)
  233. count[n]++;
  234. if (sum)
  235. sum[n] += v;
  236. if (sum2)
  237. sum2[n] += v * v;
  238. if (sum3)
  239. sum3[n] += v * v * v;
  240. if (sum4)
  241. sum4[n] += v * v * v * v;
  242. if (min && min[n] > v)
  243. min[n] = v;
  244. if (max && max[n] < v)
  245. max[n] = v;
  246. }
  247. G_percent(row, rows, 2);
  248. }
  249. G_percent(row, rows, 2);
  250. result = G_calloc(ncats, sizeof(DCELL));
  251. switch (method) {
  252. case ADEV:
  253. case VARIANCE2:
  254. case STDDEV2:
  255. case SKEWNESS2:
  256. case KURTOSIS2:
  257. mean = G_calloc(ncats, sizeof(DCELL));
  258. for (i = 0; i < ncats; i++)
  259. mean[i] = sum[i] / count[i];
  260. G_free(sum);
  261. break;
  262. }
  263. switch (method) {
  264. case ADEV:
  265. sumu = G_calloc(ncats, sizeof(DCELL));
  266. break;
  267. case VARIANCE2:
  268. case STDDEV2:
  269. sum2 = G_calloc(ncats, sizeof(DCELL));
  270. break;
  271. case SKEWNESS2:
  272. sum2 = G_calloc(ncats, sizeof(DCELL));
  273. sum3 = G_calloc(ncats, sizeof(DCELL));
  274. break;
  275. case KURTOSIS2:
  276. sum2 = G_calloc(ncats, sizeof(DCELL));
  277. sum4 = G_calloc(ncats, sizeof(DCELL));
  278. break;
  279. }
  280. if (mean) {
  281. G_message(_("Second pass"));
  282. for (row = 0; row < rows; row++) {
  283. Rast_get_c_row(base_fd, base_buf, row);
  284. Rast_get_d_row(cover_fd, cover_buf, row);
  285. for (col = 0; col < cols; col++) {
  286. int n;
  287. DCELL v, d;
  288. if (Rast_is_c_null_value(&base_buf[col]))
  289. continue;
  290. if (Rast_is_d_null_value(&cover_buf[col]))
  291. continue;
  292. n = base_buf[col] - mincat;
  293. if (n < 0 || n >= ncats)
  294. continue;
  295. v = cover_buf[col];
  296. if (usecats)
  297. sscanf(Rast_get_c_cat((CELL *) &v, &cats), "%lf", &v);
  298. d = v - mean[n];
  299. if (sumu)
  300. sumu[n] += fabs(d);
  301. if (sum2)
  302. sum2[n] += d * d;
  303. if (sum3)
  304. sum3[n] += d * d * d;
  305. if (sum4)
  306. sum4[n] += d * d * d * d;
  307. }
  308. G_percent(row, rows, 2);
  309. }
  310. G_percent(row, rows, 2);
  311. G_free(mean);
  312. G_free(cover_buf);
  313. }
  314. switch (method) {
  315. case COUNT:
  316. for (i = 0; i < ncats; i++)
  317. result[i] = count[i];
  318. break;
  319. case SUM:
  320. for (i = 0; i < ncats; i++)
  321. result[i] = sum[i];
  322. break;
  323. case AVERAGE:
  324. for (i = 0; i < ncats; i++)
  325. result[i] = sum[i] / count[i];
  326. break;
  327. case MIN:
  328. for (i = 0; i < ncats; i++)
  329. result[i] = min[i];
  330. break;
  331. case MAX:
  332. for (i = 0; i < ncats; i++)
  333. result[i] = max[i];
  334. break;
  335. case RANGE:
  336. for (i = 0; i < ncats; i++)
  337. result[i] = max[i] - min[i];
  338. break;
  339. case VARIANCE1:
  340. for (i = 0; i < ncats; i++) {
  341. double n = count[i];
  342. double var = (sum2[i] - sum[i] * sum[i] / n) / (n - 1);
  343. result[i] = var;
  344. }
  345. break;
  346. case STDDEV1:
  347. for (i = 0; i < ncats; i++) {
  348. double n = count[i];
  349. double var = (sum2[i] - sum[i] * sum[i] / n) / (n - 1);
  350. result[i] = sqrt(var);
  351. }
  352. break;
  353. case SKEWNESS1:
  354. for (i = 0; i < ncats; i++) {
  355. double n = count[i];
  356. double var = (sum2[i] - sum[i] * sum[i] / n) / (n - 1);
  357. double skew = (sum3[i] / n
  358. - 3 * sum[i] * sum2[i] / (n * n)
  359. + 2 * sum[i] * sum[i] * sum[i] / (n * n * n))
  360. / (pow(var, 1.5));
  361. result[i] = skew;
  362. }
  363. break;
  364. case KURTOSIS1:
  365. for (i = 0; i < ncats; i++) {
  366. double n = count[i];
  367. double var = (sum2[i] - sum[i] * sum[i] / n) / (n - 1);
  368. double kurt = (sum4[i] / n
  369. - 4 * sum[i] * sum3[i] / (n * n)
  370. + 6 * sum[i] * sum[i] * sum2[i] / (n * n * n)
  371. - 3 * sum[i] * sum[i] * sum[i] * sum[i] / (n * n * n * n))
  372. / (var * var) - 3;
  373. result[i] = kurt;
  374. }
  375. break;
  376. case ADEV:
  377. for (i = 0; i < ncats; i++)
  378. result[i] = sumu[i] / count[i];
  379. break;
  380. case VARIANCE2:
  381. for (i = 0; i < ncats; i++)
  382. result[i] = sum2[i] / (count[i] - 1);
  383. break;
  384. case STDDEV2:
  385. for (i = 0; i < ncats; i++)
  386. result[i] = sqrt(sum2[i] / (count[i] - 1));
  387. break;
  388. case SKEWNESS2:
  389. for (i = 0; i < ncats; i++) {
  390. double n = count[i];
  391. double var = sum2[i] / (n - 1);
  392. double sdev = sqrt(var);
  393. result[i] = sum3[i] / (sdev * sdev * sdev) / n;
  394. }
  395. G_free(count);
  396. G_free(sum2);
  397. G_free(sum3);
  398. break;
  399. case KURTOSIS2:
  400. for (i = 0; i < ncats; i++) {
  401. double n = count[i];
  402. double var = sum2[i] / (n - 1);
  403. result[i] = sum4[i] / (var * var) / n - 3;
  404. }
  405. G_free(count);
  406. G_free(sum2);
  407. G_free(sum4);
  408. break;
  409. }
  410. if (reclass) {
  411. const char *tempfile = G_tempfile();
  412. char *input_arg = G_malloc(strlen(basemap) + 7);
  413. char *output_arg = G_malloc(strlen(output) + 8);
  414. char *rules_arg = G_malloc(strlen(tempfile) + 7);
  415. FILE *fp;
  416. G_message(_("Generating reclass map"));
  417. sprintf(input_arg, "input=%s", basemap);
  418. sprintf(output_arg, "output=%s", output);
  419. sprintf(rules_arg, "rules=%s", tempfile);
  420. fp = fopen(tempfile, "w");
  421. if (!fp)
  422. G_fatal_error(_("Unable to open temporary file"));
  423. for (i = 0; i < ncats; i++)
  424. fprintf(fp, "%d = %d %f\n", mincat + i, mincat + i, result[i]);
  425. fclose(fp);
  426. G_spawn("r.reclass", "r.reclass", input_arg, output_arg, rules_arg, NULL);
  427. }
  428. else {
  429. int out_fd;
  430. DCELL *out_buf;
  431. struct Colors colors;
  432. G_message(_("Writing output map"));
  433. out_fd = Rast_open_fp_new(output);
  434. out_buf = Rast_allocate_d_buf();
  435. for (row = 0; row < rows; row++) {
  436. Rast_get_c_row(base_fd, base_buf, row);
  437. for (col = 0; col < cols; col++)
  438. if (Rast_is_c_null_value(&base_buf[col]))
  439. Rast_set_d_null_value(&out_buf[col], 1);
  440. else
  441. out_buf[col] = result[base_buf[col] - mincat];
  442. Rast_put_d_row(out_fd, out_buf);
  443. G_percent(row, rows, 2);
  444. }
  445. G_percent(row, rows, 2);
  446. Rast_close(out_fd);
  447. if (Rast_read_colors(covermap, "", &colors) > 0)
  448. Rast_write_colors(output, G_mapset(), &colors);
  449. }
  450. return 0;
  451. }