Geo-Raster
view release on metacpan or search on metacpan
lib/Geo/Raster/Image.pm view on Meta::CPAN
# @param[in] p The upper left corner cell.
# @param[in] q The lower right corner cell.
# @param[in] value (optional) The value for the cells within the rectangle.
# @return the values of the cells within the rectangle if value is not
# given. The returned value is a reference to an anonymous array of
# the form: (\@cell, value, \@cell, value, ...).
sub rect {
my($self, $i1, $j1, $i2, $j2, $pen) = @_;
unless (defined $pen) {
return ral_grid_get_rect($self->{GRID}, $i1, $j1, $i2, $j2);
} else {
ral_grid_filled_rect($self->{GRID}, $i1, $j1, $i2, $j2, $pen);
}
}
## @method listref circle(@center, $r, $value)
#
# @brief Get or set the cells within a circle.
#
# @param[in] center The center cell of the circle.
# @param[in] r The radius of the circle.
# @param[in] value (optional) The value for the cells within the circle.
# @return the values of the cells within the circle if value is not
# given. The returned value is a reference to an anonymous array of
# the form: (\@cell, value, \@cell, value, ...).
sub circle {
my($self, $i, $j, $r, $pen) = @_;
unless (defined $pen) {
return ral_grid_get_circle($self->{GRID}, $i, $j, $r);
} else {
ral_grid_filled_circle($self->{GRID}, $i, $j, $r, $pen);
}
}
## @method void floodfill(@cell, $value, $connectivity)
#
# @brief Floodfill a zone.
#
# @param[in] cell A cell identifying the zone.
# @param[in] value New value for the zone.
# @param[in] connectivity (optional). Connectivity between cells,
# either 4 or 8. Default is 8.
sub floodfill {
my($self, $i, $j, $pen, $connectivity) = @_;
$connectivity = 8 unless $connectivity;
ral_grid_floodfill($self->{GRID}, $i, $j, $pen, $connectivity);
}
## @method Geo::Raster thin(%opt)
#
# @brief Thin lines in the raster.
#
# This is an implementation of the algorithm in Jang, B-K., Chin,
# R.T. 1990. Analysis of Thinning Algorithms Using Mathematical
# Morphology. IEEE Trans. Pattern Analysis and Machine
# Intelligence. 12(6). 541-551. (Same as in GRASS but done in a bit
# different, and more generic way, I believe).
#
# The thinning algorithm defines a set of structuring templates and
# applies them in several passes until there are no matches or until the
# maxiterations is reached. Trimming means certain structuring templates
# are applied to kill emerging short limbs which appear because of the
# noise in the raster.
#
# Exple of thinning:
# @code
# $thinned_img = $img->thin(%options);
# @endcode
# or
# @code
# $img->thin(%options);
# @endcode
#
# @param[in] opt Includes as named parameters:
# - <I>algorithm</I> => character (optional). By default "B", the other option
# is "A".
# - <I>trimming</I> => binary (optional). By default 0, the other option is 1.
# Trimming removes artificial branches which grow on the side of wide lines in
# thinnning, but it also shortens a bit the real branches.
# - <I>maxiterations</I> => integer (optional). By default 0 (no maximum, will
# iterate until no cells are deleted).
# - <I>width</I> => double (optional). Used to define the maximum iterations
# count. In case the width is given then the maxiterations is set to
# int(width/2).
# @return a new raster. In void context changes this raster.
# @note The thinned raster must be a binary raster.
sub thin {
my($self, %opt) = @_;
$self = Geo::Raster->new($self) if defined wantarray;
my @D1 = (+0,+0,-1,
+0,+1,+1,
-1,+1,-1);
my @D2 = (-1,+0,+0,
+1,+1,+0,
-1,+1,-1);
my @D3 = (-1,+1,-1,
+1,+1,+0,
-1,+0,+0);
my @D4 = (-1,+1,-1,
+0,+1,+1,
+0,+0,-1);
my @E1 = (-1,+0,-1,
+1,+1,+1,
-1,+1,-1);
my @E2 = (-1,+1,-1,
+1,+1,+0,
-1,+1,-1);
my @E3 = (-1,+1,-1,
+1,+1,+1,
-1,+0,-1);
my @E4 = (-1,+1,-1,
+0,+1,+1,
-1,+1,-1);
# G are the trimming templates
my @G1 = (-1,+1,-1,
+0,+1,+0,
+0,+0,+0);
my @G2 = (+0,+0,+1,
+0,+1,+0,
+0,+0,+0);
my @G3 = (+0,+0,-1,
+0,+1,+1,
+0,+0,-1);
my @G4 = (+0,+0,+0,
+0,+1,+0,
+0,+0,+1);
my @G5 = (+0,+0,+0,
+0,+1,+0,
-1,+1,-1);
my @G6 = (+0,+0,+0,
+0,+1,+0,
+1,+0,+0);
my @G7 = (-1,+0,+0,
+1,+1,+0,
-1,+0,+0);
my @G8 = (+1,+0,+0,
+0,+1,+0,
+0,+0,+0);
my @trimmer = (\@G1,\@G2,\@G3,\@G4,\@G5,\@G6,\@G7,\@G8);
my $algorithm = $opt{algorithm};
$algorithm = 'B' unless $algorithm;
my $trimming = $opt{trimming};
$trimming = 0 unless $trimming;
my $maxiterations = $opt{maxiterations};
$maxiterations = 0 unless $maxiterations;
my $width = $opt{width};
$maxiterations = int($width/2) if $width;
my @thinner;
if ($algorithm eq 'B') {
if ($trimming) {
@thinner = (\@D1,\@D2,\@E1,@trimmer,
\@D2,\@D3,\@E2,@trimmer,
\@D3,\@D4,\@E3,@trimmer,
\@D4,\@D1,\@E4,@trimmer);
} else {
@thinner = (\@D1, \@D2, \@E1, \@D2, \@D3, \@E2,
\@D3, \@D4, \@E3, \@D4, \@D1, \@E4);
}
} elsif ($algorithm eq 'A') {
if ($trimming) {
@thinner = (\@D1, \@E1, @trimmer,
\@D2, \@E2, @trimmer,
\@D3, \@E3, @trimmer,
\@D4, \@E4, @trimmer);
} else {
@thinner = (\@D1, \@E1, \@D2, \@E2, \@D3, \@E3, \@D4, \@E4);
}
} else {
croak "thin: $algorithm: unknown algorithm";
}
my ($m, $M, $i) = (0,0,1);
do {
$M = $m;
foreach (@thinner) {
$m += ral_grid_applytempl($self->{GRID}, $_, 0);
print STDERR "#" unless $opt{quiet};
}
print STDERR " thinning, pass $i/$maxiterations: deleted ", $m-$M, " cells\n" unless $opt{quiet};
$i++;
} while ($m > $M and !($maxiterations > 0 and $i > $maxiterations));
return $self if defined wantarray;
}
## @method Geo::Raster borders(%params)
#
# @brief Borders between zones.
#
# This method returns a binary raster, where the borders have the
# value of 1.
#
# @param[in] params Named parameters:
# - <I>method</I> => string (optional). Either simple or
# recursive. Default is recursive.
# @return a new raster. In void context changes this raster.
sub borders {
my($self, %opt) = @_;
$opt{method} = 'recursive' unless $opt{method};
if ($opt{method} eq 'simple') {
if (defined wantarray) {
my $g = new Geo::Raster(ral_grid_borders($self->{GRID}));
return $g;
} else {
$self->_new_grid(ral_grid_borders($self->{GRID}));
}
} elsif ($opt{method} eq 'recursive') {
if (defined wantarray) {
my $g = new Geo::Raster(ral_grid_borders_recursive($self->{GRID}));
return $g;
} else {
$self->_new_grid(ral_grid_borders_recursive($self->{GRID}));
}
} else {
croak "borders: $opt{method}: unknown method";
}
}
## @method Geo::Raster areas($k)
#
# @brief Marks if cell belong to an area.
#
# @param[in] k (optional). A cell is part of an area if there are at least k
# consecutive nonzero cells as neighbors and the cell has also a nonzero value.
# By default the value is 3, in which case the smallest area is 2*2 cells.
# @return a new raster. In void context changes this raster.
# @note The grid has to have as datatype integer.
sub areas {
my $self = shift;
my $k = shift;
$k = 3 unless $k;
if (defined wantarray) {
my $g = new Geo::Raster(ral_grid_areas($self->{GRID}, $k));
return $g;
} else {
$self->_new_grid(ral_grid_areas($self->{GRID}, $k));
}
}
## @method Geo::Raster connect()
#
# @brief Connects broken lines.
( run in 0.659 second using v1.01-cache-2.11-cpan-71847e10f99 )