Imagerで画像を回転させる
回転させるだけならrotateで出来るんだけど、
小ネギを直立させつつ、重なっている小ネギの判定も行う。
やることは、ラベリングした画像の回転と範囲の取得を繰り返して、
幅が最小になる角度を取得する。
重なりがあると、幅と高さの比がしきい値を下回らないので、
その範囲に存在する小ネギは無視する。
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 $cur_angle = .0;
my $cur_value = calc_evaluation_value( $img, $cur_angle );
my $step = 32.0;
while ( 0.1 < abs($step) ) {
my $new_angle = $cur_angle + $step;
my $new_value = calc_evaluation_value( $img, $new_angle );
printf( "Current %5.1f: %3d, New %5.1f: %3d\n",
$cur_angle, $cur_value,
$new_angle, $new_value );
if ( $new_value < $cur_value ) {
$cur_value = $new_value;
$cur_angle = $new_angle;
}
else {
$step *= -0.5;
}
}
$img->rotate( degrees => $cur_angle, back => 'black' )->write( file => $0 . '.png' );
sub calc_evaluation_value {
my ( $img, $rot_angle ) = @_;
my $img_tmp = $img->rotate(
degrees => $rot_angle, back => 'black' );
my $xmin = int( $img_tmp->getwidth() / 2 );
my $xmax = int( $img_tmp->getwidth() / 2 );
my $iy = $img_tmp->getheight();
while ( 0 < $iy-- ) {
my $tmp = $img_tmp->getsamples( y => $iy, channels => [0] );
my @pixels = unpack( 'C*', $tmp );
if ( grep { $_ == 255 } @pixels ) {
my $st = 0;
$st++ while $pixels[$st] != 255;
my $en = scalar(@pixels) - 1;
$en-- while $pixels[$en] != 255;
$xmin = $st if $st < $xmin;
$xmax = $en if $xmax < $en;
}
}
return $xmax - $xmin + 1;
}
あんまし、うまく書けた感じはしないけど、
前回に切り抜いて出力した画像を入力すると、ちゃんと直立する。
後者は重なっているので、幅と高さの比を見て重なり判定ができる。
もちろん、その前に余白を除いた画像を作り直す必要はあるけど。
おしまい。




Leave a Comment