とりあえずHSVでフィニッシュ


ん〜。やっぱりHSVでの判定ですかね・・・?

ということで、先日のヤツを部分的に手直しした物をベベっと貼っておこう。

ソースさん(一部)

#!perl

 (省略)
 # どっかで &pickup_image_colors(ファイル名)みたいに呼ぶ。
 # 戻り値は、成功1/失敗0, 一つ目の色, 二つ目の色 で返ってきます。

sub pickup_image_colors {
 my($file, $width, $height, $hantei) = @_;
 if(! $file) {return(0);} # Miss
 if(! $width) {$width = 100;}
 if(! $height) {$height = $width;}
 if(! $hantei) {$hantei = 432;}
 my $rate_sum = 0;
 my @color = (
  ['blacK' , 0, 0],
  ['Blue'  , 1, 0],
  ['Green' , 2, 0],
  ['Cyan'  , 3, 0],
  ['Red'   , 4, 0],
  ['Purple', 5, 0],
  ['Yellow', 6, 0],
  ['White' , 7, 0],
 );

 GD::Image->trueColor(1);
 my $srcimage = GD::Image->new($file);
 if(! $srcimage) {return(0);} # Miss
 my($src_width, $src_height) = $srcimage->getBounds();

 # サイズを変更して処理する
 my $image = GD::Image->new($width, $height);
 if(! $image) {return(0);} # Miss
 $image->copyResampled($srcimage, 0,0, 0,0, $width,$height, $src_width,$src_height);
 if(! $image) {return(0);} # Miss

 for(my $y = 0; $y < $height; $y++) {
  for(my $x = 0; $x < $width; $x++) {
   # get pixel color
   my($h, $s, $v) = &rgb_to_hsv($image->rgb($image->getPixel($x, $y)));

   # rate setting
   my $rate = 1;
   $rate_sum += $rate;

   # HSV
   if(($hantei - ($s * 8) > $v) || ($hantei - ($v * 8) > $s)) {
    if($v < 121) {$color[0][2] += $rate;} # blacK
    else         {$color[7][2] += $rate;} # White
   } else {
    if   ($h <  40) {$color[4][2] += $rate;} # Red
    elsif($h <  75) {$color[6][2] += $rate;} # Yellow
    elsif($h < 150) {$color[2][2] += $rate;} # Green
    elsif($h < 210) {$color[3][2] += $rate;} # Cyan
    elsif($h < 270) {$color[1][2] += $rate;} # Blue
    elsif($h < 330) {$color[5][2] += $rate;} # Purple
    else            {$color[4][2] += $rate;} # Red
   }
  }
 }

 # Res
 @color = sort {@$b[2] <=> @$a[2]} @color;
 if(($color[0][2] / $rate_sum) > 0.9) {
  $color[1][0] = $color[0][0];
  $color[1][1] = $color[0][1];
 }

 return(1, $color[0][0], $color[1][0]);
}

sub rgb_to_hsv {
 my($r, $g, $b) = @_;
 my($h, $s, $v);
 my($min, $max);

 if($r < $g) {$min = $r; $max = $g;}
 else        {$min = $g; $max = $r;}
 if   ($max < $b) {$max = $b;}
 elsif($min > $b) {$min = $b;}

 $v = $max;
 if($v == 0 || $max == $min) {$h = 0; $s = 0;}
 else {
  $s = 255 * ($max - $min) / $max;
  my $cal_r = ($max - $r) / ($max - $min);
  my $cal_g = ($max - $g) / ($max - $min);
  my $cal_b = ($max - $b) / ($max - $min);
  $h = $max == $r ? 60 * (    $cal_b - $cal_g):
       $max == $g ? 60 * (2 + $cal_r - $cal_b):
                    60 * (4 + $cal_g - $cal_r);
  if($h >= 360) {$h -= 360;}
  elsif($h < 0) {$h += 360;}
 }

 return(int($h), int($s), int($v));
}

こんな感じでどーでしょ。

相変わらず力技ですが・・・。

グレーの扱い

この方法でも、やっぱり白黒の扱いが微妙ですね。

黒白は一色たんにして評価して、ランキングに入ったら、黒白の平均値で黒か白かを決定する方がいいかもしれないですねー。てかLabとかの方がいいかもしれないけどアレ計算がちょいと重くないですか。


まあ、そんなにこだわらなくてもいいかなー。こういうのPerlでやるのが間違ってる?w