[GRASS-SVN] r52451 - grass-addons/grass7/imagery/i.segment
svn_grass at osgeo.org
svn_grass at osgeo.org
Wed Jul 25 09:49:57 PDT 2012
Author: momsen
Date: 2012-07-25 09:49:57 -0700 (Wed, 25 Jul 2012)
New Revision: 52451
Modified:
grass-addons/grass7/imagery/i.segment/create_isegs.c
grass-addons/grass7/imagery/i.segment/iseg.h
grass-addons/grass7/imagery/i.segment/open_files.c
grass-addons/grass7/imagery/i.segment/parse_args.c
Log:
find_neighbors() returns only one pixel per bordering segment, added (quickly tested) option to limit merges to one per pass
Modified: grass-addons/grass7/imagery/i.segment/create_isegs.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/create_isegs.c 2012-07-25 15:29:10 UTC (rev 52450)
+++ grass-addons/grass7/imagery/i.segment/create_isegs.c 2012-07-25 16:49:57 UTC (rev 52451)
@@ -42,13 +42,14 @@
}
/* processing loop for polygon/boundary constraints */
+ if (files->bounds_map != NULL)
+ G_message(_("Running region growing algorithm, the percent completed is based the range of values in the boundary constraints map"));
for (files->current_bound = lower_bound;
files->current_bound <= upper_bound; files->current_bound++) {
- if (files->bounds_map == NULL)
- G_message(_("Running region growing algorithm, the percent completed is based the range of values in the boundary constraints map"));
- G_percent(files->current_bound - lower_bound,
- upper_bound - lower_bound, 1);
+ if (files->bounds_map != NULL)
+ G_percent(files->current_bound - lower_bound,
+ upper_bound - lower_bound, 1);
/* *** check the processing window *** */
@@ -148,7 +149,8 @@
int row, col;
/* from speed.c to test speed of malloc vs. memory manager */
- register int i;
+ long int i;
+ register int j, s;
struct link_head *head;
struct pixels *p;
@@ -157,17 +159,78 @@
/* G_verbose_message("writing fake data to segmentation file"); */
G_verbose_message("writing scaled input (layer 1) to output file");
G_verbose_message("weighted flag = %d", files->weighted);
+ //~ for (row = 0; row < files->nrows; row++) {
+ //~ for (col = 0; col < files->ncols; col++) {
+ //~ /*files->out_val[0] = files->out_val[0]; *//*segment number *//* just copying the map for testing. */
+ //~ /* files->out_val[0] = col + row; */
+ //~ segment_get(&files->bands_seg, (void *)files->bands_val, row,
+ //~ col);
+ //~ files->iseg[row][col] = files->bands_val[0] * 100; /*pushing DCELL into CELL */
+ //~ }
+ //~ G_percent(row, files->nrows, 1);
+ //~ }
+
+ /* Trying out peano ordering */
+ /* idea is for large maps, if the width of SEG tiles in RAM is less than the width of the map, this should avoid a lot of I/O */
+ /* this is probably closer to a z-order curve then peano order. */
+
+ /*blank slate */
for (row = 0; row < files->nrows; row++) {
for (col = 0; col < files->ncols; col++) {
- /*files->out_val[0] = files->out_val[0]; *//*segment number *//* just copying the map for testing. */
- /* files->out_val[0] = col + row; */
- segment_get(&files->bands_seg, (void *)files->bands_val, row,
- col);
- files->iseg[row][col] = files->bands_val[0] * 100; /*pushing DCELL into CELL */
+ files->iseg[row][col] = -1;
}
- G_percent(row, files->nrows, 1);
}
+ s = 0;
+ //~ for(i=1; i<9; i++)
+ //~ {
+ //~ G_message("i: %d", i);
+ //~ for(j=4; j>=0; j--){
+ //~ G_message("\tj=%d, 1 & (i >> j) = %d", j, 1 & (i >> j));
+ //~ }
+ //~ }
+ for (i = 0; i < 16; i++) { // if square and power of 2: files->nrows*files->ncols
+ row = col = 0;
+ /*bit wise construct row and col from i */
+ for (j = 8 * sizeof(long int) - 1; j > 1; j--) {
+ row = row | (1 & (i >> j));
+ row = row << 1;
+ j--;
+ col = col | (1 & (i >> j));
+ col = col << 1;
+ }
+ row = row | (1 & (i >> j));
+ j--;
+ col = col | (1 & (i >> j));
+ G_message("Done: i: %li, row: %d, col: %d", i, row, col);
+ files->iseg[row][col] = s;
+ s++;
+ }
+
+
+ //~ for(i=0; i<8; i++){ //files->nrows*files->ncols
+ // G_message("i: %d", i);
+ //~ row=col=0;
+ //~
+ //~ /*bit wise construct row and col from i*/
+ //~ for(j=4; j>0; j=j-2){ //8*sizeof(int)
+ // G_message("j: %d", j);
+ //~ row = row | ( i & (1 << (2 * j))); /* row | a[rmax-r]; */
+ //~ row = row << 1;
+ //~ col = col | ( i & (1 << (2 * j + 1)));
+ //~ col = col << 1;
+ //~ G_message("j: %d, row: %d, col: %d", j, row, col);
+ //~ }
+ //~ row = row | ( i & (1 << (2 * j))); /* row | a[rmax-r]; */
+ //~ col = col | ( i & (1 << ((2 * j) + 1)));
+ //~ G_message("(1 << ((2 * j) + 1)) = %d", (1 << ((2 * j) + 1)));
+ //~ G_message("Done: i: %d, row: %d, col: %d", i, row, col);
+ //~ files->iseg[row][col] = s;
+ //~ s++;
+ //~ }
+
+
+
/*speed test... showed a difference of 1min 9s for G_malloc and 34s for linkm. (with i < 2000000000 */
#ifdef LINKM
@@ -677,9 +740,9 @@
double threshold, Ri_similarity, Rk_similarity, tempsim;
int endflag; /* =TRUE if there were no merges on that processing iteration */
int pathflag; /* =TRUE if we didn't find mutual neighbors, and should continue with Rk */
- struct pixels *Ri_head, *Rk_head, *Rin_head, *Rkn_head, *current,
- *newpixel, *Ri_bestn;
- int Ri_count, Rk_count; /* number of pixels/cells in Ri and Rk */
+ struct pixels *Ri_head, *Rk_head, *Rin_head, *Rkn_head, *Rclose_head,
+ *Rc_head, *Rc_tail, *Rcn_head, *current, *newpixel, *Ri_bestn;
+ int Ri_count, Rk_count, Rc_count; /* number of pixels/cells in Ri and Rk */
/* files->token has the "link_head" for linkm: linked list memory allocation.
*
@@ -703,6 +766,9 @@
Rin_head = NULL;
Rkn_head = NULL;
Ri_bestn = NULL;
+ Rclose_head = NULL;
+ Rc_head = NULL;
+ Rcn_head = NULL;
/* do while loop until no merges are made, or until t reaches maximum number of iterations */
do {
@@ -735,6 +801,7 @@
my_dispose_list(files->token, &Rk_head);
my_dispose_list(files->token, &Rin_head);
my_dispose_list(files->token, &Rkn_head);
+ my_dispose_list(files->token, &Rclose_head);
Rk_count = 0;
/* First pixel in Ri is current row/col pixel. We may add more later if it is part of a segment */
@@ -747,8 +814,9 @@
pathflag = TRUE;
- while (pathflag == TRUE && files->candidate_count > 0) { /*if don't find mutual neighbors on first try, will use Rk as next Ri. */
-
+ while (pathflag == TRUE) { /*if don't find mutual neighbors on first try, will use Rk as next Ri. */
+ //TODO: do I need this && part? remove candidate_count completely? Is there a way this loop could get stuck iterating forever???
+ //&& files->candidate_count > 0
G_debug(4, "Next starting pixel: row, %d, col, %d",
Ri_head->row, Ri_head->col);
@@ -793,6 +861,17 @@
"simularity = %g for neighbor : row: %d, col %d.",
tempsim, current->row, current->col);
+ /* if very close, will merge, but continue checking other neighbors */
+ //~ if (tempsim < functions->very_close * threshold){
+ //~ /* add to Rclose list */
+ //~ newpixel = (struct pixels *)link_new(files->token);
+ //~ newpixel->next = Rclose_head;
+ //~ newpixel->row = current->row;
+ //~ newpixel->col = current->col;
+ //~ Rclose_head = newpixel;
+ //~ }
+ /* If "sort of" close, merge only if it is the mutually most similar */
+ //~ else
if (tempsim < Ri_similarity) {
Ri_similarity = tempsim;
Ri_bestn = current;
@@ -803,12 +882,48 @@
}
} /* finished similiarity check for all neighbors */
+ /* *** merge all the "very close" pixels/segments *** */
+ /* doing this after checking all Rin, so we don't change the bands_val between similarity comparisons
+ * TODO... but that leaves the possibility that we have the wrong best Neighbor after doing these merges...
+ * but it seems we can't put this merge after the Rk/Rkn portion of the loop, because we are changing the available neighbors
+ * ...maybe this extra "very close" idea has to be done completely differently or dropped??? */
+ for (current = Rclose_head; current != NULL;
+ current = current->next) {
+ my_dispose_list(files->token, &Rc_head);
+ my_dispose_list(files->token, &Rcn_head);
+
+ /* get membership of neighbor segment */
+ Rc_count = 1;
+ newpixel =
+ (struct pixels *)link_new(files->token);
+ newpixel->next = NULL;
+ newpixel->row = current->row;
+ newpixel->col = current->col;
+ Rc_head = Rc_tail = newpixel;
+ find_segment_neighbors(&Rc_head, &Rcn_head, &Rc_count, files, functions); /* just to get members, not looking at neighbors now */
+ merge_values(Ri_head, Rc_head, Ri_count,
+ Rc_count, files);
+
+ /* Add Rc pixels to Ri */
+ Rc_tail->next = Ri_head;
+ Ri_head = Rc_head;
+
+ //todo, recurse? Check all Rcn neighbors if they are very close?
+ // not needed if the combining works... my_dispose_list(files->token, &Rc_head);
+ Rc_head = NULL;
+ my_dispose_list(files->token, &Rcn_head);
+ }
+ my_dispose_list(files->token, &Rclose_head);
+
+ /* check if we have a bestn that is valid to use to look at Rk */
if (Ri_bestn != NULL) {
G_debug(4,
"Lowest Ri_similarity = %g, for neighbor pixel row: %d col: %d",
Ri_similarity, Ri_bestn->row,
Ri_bestn->col);
- if (!
+
+ //todo this "limited" flag will probably be removed? Then this entire if section could be removed if we always allow multiple merges per pass?
+ if (functions->limited && !
(FLAG_GET
(files->candidate_flag, Ri_bestn->row,
Ri_bestn->col))) {
@@ -820,7 +935,6 @@
}
if (Ri_bestn != NULL && Ri_similarity < threshold) { /* small TODO: should this be < or <= for threshold? */
-
/* Rk starts from Ri's best neighbor */
Rk_count = 1;
newpixel =
@@ -894,6 +1008,7 @@
"3b Ri's best neighbor was not valid candidate, or their similarity was > threshold");
pathflag = FALSE;
}
+
} /* end if(Rin_head != NULL) */
else { /* Ri didn't have a neighbor */
G_debug(4, "Segment had no neighbors");
@@ -951,7 +1066,7 @@
if (functions->min_segment_size > 1 && t > 2) { /* NOTE: added t > 2, it doesn't make sense to force merges if no merges were made on the original pass. Something should be adjusted first */
- G_verbose_message
+ G_message
(_("Final iteration, forcing merges for small segments, percent complete based on rows."));
/* for the final forced merge, the candidate flag is just to keep track if we have confirmed if:
@@ -1212,17 +1327,21 @@
}
else { /* segment id's were different */
- //TODO: if current ID not found in known neighbors list
- //add to known neighbors list
- /* put pixel_neighbor[n] in Rin */
- G_debug(5, "Put in neighbors_head");
- newpixel = (struct pixels *)link_new(files->token);
- newpixel->next = *neighbors_head; /*point the new pixel to the current first pixel */
- newpixel->row = pixel_neighbors[n][0];
- newpixel->col = pixel_neighbors[n][1];
- *neighbors_head = newpixel; /*change the first pixel to be the new pixel. */
- //}
+ if (!rbtree_find(known_iseg, ¤t_seg_ID)) { /* we don't have any neighbors yet from this segment */
+ /* add to known neighbors list */
+ rbtree_insert(known_iseg, ¤t_seg_ID); /* todo: could I just try to insert it, if it fails I know it is already there?
+ * I guess it would depend on how much faster the find() is, and what fraction of the
+ * neighbors are in a duplicate segment... */
+
+ /* put pixel_neighbor[n] in Rin */
+ G_debug(5, "Put in neighbors_head");
+ newpixel = (struct pixels *)link_new(files->token);
+ newpixel->next = *neighbors_head; /*point the new pixel to the current first pixel */
+ newpixel->row = pixel_neighbors[n][0];
+ newpixel->col = pixel_neighbors[n][1];
+ *neighbors_head = newpixel; /*change the first pixel to be the new pixel. */
+ }
}
@@ -1333,7 +1452,7 @@
int n;
struct pixels *current;
- /*get input values *//*TODO polish, confirm if we can assume we already have bands_val for Ri, so don't need to segment_get() again? */
+ /*get input values *//*TODO polish, confirm if we can assume we already have bands_val for Ri, so don't need to segment_get() again? note...current very_close implementation requires getting this value again... */
segment_get(&files->bands_seg, (void *)files->bands_val, Ri_head->row,
Ri_head->col);
segment_get(&files->bands_seg, (void *)files->second_val,
Modified: grass-addons/grass7/imagery/i.segment/iseg.h
===================================================================
--- grass-addons/grass7/imagery/i.segment/iseg.h 2012-07-25 15:29:10 UTC (rev 52450)
+++ grass-addons/grass7/imagery/i.segment/iseg.h 2012-07-25 16:49:57 UTC (rev 52451)
@@ -84,6 +84,13 @@
/* todo remove when decide on pathflag */
int path;
+
+ /* todo remove when decide on allowing multiple merges per pass */
+ int limited;
+
+ /* todo: should this be an option, set at a specific value, or left out. */
+ // double very_close; /* segments with very_close similarity will be merged without changing or checking the candidate flag. The algorithm will continue looking for the "most similar" neighbor that isn't "very close". */
+ // todo... tried this out briefly, but realized that we need to find the segment membership, might be some faster ways to do this, but first tries actually slowed down the processing.
};
Modified: grass-addons/grass7/imagery/i.segment/open_files.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/open_files.c 2012-07-25 15:29:10 UTC (rev 52450)
+++ grass-addons/grass7/imagery/i.segment/open_files.c 2012-07-25 16:49:57 UTC (rev 52451)
@@ -96,7 +96,7 @@
scols = 64;
/* TODO: make calculations for this, check i.cost and i.watershed */
- nseg = 10000;
+ nseg = 16;
/* ******* create temporary segmentation files ********* */
@@ -161,25 +161,10 @@
}
}
- /* keep original copy of null flag if we have boundary constraints */
- if (files->bounds_map != NULL) {
- for (row = 0; row < files->nrows; row++) {
- for (col = 0; col < files->ncols; col++) {
- if (FLAG_GET(files->null_flag, row, col))
- FLAG_SET(files->orig_null_flag, row, col);
- else /* todo polish, flags are initialized to zero... could just skip this else? */
- FLAG_UNSET(files->orig_null_flag, row, col);
- }
- }
- }
-
/* number of initial segments, will decrement when merge */
files->nsegs = s - 1;
/* bounds/constraints */
- /* TODO: You should also handle NULL cells in the bounds
- * raster map, I would suggest to replace NULL with min(bounds) - 1 or
- +* max(bounds) + 1. */
if (files->bounds_map != NULL) {
if (segment_open
(&files->bounds_seg, G_tempfile(), files->nrows, files->ncols,
@@ -194,15 +179,29 @@
for (col = 0; col < files->ncols; col++) {
files->bounds_val = boundsbuf[col];
segment_put(&files->bounds_seg, &files->bounds_val, row, col);
+ if (Rast_is_c_null_value(&boundsbuf[col]) == TRUE) {
+ FLAG_SET(files->null_flag, row, col);
+ }
}
}
Rast_close(bounds_fd);
G_free(boundsbuf);
- }
+
+ /* keep original copy of null flag if we have boundary constraints */
+ for (row = 0; row < files->nrows; row++) {
+ for (col = 0; col < files->ncols; col++) {
+ if (FLAG_GET(files->null_flag, row, col))
+ FLAG_SET(files->orig_null_flag, row, col);
+ else /* todo polish, flags are initialized to zero... could just skip this else? */
+ FLAG_UNSET(files->orig_null_flag, row, col);
+ }
+ }
+ } /* end: if (files->bounds_map != NULL) */
else {
G_debug(1, "no boundary constraint supplied.");
}
+
/* other info */
files->candidate_count = 0; /* counter for remaining candidate pixels */
Modified: grass-addons/grass7/imagery/i.segment/parse_args.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/parse_args.c 2012-07-25 15:29:10 UTC (rev 52450)
+++ grass-addons/grass7/imagery/i.segment/parse_args.c 2012-07-25 16:49:57 UTC (rev 52451)
@@ -13,9 +13,11 @@
/* reference: http://grass.osgeo.org/programming7/gislib.html#Command_Line_Parsing */
struct Option *group, *seeds, *bounds, *output, *method, *threshold, *min_segment_size, *endt; /* Establish an Option pointer for each option */
- struct Flag *diagonal, *weighted, *path; /* Establish a Flag pointer for each option */
+ struct Flag *diagonal, *weighted, *path, *limited; /* Establish a Flag pointer for each option */
struct Option *outband; /* TODO scrub: put all outband code inside of #ifdef DEBUG */
+ //~ struct Option *very_close;
+
/* required parameters */
group = G_define_standard_option(G_OPT_I_GROUP); /* TODO? Polish, consider giving the option to process just one raster directly, without creating an image group. */
@@ -50,6 +52,14 @@
min_segment_size->description =
_("The final iteration will ignore the threshold for any segments with fewer pixels.");
+ //~ very_close = G_define_option();
+ //~ very_close->key = "very_close";
+ //~ very_close->type = TYPE_DOUBLE;
+ //~ very_close->required = YES;
+ //~ very_close->answer = "0";
+ //~ very_close->options = "0-1";
+ //~ very_close->description = _("For testing: very close segments will be merged, the focus segment will not be changed.");
+
/* optional parameters */
diagonal = G_define_flag();
@@ -91,12 +101,19 @@
path->description =
_("temporary option, pathflag, select to use Rk as next Ri if not mutually best neighbors.");
+ limited = G_define_flag();
+ limited->key = 'l';
+ limited->description =
+ _("temporary option, limit to one merge to pass, if *not* selected a segment can be included in multiple merges in one pass.");
+
outband = G_define_standard_option(G_OPT_R_OUTPUT);
outband->key = "final_mean";
outband->required = NO;
outband->description =
_("debug - save band mean, currently implemented for only 1 band.");
+
+
if (G_parser(argc, argv))
exit(EXIT_FAILURE);
@@ -135,6 +152,8 @@
G_debug(1, "segmentation method: %d", functions->method);
+ //~ functions->very_close = atof(very_close->answer);
+
functions->min_segment_size = atoi(min_segment_size->answer);
if (diagonal->answer == FALSE) {
@@ -185,6 +204,8 @@
functions->path = path->answer; /* default/0 for no pathflag, but selected/1 to use Rk as next Ri if not mutually best neighbors. */
+ functions->limited = limited->answer;
+
if (outband->answer == NULL)
files->out_band = NULL;
else {
More information about the grass-commit
mailing list