[GRASS-SVN] r52006 - grass-addons/grass7/imagery/i.segment
svn_grass at osgeo.org
svn_grass at osgeo.org
Thu Jun 7 21:14:10 PDT 2012
Author: momsen
Date: 2012-06-07 21:14:09 -0700 (Thu, 07 Jun 2012)
New Revision: 52006
Modified:
grass-addons/grass7/imagery/i.segment/create_isegs.c
grass-addons/grass7/imagery/i.segment/iseg.h
grass-addons/grass7/imagery/i.segment/main.c
grass-addons/grass7/imagery/i.segment/parse_args.c
grass-addons/grass7/imagery/i.segment/write_output.c
Log:
create_isegs.c is just a draft, much to work out still. Other files with changes to support data structures and parameters.
Modified: grass-addons/grass7/imagery/i.segment/create_isegs.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/create_isegs.c 2012-06-07 23:03:39 UTC (rev 52005)
+++ grass-addons/grass7/imagery/i.segment/create_isegs.c 2012-06-08 04:14:09 UTC (rev 52006)
@@ -3,6 +3,7 @@
/* Currently only region growing is implemented */
#include <stdlib.h>
+#include <float.h> /* to get value of LDBL_MAX -> change this if there is a more usual grass way */
#include <grass/gis.h>
#include <grass/raster.h>
#include <grass/segment.h> /* segmentation library */
@@ -10,23 +11,52 @@
int create_isegs(struct files *files, struct functions *functions)
{
- int row, col, nrows, ncols;
- /* **************write fake data to test I/O portion of module */
+ int successflag = 1;
- /*picked this up in the file reading as well, just do it again? */
- nrows = Rast_window_rows();
- ncols = Rast_window_cols();
+ /* method specific parameter set up and memory allocation */
- /* initialize data structure */
- files->out_val = (int *)G_malloc(2 * sizeof(int));
+ if (functions->method == 1) { /*region growing */
+ /* nothing yet */
+ }
+
+ /*TODO: implement outer loop to process polygon interior, then all remaining pixels */
+ /* This loop could go in here, or outside in main (only make segmentation file for what is currently being processed.) */
+
+ G_debug(1, "Threshold: %g", functions->threshold);
+ G_debug(1, "segmentation method: %d", functions->method);
+
+
+ if (functions->method == 0)
+ successflag = io_debug(files, functions);
+ else if (functions->method == 1)
+ successflag = region_growing(files, functions);
+
+ if (successflag != 0)
+ G_fatal_error("Error creating segments");
+
+ /* end outer loop for processing polygons */
+
+ /* clean up */
+
+ /* should there be a free() for every malloc? Or only the large ones? */
+
+ return 0;
+}
+
+int io_debug(struct files *files, struct functions *functions)
+{
+ int row, col;
+
+ /* **************write fake data to test I/O portion of module */
+
G_verbose_message("writing fake data to segmentation file");
- for (row = 0; row < nrows; row++) {
- G_percent(row, nrows, 1); /*this didn't get displayed in the output??? Does it get erased when done? */
- for (col = 0; col < ncols; col++) {
- //files->out_val[0] = files->out_val[0]; /*segment number */ /* just copying the map for testing. */
- files->out_val[0] = col+2*row;
+ for (row = 0; row < files->nrows; row++) {
+ G_percent(row, files->nrows, 1); /*this didn't get displayed in the output??? Does it get erased when done? */
+ 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;
files->out_val[1] = 1; /*processing flag */
segment_put(&files->out_seg, (void *)files->out_val, row, col);
}
@@ -36,3 +66,212 @@
return 0;
}
+
+
+int region_growing(struct files *files, struct functions *functions)
+{
+ int row, col, n, t, pixel_neighbors[8][2]; /* could dynamically declare to be only 4 or 8 elements, but this is shorter for now */
+ double threshold, Ri_simularity, Rk_simularity, tempsim;
+ int endflag; /* =1 if there were no merges on that processing iteration */
+ int pathflag; /* =1 if we didn't find mutual neighbors, and should continue with Rk */
+ int mergeflag; /* =1 if we have mutually agreeing best neighbors */
+
+ /* Ri = current focus segment
+ * Rk = Ri's most similar neighbor
+ * Rkn = Rk's neighbors
+ * Rin = Ri's neigbors (as pixels or segments ?!?
+ */
+
+ G_verbose_message("Running region growing algorithm");
+
+ t = 0;
+
+ do {
+ /* for loop on t to slowly lower threshold. also check that endflag=0 */
+
+ threshold = functions->threshold; /* when implement t loop, this will be a function of t. */
+
+ endflag = 1;
+
+
+ /* Set candidate flag to true/1 for all pixels TODO: for polygon group, need to just set to true for those being processed */
+
+ for (row = 0; row < files->nrows; row++) {
+ for (col = 0; col < files->ncols; col++) {
+ segment_get(&files->out_seg, (void *)files->out_val, row, col); /*need to get, since we only want to change the flag, and not overwrite the segment value. */
+ /* TODO: if we are starting from seeds...and only allow merges between unassigned pixels
+ * and seeds/existing segments, then this needs an if (and will be very inefficient)
+ * maybe consider the sorted array, btree, map... but the number of seeds could still be high for a large map */
+ files->out_val[1] = 1; /*candidate pixel flag */
+ segment_put(&files->out_seg, (void *)files->out_val, row,
+ col);
+ }
+ }
+
+ /*process candidate pixels */
+
+ /*check each pixel, start the processing only if it is a candidate pixel */
+ for (row = 0; row < files->nrows; row++) {
+ for (col = 0; col < files->ncols; col++) {
+ segment_get(&files->out_seg, (void *)files->out_val, row,
+ col);
+ if (files->out_val[1] == 1) { /* out_val[1] is the candidate pixel flag */
+
+ /*TODO: need to empty/reset Ri, Rn, and Rk */
+ Ri = Rin = Rk = Rkn = NULL;
+
+ pathflag = 1;
+
+ while (pathflag == 1) { /*if don't find mutual neighbors on first try, will use Rk as next Ri. */
+
+ if (find_segment_neighbors(Ri, Rin) != 0) {
+ G_debug(1, "Couldn't find neighbors"); /*this could happen if there is a pixel surrounded by pixels that have already been processed */
+ pathflag = 0;
+ set candidate flag to false for this pixel;
+ }
+ else { /*found neighbors, go ahead until find mutually agreeing neighbors */
+
+ /* find Ri's most similar neighbor */
+ Ri_similarity
+ = LDBL_MAX;
+
+ for (each Rin) {
+ tempsim = calculate_simularity(Ri, one neighbor); /*set up as function pointer... */
+ if tempsim
+ <Ri_similarity {
+ Ri_similarity = tempsim;
+ Rk = current neighbor;
+ }
+ }
+
+ if (Rk != null(need correct null finding !) AND Ri_similarity < threshold) { /* small TODO: should this be < or <=? */
+
+ Rkn = Ri; /* we know Ri should be a neighbor of Rk *//*Todo: is there a way to skip similarity calculations on these? keep a count, and pop them before doing the similarity check? */
+ find_segment_neighbors(Rk, Rkn); /* data structure for Rk's neighbors, and pixels in Rk if we don't already have it */
+
+ /*find Rk's most similar neighbor */
+ Rk_similarity = Ri_simularity; /*Ri gets first priority - ties won't change anything, so we'll accept Ri and Rk as mutually best neighbors */
+
+ for (each Rkn) {
+ tempsim =
+ calculate_similarity(Rk,
+ one neighbor);
+ if (tempsim < Rk_similarity) {
+ Rk_similarity = tempsim;
+ break; /* exit loop here, we know that Ri and Rk aren't mutually best neighbors */
+ }
+ }
+
+ if (Rk_similarity == Ri_simularity) { /* so they agree, both are mutually most similar neighbors */
+ /* put these steps in merge_segments(Ri, Rk) function? */
+ update segment values for all pixels in Ri + Rk(mean) /* I assume this is a weighted mean? */
+ set candidate flag to false for all pixels in Ri + Rk /* do this at the same time, so there is only one segment_put statement */
+ endflag = 0; /* we've made at least one merge, so need another iteration */
+
+ pathflag = 0; /* go to next row,column pixel - end of Rk -> Ri chain since we found neighbors */
+ }
+ else { /* they weren't mutually best neighbors */
+ set candidate flag to false for all pixels in Ri; /* TODO !!!!!!!!!!!! hmm, maybe this raster should be its own data structure */
+
+ Rk
+ = Ri; /* note, this is the eCognition technique. Seems this is a bit faster, we already have segment membership pixels */
+ }
+ } /*end if Rk exists and < threshold */
+ } /* end else - Ri did have neighbors */
+ } /*end pathflag do loop */
+ } /*end if pixel is candidate pixel */
+ } /*next column */
+ } /*next row */
+
+ /* finished one pass for processing candidate pixels */
+
+ t++;
+ } while (endflag == 0);
+ /*end t loop */
+
+ /* TODO: free memory */
+
+ return 0;
+}
+
+int find_segment_neighbors(Ri, Rin)
+{
+
+ /* neighbor list will be a listing of pixels that are neighbors? Include segment numbers? Only include unique segments?
+ * Maybe the most complete return would be a structure array, structure to include the segment ID and a list of points in it?
+ * But the list of points would NOT be inclusive - just the points bordering the current segment...
+ */
+
+
+ /* Ri could be single pixel or list of pixels. */
+ /* Rin could have a list already, or could be empty ? Or just the head? */
+
+ /*local data structures... but maybe they should be allocated out in the main function, is it really slow to create/free on each pass? */
+
+ /* Ri : input parameter, list of pixels in the current segment */
+ to_check; /* queue or stack - need to check the neighbors of these pixels */
+ no_check; /* sorted array or btree: list of pixels (by row / column ?) that have been put into the to_check queue, been processed, or are not candidate pixels */
+
+ current_pixel; /*what data type? This will be the popped pixel in each loop. */
+ /* functions->pixel_neighbors ...array, 4 or 8 long. (Can be 4 or 8 neighbors to each pixel)
+ * functions->num_pn int, 4 or 8.
+
+ to_check = Ri; /*need to copy data, not just pointer... */
+ /* Put input in "current segment" list NOTE: in pseudo code, but think we should just pass Ri and use it directly */
+ no_check = Ri; /*need to copy data, not just pointer... */
+ /* empty "neighbor" list Note: in pseudo code, but think we just pass in Rin - it was already initialized, and later could have Ri data available to start from */
+
+ While(!empty(to_check)) {
+ current_pixel = pop next to_check element;
+ functions->(*find_pixel_neighbors) (current_pixel, pixel_neighbors);
+
+ for (n = 0; n < functions->num_pn; n++) {
+ if (!pixel_neighbor[n] in "don't check" list) {
+ put pixel_neighbor[n] in "don't check" list segment_get(&files->out_seg, (void *)files->out_val, pixel_neighbor[n][0], pixel_neighbor[n][1]); /*TODO : do I need a second "out_val" data structure? */
+
+ if (files->out_val[1] == 1) { /* valid candidate pixel */
+ put pixel_neighbor[n] in to_check; /*want to check this pixels neighbors */
+
+ if (files->out_val[0] = current segment ID)
+ put pixel_neighbor[n] in Ri
+ else
+ put pixel_neighbor[n] in Rin}
+ } /*end if for pixel_neighbor was in "don't check" list */
+ } /* end for loop - next neighbor */
+ } /* while to_check has more elements */
+
+ return 0;
+}
+
+find_four_pixel_neighbors(pixel, pixel_neighbors)
+{
+ /* north */
+ pixel_neighbors[0][1] = pixel column;
+ if (pixel row > 0)
+ pixel_neighbors[0][0] = pixel row + 1;
+ else
+ pixel_neighbors[0][0] = pixel row; /*This is itself, which will be in "already checked" list. TODO: use null or -1 as flag to skip? What is fastest to process? */
+
+ /* east */
+ pixel_neighbors[1][0] = pixel row;
+ if (pixel column < files->ncols)
+ pixel_neighbors[1][1] = pixel column + 1;
+ else
+ pixel_neighbors[1][1] = pixel column; /* ditto... */
+
+ /*TODO: continue for south and north */
+
+ /*TODO: seems there should be a more elegent way to do this... */
+ return 0;
+}
+
+find_eight_pixel_neighbors(pixel, neighbors)
+{
+ /* get the 4 orthogonal neighbors */
+ find_four_pixel_neighbors(pixel, neighbors);
+
+ /* get the 4 diagonal neighbors */
+
+ /*TODO... continue as above */
+ return 0;
+}
Modified: grass-addons/grass7/imagery/i.segment/iseg.h
===================================================================
--- grass-addons/grass7/imagery/i.segment/iseg.h 2012-06-07 23:03:39 UTC (rev 52005)
+++ grass-addons/grass7/imagery/i.segment/iseg.h 2012-06-08 04:14:09 UTC (rev 52006)
@@ -18,18 +18,25 @@
{
/* user parameters */
char *image_group;
-
+
+ /* region info */
+ int nrows, ncols;
+
+ /* files */
int nbands;
- SEGMENT bands_seg, out_seg; /* bands is for input, normal application is landsat bands, but other input can be included in the group. */
+ SEGMENT bands_seg, out_seg; /* bands is for input, normal application is landsat bands, but other input can be included in the group. */
double *bands_val; /* array, to hold all input values at one pixel */
- int *out_val; /* array, to hold the segment ID and processing flag(s) */
-
+ int *out_val; /* array, to hold the segment ID and processing flag(s) */
+ char *out_name; /* name of output raster map */
+
+ /* RASTER_MAP_TYPE data_type; Removed: input is always DCELL, output is CELL.
+ * TODO: if input might be smaller then DCELL, we could detect size and allocate accordingly. */
/*
- * Todo: Memory managment:
- * If we want to implement the option to load directly to memory
- * instead of declaring "SEGMENT" could we declare as void
- * then assign either a SEGMENT or a matrix during the get_input procedure?
- */
+ * Todo: Memory managment:
+ * If we want to implement the option to load directly to memory
+ * instead of declaring "SEGMENT" could we declare as void
+ * then assign either a SEGMENT or a matrix during the get_input procedure?
+ */
/* TODO: some parts of the data structure from i.smap
* confirm if there is any reason to be using them here
@@ -43,28 +50,27 @@
* Need to consider if they should be put in RAM or SEGMENT?
*/
- char *out_name; /* name of output raster map */
- /* RASTER_MAP_TYPE data_type; Removed: input is always DCELL, output is CELL.
- * TODO: if input might be smaller then DCELL, we could detect size and allocate accordingly. */
};
/* I think if I use function pointers, I can set up one time in the input
-* what similarity function, etc, will be used later in the processing
-* and make it easier to add additional variations later.
-*/
+ * what similarity function, etc, will be used later in the processing
+ * and make it easier to add additional variations later.
+ */
struct functions
{
+ int method; /* Segmentation method */
+ int (*find_pixel_neighbors) (int *[], int *[][]); /*pixel, pixel_neighbors *//*TODO need to define data types for these! */
/*based on options, such as diagonal neighbors, etc, some function pointers:
- * find_neighbor - point to euclidean or manhattan or ... neighbor function
- * calc_simularity
-*/
+ * calc_simularity
+ */
-
- float threshold; /* similarity threshold */
+ int num_pn; /* number of pixel neighbors int, 4 or 8. */
+ float threshold; /* similarity threshold */
+
};
/* parse_args.c */
@@ -74,9 +80,12 @@
/* open_files.c */
int open_files(struct files *);
+/* create_isegs.c */
+int create_isegs(struct files *, struct functions *);
+int io_debug(struct files *, struct functions *);
+int region_growing(struct files *, struct functions *);
+int find_segment_neighbors(Ri, Rin); /* TODO: need data structure for Ri, Rin */
+
/* write_output.c */
/* also currently closes files */
int write_output(struct files *);
-
-/* create_isegs.c */
-int create_isegs(struct files *, struct functions *);
Modified: grass-addons/grass7/imagery/i.segment/main.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/main.c 2012-06-07 23:03:39 UTC (rev 52005)
+++ grass-addons/grass7/imagery/i.segment/main.c 2012-06-08 04:14:09 UTC (rev 52006)
@@ -34,17 +34,23 @@
module = G_define_module();
G_add_keyword(_("imagery"));
G_add_keyword(_("segmentation"));
- module->description = _("Outputs a single segmention map (raster) based on input values in an image group.");
+ module->description =
+ _("Outputs a single segmention map (raster) based on input values in an image group.");
- parse_args(argc, argv, &files, &functions);
- G_debug(1, "Main: starting open_files()");
- open_files(&files);
-
+ if (parse_args(argc, argv, &files, &functions) != 0)
+ G_fatal_error("Error in parse_args()");
+
+ G_debug(1, "Main: starting open_files()");
+ if (open_files(&files) != 0)
+ G_fatal_error("Error in open_files()");
+
G_debug(1, "Main: starting create_isegs()");
- create_isegs(&files, &functions);
+ if (create_isegs(&files, &functions) != 0)
+ G_fatal_error("Error in create_isegs()");
- G_debug(1, "starting write_output...");
- write_output(&files);
+ G_debug(1, "Main: starting write_output()");
+ if (write_output(&files) != 0)
+ G_fatal_error("Error in write_output()");
G_done_msg("Number of segments created: ");
Modified: grass-addons/grass7/imagery/i.segment/parse_args.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/parse_args.c 2012-06-07 23:03:39 UTC (rev 52005)
+++ grass-addons/grass7/imagery/i.segment/parse_args.c 2012-06-08 04:14:09 UTC (rev 52006)
@@ -1,8 +1,10 @@
/* 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 files *files,
@@ -31,7 +33,7 @@
method->type = TYPE_STRING;
method->required = NO;
method->answer = "region_growing";
- method->options = "region_growing, io_debug";
+ method->options = "region_growing, io_debug"; /*io_debug just writes row+col to each output pixel */
method->description = _("Segmentation method.");
threshold = G_define_option();
@@ -77,21 +79,50 @@
/* Check and save parameters */
-
- files->image_group = group->answer;
-
- sscanf(threshold->answer, "%f", &functions->threshold);
+ files->image_group = group->answer;
+
/* TODO: I'm assuming it is already validated as a number. Is this OK, or is there a better way to cast the input? */
/* reference r.cost line 313
if (sscanf(opt5->answer, "%d", &maxcost) != 1 || maxcost < 0)
G_fatal_error(_("Inappropriate maximum cost: %d"), maxcost); */
- if (G_legal_filename(output->answer)==1)
- files->out_name = output->answer; /* name of output raster map */
- else
- G_fatal_error("Invalid output raster name.");
+ if (G_legal_filename(output->answer) == 1)
+ files->out_name = output->answer; /* name of output raster map */
+ else
+ G_fatal_error("Invalid output raster name.");
+ /* segmentation methods: 0 = debug, 1 = region growing */
+ if (strncmp(method->answer, "io_debug", 5) == 0)
+ functions->method = 0;
+ else if (strncmp(method->answer, "region_growing", 10) == 0)
+ functions->method = 1;
+ else
+ G_fatal_error("Couldn't assign segmentation method."); /*shouldn't be able to get here */
+
+ G_debug(1, "segmentation method: %d", functions->method);
+
+
+ sscanf(threshold->answer, "%f", &functions->threshold);
+
+ if (diagonal->answer == 0) {
+ functions->find_pixel_neighbors = &find_four_pixel_neighbors;
+ functions->num_pn = 4;
+ G_debug(1, "four pixel neighborhood");
+ }
+ else if (diagonal->answer == 1) {
+ functions->find_pixel_neighbors = &find_eight_pixel_neighbors;
+ functions->num_pn = 8;
+ G_debug(1, "eight (3x3) pixel neighborhood");
+ }
+
+ /* note from tutorial: You may have got to use the complete name of the member function
+ * including class-name and scope-operator (::).) */
+
+ /* other data */
+ files->nrows = Rast_window_rows();
+ files->ncols = Rast_window_cols();
+
return 0;
}
Modified: grass-addons/grass7/imagery/i.segment/write_output.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/write_output.c 2012-06-07 23:03:39 UTC (rev 52005)
+++ grass-addons/grass7/imagery/i.segment/write_output.c 2012-06-08 04:14:09 UTC (rev 52006)
@@ -9,15 +9,11 @@
int write_output(struct files *files)
{
- int out_fd, row, col, nrows, ncols;
+ int out_fd, row, col;
CELL *outbuf;
outbuf = Rast_allocate_c_buf(); /*hold one row of data to put into raster */
- /*picked this up in the file reading as well, just do it again? */
- nrows = Rast_window_rows();
- ncols = Rast_window_cols();
-
/* Todo: return codes are 1 for these, need to check and react to errors? programmer's manual didn't include it... */
segment_flush(&files->out_seg); /* force all data to disk */
@@ -30,9 +26,9 @@
/* transfer data from segmentation file to raster */
/* output segmentation file: each element includes the segment ID then processing flag(s). So just need the first part of it. */
- for (row = 0; row < nrows; row++) {
- G_percent(row, nrows, 1); /*TODO: Why isn't this getting printed? */
- for (col = 0; col < ncols; col++) {
+ for (row = 0; row < files->nrows; row++) {
+ G_percent(row, files->nrows, 1); /*TODO: Why isn't this getting printed? */
+ for (col = 0; col < files->ncols; col++) {
segment_get(&files->out_seg, (void *)files->out_val, row, col);
G_debug(5, "outval[0] = %i", files->out_val[0]);
outbuf[col] = files->out_val[0]; /*just want segment assignment, not the other processing flag(s) */
More information about the grass-commit
mailing list