123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555 |
- /****************************************************************************
- *
- * MODULE: r.geomorphon
- * AUTHOR(S): Jarek Jasiewicz jarekj amu.edu.pl with collaboration of Tom Stepinski stepintz uc.edu based on idea of Tomasz Stepinski and Jaroslaw Jasiewicz
- *
- * PURPOSE: Calculate terrain forms using machine-vison technique called geomorphons
- * This module allow to calculate standard set of terrain forms
- * using look-up table proposed by authors, calculate patterns (binary and ternary)
- * for every pixel as well as several geomorphometrical parameters
- * This technology is currently capable of "experimental" stage.
- *
- * COPYRIGHT: (C) 2002,2012 by the GRASS Development Team
- * (C) Scientific idea of geomotrphon copyrighted to authors.
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the file COPYING that comes with GRASS
- * for details.
- *
- *****************************************************************************/
- #define MAIN
- #include "local_proto.h"
- typedef enum
- { i_dem, o_forms, o_ternary, o_positive, o_negative, o_intensity,
- o_exposition,
- o_range, o_variance, o_elongation, o_azimuth, o_extend, o_width, io_size
- } outputs;
- int main(int argc, char **argv)
- {
- IO rasters[] = { /* rasters stores output buffers */
- {"elevation", YES, "Name of input elevation raster map", "input", UNKNOWN, -1, NULL}, /* WARNING: this one map is input */
- {"forms", NO, "Most common geomorphic forms", "Patterns", CELL_TYPE,
- -1, NULL},
- {"ternary", NO, "Code of ternary patterns", "Patterns", CELL_TYPE, -1,
- NULL},
- {"positive", NO, "Code of binary positive patterns", "Patterns",
- CELL_TYPE, -1, NULL},
- {"negative", NO, "Code of binary negative patterns", "Patterns",
- CELL_TYPE, -1, NULL},
- {"intensity", NO,
- "Rasters containing mean relative elevation of the form", "Geometry",
- FCELL_TYPE, -1, NULL},
- {"exposition", NO,
- "Rasters containing maximum difference between extend and central cell",
- "Geometry", FCELL_TYPE, -1, NULL},
- {"range", NO,
- "Rasters containing difference between max and min elevation of the form extend",
- "Geometry", FCELL_TYPE, -1, NULL},
- {"variance", NO, "Rasters containing variance of form boundary",
- "Geometry", FCELL_TYPE, -1, NULL},
- {"elongation", NO, "Rasters containing local elongation", "Geometry",
- FCELL_TYPE, -1, NULL},
- {"azimuth", NO, "Rasters containing local azimuth of the elongation",
- "Geometry", FCELL_TYPE, -1, NULL},
- {"extend", NO, "Rasters containing local extend (area) of the form",
- "Geometry", FCELL_TYPE, -1, NULL},
- {"width", NO, "Rasters containing local width of the form",
- "Geometry", FCELL_TYPE, -1, NULL}
- }; /* adding more maps change IOSIZE macro */
- CATCOLORS ccolors[CNT] = { /* colors and cats for forms */
- {ZERO, 0, 0, 0, "forms"},
- {FL, 220, 220, 220, "flat"},
- {PK, 56, 0, 0, "summit"},
- {RI, 200, 0, 0, "ridge"},
- {SH, 255, 80, 20, "shoulder"},
- {CV, 250, 210, 60, "spur"},
- {SL, 255, 255, 60, "slope"},
- {CN, 180, 230, 20, "hollow"},
- {FS, 60, 250, 150, "footslope"},
- {VL, 0, 0, 255, "valley"},
- {PT, 0, 0, 56, "depression"},
- {__, 255, 0, 255, "ERROR"}
- };
- struct GModule *module;
- struct Option
- *opt_input,
- *opt_output[io_size],
- *par_search_radius,
- *par_skip_radius,
- *par_flat_threshold,
- *par_flat_distance,
- *par_multi_prefix, *par_multi_step, *par_multi_start;
- struct Flag *flag_units, *flag_extended;
- struct History history;
- int i;
- int meters = 0, multires = 0, extended = 0; /* flags */
- int row, cur_row, col;
- int pattern_size;
- double max_resolution;
- char prefix[20];
- G_gisinit(argv[0]);
- { /* interface parameters */
- module = G_define_module();
- module->description =
- _("Calculates geomorphons (terrain forms) and associated geometry using machine vision approach.");
- G_add_keyword(_("raster"));
- G_add_keyword(_("geomorphons"));
- G_add_keyword(_("terrain patterns"));
- G_add_keyword(_("machine vision geomorphometry"));
- opt_input = G_define_standard_option(G_OPT_R_ELEV);
- opt_input->key = rasters[0].name;
- opt_input->required = rasters[0].required;
- opt_input->description = _(rasters[0].description);
- for (i = 1; i < io_size; ++i) { /* WARNING: loop starts from one, zero is for input */
- opt_output[i] = G_define_standard_option(G_OPT_R_OUTPUT);
- opt_output[i]->key = rasters[i].name;
- opt_output[i]->required = NO;
- opt_output[i]->description = _(rasters[i].description);
- opt_output[i]->guisection = _(rasters[i].gui);
- }
- par_search_radius = G_define_option();
- par_search_radius->key = "search";
- par_search_radius->type = TYPE_INTEGER;
- par_search_radius->answer = "3";
- par_search_radius->required = YES;
- par_search_radius->description = _("Outer search radius");
- par_skip_radius = G_define_option();
- par_skip_radius->key = "skip";
- par_skip_radius->type = TYPE_INTEGER;
- par_skip_radius->answer = "0";
- par_skip_radius->required = YES;
- par_skip_radius->description = _("Inner search radius");
- par_flat_threshold = G_define_option();
- par_flat_threshold->key = "flat";
- par_flat_threshold->type = TYPE_DOUBLE;
- par_flat_threshold->answer = "1";
- par_flat_threshold->required = YES;
- par_flat_threshold->description = _("Flatenss threshold (degrees)");
- par_flat_distance = G_define_option();
- par_flat_distance->key = "dist";
- par_flat_distance->type = TYPE_DOUBLE;
- par_flat_distance->answer = "0";
- par_flat_distance->required = YES;
- par_flat_distance->description =
- _("Flatenss distance, zero for none");
- par_multi_prefix = G_define_option();
- par_multi_prefix->key = "prefix";
- par_multi_prefix->type = TYPE_STRING;
- par_multi_prefix->description =
- _("Prefix for maps resulting from multiresolution approach");
- par_multi_prefix->guisection = _("Multires");
- par_multi_step = G_define_option();
- par_multi_step->key = "step";
- par_multi_step->type = TYPE_DOUBLE;
- par_multi_step->answer = "0";
- par_multi_step->description =
- _("Distance step for every iteration (zero to omit)");
- par_multi_step->guisection = _("Multires");
- par_multi_start = G_define_option();
- par_multi_start->key = "start";
- par_multi_start->type = TYPE_DOUBLE;
- par_multi_start->answer = "0";
- par_multi_start->description =
- _("Distance where serch will start in multiple mode (zero to omit)");
- par_multi_start->guisection = _("Multires");
- flag_units = G_define_flag();
- flag_units->key = 'm';
- flag_units->description =
- _("Use meters to define search units (default is cells)");
- flag_extended = G_define_flag();
- flag_extended->key = 'e';
- flag_extended->description = _("Use extended form correction");
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- }
- { /* calculate parameters */
- int num_outputs = 0;
- double search_radius, skip_radius, start_radius, step_radius;
- double ns_resolution;
- multires = (par_multi_prefix->answer) ? 1 : 0;
- for (i = 1; i < io_size; ++i) /* check for outputs */
- if (opt_output[i]->answer) {
- if (G_legal_filename(opt_output[i]->answer) < 0)
- G_fatal_error(_("<%s> is an illegal file name"),
- opt_output[i]->answer);
- num_outputs++;
- }
- if (!num_outputs && !multires)
- G_fatal_error(_("At least one output is required, e.g. %s"),
- opt_output[o_forms]->key);
- meters = (flag_units->answer != 0);
- extended = (flag_extended->answer != 0);
- nrows = Rast_window_rows();
- ncols = Rast_window_cols();
- Rast_get_window(&window);
- G_begin_distance_calculations();
- if (G_projection() == PROJECTION_LL) { /* for LL max_res should be NS */
- ns_resolution =
- G_distance(0, Rast_row_to_northing(0, &window), 0,
- Rast_row_to_northing(1, &window));
- max_resolution = ns_resolution;
- }
- else {
- max_resolution = MAX(window.ns_res, window.ew_res); /* max_resolution MORE meters per cell */
- ns_resolution = window.ns_res;
- }
- /* search distance */
- search_radius = atof(par_search_radius->answer);
- search_cells =
- meters ? (int)(search_radius / max_resolution) : search_radius;
- if (search_cells < 1)
- G_fatal_error(_("Search radius size must cover at least 1 cell"));
- row_radius_size =
- meters ? ceil(search_radius / ns_resolution) : search_radius;
- row_buffer_size = row_radius_size * 2 + 1;
- search_distance =
- (meters) ? search_radius : ns_resolution * search_cells;
- /* skip distance */
- skip_radius = atof(par_skip_radius->answer);
- skip_cells =
- meters ? (int)(skip_radius / max_resolution) : skip_radius;
- if (skip_cells >= search_cells)
- G_fatal_error(_("Skip radius size must be at least 1 cell lower than radius"));
- skip_distance = (meters) ? skip_radius : ns_resolution * skip_cells;
- /* flatness parameters */
- flat_threshold = atof(par_flat_threshold->answer);
- if (flat_threshold <= 0.)
- G_fatal_error(_("Flatenss threshold must be grater than 0"));
- flat_threshold = DEGREE2RAD(flat_threshold);
- flat_distance = atof(par_flat_distance->answer);
- flat_distance =
- (meters) ? flat_distance : ns_resolution * flat_distance;
- flat_threshold_height = tan(flat_threshold) * flat_distance;
- if ((flat_distance > 0 && flat_distance <= skip_distance) ||
- flat_distance >= search_distance) {
- G_warning(_("Flatenss distance should be between skip and search radius. Otherwise ignored"));
- flat_distance = 0;
- }
- if (multires) {
- start_radius = atof(par_multi_start->answer);
- start_cells =
- meters ? (int)(start_radius / max_resolution) : start_radius;
- if (start_cells <= skip_cells)
- start_cells = skip_cells + 1;
- start_distance =
- (meters) ? start_radius : ns_resolution * start_cells;
- step_radius = atof(par_multi_step->answer);
- step_cells =
- meters ? (int)(step_radius / max_resolution) : step_radius;
- step_distance =
- (meters) ? step_radius : ns_resolution * step_cells;
- if (step_distance < ns_resolution)
- G_fatal_error(_("For multiresolution mode step must be greater than or equal to resolution of one cell"));
- if (G_legal_filename(par_multi_prefix->answer) < 0 ||
- strlen(par_multi_prefix->answer) > 19)
- G_fatal_error(_("<%s> is an incorrect prefix"),
- par_multi_prefix->answer);
- strcpy(prefix, par_multi_prefix->answer);
- strcat(prefix, "_");
- num_of_steps = (int)ceil(search_distance / step_distance);
- } /* end multires preparation */
- /* print information about distances */
- G_verbose_message("Search distance m: %f, cells: %d", search_distance,
- search_cells);
- G_verbose_message("Skip distance m: %f, cells: %d", skip_distance,
- skip_cells);
- G_verbose_message("Flat threshold distance m: %f, height: %f", flat_distance,
- flat_threshold_height);
- G_verbose_message("%s version", (extended) ? "Extended" : "Basic");
- if (multires) {
- G_verbose_message
- ("Multiresolution mode: search start at: m: %f, cells: %d",
- start_distance, start_cells);
- G_verbose_message
- ("Multiresolution mode: search step is: m: %f, number of steps %d",
- step_distance, num_of_steps);
- G_verbose_message("Prefix for output: %s", prefix);
- }
- }
- /* generate global ternary codes */
- for (i = 0; i < 6561; ++i)
- global_ternary_codes[i] = ternary_rotate(i);
- /* open DEM */
- strcpy(elevation.elevname, opt_input->answer);
- open_map(&elevation);
- if (!multires) {
- PATTERN *pattern;
- PATTERN patterns[4];
- void *pointer_buf;
- double search_dist = search_distance;
- double skip_dist = skip_distance;
- double flat_dist = flat_distance;
- double area_of_octagon =
- 4 * (search_distance * search_distance) * sin(DEGREE2RAD(45.));
- cell_step = 1;
- /* prepare outputs */
- for (i = 1; i < io_size; ++i)
- if (opt_output[i]->answer) {
- rasters[i].fd =
- Rast_open_new(opt_output[i]->answer,
- rasters[i].out_data_type);
- rasters[i].buffer =
- Rast_allocate_buf(rasters[i].out_data_type);
- }
- /* main loop */
- for (row = 0; row < nrows; ++row) {
- G_percent(row, nrows, 2);
- cur_row = (row < row_radius_size) ? row :
- ((row >=
- nrows - row_radius_size - 1) ? row_buffer_size - (nrows -
- row -
- 1) :
- row_radius_size);
- if (row > (row_radius_size) &&
- row < nrows - (row_radius_size + 1))
- shift_buffers(row);
- for (col = 0; col < ncols; ++col) {
- /* on borders forms ussualy are innatural. */
- if (row < (skip_cells + 1) || row > nrows - (skip_cells + 2)
- || col < (skip_cells + 1) ||
- col > ncols - (skip_cells + 2) ||
- Rast_is_f_null_value(&elevation.elev[cur_row][col])) {
- /* set outputs to NULL and do nothing if source value is null or border */
- for (i = 1; i < io_size; ++i)
- if (opt_output[i]->answer) {
- pointer_buf = rasters[i].buffer;
- switch (rasters[i].out_data_type) {
- case CELL_TYPE:
- Rast_set_c_null_value(&((CELL *) pointer_buf)
- [col], 1);
- break;
- case FCELL_TYPE:
- Rast_set_f_null_value(&((FCELL *) pointer_buf)
- [col], 1);
- break;
- case DCELL_TYPE:
- Rast_set_d_null_value(&((DCELL *) pointer_buf)
- [col], 1);
- break;
- default:
- G_fatal_error(_("Unknown output data type"));
- }
- }
- continue;
- } /* end null value */
- {
- int cur_form, small_form;
- search_distance = search_dist;
- skip_distance = skip_dist;
- flat_distance = flat_dist;
- pattern_size =
- calc_pattern(&patterns[0], row, cur_row, col);
- pattern = &patterns[0];
- cur_form =
- determine_form(pattern->num_negatives,
- pattern->num_positives);
- /* correction of forms */
- if (extended && search_distance > 10 * max_resolution) {
- /* 1) remove extensive innatural forms: ridges, peaks, shoulders and footslopes */
- if ((cur_form == 4 || cur_form == 8 || cur_form == 2
- || cur_form == 3)) {
- search_distance =
- (search_dist / 2. <
- 4 * max_resolution) ? 4 *
- max_resolution : search_dist / 2.;
- skip_distance = 0;
- flat_distance = 0;
- pattern_size =
- calc_pattern(&patterns[1], row, cur_row, col);
- pattern = &patterns[1];
- small_form =
- determine_form(pattern->num_negatives,
- pattern->num_positives);
- if (cur_form == 4 || cur_form == 8)
- cur_form = (small_form == 1) ? 1 : cur_form;
- if (cur_form == 2 || cur_form == 3)
- cur_form = small_form;
- }
- /* 3) Depressions */
- } /* end of correction */
- pattern = &patterns[0];
- if (opt_output[o_forms]->answer)
- ((CELL *) rasters[o_forms].buffer)[col] = cur_form;
- }
- if (opt_output[o_ternary]->answer)
- ((CELL *) rasters[o_ternary].buffer)[col] =
- determine_ternary(pattern->pattern);
- if (opt_output[o_positive]->answer)
- ((CELL *) rasters[o_positive].buffer)[col] =
- rotate(pattern->positives);
- if (opt_output[o_negative]->answer)
- ((CELL *) rasters[o_negative].buffer)[col] =
- rotate(pattern->negatives);
- if (opt_output[o_intensity]->answer)
- ((FCELL *) rasters[o_intensity].buffer)[col] =
- intensity(pattern->elevation, pattern_size);
- if (opt_output[o_exposition]->answer)
- ((FCELL *) rasters[o_exposition].buffer)[col] =
- exposition(pattern->elevation);
- if (opt_output[o_range]->answer)
- ((FCELL *) rasters[o_range].buffer)[col] =
- range(pattern->elevation);
- if (opt_output[o_variance]->answer)
- ((FCELL *) rasters[o_variance].buffer)[col] =
- variance(pattern->elevation, pattern_size);
- /* used only for next four shape functions */
- if (opt_output[o_elongation]->answer ||
- opt_output[o_azimuth]->answer ||
- opt_output[o_extend]->answer ||
- opt_output[o_width]->answer) {
- float azimuth, elongation, width;
- radial2cartesian(pattern);
- shape(pattern, pattern_size, &azimuth, &elongation,
- &width);
- if (opt_output[o_azimuth]->answer)
- ((FCELL *) rasters[o_azimuth].buffer)[col] = azimuth;
- if (opt_output[o_elongation]->answer)
- ((FCELL *) rasters[o_elongation].buffer)[col] =
- elongation;
- if (opt_output[o_width]->answer)
- ((FCELL *) rasters[o_width].buffer)[col] = width;
- }
- if (opt_output[o_extend]->answer)
- ((FCELL *) rasters[o_extend].buffer)[col] =
- extends(pattern, pattern_size) / area_of_octagon;
- } /* end for col */
- /* write existing outputs */
- for (i = 1; i < io_size; ++i)
- if (opt_output[i]->answer)
- Rast_put_row(rasters[i].fd, rasters[i].buffer,
- rasters[i].out_data_type);
- }
- G_percent(row, nrows, 2); /* end main loop */
- /* finish and close */
- free_map(elevation.elev, row_buffer_size + 1);
- for (i = 1; i < io_size; ++i)
- if (opt_output[i]->answer) {
- G_free(rasters[i].buffer);
- Rast_close(rasters[i].fd);
- Rast_short_history(opt_output[i]->answer, "raster", &history);
- Rast_command_history(&history);
- Rast_write_history(opt_output[i]->answer, &history);
- }
- if (opt_output[o_forms]->answer)
- write_form_cat_colors(opt_output[o_forms]->answer, ccolors);
- if (opt_output[o_intensity]->answer)
- write_contrast_colors(opt_output[o_intensity]->answer);
- if (opt_output[o_exposition]->answer)
- write_contrast_colors(opt_output[o_exposition]->answer);
- if (opt_output[o_range]->answer)
- write_contrast_colors(opt_output[o_range]->answer);
- G_done_msg(" ");
- exit(EXIT_SUCCESS);
- } /* end of multiresolution */
- if (multires) {
- PATTERN *multi_patterns;
- MULTI multiple_output[5]; /* ten form maps + all forms */
- char *postfixes[] = { "scale_300", "scale_100", "scale_50", "scale_20" "scale_10" }; /* in pixels */
- num_of_steps = 5;
- multi_patterns = G_malloc(num_of_steps * sizeof(PATTERN));
- /* prepare outputs */
- for (i = 0; i < 5; ++i) {
- multiple_output[i].forms_buffer = Rast_allocate_buf(CELL_TYPE);
- strcpy(multiple_output[i].name, prefix);
- strcat(multiple_output[11].name, postfixes[i]);
- multiple_output[i].fd =
- Rast_open_new(multiple_output[i].name, CELL_TYPE);
- }
- /* main loop */
- for (row = 0; row < nrows; ++row) {
- G_percent(row, nrows, 2);
- cur_row = (row < row_radius_size) ? row :
- ((row >=
- nrows - row_radius_size - 1) ? row_buffer_size - (nrows -
- row -
- 1) :
- row_radius_size);
- if (row > (row_radius_size) &&
- row < nrows - (row_radius_size + 1))
- shift_buffers(row);
- for (col = 0; col < ncols; ++col) {
- if (row < (skip_cells + 1) || row > nrows - (skip_cells + 2)
- || col < (skip_cells + 1) ||
- col > ncols - (skip_cells + 2) ||
- Rast_is_f_null_value(&elevation.elev[cur_row][col])) {
- for (i = 0; i < num_of_steps; ++i)
- Rast_set_c_null_value(&multiple_output[i].
- forms_buffer[col], 1);
- continue;
- }
- cell_step = 10;
- calc_pattern(&multi_patterns[0], row, cur_row, col);
- }
- for (i = 0; i < num_of_steps; ++i)
- Rast_put_row(multiple_output[i].fd,
- multiple_output[i].forms_buffer, CELL_TYPE);
- }
- G_percent(row, nrows, 2); /* end main loop */
- for (i = 0; i < num_of_steps; ++i) {
- G_free(multiple_output[i].forms_buffer);
- Rast_close(multiple_output[i].fd);
- Rast_short_history(multiple_output[i].name, "raster", &history);
- Rast_command_history(&history);
- Rast_write_history(multiple_output[i].name, &history);
- }
- G_message("Multiresolution Done!");
- exit(EXIT_SUCCESS);
- }
- }
|