ruby-opencvの進捗の話(2014年2月版)
はじめに
なんか気がついたら2014年も1ヶ月が過ぎてますが、ruby-opencvのお話です。 前回からバージョンもだいぶ上がり、機能も地味にいろいろ追加されてるので、ちょっとだけ紹介します。
APIリファレンス的なものを(ようやく)用意しました
前からちょっとずつYARDで書いてたアレをようやくマージしました。 rubydoc.infoで見れるのでどうぞ。
微妙に網羅できてないのもありますが、よく使うやつはだいたい書いてあります。
FaceRecognizerを追加しました
FaceRecognizer #17 でご要望を頂いておきながらずーっと放っておいたFaceRecognizerが(v0.0.11から)使えるようになりました。 公式のチュートリアル Face Recognition with OpenCV に相当するサンプルも用意してあるので、興味のある方はぜひどうぞ。
https://github.com/ruby-opencv/ruby-opencv/tree/master/examples/facerec
FaceRecognizer(EigenFaces)のサンプルコード
せっかくなので、FaceRecognizerのEigenFacesを使って顔認識してみましょう。 Ubuntu 13.10 + Ruby 2.1.0-p0(x86_64-linux) + ruby-opencv 0.0.12 で動作確認していますが、だいたいどの環境でも同じように動くはずです。
1. 認識用の顔画像を AT&T Facedatabase から取ってくる
http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html から認識用の顔画像を取ってきて展開します。
$ wget http://www.cl.cam.ac.uk/Research/DTG/attarchive/pub/data/att_faces.zip $ unzip att_faces.zip
2. テストデータを用意する
学習用に顔画像をラベルと対応付けたファイルを作成します。 OpenCV公式チュートリアルのこれを使ってもいいですが、 Ruby版のcreate_csv.rbも作ったので今回はこっちを使いましょう。
# create_csv.rb if ARGV.size != 1 puts "usage: ruby #{__FILE__} <base_path>" exit end BASE_PATH = ARGV[0] SEPARATOR = ';' label = 0 Dir.glob("#{BASE_PATH}/*").each { |dir| if FileTest::directory? dir Dir.glob("#{dir}/*") { |filename| puts "#{filename}#{SEPARATOR}#{label}" } label += 1 end }
画像ファイルのフォルダを引数で指定して実行します。 結果は標準出力に出るので、適当にリダイレクトしてください。
$ ruby create_csv.rb att_faces > at.txt
実行すると、下記のように 画像ファイル名;ラベル というフォーマットで対応付けのファイルが作成されます。
$ cat at.txt att_faces/s34/2.pgm;0 att_faces/s34/3.pgm;0 att_faces/s34/8.pgm;0 att_faces/s34/4.pgm;0 att_faces/s34/5.pgm;0 att_faces/s34/10.pgm;0 att_faces/s34/9.pgm;0 att_faces/s34/7.pgm;0 att_faces/s34/6.pgm;0 att_faces/s34/1.pgm;0 ...
3. 顔認識してみる
こんな感じのプログラム(eigenfaces.rb)を作ります。
# eigenfaces.rb require 'opencv' include OpenCV def read_csv(filename, sepalator = ';') images = [] labels = [] open(filename, 'r') { |f| f.each { |line| path, label = line.chomp.split(sepalator) images << CvMat.load(path, CV_LOAD_IMAGE_GRAYSCALE) labels << label.to_i } } [images, labels] end if ARGV.size < 1 puts "usage: ruby #{__FILE__} <csv.ext>" exit 1 end fn_csv = ARGV.shift output_folder = ARGV.shift # 顔画像を読み込む images, labels = read_csv(fn_csv); height = images[0].rows; # 識別対象の顔画像は学習対象とは別にしておく test_sample = images.pop test_label = labels.pop # Eigenfacesのモデルを作成して学習 model = EigenFaces.new model.train(images, labels) # 識別処理 # 識別結果のラベルと一致度が返ってくる predicted_label, predicted_confidence = model.predict(test_sample) # 結果を表示 puts "Predicted class: #{predicted_label} / Actual class: #{test_label}" puts "Confidence: #{predicted_confidence}" w1 = GUI::Window.new('Predicted') w2 = GUI::Window.new('Actual') w1.show images[predicted_label] w2.show images[test_label] GUI::wait_key
で、実行します。引数は2で作ったファイルのファイル名です。
$ ruby eigenfaces.rb at.txt
実行結果はこんな感じ(左が識別結果で右が実際の顔)。どうやらそれっぽく動いているようです。