[GRASS-SVN] r52505 - grass-addons/grass7/imagery/i.segment

svn_grass at osgeo.org svn_grass at osgeo.org
Thu Aug 2 13:29:38 PDT 2012


Author: momsen
Date: 2012-08-02 13:29:32 -0700 (Thu, 02 Aug 2012)
New Revision: 52505

Modified:
   grass-addons/grass7/imagery/i.segment/create_isegs.c
   grass-addons/grass7/imagery/i.segment/i.segment.html
   grass-addons/grass7/imagery/i.segment/iseg.h
   grass-addons/grass7/imagery/i.segment/main.c
   grass-addons/grass7/imagery/i.segment/open_files.c
   grass-addons/grass7/imagery/i.segment/write_output.c
Log:
starting seeds methodology updated

Modified: grass-addons/grass7/imagery/i.segment/create_isegs.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/create_isegs.c	2012-08-02 13:25:40 UTC (rev 52504)
+++ grass-addons/grass7/imagery/i.segment/create_isegs.c	2012-08-02 20:29:32 UTC (rev 52505)
@@ -812,7 +812,7 @@
 		  functions->end_t);
 
     t = 1;
-    files->candidate_count = 0;
+    //~ files->candidate_count = 0;
 
     /*set linked list head pointers to null. */
     Ri_head = NULL;
@@ -828,8 +828,8 @@
     do {
 #ifdef PROFILE
 	pass_start = clock();
+#endif
 	fprintf(stdout, "pass %d\n", t);
-#endif
 	G_debug(3, "#######   Starting outer do loop! t = %d    #######", t);
 	/* todo, delete this?  G_verbose_message("Pass %d: ", t); */
 	G_percent(t, functions->end_t, 1);
@@ -841,8 +841,8 @@
 	set_all_candidate_flags(files);
 	/* Set candidate flag to true/1 for all pixels */
 
-	G_debug(4, "Starting to process %d candidate pixels",
-		files->candidate_count);
+	//~ G_debug(4, "Starting to process %d candidate pixels",
+		//~ files->candidate_count);
 
 	/*process candidate pixels for this iteration */
 
@@ -894,7 +894,7 @@
 #endif
 		G_debug(4, "Starting pixel from next row/col, not from Rk");
 
-		if (FLAG_GET(files->candidate_flag, row, col)) {
+		if (FLAG_GET(files->candidate_flag, row, col) && FLAG_GET(files->seeds_flag, row, col)) {  //todo OK?  added the && for seed_flag...
 		    /*free memory for linked lists */
 		    my_dispose_list(files->token, &Ri_head);
 		    my_dispose_list(files->token, &Rk_head);
@@ -1035,8 +1035,6 @@
 					Ri_similarity, Ri_bestn->row,
 					Ri_bestn->col);
 
-				//if seeds map, can't check if it is a candidate.  TODO better way to include this check after decide on using the candidate flag here.
-				if (files->seeds_map == NULL) {
 				    //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 == TRUE) && !
 					(FLAG_GET
@@ -1046,7 +1044,6 @@
 					 * best neighbor is not a valid candidate, was already merged earlier in this time step */
 					Ri_bestn = NULL;
 				    }
-				}
 			    }
 			    if (Ri_bestn != NULL && Ri_similarity < threshold) {	/* small TODO: should this be < or <= for threshold? */
 				/* Rk starts from Ri's best neighbor */
@@ -1127,12 +1124,10 @@
 
 				    /* checked Ri once, didn't find a mutually best neighbor, so remove all members of Ri from candidate pixels for this iteration */
 				    set_candidate_flag(Ri_head, FALSE, files);
-				    G_debug(4, "line 247, \t\t\t\tcc = %d",
-					    files->candidate_count);
+				    //~ G_debug(4, "line 247, \t\t\t\tcc = %d",
+					    //~ files->candidate_count);
 
-				    if (!(FLAG_GET
-					  (files->candidate_flag,
-					   Rk_head->row, Rk_head->col)))
+				    if (FLAG_GET(files->candidate_flag, Rk_head->row, Rk_head->col) && FLAG_GET(files->seeds_flag, Rk_head->row, Rk_head->col))
 					pathflag = TRUE;
 				}
 			    }	/* end if (Ri_bestn != NULL && Ri_similarity < threshold) */
@@ -1151,8 +1146,8 @@
 			else {	/* Ri didn't have a neighbor */
 			    G_debug(4, "Segment had no neighbors");
 			    set_candidate_flag(Ri_head, FALSE, files);
-			    G_debug(4, "line 176, \t\t\t\tcc = %d",
-				    files->candidate_count);
+			    //~ G_debug(4, "line 176, \t\t\t\tcc = %d",
+				    //~ files->candidate_count);
 			}
 
 			if (pathflag) {	/*initialize Ri, Rin, Rk, Rin using Rk as Ri. */
@@ -1179,7 +1174,7 @@
 			}
 
 		    }		/*end pathflag do loop */
-		}		/*end if pixel is candidate pixel */
+		}		/*end if pixel is candidate and seed pixel */
 	    }			/*next column (or next z) */
 	    #ifdef ROWMAJOR
 	}			/*next row */
@@ -1624,7 +1619,7 @@
 int merge_values(struct pixels *Ri_head, struct pixels *Rk_head,
 		 int Ri_count, int Rk_count, struct files *files)
 {
-    int n, Ri_iseg = 42, Rk_iseg = 43;
+    int n, Ri_iseg, Rk_iseg;
     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?  note...current very_close implementation requires getting this value again... */
@@ -1649,7 +1644,7 @@
     //~ files->iseg[Ri_head->row][Ri_head->col]);
 
     fprintf(stdout,
-	    "merging Ri (pixel count): %d (%d) with Rk (count): %d (%d).\t",
+	    "merging Ri (pixel count): %d (%d) with Rk (count): %d (%d).\n",
 	    Ri_iseg, Ri_count, Rk_iseg, Rk_count);
 
     /* for each member of Ri and Rk, write new average bands values and segment values */
@@ -1657,8 +1652,8 @@
 	segment_put(&files->bands_seg, (void *)files->bands_val,
 		    current->row, current->col);
 	FLAG_UNSET(files->candidate_flag, current->row, current->col);	/*candidate pixel flag, only one merge allowed per t iteration */
-	files->candidate_count--;
-	G_debug(4, "line 508, \t\t\t\tcc = %d", files->candidate_count);
+	//~ files->candidate_count--;
+	//~ G_debug(4, "line 508, \t\t\t\tcc = %d", files->candidate_count);
 	G_debug(4, "\t\tRi row: %d, col: %d", current->row, current->col);
     }
     for (current = Rk_head; current != NULL; current = current->next) {
@@ -1666,21 +1661,60 @@
 		    current->row, current->col);
 	segment_put(&files->iseg_seg, &Ri_iseg, current->row, current->col);
 	FLAG_UNSET(files->candidate_flag, current->row, current->col);
-	files->candidate_count--;
-	G_debug(4, "line 516, \t\t\t\tcc = %d", files->candidate_count);
+	//~ files->candidate_count--;
+	//~ G_debug(4, "line 516, \t\t\t\tcc = %d", files->candidate_count);
 	G_debug(4, "\t\tRk row: %d, col: %d", current->row, current->col);
 
     }
 
-    /* merged two segments, decrement count 
-     * if seeds were provided, need to adjust the candidate_count*/
-    if (files->seeds_map == NULL)
+    /* merged two segments, decrement count if Rk was an actual segment (not a non-seed pixel) */
+    if (Rk_iseg > 0)
 	files->nsegs--;
-    else {
-	files->candidate_count += Ri_count + Rk_count - 1;
-	/* todo if allow seeded segments to merge, need to decrement nsegs if Rk_count = 1 and it isn't a seed */
+
+	
+	//~ if (files->seeds_map != NULL) //todo delete???  or is it even correct?
+	//~ files->candidate_count += Ri_count + Rk_count - 1;
+
+    return TRUE;
+}
+
+/* calculates and stores the mean value for all pixels in a list, assuming they are all in the same segment */
+int merge_pixels(struct pixels *R_head, struct files *files)
+{
+    int n, count = 0;
+    struct pixels *current;
+
+	/* Note: using files->bands_val for current pixel values, and files->second_val for the accumulated value */
+	
+	/* initialize second_val */
+	for (n = 0; n < files->nbands; n++) {
+	files->second_val[n] = 0;
     }
 
+	if (R_head->next != NULL) {
+    /* total up bands values for all pixels */
+    for (current = R_head; current != NULL; current = current->next) {
+		segment_get(&files->bands_seg, (void *)files->bands_val, current->row,
+		current->col);
+		for (n = 0; n < files->nbands; n++) {
+		files->second_val[n] += files->bands_val[n];
+		}
+	count ++;
+	}
+	
+	/* calculate the mean */
+	for (n = 0; n < files->nbands; n++) {
+	files->second_val[n] = files->second_val[n] / count;
+    }
+
+	/* save the results */
+	for (current = R_head; current != NULL; current = current->next) {
+		segment_put(&files->bands_seg, (void *)files->second_val,
+		    current->row, current->col);
+    }
+
+	}
+
     return TRUE;
 }
 
@@ -1695,17 +1729,17 @@
 
 	if (value == FALSE) {
 	    FLAG_UNSET(files->candidate_flag, current->row, current->col);
-	    files->candidate_count--;
+	    //~ files->candidate_count--;
 	}
 	else if (value == TRUE) {
 	    FLAG_SET(files->candidate_flag, current->row, current->col);
-	    files->candidate_count++;
+	    //~ files->candidate_count++;
 	}
 	else
 	    G_fatal_error
 		("programming bug, helper function called with invalid argument");
 
-	G_debug(4, "line 1253, \t\t\t\tcc = %d", files->candidate_count);
+	//~ G_debug(4, "line 1253, \t\t\t\tcc = %d", files->candidate_count);
     }
     return TRUE;
 }
@@ -1771,7 +1805,7 @@
 {
     int row, col;
 
-    if (files->seeds_map == NULL) {	/* entire map is considered as candidates */
+    //~ if (files->seeds_map == NULL) {	/* entire map is considered as candidates */ //todo OK? updated meanings of seeds/candidates
 	//G_message("No seeds map, setting all pixels to be candidates");
 	//~ if (files->bounds_map == NULL) {        /* process entire raster */
 	for (row = files->minrow; row < files->maxrow; row++) {
@@ -1782,7 +1816,7 @@
 		/* MM: could be solved/not necessary if all pixels of an existing segment have the same ID */
 		if (!(FLAG_GET(files->null_flag, row, col))) {
 		    FLAG_SET(files->candidate_flag, row, col);
-		    files->candidate_count++;
+		    //~ files->candidate_count++;
 		}
 		else
 		    FLAG_UNSET(files->candidate_flag, row, col);
@@ -1801,20 +1835,20 @@
 	//~ }
 	//~ }
 	//~ }
-    }
-    else {			/* seeds were provided */
-	//G_message("seeds provided, just setting those pixels as candidates");
-	for (row = files->minrow; row < files->maxrow; row++) {
-	    for (col = files->mincol; col < files->maxcol; col++) {
-		if ((FLAG_GET(files->seeds_flag, row, col))) {
-		    FLAG_SET(files->candidate_flag, row, col);
-		    files->candidate_count++;	//TODO, how deal with this...
-		}
-		else
-		    FLAG_UNSET(files->candidate_flag, row, col);	//todo maybe can skip this...
-	    }
-	}
-    }
+    //~ }
+    //~ else {			/* seeds were provided */
+	//~ //G_message("seeds provided, just setting those pixels as candidates");
+	//~ for (row = files->minrow; row < files->maxrow; row++) {
+	    //~ for (col = files->mincol; col < files->maxcol; col++) {
+		//~ if ((FLAG_GET(files->seeds_flag, row, col))) {
+		    //~ FLAG_SET(files->candidate_flag, row, col);
+		    //~ files->candidate_count++;	//TODO, how deal with this...
+		//~ }
+		//~ else
+		    //~ FLAG_UNSET(files->candidate_flag, row, col);	//todo maybe can skip this...
+	    //~ }
+	//~ }
+    //~ }
 
 
     return TRUE;

Modified: grass-addons/grass7/imagery/i.segment/i.segment.html
===================================================================
--- grass-addons/grass7/imagery/i.segment/i.segment.html	2012-08-02 13:25:40 UTC (rev 52504)
+++ grass-addons/grass7/imagery/i.segment/i.segment.html	2012-08-02 20:29:32 UTC (rev 52505)
@@ -1,5 +1,6 @@
 <h2>DESCRIPTION</h2>
 <H2>NOTES</h2>
+The final forced merge (if minsize is set > 1) ignores the (optional) seed map.
 <H2>EXAMPLES</h2>
 <h2>TODO</h2>
 For Region Growing, the current limit with CELL storage is 2 billion starting segment ID's.  Workaround: If the original image has a larger number of pixels, please use the starting seeds option to limit the number of starting segments.

Modified: grass-addons/grass7/imagery/i.segment/iseg.h
===================================================================
--- grass-addons/grass7/imagery/i.segment/iseg.h	2012-08-02 13:25:40 UTC (rev 52504)
+++ grass-addons/grass7/imagery/i.segment/iseg.h	2012-08-02 20:29:32 UTC (rev 52505)
@@ -61,13 +61,15 @@
     int nsegs;			/* number of segments */
 
     /* processing flags */
+    /* candidate flag for if a cell/segment has already been merged in that pass. */
+    /* seeds flag for if a cell/segment is a seed (can be Ri to start a merge).  All cells are valid seeds if a starting seeds map is not supplied. */
     FLAG *candidate_flag, *null_flag, *orig_null_flag, *seeds_flag;
 
     /* memory management, linked lists */
     struct link_head *token;	/* for linkm.h linked list memory management. */
 
-    /* other info */
-    int candidate_count;	/*Number of remaining candidate pixels */
+    //~ /* other info */
+    //~ int candidate_count;	/*Number of remaining candidate pixels */
 
 };
 
@@ -102,7 +104,7 @@
 int parse_args(int, char *[], struct files *, struct functions *);
 
 /* open_files.c */
-int open_files(struct files *);
+int open_files(struct files *, struct functions *);
 
 /* create_isegs.c */
 int create_isegs(struct files *, struct functions *);
@@ -117,6 +119,7 @@
 			   struct files *, struct functions *);
 int set_candidate_flag(struct pixels *, int, struct files *);
 int merge_values(struct pixels *, struct pixels *, int, int, struct files *);
+int merge_pixels(struct pixels *, struct files *);
 int find_four_pixel_neighbors(int, int, int[][2], struct files *);
 int find_eight_pixel_neighbors(int, int, int[8][2], struct files *);
 double calculate_euclidean_similarity(struct pixels *, struct pixels *,

Modified: grass-addons/grass7/imagery/i.segment/main.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/main.c	2012-08-02 13:25:40 UTC (rev 52504)
+++ grass-addons/grass7/imagery/i.segment/main.c	2012-08-02 20:29:32 UTC (rev 52505)
@@ -41,7 +41,7 @@
 	G_fatal_error(_("Error in parse_args()"));
 
     G_debug(1, "Main: starting open_files()");
-    if (open_files(&files) != TRUE)
+    if (open_files(&files, &functions) != TRUE)
 	G_fatal_error(_("Error in open_files()"));
 
     G_debug(1, "Main: starting create_isegs()");

Modified: grass-addons/grass7/imagery/i.segment/open_files.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/open_files.c	2012-08-02 13:25:40 UTC (rev 52504)
+++ grass-addons/grass7/imagery/i.segment/open_files.c	2012-08-02 20:29:32 UTC (rev 52505)
@@ -7,7 +7,7 @@
 #include <grass/segment.h>	/* segmentation library */
 #include "iseg.h"
 
-int open_files(struct files *files)
+int open_files(struct files *files, struct functions *functions)
 {
     struct Ref Ref;		/* group reference list */
     int *in_fd, seeds_fd, bounds_fd, null_check, out_fd, mean_fd;
@@ -20,6 +20,10 @@
     struct FPRange *fp_range;	/* for getting min/max values on each input raster */
     DCELL *min, *max;
 
+	/* for merging seed values */
+	struct pixels *R_head, *Rn_head, *newpixel;
+	int R_count;
+
     /* confirm output maps can be opened (don't want to do all this work for nothing!) */
     out_fd = Rast_open_new(files->out_name, CELL_TYPE);
     if (out_fd < 0)
@@ -40,7 +44,7 @@
     files->candidate_flag = flag_create(files->nrows, files->ncols);
     if (files->bounds_map != NULL)
 	files->orig_null_flag = flag_create(files->nrows, files->ncols);
-    if (files->seeds_map != NULL)
+    //if (files->seeds_map != NULL)
 	files->seeds_flag = flag_create(files->nrows, files->ncols);
 
     /* references for segmentation library: i.cost r.watershed/seg and http://grass.osgeo.org/programming7/segmentlib.html */
@@ -175,10 +179,13 @@
 			FLAG_UNSET(files->seeds_flag, row, col);	//todo shouldn't need to this, flag is initialized to zero?
 		    }
 		    else {
-			s++;	/* sequentially number each seed pixel with its own segment ID */
-			FLAG_SET(files->seeds_flag, row, col);	//todo might not need this... just use the zero as seg ID?  If go this route, need to enforce constraints are positive integers.
-			segment_put(&files->iseg_seg, &s, row, col);
-			G_message("set seed for row: %d, col: %d", row, col);
+//			s++;	/* sequentially number each seed pixel with its own segment ID */
+			
+			FLAG_SET(files->seeds_flag, row, col);	//todo might not need this... just look for seg ID > 0 ?  If go this route, need to enforce constraints are positive integers.
+//			segment_put(&files->iseg_seg, &s, row, col);
+			/* seed value is starting segment ID.  TODO document: seeds must be positive integers, and will be assigned as starting segment IDs. */
+			segment_put(&files->iseg_seg, ptr, row, col); //can I just use ptr as the address with the value I want to store? TODO enforce that seeds map is an integer.
+//			G_message("set seed for row: %d, col: %d", row, col);
 
 		    }
 		    ptr = G_incr_void_ptr(ptr, ptrsize);
@@ -186,6 +193,7 @@
 		else {		/* no seeds provided */
 		    s++;	/* sequentially number all pixels with their own segment ID */
 		    segment_put(&files->iseg_seg, &s, row, col);	/*starting segment number */
+		    FLAG_SET(files->seeds_flag, row, col); 			/*all pixels are seeds */
 		}
 	    }
 	    else {		/*don't use this pixel */
@@ -197,8 +205,14 @@
     }
 
     /* number of initial segments, will decrement when merge */
+    if (files->seeds_map == NULL)
     files->nsegs = s;
-
+    else
+    {
+		/* TODO: Markus, is there an easy GRASS function to count the unique values in the seeds map???
+		 * or count during the processing? */
+	}
+	
     /* bounds/constraints */
     if (files->bounds_map != NULL) {
 	if (segment_open
@@ -236,8 +250,8 @@
 	G_debug(1, "no boundary constraint supplied.");
     }
 
-    /* other info */
-    files->candidate_count = 0;	/* counter for remaining candidate pixels */
+    //~ /* other info */
+    //~ files->candidate_count = 0;	/* counter for remaining candidate pixels */
 
     /* translate seeds to unique segments TODO MM mentioned it here... */
     /* todo decide if we need to take the seeds value, and use it to start the segments... or if each pixel starts a unique segment. */
@@ -247,6 +261,44 @@
 
     files->token = link_init(sizeof(struct pixels));
 
+	/* if we have seeds that are segments (not pixels) we need to update the bands_seg */
+	if(files->seeds_map != NULL){
+
+	/*initialization*/
+	files->minrow = files->mincol = 0;
+	files->maxrow = files->nrows;
+	files->maxcol = files->ncols;
+	R_count=1;
+	R_head=NULL;
+	Rn_head=NULL;
+	newpixel=NULL;
+	set_all_candidate_flags(files);
+	for (row = 0; row < files->nrows; row++) {
+	for (col = 0; col < files->ncols; col++) {
+		if(!(FLAG_GET(files->candidate_flag, row, col)) || FLAG_GET(files->null_flag, row, col)) continue;
+		/*start R_head*/
+		newpixel = (struct pixels *)link_new(files->token);
+		newpixel->next = NULL;
+		newpixel->row = row;
+		newpixel->col = col;
+		R_head = newpixel;
+
+		/*get pixel list, todo polish, could use custom (shorter) function, not using all of what fsn() does...*/
+		find_segment_neighbors(&R_head, &Rn_head, &R_count, files, functions);
+		
+		/*merge pixels*/
+		merge_pixels(R_head, files);
+		
+		/*todo calculate perimeter (?and area?) here?*/
+		
+		/*clean up*/
+		my_dispose_list(files->token, &R_head);
+		my_dispose_list(files->token, &Rn_head);
+		R_count=1;
+	}
+	}
+	}
+
     /* Free memory */
 
     for (n = 0; n < Ref.nfiles; n++) {

Modified: grass-addons/grass7/imagery/i.segment/write_output.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/write_output.c	2012-08-02 13:25:40 UTC (rev 52504)
+++ grass-addons/grass7/imagery/i.segment/write_output.c	2012-08-02 20:29:32 UTC (rev 52505)
@@ -18,7 +18,9 @@
     CELL *outbuf;
     DCELL *meanbuf;
     struct Colors colors;
+	struct History history;
 
+
     outbuf = Rast_allocate_c_buf();	/* hold one row of data to put into raster */
     meanbuf = Rast_allocate_d_buf();
 
@@ -51,13 +53,6 @@
 	G_percent(row, files->nrows, 1);
     }
 
-    /* TODO polish: update the data found by r.info
-     * current:         |   Data Description:                                                        |
-     *                          |    generated by i.segment                                                  |
-     * It would be nice to save the segmentation settings (just the CL?  Or something more human readable?)
-     * * MM: see e.g. i.pca for an example of setting custom info
-     */
-
     /* close and save file */
     Rast_close(out_fd);
     if (files->out_band != NULL)
@@ -68,6 +63,13 @@
     Rast_make_random_colors(&colors, 1, files->nrows * files->ncols);	/* TODO polish - number segments from 1 - max ? and then can use that max here. */
     Rast_write_colors(files->out_name, G_mapset(), &colors);
 
+	/* add command line to history */
+	/* todo polish, any other information that would be interesting?  Number of passes?  Number of segments made? */
+	/* see i.pca as an example of setting custom info */
+	Rast_short_history(files->out_name, "raster", &history);
+	Rast_command_history(&history);
+	Rast_write_history(files->out_name, &history);
+
     /* free memory */
     G_free(outbuf);
     G_free(meanbuf);
@@ -96,6 +98,7 @@
     G_debug(1, "destroying flags");
     flag_destroy(files->null_flag);
     flag_destroy(files->candidate_flag);
+    flag_destroy(files->seeds_flag);
 
     G_debug(1, "close_files() before link_cleanup()");
     link_cleanup(files->token);



More information about the grass-commit mailing list