画像を「色別」してみる〜(プログラムの話)
えーと、たぶん、このエントリの前後にも書いてると思うんだけど、「はてなフォトライフ」の「色別」みたいなことしてみたかったんですよ。
このエントリは、どーやってやってみたのか。そのプログラムについて語っちゃおうかな〜ってカンジですよ! うっひゃーwww
・・・・と言いつつも、
なんか書いてて疲れてきたので(マジで風邪引いてて全身だるいのdeath)使ったperlソースべた貼りします。
そのうち、コメント書きますかね・・・。
「こうやった方がいいぜ!」的なものがあったら教えていただけると嬉しいです。
ソースさん(classification.pl)
#!perl use strict; use GD; # ↓テーブルヘッダみたいな my $starttimes = time; print '[start] '.$starttimes."\n"; print "file:\twidth\theight\t"; print "hsv:1st\thsv:2nd\thsv:3rd\t"; print "rgb:1st\trgb:2nd\trgb:3rd\t"; print "len:1st\tlen:2nd\tlen:3rd\t"; print "\n"; my $count = 0; # ファイル名渡して回す〜 my @files = glob('*.jpg'); # 調査対象指定♪ foreach(@files) { $count += &check_classification($_); } if(! $count) {exit;} # ↓テーブルフッタみたいな my $endtimes = time; my $stay = $endtimes - $starttimes; my $one = $stay / $count; print '[end] '.$endtimes."\n"; print ' -> '.$stay.'sec/'.$count.'files ('.$one.'sec@1file)'."\n"; exit; ### 以下はサブルーチンさん sub check_classification { # 名前悪すぎwww my($fno, $file) = @_; my @c = ( ['blacK ', 0, 0, 0], ['Blue ', 0, 0, 0], ['Green ', 0, 0, 0], ['Cyan ', 0, 0, 0], ['Red ', 0, 0, 0], ['Purple', 0, 0, 0], ['Yellow', 0, 0, 0], ['White ', 0, 0, 0], ); # hsv[x][1], rgb[x][2], length[x][3] となっとります print $fno."\t".$file."\t"; GD::Image->trueColor(1); my $image = GD::Image->new($file); if(! $image) {print "failure...\n"; return(0);} # 失敗したら0 my($width, $height) = $image->getBounds(); print $width."\t".$height."\t"; for(my $y = 0; $y < $height; $y++) { for(my $x = 0; $x < $width; $x++) { my($r, $g, $b) = $image->rgb($image->getPixel($x, $y)); my($h, $s, $v) = &rgb_to_hsv($r, $g, $b); # HSV投票 白と黒の判別は・・・テキトーです if ($v < 32) {$c[0][1]++;} elsif($s < 12) {$c[7][1]++;} elsif($h < 30) {$c[4][1]++;} elsif($h < 90) {$c[6][1]++;} elsif($h < 150) {$c[2][1]++;} elsif($h < 210) {$c[3][1]++;} elsif($h < 270) {$c[1][1]++;} elsif($h < 330) {$c[5][1]++;} else {$c[4][1]++;} # RGB投票 $c[&is_over($r)*4+&is_over($g)*2+&is_over($b)][2]++; # Length測定(全累計) $c[0][3] += &cal_length_rgb($r,$g,$b, 0, 0, 0); $c[1][3] += &cal_length_rgb($r,$g,$b, 0, 0,255); $c[2][3] += &cal_length_rgb($r,$g,$b, 0,255, 0); $c[3][3] += &cal_length_rgb($r,$g,$b, 0,255,255); $c[4][3] += &cal_length_rgb($r,$g,$b, 255, 0, 0); $c[5][3] += &cal_length_rgb($r,$g,$b, 255, 0,255); $c[6][3] += &cal_length_rgb($r,$g,$b, 255,255, 0); $c[7][3] += &cal_length_rgb($r,$g,$b, 255,255,255); } } # RGBカラーのものは白と黒の評価をテキトーに下げとく $c[0][2] /= (2**3); $c[7][2] /= (2**3); $c[0][3] *= (2); $c[7][3] *= (2); # HSV要素でソートしますよ(降順?) @c = sort {@$b[1] <=> @$a[1]} @c; for(my $i = 0; $i < 3; $i++) {print $c[$i][0]."\t";} # RGB要素でソートしますよ(降順?) @c = sort {@$b[2] <=> @$a[2]} @c; for(my $i = 0; $i < 3; $i++) {print $c[$i][0]."\t";} # length(RGB)要素でソートしますよ(昇順?) @c = sort {@$a[3] <=> @$b[3]} @c; for(my $i = 0; $i < 3; $i++) {print $c[$i][0]."\t";} print "\n"; return(1); # ここまで来たら成功扱いで1を返しときます } sub rgb_to_hsv { # 書き方に統一感がなくてスマソ(並べたかった) my($r, $g, $b) = @_; my($h, $s, $v, $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($max == 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($h, $s, $v); } sub is_over { # RGBカラー判定で半分より上(1)か下(0)か my($value,) = @_; return($value < 128 ? 0 : 1); } sub cal_length_rgb { # 2点間の3次元での距離を計算 my($r1,$g1,$b1, $r2,$g2,$b2) = @_; return(sqrt(($r2 - $r1)**2 + ($g2 - $g1)**2 + ($b2 - $b1)**2)); }
あー、やっちまったなw
う〜ん。よい子はまねしちゃいかん、感じになってますね〜。まーしゃーないwww
HSVのSとVは0〜100(%)が一般ポイらしいですがこのプログラムではRGBに合わせて0〜255にしてます。
そーいや、perlって次乗計算を ** って書くんだね。最初 ^2 とか書いてて全然わけわかんない計算されててビビったよw
てか、perlで次乗計算したの初めてか自分orz ダメじゃんwww
あと、Image::Magickさんを使う場合はnewするあたり(ファイルを指定したりするあたり)を
my $image = Image::Magick->new(); $image->Read($file); my($width, $height) = $image->Get('width', 'height');
みたいに変えて、ピクセルカラーを取得するあたりを
my($r, $g, $b,) = split(',', $image->Get("pixel[$x, $y]")); $r /= 256; $g /= 256; $b /= 256; # ↑各要素が16ビットで返ってくるみたいなので
みたいにしとけば良いと思います。(途中までこれでやってたw
参考・参照
他にもお手本にしたページとか一杯あったのですが・・・。どこだったっけ?w