123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- /****************************************************************************
- *
- * MODULE: r.neighbors
- * AUTHOR(S): Michael Shapiro, CERL (original contributor)
- * Markus Neteler <neteler itc.it>, Bob Covill <bcovill tekmap.ns.ca>,
- * Brad Douglas <rez touchofmadness.com>, Glynn Clements <glynn gclements.plus.com>,
- * Jachym Cepicky <jachym les-ejk.cz>, Jan-Oliver Wagner <jan intevation.de>,
- * Radim Blazek <radim.blazek gmail.com>
- *
- * PURPOSE: Makes each cell category value a function of the category values
- * assigned to the cells around it, and stores new cell values in an
- * output raster map layer
- * COPYRIGHT: (C) 1999-2006 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the file COPYING that comes with GRASS
- * for details.
- *
- *****************************************************************************/
- #include <string.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <grass/gis.h>
- #include <grass/raster.h>
- #include <grass/glocale.h>
- #include <grass/stats.h>
- #include "ncb.h"
- #include "local_proto.h"
- typedef int (*ifunc) (void);
- struct menu
- {
- stat_func *method; /* routine to compute new value */
- stat_func_w *method_w; /* routine to compute new value (weighted) */
- ifunc cat_names; /* routine to make category names */
- int copycolr; /* flag if color table can be copied */
- int half; /* whether to add 0.5 to result (redundant) */
- int otype; /* output type */
- char *name; /* method name */
- char *text; /* menu display - full description */
- };
- struct weight_functions
- {
- char *name; /* name of the weight type */
- char *text; /* weight types display - full description */
- };
- enum out_type {
- T_FLOAT = 1,
- T_INT = 2,
- T_COUNT = 3,
- T_COPY = 4,
- T_SUM = 5
- };
- #define NO_CATS 0
- /* modify this table to add new methods */
- static struct menu menu[] = {
- {c_ave, w_ave, NO_CATS, 1, 1, T_FLOAT, "average", "average value"},
- {c_median, w_median, NO_CATS, 1, 0, T_FLOAT, "median", "median value"},
- {c_mode, w_mode, NO_CATS, 1, 0, T_COPY, "mode", "most frequently occurring value"},
- {c_min, NULL, NO_CATS, 1, 0, T_COPY, "minimum", "lowest value"},
- {c_max, NULL, NO_CATS, 1, 0, T_COPY, "maximum", "highest value"},
- {c_range, NULL, NO_CATS, 1, 0, T_COPY, "range", "range value"},
- {c_stddev, w_stddev, NO_CATS, 0, 1, T_FLOAT, "stddev", "standard deviation"},
- {c_sum, w_sum, NO_CATS, 1, 0, T_SUM, "sum", "sum of values"},
- {c_count, w_count, NO_CATS, 0, 0, T_COUNT, "count", "count of non-NULL values"},
- {c_var, w_var, NO_CATS, 0, 1, T_FLOAT, "variance", "statistical variance"},
- {c_divr, NULL, divr_cats, 0, 0, T_INT, "diversity",
- "number of different values"},
- {c_intr, NULL, intr_cats, 0, 0, T_INT, "interspersion",
- "number of values different than center value"},
- {c_quart1, w_quart1, NO_CATS, 1, 0, T_FLOAT, "quart1", "first quartile"},
- {c_quart3, w_quart3, NO_CATS, 1, 0, T_FLOAT, "quart3", "third quartile"},
- {c_perc90, w_perc90, NO_CATS, 1, 0, T_FLOAT, "perc90", "ninetieth percentile"},
- {c_quant, w_quant, NO_CATS, 1, 0, T_FLOAT, "quantile", "arbitrary quantile"},
- {0, 0, 0, 0, 0, 0, 0, 0}
- };
- struct ncb ncb;
- struct output
- {
- const char *name;
- char title[1024];
- int fd;
- DCELL *buf;
- stat_func *method_fn;
- stat_func_w *method_fn_w;
- int copycolr;
- ifunc cat_names;
- int map_type;
- double quantile;
- };
- static int find_method(const char *method_name)
- {
- int i;
- for (i = 0; menu[i].name; i++)
- if (strcmp(menu[i].name, method_name) == 0)
- return i;
- G_fatal_error(_("Unknown method <%s>"), method_name);
- return -1;
- }
- static RASTER_MAP_TYPE output_type(RASTER_MAP_TYPE input_type, int weighted, int mode)
- {
- switch (mode) {
- case T_FLOAT:
- return DCELL_TYPE;
- case T_INT:
- return CELL_TYPE;
- case T_COUNT:
- return weighted ? DCELL_TYPE : CELL_TYPE;
- case T_COPY:
- return input_type;
- case T_SUM:
- return weighted ? DCELL_TYPE : input_type;
- default:
- G_fatal_error(_("Invalid out_type enumeration: %d"), mode);
- return -1;
- }
- }
- int main(int argc, char *argv[])
- {
- char *p;
- int in_fd;
- int selection_fd;
- int num_outputs;
- struct output *outputs = NULL;
- int copycolr, weights, have_weights_mask;
- char *selection;
- RASTER_MAP_TYPE map_type;
- int row, col;
- int readrow;
- int nrows, ncols;
- int i, n;
- struct Colors colr;
- struct Cell_head cellhd;
- struct Cell_head window;
- struct History history;
- struct GModule *module;
- struct
- {
- struct Option *input, *output, *selection;
- struct Option *method, *size;
- struct Option *title;
- struct Option *weight;
- struct Option *weighting_function;
- struct Option *weighting_factor;
- struct Option *quantile;
- } parm;
- struct
- {
- struct Flag *align, *circle;
- } flag;
- DCELL *values; /* list of neighborhood values */
- DCELL *values_tmp; /* list of neighborhood values */
- DCELL(*values_w)[2]; /* list of neighborhood values and weights */
- DCELL(*values_w_tmp)[2]; /* list of neighborhood values and weights */
- G_gisinit(argv[0]);
- module = G_define_module();
- G_add_keyword(_("raster"));
- G_add_keyword(_("algebra"));
- G_add_keyword(_("statistics"));
- G_add_keyword(_("aggregation"));
- G_add_keyword(_("neighbor"));
- G_add_keyword(_("focal statistics"));
- G_add_keyword(_("filter"));
- module->description =
- _("Makes each cell category value a "
- "function of the category values assigned to the cells "
- "around it, and stores new cell values in an output raster "
- "map layer.");
- parm.input = G_define_standard_option(G_OPT_R_INPUT);
- parm.selection = G_define_standard_option(G_OPT_R_INPUT);
- parm.selection->key = "selection";
- parm.selection->required = NO;
- parm.selection->description = _("Name of an input raster map to select the cells which should be processed");
- parm.output = G_define_standard_option(G_OPT_R_OUTPUT);
- parm.output->multiple = YES;
- parm.size = G_define_option();
- parm.size->key = "size";
- parm.size->type = TYPE_INTEGER;
- parm.size->required = NO;
- parm.size->description = _("Neighborhood size");
- parm.size->answer = "3";
- parm.size->guisection = _("Neighborhood");
- parm.method = G_define_option();
- parm.method->key = "method";
- parm.method->type = TYPE_STRING;
- parm.method->required = NO;
- parm.method->answer = "average";
- p = G_malloc(1024);
- for (n = 0; menu[n].name; n++) {
- if (n)
- strcat(p, ",");
- else
- *p = 0;
- strcat(p, menu[n].name);
- }
- parm.method->options = p;
- parm.method->description = _("Neighborhood operation");
- parm.method->multiple = YES;
- parm.method->guisection = _("Neighborhood");
- parm.weighting_function = G_define_option();
- parm.weighting_function->key = "weighting_function";
- parm.weighting_function->type = TYPE_STRING;
- parm.weighting_function->required = NO;
- parm.weighting_function->answer = "none";
- parm.weighting_function->options = "none,gaussian,exponential,file";
- G_asprintf((char **)&(parm.weighting_function->descriptions),
- "none;%s;"
- "gaussian;%s;"
- "exponential;%s;"
- "file;%s;",
- _("No weighting"),
- _("Gaussian weighting function"),
- _("Exponential weighting function"),
- _("File with a custom weighting matrix"));
- parm.weighting_function->description = _("Weighting function");
- parm.weighting_function->multiple = NO;
- parm.weighting_factor = G_define_option();
- parm.weighting_factor->key = "weighting_factor";
- parm.weighting_factor->type = TYPE_DOUBLE;
- parm.weighting_factor->required = NO;
- parm.weighting_factor->multiple = NO;
- parm.weighting_factor->description = _("Factor used in the selected weighting function (ignored for none and file)");
- parm.weight = G_define_standard_option(G_OPT_F_INPUT);
- parm.weight->key = "weight";
- parm.weight->required = NO;
- parm.weight->description = _("Text file containing weights");
- parm.quantile = G_define_option();
- parm.quantile->key = "quantile";
- parm.quantile->type = TYPE_DOUBLE;
- parm.quantile->required = NO;
- parm.quantile->multiple = YES;
- parm.quantile->description = _("Quantile to calculate for method=quantile");
- parm.quantile->options = "0.0-1.0";
- parm.quantile->guisection = _("Neighborhood");
- parm.title = G_define_option();
- parm.title->key = "title";
- parm.title->key_desc = "phrase";
- parm.title->type = TYPE_STRING;
- parm.title->required = NO;
- parm.title->description = _("Title for output raster map");
- flag.align = G_define_flag();
- flag.align->key = 'a';
- flag.align->description = _("Do not align output with the input");
- flag.circle = G_define_flag();
- flag.circle->key = 'c';
- flag.circle->description = _("Use circular neighborhood");
- flag.circle->guisection = _("Neighborhood");
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- sscanf(parm.size->answer, "%d", &ncb.nsize);
- if (ncb.nsize <= 0)
- G_fatal_error(_("Neighborhood size must be positive"));
- if (ncb.nsize % 2 == 0)
- G_fatal_error(_("Neighborhood size must be odd"));
- ncb.dist = ncb.nsize / 2;
- if (strcmp(parm.weighting_function->answer, "none") && flag.circle->answer)
- G_fatal_error(_("-%c and %s= are mutually exclusive"),
- flag.circle->key, parm.weighting_function->answer);
- if (strcmp(parm.weighting_function->answer, "file") == 0 && !parm.weight->answer)
- G_fatal_error(_("File with weighting matrix is missing."));
- /* Check if weighting factor is given for all other weighting functions*/
- if (strcmp(parm.weighting_function->answer, "none") &&
- strcmp(parm.weighting_function->answer, "file") &&
- !parm.weighting_factor->answer)
- G_fatal_error(_("Weighting function '%s' requires a %s."),
- parm.weighting_function->answer, parm.weighting_factor->key);
- ncb.oldcell = parm.input->answer;
- if (!flag.align->answer) {
- Rast_get_cellhd(ncb.oldcell, "", &cellhd);
- G_get_window(&window);
- Rast_align_window(&window, &cellhd);
- Rast_set_window(&window);
- }
- nrows = Rast_window_rows();
- ncols = Rast_window_cols();
- /* open raster maps */
- in_fd = Rast_open_old(ncb.oldcell, "");
- map_type = Rast_get_map_type(in_fd);
- /* process the output maps */
- for (i = 0; parm.output->answers[i]; i++)
- ;
- num_outputs = i;
- for (i = 0; parm.method->answers[i]; i++)
- ;
- if (num_outputs != i)
- G_fatal_error(_("%s= and %s= must have the same number of values"),
- parm.output->key, parm.method->key);
- outputs = G_calloc(num_outputs, sizeof(struct output));
- /* read the weights */
- weights = 0;
- ncb.weights = NULL;
- ncb.mask = NULL;
- if (strcmp(parm.weighting_function->answer, "file") == 0) {
- read_weights(parm.weight->answer);
- weights = 1;
- }
- else if (strcmp(parm.weighting_function->answer, "none")) {
- G_verbose_message(_("Computing %s weights..."),
- parm.weighting_function->answer);
- compute_weights(parm.weighting_function->answer,
- atof(parm.weighting_factor->answer));
- weights = 1;
- }
-
- copycolr = 0;
- have_weights_mask = 0;
- for (i = 0; i < num_outputs; i++) {
- struct output *out = &outputs[i];
- const char *output_name = parm.output->answers[i];
- const char *method_name = parm.method->answers[i];
- int method = find_method(method_name);
- RASTER_MAP_TYPE otype = output_type(map_type, weights, menu[method].otype);
- out->name = output_name;
- if (weights) {
- if (menu[method].method_w) {
- out->method_fn = NULL;
- out->method_fn_w = menu[method].method_w;
- }
- else {
- if (strcmp(parm.weighting_function->answer,"none")) {
- G_warning(_("Method %s not compatible with weighing window, using weight mask instead"),
- method_name);
- if (!have_weights_mask) {
- weights_mask();
- have_weights_mask = 1;
- }
- }
- out->method_fn = menu[method].method;
- out->method_fn_w = NULL;
- }
- }
- else {
- out->method_fn = menu[method].method;
- out->method_fn_w = NULL;
- }
- out->copycolr = menu[method].copycolr;
- out->cat_names = menu[method].cat_names;
- if (out->copycolr)
- copycolr = 1;
- out->quantile = (parm.quantile->answer && parm.quantile->answers[i])
- ? atof(parm.quantile->answers[i])
- : 0;
- out->buf = Rast_allocate_d_buf();
- out->fd = Rast_open_new(output_name, otype);
- /* TODO: method=mode should propagate its type */
- /* get title, initialize the category and stat info */
- if (parm.title->answer)
- strcpy(out->title, parm.title->answer);
- else
- sprintf(out->title, "%dx%d neighborhood: %s of %s",
- ncb.nsize, ncb.nsize, menu[method].name, ncb.oldcell);
- }
- /* copy color table? */
- if (copycolr) {
- G_suppress_warnings(1);
- copycolr =
- (Rast_read_colors(ncb.oldcell, "", &colr) > 0);
- G_suppress_warnings(0);
- }
- /* allocate the cell buffers */
- allocate_bufs();
- /* initialize the cell bufs with 'dist' rows of the old cellfile */
- readrow = 0;
- for (row = 0; row < ncb.dist; row++)
- readcell(in_fd, readrow++, nrows, ncols);
- /* open the selection raster map */
- if (parm.selection->answer) {
- G_message(_("Opening selection map <%s>"), parm.selection->answer);
- selection_fd = Rast_open_old(parm.selection->answer, "");
- selection = Rast_allocate_null_buf();
- } else {
- selection_fd = -1;
- selection = NULL;
- }
- if (flag.circle->answer)
- circle_mask();
- values_w = NULL;
- values_w_tmp = NULL;
- if (weights) {
- values_w =
- (DCELL(*)[2]) G_malloc(ncb.nsize * ncb.nsize * 2 * sizeof(DCELL));
- values_w_tmp =
- (DCELL(*)[2]) G_malloc(ncb.nsize * ncb.nsize * 2 * sizeof(DCELL));
- }
- values = (DCELL *) G_malloc(ncb.nsize * ncb.nsize * sizeof(DCELL));
- values_tmp = (DCELL *) G_malloc(ncb.nsize * ncb.nsize * sizeof(DCELL));
- for (row = 0; row < nrows; row++) {
- G_percent(row, nrows, 2);
- readcell(in_fd, readrow++, nrows, ncols);
- if (selection)
- Rast_get_null_value_row(selection_fd, selection, row);
- for (col = 0; col < ncols; col++) {
- if (selection && selection[col]) {
- /* ncb.buf length is region row length + 2 * ncb.dist (eq. floor(neighborhood/2))
- * Thus original data start is shifted by ncb.dist! */
- for (i = 0; i < num_outputs; i++)
- outputs[i].buf[col] = ncb.buf[ncb.dist][col + ncb.dist];
- continue;
- }
- if (weights)
- n = gather_w(values, values_w, col);
- else
- n = gather(values, col);
- for (i = 0; i < num_outputs; i++) {
- struct output *out = &outputs[i];
- DCELL *rp = &out->buf[col];
- if (n == 0) {
- Rast_set_d_null_value(rp, 1);
- }
- else {
- if (out->method_fn_w) {
- memcpy(values_w_tmp, values_w, n * 2 * sizeof(DCELL));
- (*out->method_fn_w)(rp, values_w_tmp, n, &out->quantile);
- }
- else {
- memcpy(values_tmp, values, n * sizeof(DCELL));
- (*out->method_fn)(rp, values_tmp, n, &out->quantile);
- }
- }
- }
- }
- for (i = 0; i < num_outputs; i++) {
- struct output *out = &outputs[i];
- Rast_put_d_row(out->fd, out->buf);
- }
- }
- G_percent(row, nrows, 2);
- Rast_close(in_fd);
- if (selection)
- Rast_close(selection_fd);
- for (i = 0; i < num_outputs; i++) {
- Rast_close(outputs[i].fd);
- /* put out category info */
- null_cats(outputs[i].title);
- if (outputs[i].cat_names)
- outputs[i].cat_names();
- Rast_write_cats(outputs[i].name, &ncb.cats);
- if (copycolr && outputs[i].copycolr)
- Rast_write_colors(outputs[i].name, G_mapset(), &colr);
- Rast_short_history(outputs[i].name, "raster", &history);
- Rast_command_history(&history);
- Rast_write_history(outputs[i].name, &history);
- }
- exit(EXIT_SUCCESS);
- }
|