[GRASS-SVN] r52053 - grass-addons/grass7/imagery/i.segment
svn_grass at osgeo.org
svn_grass at osgeo.org
Tue Jun 12 16:03:05 PDT 2012
Author: momsen
Date: 2012-06-12 16:03:03 -0700 (Tue, 12 Jun 2012)
New Revision: 52053
Added:
grass-addons/grass7/imagery/i.segment/open_files.c
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:
Modified: grass-addons/grass7/imagery/i.segment/create_isegs.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/create_isegs.c 2012-06-12 21:45:12 UTC (rev 52052)
+++ grass-addons/grass7/imagery/i.segment/create_isegs.c 2012-06-12 23:03:03 UTC (rev 52053)
@@ -16,7 +16,7 @@
int successflag = 1;
- /* method specific parameter set up and memory allocation */
+ /* TODO consider if there are _method specific_ parameter set up and memory allocation, should that happen here? */
if (functions->method == 1) { /*region growing */
@@ -24,28 +24,24 @@
}
/*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.) */
+ /* This loop could go in here, or in main to contain open/create/write to reduced memory reqs. But how merge the writes? */
G_debug(1, "Threshold: %g", functions->threshold);
G_debug(1, "segmentation method: %d", functions->method);
if (functions->method == 0)
- successflag = io_debug(files, functions); /* TODO: why does it want &files in main, but files here ??? */
+ successflag = io_debug(files, functions); /* TODO: why does it want `&files` in main, but `files` here ??? */
else if (functions->method == 1) {
G_debug(1, "starting region_growing()");
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;
+ return successflag;
}
int io_debug(struct files *files, struct functions *functions)
@@ -56,7 +52,7 @@
G_verbose_message("writing fake data to segmentation file");
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? */
+ G_percent(row, files->nrows, 1); /* TODO 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;
@@ -65,8 +61,10 @@
}
}
- /* TODO: free memory */
+ /* spot to test things... */
+
+
return 0;
}
@@ -83,7 +81,7 @@
/* Ri = current focus segment
* Rk = Ri's most similar neighbor
* Rkn = Rk's neighbors
- * Rin = Ri's neigbors (as pixels or segments ?!?
+ * Rin = Ri's neigbors (as pixels or segments ?) currently as pixels, so repeat calculations are made when multiple neighbors in same segment
*/
/* lets get this running, and just use fixed dimension arrays for now. t is limited to 90, segments will be small. */
@@ -95,21 +93,23 @@
G_verbose_message("Running region growing algorithm");
t = 0;
+ files->candidate_count = 0;
do {
- /* for loop on t to slowly lower threshold. also check that endflag=0 */
+ /* do while 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. */
+ G_debug(1,
+ "############# Starting outer do loop! t = %d ###############",
+ t);
+ threshold = functions->threshold; /* TODO, consider making this 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++) { -----need to deal with edges.... */
- for (row = 1; row < files->nrows - 1; row++) {
- for (col = 1; col < files->ncols - 1; col++) {
+ 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)
@@ -117,18 +117,30 @@
files->out_val[1] = 1; /*candidate pixel flag */
segment_put(&files->out_seg, (void *)files->out_val, row,
col);
+
+ files->candidate_count++; /*TODO this assumes full grid with no null or mask!! But need something to prevent "pathflag" infinite loop */
+
}
}
- G_debug(1, "Starting to process candidate pixels");
+ G_debug(1, "Starting to process %d candidate pixels",
+ files->candidate_count);
+
/*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 */
+ G_verbose_message("Completion for pass number %d: ", t);
+ G_percent(row, files->nrows, 1); /*this didn't get displayed in the output??? Does it get erased when done? */
+
+ G_debug(1,
+ "Next starting pixel from next row/col, not from Rk");
+ segment_get(&files->out_seg, (void *)files->out_val, row, col); /*TODO small time savings - if candidate_count reaches zero, bail out of these loops too? */
+ if (files->out_val[1] == 1) { /* out_val[1] is the candidate pixel flag, want to process the 1's */
+
+ /* ... need to switch to lists/stacks/maps... */
+
/*need to empty/reset Ri, Rn, and Rk */
/* TODO: this will be different when Ri is different data structure. */
for (n = 0; n < 100; n++) {
@@ -137,95 +149,151 @@
}
}
Rin_count = Rkn_count = Rk_count = 0;
+
+ /* First pixel in Ri is current pixel. We may add more later if it is part of a segment */
Ri_count = 1; /*we'll have the focus pixel to start with. */
- /* First pixel in Ri is current pixel. We may add more later if it is part of a segment */
Ri[0][0] = row;
Ri[0][1] = col;
- /* Ri_seg = files->out_val[0]; don't need this here -have it in merge_segments() *//* out_val[0] is segment ID, we still have data from call to check the flag. *//* TODO: if seperate segment ID from flag, need to get this value. */
pathflag = 1;
- while (pathflag == 1) { /*if don't find mutual neighbors on first try, will use Rk as next Ri. */
- G_debug(1, "just before find_segment_neighbors(Ri)");
- if (find_segment_neighbors
- (Ri, Rin, Ri_count, Rin_count, files,
- functions) != 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;
- Ri_count = 0;
- set_candidate_flag(Ri, 0, files); /* TODO: error trap? */
- }
- else { /*found neighbors, go ahead until find mutually agreeing neighbors */
- G_debug(1, "Found neighbors");
- /* find Ri's most similar neighbor */
- Rk_id = -1;
- Ri_similarity = LDBL_MAX; /* set current similarity to max value */
- segment_get(&files->bands_seg, (void *)files->bands_val, Ri[0][0], Ri[0][1]); /* current segment values */
+ // while (pathflag == 1 && files->candidate_count > 0) { /*if don't find mutual neighbors on first try, will use Rk as next Ri. */
- for (n = 0; n < Rin_count; n++) { /* for each of Ri's neighbors */
- tempsim = (*functions->calculate_similarity) (Ri[0], Rin[n], files, functions); /*TODO: does this pass just the single point, row/col ???? */
- if (tempsim < Ri_similarity) {
- Ri_similarity = tempsim;
- Rk_id = n;
- }
+ G_debug(1, "Next starting pixel: row, %d, col, %d",
+ Ri[0][0], Ri[0][1]);
+
+ /* Setting Ri to be not a candidate allows using "itself" when at edge of raster.
+ * Otherwise need to use a list/count/something to know the number of pixel neighbors */
+ set_candidate_flag(Ri, 0, 0, files); /* TODO: error trap? */
+ G_debug(1, "line 165, \t\t\t\tcc = %d",
+ files->candidate_count);
+
+
+ /* find segment neighbors */
+ if (find_segment_neighbors
+ (Ri, Rin, &Ri_count, &Rin_count, files,
+ functions) != 0) {
+ G_fatal_error("find_segment_neighbors() failed");
+ }
+
+ if (Rin_count == 0) {
+ G_debug(1, "2a, Segment had no valid neighbors"); /*this could happen if there is a segment surrounded by pixels that have already been processed */
+ pathflag = 0;
+ Ri_count = 0;
+ set_candidate_flag(Ri, Ri_count, 0, files); /* TODO: error trap? */
+ files->candidate_count++; /* already counted out Ri[0]; */
+ G_debug(1, "line 176, \t\t\t\tcc = %d",
+ files->candidate_count);
+ }
+ else { /*found neighbors, go ahead until find mutually agreeing neighbors */
+
+ G_debug(1, "2b, Found Ri's pixels");
+ /*print out neighbors */
+ for (n = 0; n < Ri_count; n++)
+ G_debug(1, "Ri %d: row: %d, col: %d", n, Ri[n][0],
+ Ri[n][1]);
+
+ G_debug(1, "2b, Found Ri's neighbors");
+ /*print out neighbors */
+ for (n = 0; n < Rin_count; n++)
+ G_debug(1, "Rin %d: row: %d, col: %d", n,
+ Rin[n][0], Rin[n][1]);
+
+ /* find Ri's most similar neighbor */
+ Rk_id = -1;
+ Ri_similarity = LDBL_MAX; /* set current similarity to max value */
+ segment_get(&files->bands_seg, (void *)files->bands_val, Ri[0][0], Ri[0][1]); /* current segment values */
+
+ for (n = 0; n < Rin_count; n++) { /* for each of Ri's neighbors */
+ tempsim = (*functions->calculate_similarity) (Ri[0], Rin[n], files, functions); /*TODO: does this pass just the single point, row/col ???? */
+ G_debug(1,
+ "simularity = %g for neighbor %d: row: %d, col %d.",
+ tempsim, n, Rin[n][0], Rin[n][1]);
+ if (tempsim < Ri_similarity) {
+ Ri_similarity = tempsim;
+ Rk_id = n;
}
+ }
- if (Rk_id >= 0 && Ri_similarity < threshold) { /* small TODO: should this be < or <= for threshold? */
- /*we'll have the neighbor pixel to start with. */
- Rk_count = 1;
- Rk[0][0] = Rin[Rk_id][0];
- Rk[0][1] = Rin[Rk_id][1];
+ G_debug(1,
+ "Lowest Ri_similarity = %g, for neighbor pixel Rk_id (n) = %d",
+ Ri_similarity, Rk_id);
- /* 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, Rk_count, Rkn_count, files, functions); /* data structure for Rk's neighbors, and pixels in Rk if we don't already have it */
+ if (Rk_id >= 0 && Ri_similarity < threshold) { /* small TODO: should this be < or <= for threshold? */
+ /* we'll have the neighbor pixel to start with. */
+ G_debug(1, "3a: Working with Rk");
+ Rk_count = 1;
+ Rk[0][0] = Rin[Rk_id][0];
+ Rk[0][1] = Rin[Rk_id][1];
- /*find Rk's most similar neighbor */
- Rk_similarity = Ri_similarity; /*Ri gets first priority - ties won't change anything, so we'll accept Ri and Rk as mutually best neighbors */
- segment_get(&files->bands_seg, (void *)files->bands_val, Rk[0][0], Rk[0][1]); /* current segment values */
+ /* 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, &Rk_count, &Rkn_count, files, functions); /* data structure for Rk's neighbors, and pixels in Rk if we don't already have it */
- for (n = 0; n < Rkn_count; n++) { /* for each of Rk's neighbors */
- tempsim =
- functions->calculate_similarity(Rk[0],
- Rkn
- [n],
- files,
- functions);
- if (tempsim < Rk_similarity) {
- Rk_similarity = tempsim;
- break; /* exit for Rk's neighbors loop here, we know that Ri and Rk aren't mutually best neighbors */
- }
- }
+ G_debug(1, "Found Rk's pixels");
+ /*print out neighbors */
+ for (n = 0; n < Rk_count; n++)
+ G_debug(1, "Rk %d: row: %d, col: %d", n,
+ Rk[n][0], Rk[n][1]);
- if (Rk_similarity == Ri_similarity) { /* so they agree, both are mutually most similar neighbors */
- /* TODO: put these steps in merge_segments(Ri, Rk) function? */
- merge_values(Ri, Rk, Ri_count, Rk_count, files); /* TODO error trap */
- endflag = 0; /* we've made at least one merge, so need another t iteration */
- pathflag = 0; /* go to next row,column pixel - end of Rk -> Ri chain since we found mutual best neighbors */
+ G_debug(1, "Found Rk's neighbors");
+ /*print out neighbors */
+ for (n = 0; n < Rkn_count; n++)
+ G_debug(1, "Rkn %d: row: %d, col: %d", n,
+ Rkn[n][0], Rkn[n][1]);
+
+ /*find Rk's most similar neighbor */
+ Rk_similarity = Ri_similarity; /*Ri gets first priority - ties won't change anything, so we'll accept Ri and Rk as mutually best neighbors */
+ segment_get(&files->bands_seg, (void *)files->bands_val, Rk[0][0], Rk[0][1]); /* current segment values */
+
+ for (n = 0; n < Rkn_count; n++) { /* for each of Rk's neighbors */
+ tempsim = functions->calculate_similarity(Rk[0], Rkn[n], files, functions); /*TODO: need an error trap here, if something goes wrong with calculating similarity? */
+ if (tempsim < Rk_similarity) {
+ Rk_similarity = tempsim;
+ break; /* exit for Rk's neighbors loop here, we know that Ri and Rk aren't mutually best neighbors */
}
- else { /* they weren't mutually best neighbors */
- set_candidate_flag(Ri, 0, files); /* remove Ri from candidate pixels (set flag) */
+ }
- /* Use Rk as next Ri: this is the eCognition technique. Seems this is a bit faster, we already have segment membership pixels */
- Ri_count = Rk_count;
- /* Ri = &Rk; *//* TODO fast/correct way to use arrays and pointers? Ri now will just point to Rk? */
- /* at beginning, when initialize Rk ` Rk[n][m] = 0 ` ?? with that just remove the Rk pointer, and leave Ri pointing to the original Rk data? */
- for (n = 0; n < 100; n++) { /*TODO shortcut code...get rid of this... */
- for (m = 0; m < 2; m++) {
- Ri[n][m] = Rk[n][m];
- }
- }
+ if (Rk_similarity == Ri_similarity) { /* so they agree, both are mutually most similar neighbors, none of Rk's other neighbors were more similar */
+ /* TODO: put these steps in merge_segments(Ri, Rk) function? */
+ merge_values(Ri, Rk, Ri_count, Rk_count, files); /* TODO error trap */
+ endflag = 0; /* we've made at least one merge, so need another t iteration */
+ pathflag = 0; /* go to next row,column pixel - end of Rk -> Ri chain since we found mutual best neighbors */
+ }
+ else { /* they weren't mutually best neighbors */
+ G_debug(1,
+ "Ri was not Rk's best neighbor, Ri_sim: %g, Rk_sim, %g",
+ Ri_similarity, Rk_similarity);
- }
- } /*end if Rk exists and < threshold */
- } /* end else - Ri did have neighbors */
- } /*end pathflag do loop */
+ /* did this at beginning of trail loop */
+ set_candidate_flag(Ri, Ri_count, 0, files); /* remove all Ri members from candidate pixels (set flag) */
+ files->candidate_count++; /* add one back, we had already set Ri[0] flag at the beginning. */
+ G_debug(1, "line 247, \t\t\t\tcc = %d",
+ files->candidate_count);
+ //~ /* Use Rk as next Ri: this is the eCognition technique. Seems this is a bit faster, we already have segment membership pixels */
+ //~ Ri_count = Rk_count;
+ //~ /* Ri = &Rk; *//* TODO fast/correct way to use arrays and pointers? Ri now will just point to Rk? */
+ //~ /* at beginning, when initialize Rk ` Rk[n][m] = 0 ` ?? with that just remove the Rk pointer, and leave Ri pointing to the original Rk data? */
+ //~ for (n = 0; n < 100; n++) { /*TODO shortcut code...get rid of this... */
+ //~ for (m = 0; m < 2; m++) {
+ //~ Ri[n][m] = Rk[n][m];
+ //~ }
+ //~ }
+
+ }
+ } /*end if Rk exists and < threshold */
+ else
+ G_debug(1,
+ "3b Rk didn't didn't exist or similarity was > 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 */
+ G_debug(1, "Finished one pass, t was = %d", t);
t++;
} while (t < 90 && endflag == 0);
/*end t loop */
@@ -235,11 +303,11 @@
return 0;
}
-int find_segment_neighbors(int Ri[][2], int Rin[][2], int seg_count,
- int segn_count, struct files *files,
+int find_segment_neighbors(int Ri[][2], int Rin[][2], int *seg_count,
+ int *segn_count, struct files *files,
struct functions *functions)
{
- G_debug(1, "in find_segment_neighbors()");
+ // G_debug(1, "\tin find_segment_neighbors()");
int n, m, Ri_seg_ID = -1;
/* neighbor list will be a listing of pixels that are neighbors? Include segment numbers? Only include unique segments?
@@ -248,78 +316,105 @@
*/
- /* Ri could be single pixel or list of pixels. */
- /* Rin could have a list already, or could be empty ? Or just the head? */
+ /* parameter: Ri, current segment membership, could be single pixel or list of pixels. */
+ /* parameter: Rin, neighbor pixels, could have a list already, or could be empty ? Or just the head of a list? */
- /*local data structures... but maybe they should be allocated out in the main function, is it really slow to create/free on each pass? */
+ /* TODO 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 */
int to_check[100][2]; /* queue or stack - need to check the neighbors of these pixels */
+ /* put no_check in files structure for now... */
/* int[100][2] 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 */
/* or use flag for no_check? ... need a better name for this variable??? */
- int pixel_neighbors[8][2]; /* data type? put in files to allocate memory once? */
+ int val_no_check = -1; /*value of the no_check flag for the particular pixel. */
- int current_pixel = 0; /*what data type? This will be the popped pixel in each loop. */
+ int pixel_neighbors[8][2]; /* TODO: data type? put in files to allocate memory once? */
- /* functions->pixel_neighbors ...array, 4 or 8 long. (Can be 4 or 8 neighbors to each pixel)
- * functions->num_pn int, 4 or 8. */
+ int current_pixel = 0; /* TODO: for now, row index for pixel_neighbors[][]. With linked list will be the popped pixel in each loop. */
+ /* Notes, these are in fucntions structure:
+ * functions->num_pn int, 4 or 8, for number of pixel neighbors */
+
/*initialize data.... TODO: maybe remember min max row/col that was looked at each time, initialize in open_files, and reset smaller region at end of this functions */
- G_debug(1, "setting files->no_check to 0...");
- for (n = 0; n < files->nrows; n++)
- for (m = 0; n < files->ncols; n++)
- files->no_check[n][m] = 0; /* 0 means should be checked/expanded, 1 means it has already been checked/expanded. */
+ for (n = 0; n < files->nrows; n++) {
+ for (m = 0; m < files->ncols; m++) {
+ val_no_check = 0;
+ segment_put(&files->no_check, &val_no_check, n, m);
+ }
+ }
- G_debug(1, "setting to_check to 0");
-
for (n = 0; n < 100; n++) {
for (m = 0; m < 2; m++) {
- to_check[n][m] = files->no_check[n][m] = 0;
+ to_check[n][m] = 0;
}
}
/* Put Ri in to be checked and no check lists (don't expand them if we find them again) */
/* NOTE: in pseudo code also have a "current segment" list, but think we can just pass Ri and use it directly */
- G_debug(1, "Setting up Ri... ");
- for (n = 0; n < seg_count; n++) {
+ for (n = 0; n < *seg_count; n++) {
to_check[n][0] = Ri[n][0];
to_check[n][1] = Ri[n][1];
- files->no_check[Ri[n][0]][Ri[n][1]] = 1;
+ val_no_check = 1;
+ segment_put(&files->no_check, &val_no_check, Ri[n][0], Ri[n][1]);
+
}
- /* 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 */
+ /* empty "neighbor" list Note: this step is in pseudo code, but think we just pass in Rin - it was already initialized, and later could have Ri data available to start from */
/* get Ri's segment ID */
segment_get(&files->out_seg, (void *)files->out_val, Ri[0][0], Ri[0][1]);
- Ri_seg_ID = files->out_val[1];
- G_debug(1, "initializing is done, start processing");
- while (current_pixel >= 0) { /* change to not empty once there is a stack... */
- G_debug(1, "current_pixel: %d", current_pixel);
+ Ri_seg_ID = files->out_val[0];
+
+ while (current_pixel >= 0) { /* change to not empty once there is a linked list... */
+ G_debug(1, "\tfind neighbors(): current_pixel: %d", current_pixel);
/* current_pixel = pop next to_check element; */
- /*syntax for function pointer? functions->(*find_pixel_neighbors) (to_check[current_pixel], pixel_neighbors, files); */
- functions->find_pixel_neighbors(to_check[current_pixel],
+
+ G_debug(1,
+ "\tbefore fpn: to_check[current_pixel][0] %d , to_check[current_pixel][1] %d",
+ to_check[current_pixel][0], to_check[current_pixel][1]);
+
+ functions->find_pixel_neighbors(to_check[current_pixel][0],
+ to_check[current_pixel][1],
pixel_neighbors, files);
current_pixel--; /* Done using this pixels coords, now check neighbors and add to the lists */
- G_debug(1, "found pixel neighbors");
- for (n = 0; n < functions->num_pn; n++) { /*with pixel neighbors */
- if (files->no_check[pixel_neighbors[n][0]][pixel_neighbors[n][1]] == 0) { /* want to check this neighbor */
- files->no_check[pixel_neighbors[n][0]][pixel_neighbors[n][1]] = 1; /* OK, check it, but don't check it again! */
+ G_debug(1,
+ "\tafter fpn: to_check[current_pixel][0] %d , to_check[current_pixel][1] %d",
+ to_check[current_pixel][0], to_check[current_pixel][1]);
+
+ /*debug what neighbors were found: */
+ /* for (n = 0; n < functions->num_pn; n++){
+ G_debug(1, "\tpixel_neighbors[n][0]: %d, pixel_neighbors[n][1]: %d", pixel_neighbors[n][0], pixel_neighbors[n][1]);
+ } */
+
+ for (n = 0; n < functions->num_pn; n++) { /* with pixel neighbors */
+
+ segment_get(&files->no_check, &val_no_check,
+ pixel_neighbors[n][0], pixel_neighbors[n][1]);
+ G_debug(1,
+ "\twith pixel neighbor %d, row: %d col: %d, val_no_check = %d",
+ n, pixel_neighbors[n][0], pixel_neighbors[n][1],
+ val_no_check);
+ if (val_no_check == 0) { /* want to check this neighbor */
+ val_no_check = 1;
+ segment_put(&files->no_check, &val_no_check,
+ pixel_neighbors[n][0], pixel_neighbors[n][1]);
+
segment_get(&files->out_seg, (void *)files->out_val, pixel_neighbors[n][0], pixel_neighbors[n][1]); /*TODO : do I need a second "out_val" data structure? */
if (files->out_val[1] == 1) { /* valid candidate pixel */
- G_debug(1, "files->out_val[0] = %d Ri_seg_ID = %d",
+ G_debug(1, "\tfiles->out_val[0] = %d Ri_seg_ID = %d",
files->out_val[0], Ri_seg_ID);
if (files->out_val[0] == Ri_seg_ID) {
- G_debug(1, "puting pixel_neighbor in Ri");
+ G_debug(1, "\tputing pixel_neighbor in Ri");
/* put pixel_neighbor[n] in Ri */
- Ri[seg_count][0] = pixel_neighbors[n][0];
- Ri[seg_count][1] = pixel_neighbors[n][1];
- seg_count++; /* zero index... so increment after save data. */
+ Ri[*seg_count][0] = pixel_neighbors[n][0];
+ Ri[*seg_count][1] = pixel_neighbors[n][1];
+ *seg_count = *seg_count + 1; /* zero index... Ri[0] had first pixel and set count =1. increment after save data. */
+ G_debug(1, "\t*seg_count now = %d", *seg_count);
/* put pixel_neighbor[n] in to_check -- want to check this pixels neighbors */
current_pixel++;
@@ -329,9 +424,9 @@
}
else {
/* put pixel_neighbor[n] in Rin */
- Rin[segn_count][0] = pixel_neighbors[n][0];
- Rin[segn_count][1] = pixel_neighbors[n][1];
- segn_count++;
+ Rin[*segn_count][0] = pixel_neighbors[n][0];
+ Rin[*segn_count][1] = pixel_neighbors[n][1];
+ *segn_count = *segn_count + 1;
}
} /*end if valid candidate pixel */
} /*end if for pixel_neighbor was in "don't check" list */
@@ -341,51 +436,51 @@
return 0;
}
-int find_four_pixel_neighbors(int pixel[2], int pixel_neighbors[][2],
+int find_four_pixel_neighbors(int p_row, int p_col, int pixel_neighbors[][2],
struct files *files)
{
- /*
- G_debug(1,"in find 4 pixel neighbors () ");
- G_debug(1,"pixel row: %d pixel col: %d", pixel[0], pixel[1]);
- G_debug(1, "Total rows: %d, total cols: %d", files->nrows, files->ncols); /*check that we have files... */
+ /*
+ G_debug(1,"\t\tin find 4 pixel neighbors () ");
+ G_debug(1,"\t\tpixel row: %d pixel col: %d", p_row, p_col);
+ G_debug(1, "\t\tTotal rows: %d, total cols: %d", files->nrows, files->ncols); *//*check that we have files... */
/* north */
- pixel_neighbors[0][1] = pixel[1];
- if (pixel[0] > 0)
- pixel_neighbors[0][0] = pixel[0] + 1;
+ pixel_neighbors[0][1] = p_col;
+ if (p_row > 0)
+ pixel_neighbors[0][0] = p_row - 1;
else
- pixel_neighbors[0][0] = pixel[0]; /*This is itself, which will be in "already checked" list. TODO: use null or -1 as flag to skip? What is fastest to process? */
+ pixel_neighbors[0][0] = p_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[0];
- if (pixel[1] < files->ncols)
- pixel_neighbors[1][1] = pixel[1] + 1;
+ pixel_neighbors[1][0] = p_row;
+ if (p_col < files->ncols - 1)
+ pixel_neighbors[1][1] = p_col + 1;
else
- pixel_neighbors[1][1] = pixel[1];
+ pixel_neighbors[1][1] = p_col;
/* south */
- pixel_neighbors[2][1] = pixel[1];
- if (pixel[0] < files->nrows)
- pixel_neighbors[2][0] = pixel[0] - 1;
+ pixel_neighbors[2][1] = p_col;
+ if (p_row < files->nrows - 1)
+ pixel_neighbors[2][0] = p_row + 1;
else
- pixel_neighbors[2][0] = pixel[0];
+ pixel_neighbors[2][0] = p_row;
/* west */
- pixel_neighbors[3][0] = pixel[0];
- if (pixel[1] < 0)
- pixel_neighbors[3][1] = pixel[1] - 1;
+ pixel_neighbors[3][0] = p_row;
+ if (p_col > 0)
+ pixel_neighbors[3][1] = p_col - 1;
else
- pixel_neighbors[3][1] = pixel[1];
+ pixel_neighbors[3][1] = p_col;
/*TODO: seems there should be a more elegent way to do this... */
return 0;
}
-int find_eight_pixel_neighbors(int pixel[2], int pixel_neighbors[8][2],
- struct files *files)
+int find_eight_pixel_neighbors(int p_row, int p_col,
+ int pixel_neighbors[8][2], struct files *files)
{
/* get the 4 orthogonal neighbors */
- find_four_pixel_neighbors(pixel, pixel_neighbors, files);
+ find_four_pixel_neighbors(p_row, p_col, pixel_neighbors, files);
/* get the 4 diagonal neighbors */
@@ -394,14 +489,15 @@
}
/* similarity / distance between two points based on their input raster values */
-/* TODO: I pulled getting the a values into the main function, they are stored in files. Remove a from these parameters */
+/* assumes first point values already saved in files->bands_seg - only run segment_get once for that value... */
+/* TODO: segment_get already happened for a[] values in the main function. Could remove a[] from these parameters */
double calculate_euclidean_similarity(int a[2], int b[2], struct files *files,
struct functions *functions)
{
double val = 0;
int n;
- /* get comparison values for point b (got values for a before loop on all neighbors... */
+ /* get values for point b[] */
segment_get(&files->bands_seg, (void *)files->second_val, b[0], b[1]);
/* euclidean distance, sum the square differences for each dimension */
@@ -417,7 +513,7 @@
int merge_values(int Ri[100][2], int Rk[100][2], int Ri_count, int Rk_count,
struct files *files)
-{ /* I assume this is a weighted mean? */
+{ /* TODO: correct assumption that this should be a weighted mean. */
int n;
/*get input values, maybe if handle earlier gets correctly this can be avoided. */
@@ -436,38 +532,60 @@
segment_get(&files->out_seg, (void *)files->out_val, Ri[0][0], Ri[0][1]);
files->out_val[1] = 0; /*candidate pixel flag, only one merge allowed per t iteration */
+ /* if separate out candidate flag, can do all changes with helper function...otherwise remember: */
+ G_debug(1, "\t\tMerging, segment number: %d, including pixels:",
+ files->out_val[0]);
+
/* for each member of Ri and Rk, write new average bands values and segment values */
for (n = 0; n < Ri_count; n++) {
segment_put(&files->bands_seg, (void *)files->bands_val, Ri[n][0],
Ri[n][1]);
segment_put(&files->out_seg, (void *)files->out_val, Ri[n][0],
Ri[n][1]);
+ files->candidate_count--;
+ G_debug(1, "line 508, \t\t\t\tcc = %d", files->candidate_count);
+ G_debug(1, "\t\tRi row: %d, col: %d", Ri[n][0], Ri[n][1]);
}
for (n = 0; n < Rk_count; n++) {
segment_put(&files->bands_seg, (void *)files->bands_val, Rk[n][0],
Rk[n][1]);
segment_put(&files->out_seg, (void *)files->out_val, Rk[n][0],
Rk[n][1]);
+ files->candidate_count--;
+ G_debug(1, "line 516, \t\t\t\tcc = %d", files->candidate_count);
+ G_debug(1, "\t\tRk row: %d, col: %d", Rk[n][0], Rk[n][1]);
+
}
+ files->candidate_count++; /* had already counted down the starting pixel Ri[0] at the beginning... */
+ G_debug(1, "line 522, \t\t\t\tcc = %d", files->candidate_count);
return 0;
}
/* TODO.. helper function, maybe make more general? */
-int set_candidate_flag(int Ri[100][2], int value, struct files *files)
+int set_candidate_flag(int Ri[100][2], int count, int value,
+ struct files *files)
{
/* Ri is list of pixels, value is new value of flag */
int n;
/* TODO: Ri data structure... eventually just need to process all pixels in Ri. */
- for (n = 0; n < 100; n++) {
+ for (n = 0; n <= count; n++) {
segment_get(&files->out_seg, (void *)files->out_val, Ri[n][0], Ri[n][1]); /* this may change... */
files->out_val[1] = value; /*candidate pixel flag */
segment_put(&files->out_seg, (void *)files->out_val, Ri[n][0],
Ri[n][1]);
+ /* also increment how many pixels remain to be processed */
+
+ if (value == 0)
+ files->candidate_count--;
+ else if (value == 1)
+ files->candidate_count++;
+ G_debug(1, "line 544, \t\t\t\tcc = %d", files->candidate_count);
+
}
return 0;
}
Modified: grass-addons/grass7/imagery/i.segment/iseg.h
===================================================================
--- grass-addons/grass7/imagery/i.segment/iseg.h 2012-06-12 21:45:12 UTC (rev 52052)
+++ grass-addons/grass7/imagery/i.segment/iseg.h 2012-06-12 23:03:03 UTC (rev 52053)
@@ -24,14 +24,14 @@
/* files */
int nbands;
+ int candidate_count; /*how many candidate pixels remain */
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 */
double *second_val; /* to hold values at second point for similarity comparison */
int *out_val; /* array, to hold the segment ID and processing flag(s) */
char *out_name; /* name of output raster map */
- /*int **no_check; *//* TODO maybe as SEGMENT. Also can this be smaller then an int? Just need to save 0 and 1. */
- int no_check[100][2];
+ SEGMENT no_check; /* pixels that have already been checked during this neighbor finding routine */
/* 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. */
@@ -56,25 +56,27 @@
};
-
-/* 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.
- */
-
struct functions
{
int method; /* Segmentation method */
- int (*find_pixel_neighbors) (int[2], int[8][2], struct files *); /*pixel, pixel_neighbors */
- double (*calculate_similarity) (int[2], int[2], struct files *,
+
+ /* Some function pointers to set one time in parse_args() */
+ int (*find_pixel_neighbors) (int, int, int[8][2], struct files *); /*parameters: row, col, pixel_neighbors */
+ double (*calculate_similarity) (int[2], int[2], struct files *, /*parameters: two points (row,col) to compare */
struct functions *);
- int num_pn; /* number of pixel neighbors int, 4 or 8. */
-
+ int num_pn; /* number of pixel neighbors int, 4 or 8. TODO: can remove if pixel neighbors is list instead of array. But maybe this one is small enough that is faster as array? */
float threshold; /* similarity threshold */
};
+struct pixel
+{
+ int row;
+ int col;
+ struct pixel *next;
+};
+
/* parse_args.c */
/* gets input from user, validates, and sets up functions */
int parse_args(int, char *[], struct files *, struct functions *);
@@ -86,15 +88,15 @@
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(int[][2], int[][2], int, int, struct files *, struct functions *); /* TODO: need data structure for Ri, Rin */
-int set_candidate_flag(int[100][2], int, struct files *);
+int find_segment_neighbors(int[][2], int[][2], int *, int *, struct files *, struct functions *); /* TODO: need data structure for Ri, Rin */
+int set_candidate_flag(int[100][2], int, int, struct files *);
int merge_values(int[100][2], int[100][2], int, int, struct files *); /* I assume this is a weighted mean? */
-int find_four_pixel_neighbors(int[2], int[][2], struct files *);
-int find_eight_pixel_neighbors(int[2], int[8][2], 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(int[2], int[2], struct files *,
struct functions *);
/* write_output.c */
-/* also currently closes files */
int write_output(struct files *);
+int close_files(struct files *);
Modified: grass-addons/grass7/imagery/i.segment/main.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/main.c 2012-06-12 21:45:12 UTC (rev 52052)
+++ grass-addons/grass7/imagery/i.segment/main.c 2012-06-12 23:03:03 UTC (rev 52053)
@@ -38,20 +38,28 @@
_("Outputs a single segmention map (raster) based on input values in an image group.");
if (parse_args(argc, argv, &files, &functions) != 0)
- G_fatal_error("Error in parse_args()");
+ G_debug(1, "Error in parse_args()"); /* TODO: should these be debug or G_fatal_error() or nested if statement? want to clean up mem and temp files */
G_debug(1, "Main: starting open_files()");
if (open_files(&files) != 0)
- G_fatal_error("Error in open_files()");
+ G_debug(1, "Error in open_files()");
G_debug(1, "Main: starting create_isegs()");
if (create_isegs(&files, &functions) != 0)
- G_fatal_error("Error in create_isegs()");
+ G_debug(1, "Error in create_isegs()");
G_debug(1, "Main: starting write_output()");
if (write_output(&files) != 0)
- G_fatal_error("Error in write_output()");
+ G_debug(1, "Error in write_output()");
+ G_debug(1, "Main: starting close_files()");
+ close_files(&files);
+
+ /* TODO - G_fatal_error() called in sub routines - do I need to run close_files() before quitting?
+ * http://rackerhacker.com/2010/03/18/sigterm-vs-sigkill/
+ * "Standard C applications have a header file that contains the steps that the process should follow if it receives a particular signal. "
+ * */
+
G_done_msg("Number of segments created: ");
exit(EXIT_SUCCESS);
Added: grass-addons/grass7/imagery/i.segment/open_files.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/open_files.c (rev 0)
+++ grass-addons/grass7/imagery/i.segment/open_files.c 2012-06-12 23:03:03 UTC (rev 52053)
@@ -0,0 +1,140 @@
+/* PURPOSE: opening input rasters and creating segmentation files */
+
+#include <stdlib.h>
+#include <grass/gis.h>
+#include <grass/glocale.h>
+#include <grass/imagery.h>
+#include <grass/segment.h> /* segmentation library */
+#include "iseg.h"
+
+int open_files(struct files *files)
+{
+ struct Ref Ref; /* group reference list */
+ int *in_fd;
+ int n, row, col, srows, scols, inlen, outlen, nseg;
+ DCELL **inbuf; /* buffer array, to store lines from each of the imagery group rasters */
+
+
+ G_debug(1, "Checking image group...");
+ /* references: i.cost r.watershed/seg and http://grass.osgeo.org/programming7/segmentlib.html */
+
+ /* ****** open the input rasters ******* */
+
+ /* TODO, this is from i.smap/openfiles.c lines 17-23 checked if subgroup had maps, does API handles the checks? */
+
+ if (!I_get_group_ref(files->image_group, &Ref))
+ G_fatal_error(_("Unable to read REF file for group <%s>"),
+ files->image_group);
+
+ if (Ref.nfiles <= 0)
+ G_fatal_error(_("Group <%s> contains no raster maps"),
+ files->image_group);
+
+ /* Read Imagery Group */
+
+ in_fd = G_malloc(Ref.nfiles * sizeof(int));
+ inbuf = (DCELL **) G_malloc(Ref.nfiles * sizeof(DCELL *));
+
+ G_debug(1, "Opening input rasters...");
+ for (n = 0; n < Ref.nfiles; n++) {
+ inbuf[n] = Rast_allocate_d_buf();
+ in_fd[n] = Rast_open_old(Ref.file[n].name, Ref.file[n].mapset);
+ }
+
+
+ /* ********** find out file segmentation size ************ */
+ G_debug(1, "Calculate temp file sizes...");
+
+ files->nbands = Ref.nfiles;
+
+ /* size of each element to be stored */
+
+ inlen = sizeof(double) * Ref.nfiles;
+ outlen = sizeof(int) * 2; /* change in write_output.c if this value changes TODO: better to save this in the files data structure? */
+
+ /*TODO: i.cost and i.watershed take different approaches...hardcode for now */
+ /* when fine tuning, should be a power of 2 and not larger than 256 for speed reasons */
+ srows = 64;
+ scols = 64;
+
+ /* TODO: make calculations for this */
+ nseg = 8;
+
+
+ /* ******* create temporary segmentation files ********* */
+ G_debug(1, "Getting temporary file names...");
+ /* Initalize access to database and create temporary files */
+
+ G_debug(1, "Image size: %d rows, %d cols", files->nrows, files->ncols);
+ G_debug(1, "Segmented to tiles with size: %d rows, %d cols", srows,
+ scols);
+ G_debug(1, "Data element size, in: %d , out: %d ", inlen, outlen);
+ G_debug(1, "number of segments to have in memory: %d", nseg);
+
+ /* size: reading all input bands as DCELL TODO: could consider checking input to see if it is all FCELL or CELL, could reduce memory requirements. */
+
+ if (segment_open
+ (&files->bands_seg, G_tempfile(), files->nrows, files->ncols, srows,
+ scols, inlen, nseg) != 1)
+ G_fatal_error("Unable to create input temporary files");
+
+ G_debug(1, "finished segment_open(...bands_seg...)");
+
+ /* TODO: signed integer gives a 2 billion segment limit, depending on how the initialization is done, this means 2 billion max input pixels. */
+ if (segment_open
+ (&files->out_seg, G_tempfile(), files->nrows, files->ncols, srows,
+ scols, outlen, nseg) != 1)
+ G_fatal_error("Unable to create output temporary files");
+
+ if (segment_open(&files->no_check, G_tempfile(), files->nrows, files->ncols, srows, scols, sizeof(int), nseg) != 1) /* todo could make this smaller ? just need 0 or 1 */
+ G_fatal_error("Unable to create flag temporary files");
+
+ /* load input bands to segment structure */
+ G_debug(1, "Reading input rasters into segmentation data files...");
+
+ files->bands_val = (double *)G_malloc(inlen);
+ files->second_val = (double *)G_malloc(inlen);
+
+ for (row = 0; row < files->nrows; row++) {
+ for (n = 0; n < Ref.nfiles; n++) {
+ Rast_get_d_row(in_fd[n], inbuf[n], row);
+ }
+ for (col = 0; col < files->ncols; col++) {
+ for (n = 0; n < Ref.nfiles; n++) {
+ files->bands_val[n] = inbuf[n][col];
+ }
+ segment_put(&files->bands_seg, (void *)files->bands_val, row,
+ col);
+ }
+ }
+
+ /* Initialize output segmentation file */
+
+ G_debug(1, "G_malloc size: = <%d>", (int)(2 * sizeof(int)));
+ files->out_val = (int *)G_malloc(2 * sizeof(int));
+
+ n = 1;
+ for (row = 0; row < files->nrows; row++) {
+ for (col = 0; col < files->ncols; col++) {
+ files->out_val[0] = n; /*starting segment number TODO: for seeds this will be different */
+ files->out_val[1] = 0; /*flag */
+ segment_put(&files->out_seg, (void *)files->out_val, row, col);
+ n++; /* sequentially number all pixels with their own segment ID */
+ }
+ }
+
+ files->candidate_count = 0; /* counter for remaining candidate pixels */
+
+ /* Free memory */
+
+ for (n = 0; n < Ref.nfiles; n++) {
+ Rast_close(in_fd[n]);
+ }
+
+ G_free(inbuf);
+ G_free(in_fd);
+
+ /* Need to clean up anything else? */
+
+ return 0;
+}
Modified: grass-addons/grass7/imagery/i.segment/parse_args.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/parse_args.c 2012-06-12 21:45:12 UTC (rev 52052)
+++ grass-addons/grass7/imagery/i.segment/parse_args.c 2012-06-12 23:03:03 UTC (rev 52053)
@@ -84,17 +84,13 @@
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.");
/* segmentation methods: 0 = debug, 1 = region growing */
+ /* TODO, instead of string compare, does the Option structure have these already numbered? */
if (strncmp(method->answer, "io_debug", 5) == 0)
functions->method = 0;
@@ -105,7 +101,10 @@
G_debug(1, "segmentation method: %d", functions->method);
-
+ /* TODO: I'm assuming threshold 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); */
sscanf(threshold->answer, "%f", &functions->threshold);
if (diagonal->answer == 0) {
@@ -119,9 +118,6 @@
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 (::).) */
-
/* TODO add user input for this */
functions->calculate_similarity = &calculate_euclidean_similarity;
Modified: grass-addons/grass7/imagery/i.segment/write_output.c
===================================================================
--- grass-addons/grass7/imagery/i.segment/write_output.c 2012-06-12 21:45:12 UTC (rev 52052)
+++ grass-addons/grass7/imagery/i.segment/write_output.c 2012-06-12 23:03:03 UTC (rev 52053)
@@ -1,5 +1,5 @@
/* transfer the segmented regions from the segmented data file to a raster file */
-/* put closing segment files here for now, OK to combine or better to put in a seperate function? */
+/* close_files() function is at bottom */
#include <stdlib.h>
#include <grass/gis.h>
@@ -36,17 +36,26 @@
Rast_put_row(out_fd, outbuf, CELL_TYPE);
}
+ /* close and save file */
+ Rast_close(out_fd);
+ return 0;
+}
+
+int close_files(struct files *files)
+{
/* close segmentation files and output raster */
G_debug(1, "closing files");
segment_close(&files->bands_seg);
segment_close(&files->out_seg);
- Rast_close(out_fd);
+ segment_close(&files->no_check);
- for (n = 0; n < files->nrows; n++)
- G_free(files->no_check[n]);
- G_free(files->no_check);
+ /* close segmentation files and output raster */
+ G_free(files->bands_val);
+ G_free(files->second_val);
+ G_free(files->out_val);
+
/* anything else left to clean up? */
return 0;
More information about the grass-commit
mailing list