[GRASS-SVN] r59122 - grass/trunk/raster/r.clump
svn_grass at osgeo.org
svn_grass at osgeo.org
Sat Feb 22 05:23:21 PST 2014
Author: mmetz
Date: 2014-02-22 05:23:21 -0800 (Sat, 22 Feb 2014)
New Revision: 59122
Modified:
grass/trunk/raster/r.clump/clump.c
grass/trunk/raster/r.clump/local_proto.h
grass/trunk/raster/r.clump/main.c
grass/trunk/raster/r.clump/r.clump.html
Log:
r.clump: add flag to also consider diagonal neighbors
Modified: grass/trunk/raster/r.clump/clump.c
===================================================================
--- grass/trunk/raster/r.clump/clump.c 2014-02-21 22:25:14 UTC (rev 59121)
+++ grass/trunk/raster/r.clump/clump.c 2014-02-22 13:23:21 UTC (rev 59122)
@@ -4,6 +4,7 @@
* MODULE: r.clump
*
* AUTHOR(S): Michael Shapiro - CERL
+ * Markus Metz
*
* PURPOSE: Recategorizes data in a raster map layer by grouping cells
* that form physically discrete areas into unique categories.
@@ -24,7 +25,7 @@
#define INCR 1024
-
+/* 4 neighbor algorithm */
CELL clump(int in_fd, int out_fd)
{
register int col;
@@ -246,6 +247,228 @@
return 0;
}
+/* 8 neighbor algorithm */
+CELL clumpd(int in_fd, int out_fd)
+{
+ register int col;
+ register CELL *prev_clump, *cur_clump;
+ register CELL *index, *index2;
+ register int n;
+ CELL *prev_in, *cur_in;
+ CELL *temp_cell, *temp_clump, *out_cell;
+ CELL X, UP, LEFT, UL, UR, NEW, OLD;
+ CELL label;
+ int nrows, ncols;
+ int row;
+ int len;
+ int pass;
+ int nalloc;
+ long cur_time;
+ int column;
+
+ nrows = Rast_window_rows();
+ ncols = Rast_window_cols();
+
+ /* allocate clump index */
+ nalloc = INCR;
+ index = (CELL *) G_malloc(nalloc * sizeof(CELL));
+ index[0] = 0;
+ index2 = NULL;
+
+ /* allocate CELL buffers two columns larger than current window */
+ len = (ncols + 2) * sizeof(CELL);
+ prev_in = (CELL *) G_malloc(len);
+ cur_in = (CELL *) G_malloc(len);
+ prev_clump = (CELL *) G_malloc(len);
+ cur_clump = (CELL *) G_malloc(len);
+ out_cell = (CELL *) G_malloc(len);
+
+/******************************** PASS 1 ************************************
+ * first pass thru the input simulates the clump to determine
+ * the reclumping index.
+ * second pass does the clumping for real
+ */
+ time(&cur_time);
+ for (pass = 1; pass <= 2; pass++) {
+ /* second pass must generate a renumbering scheme */
+ if (pass == 2) {
+ CELL cat;
+
+ cat = 1;
+ index2 = (CELL *) G_malloc((label + 1) * sizeof(CELL));
+ index2[0] = 0;
+ for (n = 1; n <= label; n++) {
+ OLD = n;
+ NEW = index[n];
+ if (OLD != NEW) {
+ /* find final clump id */
+ while (OLD != NEW) {
+ OLD = NEW;
+ NEW = index[OLD];
+ }
+ index[n] = NEW;
+ }
+ else
+ index2[n] = cat++;
+ }
+ }
+
+ /* fake a previous row which is all zero */
+ Rast_set_c_null_value(prev_in, ncols + 2);
+ G_zero(prev_clump, len);
+
+ /* set left and right edge to NULL */
+ Rast_set_c_null_value(&cur_in[0], 1);
+ Rast_set_c_null_value(&cur_in[ncols + 1], 1);
+
+ /* create a left and right edge of zero */
+ G_zero(cur_clump, len);
+
+ /* initialize clump labels */
+ label = 0;
+
+ G_message(_("Pass %d..."), pass);
+ for (row = 0; row < nrows; row++) {
+ Rast_get_c_row(in_fd, cur_in + 1, row);
+
+ G_percent(row, nrows, 4);
+ X = 0;
+ Rast_set_c_null_value(&X, 1);
+ for (col = 1; col <= ncols; col++) {
+ LEFT = X;
+ X = cur_in[col];
+ if (Rast_is_c_null_value(&X)) { /* don't clump NULL data */
+ cur_clump[col] = 0;
+ continue;
+ }
+
+ UL = prev_in[col - 1];
+ UP = prev_in[col];
+ UR = prev_in[col + 1];
+
+ /*
+ * if the cell value is different above and to the left
+ * then we must start a new clump
+ *
+ * this new clump may eventually collide with another
+ * clump and have to be merged
+ */
+ if (X != LEFT && X != UP && X != UL && X != UR) { /* start a new clump */
+ label++;
+ cur_clump[col] = label;
+ if (pass == 1) {
+ if (label >= nalloc) {
+ nalloc += INCR;
+ index =
+ (CELL *) G_realloc(index,
+ nalloc * sizeof(CELL));
+ }
+ index[label] = label;
+ }
+ continue;
+ }
+ OLD = NEW = 0;
+ if (X == LEFT) { /* same clump as to the left */
+ OLD = cur_clump[col - 1];
+ cur_clump[col] = OLD;
+ }
+ /* check UL, UP, UR */
+ n = 2;
+ temp_clump = prev_clump + col + 1;
+ temp_cell = prev_in + col + 1;
+ do {
+ if (X == *temp_cell) {
+ if (OLD == 0) {
+ OLD = *temp_clump;
+ cur_clump[col] = OLD;
+ }
+ else {
+ NEW = *temp_clump;
+ cur_clump[col] = NEW;
+ }
+ }
+ if (NEW != 0)
+ break;
+ temp_cell--;
+ temp_clump--;
+ } while (n-- > 0);
+
+ if (NEW == 0 || OLD == NEW) { /* ok */
+ continue;
+ }
+
+ /* conflict! preserve the clump from above and change the left.
+ * Must also go back to the left in the current row and to the right
+ * in the previous row to change all the clump values as well.
+ *
+ */
+
+ /* left of the current row from 1 to col - 1 */
+ temp_clump = cur_clump;
+ n = col - 1;
+ while (n-- > 0) {
+ temp_clump++; /* skip left edge */
+ if (*temp_clump == OLD)
+ *temp_clump = NEW;
+ }
+
+ /* right of previous row from col + 1 to ncols */
+ temp_clump = prev_clump;
+ temp_clump += col;
+ n = ncols - col;
+ while (n-- > 0) {
+ temp_clump++; /* skip col */
+ if (*temp_clump == OLD)
+ *temp_clump = NEW;
+ }
+
+ /* modify the indexes
+ if (pass == 1)
+ for (n = 1; n <= label; n++)
+ if (index[n] == OLD)
+ index[n] = NEW;
+ */
+
+ if (pass == 1)
+ index[OLD] = NEW;
+ }
+
+ if (pass == 2) {
+ /*
+ for (col = 1; col <= ncols; col++)
+ out_cell[col] = index[cur_clump[col]];
+
+ Rast_put_row (out_fd, out_cell+1, CELL_TYPE);
+ */
+ temp_clump = cur_clump;
+ temp_cell = out_cell;
+
+ for (column = 0; column < ncols; column++) {
+ temp_clump++; /* skip left edge */
+ *temp_cell = index2[index[*temp_clump]];
+ if (*temp_cell == 0)
+ Rast_set_null_value(temp_cell, 1, CELL_TYPE);
+ temp_cell++;
+ }
+ Rast_put_row(out_fd, out_cell, CELL_TYPE);
+ }
+
+ /* switch the buffers so that the current buffer becomes the previous */
+ temp_cell = cur_in;
+ cur_in = prev_in;
+ prev_in = temp_cell;
+
+ temp_clump = cur_clump;
+ cur_clump = prev_clump;
+ prev_clump = temp_clump;
+ }
+ G_percent(1, 1, 1);
+
+ print_time(&cur_time);
+ }
+ return 0;
+}
+
int print_time(long *start)
{
int hours, minutes, seconds;
Modified: grass/trunk/raster/r.clump/local_proto.h
===================================================================
--- grass/trunk/raster/r.clump/local_proto.h 2014-02-21 22:25:14 UTC (rev 59121)
+++ grass/trunk/raster/r.clump/local_proto.h 2014-02-22 13:23:21 UTC (rev 59122)
@@ -21,6 +21,7 @@
/* clump.c */
CELL clump(int, int);
+CELL clumpd(int, int);
int print_time(long *);
/* main.c */
Modified: grass/trunk/raster/r.clump/main.c
===================================================================
--- grass/trunk/raster/r.clump/main.c 2014-02-21 22:25:14 UTC (rev 59121)
+++ grass/trunk/raster/r.clump/main.c 2014-02-22 13:23:21 UTC (rev 59122)
@@ -27,6 +27,7 @@
{
struct Colors colr;
struct Range range;
+ struct History hist;
CELL min, max;
int in_fd, out_fd;
char title[512];
@@ -37,6 +38,7 @@
struct Option *opt_in;
struct Option *opt_out;
struct Option *opt_title;
+ struct Flag *flag_diag;
G_gisinit(argv[0]);
@@ -60,6 +62,11 @@
opt_title->required = NO;
opt_title->description = _("Title for output raster map");
+ flag_diag = G_define_flag();
+ flag_diag->key = 'd';
+ flag_diag->label = _("Clump also diagonal cells");
+ flag_diag->description = _("Clumps are also traced along diagonal neighboring cells");
+
/* parse options */
if (G_parser(argc, argv))
exit(EXIT_FAILURE);
@@ -73,7 +80,10 @@
out_fd = Rast_open_c_new(OUTPUT);
- clump(in_fd, out_fd);
+ if (flag_diag->answer)
+ clumpd(in_fd, out_fd);
+ else
+ clump(in_fd, out_fd);
G_debug(1, "Creating support files...");
@@ -86,13 +96,20 @@
strcpy(title, opt_title->answer);
else
sprintf(title, "clump of <%s@%s>", name, G_mapset());
-
Rast_put_cell_title(OUTPUT, title);
+
+ /* colors */
Rast_read_range(OUTPUT, G_mapset(), &range);
Rast_get_range_min_max(&range, &min, &max);
Rast_make_random_colors(&colr, min, max);
Rast_write_colors(OUTPUT, G_mapset(), &colr);
+ /* history */
+ Rast_short_history(OUTPUT, "raster", &hist);
+ Rast_set_history(&hist, HIST_DATSRC_1, INPUT);
+ Rast_command_history(&hist);
+ Rast_write_history(OUTPUT, &hist);
+
G_done_msg(_("%d clumps."), range.max);
exit(EXIT_SUCCESS);
Modified: grass/trunk/raster/r.clump/r.clump.html
===================================================================
--- grass/trunk/raster/r.clump/r.clump.html 2014-02-21 22:25:14 UTC (rev 59121)
+++ grass/trunk/raster/r.clump/r.clump.html 2014-02-22 13:23:21 UTC (rev 59122)
@@ -1,8 +1,9 @@
<h2>DESCRIPTION</h2>
<em>r.clump</em> finds all areas of contiguous cell category values in
-the input raster map. It assigns a unique category value to each such
-area ("clump") in the resulting output raster map.
+the input raster map. NULL values in the input are ignored. It assigns
+a unique category value to each such area ("clump") in the
+resulting output raster map.
<p>
Category distinctions in the input raster map are preserved. This
@@ -14,18 +15,18 @@
<h2>NOTES</h2>
-<em>r.clump</em> moves a 2x2 matrix over the input raster map. The
-lower right-hand corner of the matrix is grouped with the cells above
-it, or to the left of it (diagonal cells are not considered.)
+By default, the resulting clumps are connected only by their four
+direct neighbors (left, right, top, bottom). The <em>-d</em> flag
+activates also diagonal clump tracing.
<p>
-<em>r.clump</em> works properly with raster map that contain only
+<em>r.clump</em> works properly with raster map that contains only
"fat" areas (more than a single cell in width). Linear
elements (lines that are a single cell wide) may or may not be clumped
together depending on the direction of the line - horizontal and
vertical lines of cells are considered to be contiguous, but diagonal
lines of cells are not considered to be contiguous and are broken up
-into separate clumps.
+into separate clumps unless the <em>-d</em> flag is used.
<p>
A random color table and other support files are generated for the
@@ -50,7 +51,8 @@
<h2>AUTHOR</h2>
Michael Shapiro, U.S. Army Construction Engineering Research
-Laboratory
+Laboratory<br>
+Markus Metz (diagonal clump tracing)
<p>
<i>Last changed: $Date$</i>
More information about the grass-commit
mailing list