画像の肌色率をもとにソートしてHTMLに出力するスクリプト
前からやりたいと思っていたアレ。こういう馬鹿なスクリプトは、できるなら昨日のうちに公開しておきたかった。仕組みは単純で、画像から適当な数のピクセルを抽出し、HSV色空間上で指定した色相空間と合致するかどうかを確かめるだけ。手元の環境で試してみたところ、認識率は微妙だった。ちなみに、スクリプトを実行するためには RMagick を使用できる環境が必要です。何かサンプルになる画像募集中。
うさげ
ruby image_sort.rb '*.{bmp,jpg,png,gif}'
Windowsネイティブ版のRubyで、カレントフォルダ内にあるすべての画像を対象に実行する場合はこんな感じ。シングルクオートでパス指定を括っているのは、ワイルドカードが展開されるのを防ぐため。他のシェルでどうやるかは知らない。スクリプトを実行すると output.html というファイルが生成されるので、ブラウザで眺めてニヨニヨしてください。これを応用するとおもしろいものが作れるかも。
ソース
#!/usr/bin/ruby # image_sort.rb require 'rubygems' require 'RMagick' include Magick LineSamples = 64 # 一辺当たりのサンプル数 Samples = LineSamples ** 2 # 全体のサンプル数 path = ARGV.shift # 引数から受け取ったパス class CompareColor # 色相範囲を指定して初期化 def initialize(min, max) @min, @max = min, max end # 色相範囲の合致率を返す def compare(img) width = img.columns height = img.rows if width * height > Samples then return compare_big(img, width, height) else return compare_small(img, width, height) end end # 画像が小さいとき def compare_small(img, width, height) ret = 0.0 height.times {|y| width.times {|x| ret += match(img, x, y) } } ret / (width * height) end # 画像が大きいとき def compare_big(img, width, height) dx = width.to_f / LineSamples dy = height.to_f / LineSamples ret = 0.0 LineSamples.times {|y| LineSamples.times {|x| ret += diff(img, x*dx, y*dy) } } ret / Samples end # ピクセルが色相範囲に合致するかどうか def match(img, x, y) color = img.pixel_color(x, y) color = rgb2hsv(color.red, color.green, color.blue) if color[0] >= @min && color[0] <= @max then return 1.0 else return 0.0 end end # HSVに変換 def rgb2hsv(red, green, blue) min = [red, green, blue].min max = [red, green, blue].max if max == min then sat = 0 hue = 0 else sat = 255.0 * (max - min) / max cr = 1.0 * (max - red) / (max - min) cg = 1.0 * (max - green) / (max - min) cb = 1.0 * (max - blue) / (max - min) case max when red hue = 60.0 * (cb - cg) when green hue = 60.0 * (2.0 + cr - cb) when blue hue = 60.0 * (4.0 + cg - cr) end hue += 360 if hue < 0 end [hue, sat, max] end end begin puts("comparing...") cc = CompareColor.new(6, 38) # 値は適当に files = Dir.glob(path) files.map! {|name| puts name img = ImageList.new(name) {'name' => name, 'key' => cc.compare(img)} } puts("sorting...") files.sort! {|a, b| a['key'] <=> b['key'] } files.reverse! puts("putting...") File.open("output.html", "w") {|out| out.puts("<html><body><p>") files.each {|fi| out.puts("<h1>#{fi['name']} => #{fi['key']}</h1>") out.puts("<img width=\"400\" height=\"300\" src=\"#{fi['name']}\" />") } out.puts("</p></body></html>") } rescue puts $! end