123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- /* PURPOSE: Parse and validate the input */
- #include <stdlib.h>
- #include <string.h>
- #include <grass/gis.h>
- #include <grass/glocale.h>
- #include <grass/raster.h>
- #include "iseg.h"
- int parse_args(int argc, char *argv[], struct globals *globals)
- {
- struct Option *group, *seeds, *bounds, *output,
- *method, *similarity, *threshold, *min_segment_size,
- *hs, *hr, *bsuf,
- #ifdef _OR_SHAPE_
- *shape_weight, *smooth_weight,
- #endif
- *mem;
- struct Flag *diagonal, *weighted, *ms_a, *ms_p;
- struct Option *gof, *endt;
- /* required parameters */
- group = G_define_standard_option(G_OPT_I_GROUP);
- output = G_define_standard_option(G_OPT_R_OUTPUT);
- bsuf = G_define_standard_option(G_OPT_R_OUTPUT);
- bsuf->key = "band_suffix";
- bsuf->required = NO;
- bsuf->label = _("Suffix for output bands with modified band values");
- threshold = G_define_option();
- threshold->key = "threshold";
- threshold->type = TYPE_DOUBLE;
- threshold->required = YES;
- threshold->label = _("Difference threshold between 0 and 1");
- threshold->description = _("Threshold = 0 merges only identical segments; threshold = 1 merges all");
- /* optional parameters */
- hs = G_define_option();
- hs->key = "radius";
- hs->type = TYPE_DOUBLE;
- hs->required = NO;
- hs->answer = "1.5";
- hs->label = _("Spatial radius in number of cells");
- hs->description = _("Must be >= 1, only cells within spatial bandwidth are considered for mean shift");
- hr = G_define_option();
- hr->key = "hr";
- hr->type = TYPE_DOUBLE;
- hr->required = NO;
- hr->label = _("Range (spectral) bandwidth [0, 1]");
- hr->description = _("Only cells within range (spectral) bandwidth are considered for mean shift. Range bandwidth is used as conductance parameter for adaptive bandwidth");
- method = G_define_option();
- method->key = "method";
- method->type = TYPE_STRING;
- method->required = NO;
- method->answer = "region_growing";
- method->options = "region_growing,mean_shift";
- /*
- Watershed method disabled, it's not implemented yet, see
- https://trac.osgeo.org/grass/ticket/3181
- method->options = "region_growing,mean_shift,watershed";
- */
- method->description = _("Segmentation method");
- method->guisection = _("Settings");
- similarity = G_define_option();
- similarity->key = "similarity";
- similarity->type = TYPE_STRING;
- similarity->required = NO;
- similarity->answer = "euclidean";
- similarity->options = "euclidean,manhattan";
- similarity->description = _("Similarity calculation method");
- similarity->guisection = _("Settings");
- min_segment_size = G_define_option();
- min_segment_size->key = "minsize";
- min_segment_size->type = TYPE_INTEGER;
- min_segment_size->required = NO;
- min_segment_size->answer = "1";
- min_segment_size->options = "1-100000";
- min_segment_size->label = _("Minimum number of cells in a segment");
- min_segment_size->description =
- _("The final step will merge small segments with their best neighbor");
- min_segment_size->guisection = _("Settings");
- #ifdef _OR_SHAPE_
- radio_weight = G_define_option();
- radio_weight->key = "radio_weight";
- radio_weight->type = TYPE_DOUBLE;
- radio_weight->required = NO;
- radio_weight->answer = "1";
- radio_weight->options = "0-1";
- radio_weight->label =
- _("Importance of radiometric (input raster) values relative to shape");
- radio_weight->guisection = _("Settings");
- smooth_weight = G_define_option();
- smooth_weight->key = "smooth_weight";
- smooth_weight->type = TYPE_DOUBLE;
- smooth_weight->required = NO;
- smooth_weight->answer = "0.5";
- smooth_weight->options = "0-1";
- smooth_weight->label =
- _("Importance of smoothness relative to compactness");
- smooth_weight->guisection = _("Settings");
- #endif
- mem = G_define_option();
- mem->key = "memory";
- mem->type = TYPE_INTEGER;
- mem->required = NO;
- mem->answer = "300";
- mem->description = _("Memory in MB");
- /* TODO input for distance function */
- /* debug parameters */
- endt = G_define_option();
- endt->key = "iterations";
- endt->type = TYPE_INTEGER;
- endt->required = NO;
- endt->description = _("Maximum number of iterations");
- endt->guisection = _("Settings");
- /* Using raster for seeds
- * Low priority TODO: allow vector points/centroids seed input. */
- seeds = G_define_standard_option(G_OPT_R_INPUT);
- seeds->key = "seeds";
- seeds->required = NO;
- seeds->description = _("Name for input raster map with starting seeds");
- seeds->guisection = _("Settings");
- /* Polygon constraints. */
- bounds = G_define_standard_option(G_OPT_R_INPUT);
- bounds->key = "bounds";
- bounds->required = NO;
- bounds->label = _("Name of input bounding/constraining raster map");
- bounds->description =
- _("Must be integer values, each area will be segmented independent of the others");
- bounds->guisection = _("Settings");
- gof = G_define_standard_option(G_OPT_R_OUTPUT);
- gof->key = "goodness";
- gof->required = NO;
- gof->description =
- _("Name for output goodness of fit estimate map");
- gof->guisection = _("Settings");
- diagonal = G_define_flag();
- diagonal->key = 'd';
- diagonal->description =
- _("Use 8 neighbors (3x3 neighborhood) instead of the default 4 neighbors for each pixel");
- diagonal->guisection = _("Settings");
- weighted = G_define_flag();
- weighted->key = 'w';
- weighted->description =
- _("Weighted input, do not perform the default scaling of input raster maps");
- weighted->guisection = _("Settings");
- ms_a = G_define_flag();
- ms_a->key = 'a';
- ms_a->label = _("Use adaptive bandwidth for mean shift");
- ms_a->description = _("Range (spectral) bandwidth is adapted for each moving window");
- ms_a->guisection = _("Settings");
- ms_p = G_define_flag();
- ms_p->key = 'p';
- ms_p->label = _("Use progressive bandwidth for mean shift");
- ms_p->description =
- _("Spatial bandwidth is increased, range (spectral) bandwidth is decreased in each iteration");
- ms_p->guisection = _("Settings");
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- /* Check and save parameters */
- globals->image_group = group->answer;
- if (G_legal_filename(output->answer) == TRUE)
- globals->out_name = output->answer;
- else
- G_fatal_error("Invalid output raster name");
- globals->bsuf = bsuf->answer;
- globals->alpha = atof(threshold->answer);
- if (globals->alpha <= 0 || globals->alpha >= 1)
- G_fatal_error(_("Threshold should be > 0 and < 1"));
- globals->hs = -1;
- if (hs->answer) {
- globals->hs = atof(hs->answer);
- if (globals->hs < 1) {
- G_fatal_error(_("Option '%s' must be >= 1"), hs->key);
- }
- }
- globals->hr = -1;
- if (hr->answer) {
- globals->hr = atof(hr->answer);
- if (globals->hr < 0) {
- G_warning(_("Negative value %s for option '%s': disabling"),
- hr->answer, hr->key);
- globals->hr = -1;
- }
- if (globals->hr >= 1) {
- G_warning(_("Value %s for option '%s' is >= 1: disabling"),
- hr->answer, hr->key);
- globals->hr = -1;
- }
- }
- globals->ms_adaptive = ms_a->answer;
- globals->ms_progressive = ms_p->answer;
- /* segmentation methods */
- if (strcmp(method->answer, "region_growing") == 0) {
- globals->method = ORM_RG;
- globals->method_fn = region_growing;
- }
- else if (strcmp(method->answer, "mean_shift") == 0) {
- globals->method = ORM_MS;
- globals->method_fn = mean_shift;
- }
- else if (strcmp(method->answer, "watershed") == 0) {
- globals->method = ORM_WS;
- globals->method_fn = watershed;
- }
- else
- G_fatal_error(_("Unable to assign segmentation method"));
- G_debug(1, "segmentation method: %s (%d)", method->answer, globals->method);
- /* distance methods for similarity measurement */
- if (strcmp(similarity->answer, "euclidean") == 0)
- globals->calculate_similarity = calculate_euclidean_similarity;
- else if (strcmp(similarity->answer, "manhattan") == 0)
- globals->calculate_similarity = calculate_manhattan_similarity;
- else
- G_fatal_error(_("Invalid similarity method"));
- #ifdef _OR_SHAPE_
- /* consider shape */
- globals->radio_weight = atof(radio_weight->answer);
- if (globals->radio_weight <= 0)
- G_fatal_error(_("Option '%s' must be > 0"), radio_weight->key);
- if (globals->radio_weight > 1)
- G_fatal_error(_("Option '%s' must be <= 1"), radio_weight->key);
- globals->smooth_weight = atof(smooth_weight->answer);
- if (globals->smooth_weight < 0)
- G_fatal_error(_("Option '%s' must be >= 0"), smooth_weight->key);
- if (globals->smooth_weight > 1)
- G_fatal_error(_("Option '%s' must be <= 1"), smooth_weight->key);
- #else
- globals->radio_weight = 1;
- globals->smooth_weight = 0.5;
- #endif
- globals->min_segment_size = atoi(min_segment_size->answer);
- if (diagonal->answer == FALSE) {
- globals->find_neighbors = find_four_neighbors;
- globals->nn = 4;
- G_debug(1, "four pixel neighborhood");
- }
- else if (diagonal->answer == TRUE) {
- globals->find_neighbors = find_eight_neighbors;
- globals->nn = 8;
- G_debug(1, "eight (3x3) pixel neighborhood");
- }
- /* default/0 for performing the scaling
- * selected/1 if scaling should be skipped. */
- globals->weighted = weighted->answer;
- globals->seeds = seeds->answer;
- if (globals->seeds) {
- if (G_find_raster(globals->seeds, "") == NULL) {
- G_fatal_error(_("Seeds raster map not found"));
- }
- if (Rast_map_type(globals->seeds, "") !=
- CELL_TYPE) {
- G_fatal_error(_("Seeeds raster map must be CELL type (integers)"));
- }
- }
- if (bounds->answer == NULL) {
- globals->bounds_map = NULL;
- }
- else {
- globals->bounds_map = bounds->answer;
- if ((globals->bounds_mapset = G_find_raster(globals->bounds_map, "")) == NULL) {
- G_fatal_error(_("Segmentation constraint/boundary raster map not found"));
- }
- if (Rast_map_type(globals->bounds_map, globals->bounds_mapset) !=
- CELL_TYPE) {
- G_fatal_error(_("Segmentation constraint raster map must be CELL type (integers)"));
- }
- }
- /* other data */
- globals->nrows = Rast_window_rows();
- globals->ncols = Rast_window_cols();
- if (sizeof(LARGEINT) < 8) {
- int i;
- LARGEINT intmax;
- intmax = ((LARGEINT)1 << (sizeof(LARGEINT) * 8 - 2)) - 1;
- intmax += ((LARGEINT)1 << (sizeof(LARGEINT) * 8 - 2));
- globals->ncells = globals->ncols;
- for (i = 1; i < globals->nrows; i++) {
- if (globals->ncols > intmax - globals->ncells)
- G_fatal_error(_("Integer overflow: too many cells in current region"));
- globals->ncells += globals->ncols;
- }
- }
- /* debug help */
- if (gof->answer == NULL)
- globals->gof = NULL;
- else {
- if (G_legal_filename(gof->answer) == TRUE)
- globals->gof = gof->answer;
- else
- G_fatal_error(_("Invalid output raster name for goodness of fit"));
- }
- if (!endt->answer) {
- globals->end_t = 50;
- if (globals->method == ORM_MS)
- globals->end_t = 10;
- G_message(_("Maximum number of iterations set to %d"),
- globals->end_t);
- }
- else {
- if (atoi(endt->answer) > 0)
- globals->end_t = atoi(endt->answer);
- else {
- globals->end_t = 50;
- if (globals->method == ORM_MS)
- globals->end_t = 10;
- G_warning(_("Invalid number of iterations, %d will be used"),
- globals->end_t);
- }
- }
- if (mem->answer && atoi(mem->answer) > 10)
- globals->mb = atoi(mem->answer);
- else {
- globals->mb = 300;
- G_warning(_("Invalid number of MB, 300 will be used"));
- }
- return TRUE;
- }
|