Ruby Rmagick で同じ画像を見つける
やってることは、ImageMagick の compare で2つの画像を比較し RSME を出して、小さいものを表示することです。RSME はピクセルの何かの値の二乗和のルートです。
最初に黒の画像との比較で RSME を出して、小さい順に並べて、順番に 10 個ずつ比較する。似た画像なら、RSME も近い値になっているという仮定でそうしてる。もし、全組み合わせをすると大変な量になる、例えば 1000 個の画像があると、1000*(1000-1)/2 = 499,500 通りとなるが、このやりかただと、990x10 + 10*(10-1)/2 = 9945通りですむので。
RMagick と Parallel が必要。あとはコメントを参照
http://rmagick.rubyforge.org/
https://github.com/grosser/parallel
ソースは http://ge.tt/7Hn3Uzh/v/0?c からダウンロードもできます。
#!/usr/bin/ruby require 'tmpdir' require 'parallel' require 'readline' require 'RMagick' require 'tempfile' include Magick if ARGV[0] != nil then srcdir=ARGV[0] if FileTest.exist?(srcdir) then if File::ftype(srcdir) != "directory" then srcdir=Dir.pwd end else srcdir=Dir.pwd end else srcdir=Dir.pwd end picsuffix="jpg,png,gif" piclist=[] black=Magick::Image.new(300,300) {self.background_color = "black"} Dir.mktmpdir("tmp",ENV["HOME"]){|td| # Parallel だと piclist が空になってしまったので、普通の foreach # Global 変数とか使えばうまく行くのかな? Dir.glob(srcdir+"/*{"+picsuffix+"}").each {|f| tp=Tempfile.open(["",".png"],td) # 最初 .difference まで一気にやったら、メモリ消費がすごいことに # 一旦ファイルに吐くとだいぶ良くなった ImageList.new(f).resize(300,300).write(tp.path) a=ImageList.new(tp.path).difference(black)[0] tp.close piclist=piclist+[[a,f]] } piclist=piclist.sort{|p,q| p[0]<=>q[0]} while piclist.length>0 tp1=Tempfile.open(["",".png"],td) pic1=ImageList.new(piclist[0][1]).resize(300,300).write(tp1.path) pic1=ImageList.new(tp1.path) Parallel.each(piclist[1,10], in_threads:4){|i| tp2=Tempfile.open(["",".png"],td) pic2= ImageList.new(i[1]).resize(300,300).write(tp2.path) pic2=ImageList.new(tp2.path) difference=pic1.difference(pic2)[1] if difference < 0.05 then puts piclist[0][1]+","+i[1]+","+difference.to_s+"\n" end tp2.close } tp1.close piclist.shift end }