Imagerでラベリングするのおさらい
久々なので、リファクタリングしておさらいしてみる。
あんまし、お行儀の良い書き方じゃないけど、
こんな感じで、塗りつぶし領域の結果を取得すると、
ちょっと無理矢理だけど、手を抜くことが出来る。
use v5.14;
use strict;
use warnings;
use Imager;
if ( (not @ARGV) or (not -e $ARGV[0]) ) {
say "Usage:
perl $0 file_path";
exit( 0 );
}
my $img = Imager->new( file => $ARGV[0] )
or die Imager->errstr();
my $img_dst = $img->convert( preset => 'rgb' ); # gray -> rgb
my $h = $img->getheight();
my ( $ix, $iy ) = ( 0, 0 );
my $area_no = 1;
while ( $iy < $h ) {
my $tmp = $img->getsamples( y => $iy, channels => [0] );
my @pixels = unpack( 'C*', $tmp );
my $found = 0;
while ( $ix < scalar(@pixels) ) {
if ( $pixels[$ix] == 255 ) {
my $c = Imager::Color->new( $area_no, $area_no, $area_no );
$img->flood_fill( x => $ix, y => $iy, color => $c );
my $area = calc_filled_area( $img, $area_no, $ix, $iy );
print_area_info( $area_no, $area );
$img_dst->box( color => 'red', %{$area} );
$area_no++;
$found = 1;
last;
}
$ix++;
}
if ( not $found ) {
$ix = 0;
$iy++;
}
if ( 255 < $area_no ) {
die 'area_no = ', $area_no, ' too many areas! sorry.';
}
}
sub calc_filled_area {
my ( $img, $area_no, $filled_x, $filled_y ) = @_;
my ( $xmin, $xmax ) = ( $filled_x, $filled_x );
my ( $ymin, $ymax ) = ( $filled_y, $filled_y );
my $h = $img->getheight();
my $iy = $ymin;
while ( $iy < $h ) {
my $tmp = $img->getsamples( y => $iy, channels => [0] );
my @pixels = unpack( 'C*', $tmp );
my $found = grep { $_ == $area_no } @pixels;
if ( $found ) {
my $st = 0;
$st++ while $pixels[$st] != $area_no;
my $en = scalar(@pixels) - 1;
$en-- while $pixels[$en] != $area_no;
$xmin = $st if $st < $xmin;
$xmax = $en if $xmax < $en;
}
if ( not $found ) {
last;
}
else {
$ymax = $iy;
$iy++;
}
}
return +{
xmin => $xmin,
ymin => $ymin,
xmax => $xmax,
ymax => $ymax
};
}
sub print_area_info {
my ( $area_no, $area ) = @_;
printf( "area_no = %3d, (x, y) = (%4d, %4d), w = %4d, h = %4d",
$area_no,
$area->{xmin},
$area->{ymin},
$area->{xmax} - $area->{xmin} + 1,
$area->{ymax} - $area->{ymin} + 1 );
print "\n";
}
$img_dst->write( file => $0 . '.png' );
結果は、こんな感じ。
入力画像がモノクロだったので、
赤線で枠を描画する前に、RGBに変換してる。
やりたいことは、
1つ1つ切り抜いて、垂直になるように回転して、
高さでソートしつつ、それをGIFアニメとしてファイル出力したい。
次は、回転後の画像を1つの画像に集めることかな。
おしまい。

Leave a Comment