Help us understand the problem. What is going on with this article?

ruby-opencvでプロ生ちゃん!

More than 5 years have passed since last update.

はじめに

こんばんは.
このエントリーは プロ生ちゃん Advent Calendar 2014 の第25日目の記事です.

環境

  • Mac OSX 10.10.1 Yosemite
  • Ruby 2.0.0p481

目的

  • Rubyで顔認識したい
  • ruby-opencvなるものがあるらしい
  • ruby-opencvで自分の顔をプロ生ちゃんにしよう!
  • gifアニメーションも作りたい!

使うもの

環境構築

  • ruby-opencvの導入
zsh
$ brew tap homebrew/science
$ brew install opencv
$ gem install ruby-opencv -- --with-opencv-dir=/path/to/opencvdir

今回は使いませんがruby-opencvをcloneして遊ぶと勉強になります


実装

今回,顔の検出にはOpenCV付属の顔検出用分類器を使います.
同じ手順でインストールしていれば以下のコマンドで大丈夫です.

zsh
$ cp /usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml ./haarcascade_frontalface_alt.xml

僕のソースコードをそのまま使ってみる人は

zsh
$ mkdir gif

ruby-opencvのサンプル,face_detect.rbを参考に開発していきます.
これをそのまま動かすだけで顔を検出して赤い線で囲みます!すごい!
当初の顔検出したい願望が叶ってしまった!

やりたいこと① 自分の顔とプロ生ちゃんの顔を置き換えたい

検出した顔の領域とプロ生ちゃん アイコンジェネレーターで作ったアイコンを置き換えてみましょう!

detector.detect_objects(image).each do |rect|
    #imageを顔検出した範囲に限定
    image.set_roi rect

    #プロ生ちゃん画像を顔検出したサイズにリサイズ
    resize_pronamachan = pronama.resize rect

    #顔検出した範囲とプロ生ちゃんの画像を1画素ずつ置き換える
    (image.rows * image.cols).times do |j|
        image[j] = resize_pronamachan[j]
    end

    #範囲の限定の開放
    image.reset_roi
end

結果が
up1.jpg
ちゃんと置き換わりました!

やりたいこと② アイコンの背景を透過させたい

今回,プロ生ちゃん アイコンジェネレーターで簡単に背景の色を変えられるので,背景を使われてなさそうな色(今回はRGB(f0,f0,f0))にしてその色の時は置き換えないという手法で透過.

(image.rows * image.cols).times do |j|
     #rectの範囲でrgb(f0,f0,f0)以外の時置き換え(背景透過)
    image[j] = resize_pronamachan[j] if resize_pronamachan[j][0] != 240.0 && resize_pronamachan[j][0] != 240.0 && resize_pronamachan[j][0] != 240.0
end

結果が
up2.jpg
背景透過ができました!
メリークリスマス!

やりたいこと③ gifアニメーションをつくりたい

生成された画像を000〜999の数字を振って保存.
(読みながら実装している人は保存しすぎに注意)

#生成された画像の保存
image.save_image("./gif/image%03d.jpg"%i.to_s)

その後,ImageMagickの以下のコマンドで変換して保存

zsh
$ convert ./gif/*.jpg ./gif/hoge.gif

結果は最後に!

まとめると

face_pronamachan.rb
#!/usr/bin/env ruby
# face_detect.rb
require "rubygems"
require 'opencv'
include OpenCV
window = GUI::Window.new "face detect"
#カメラからの読み込み
capture = CvCapture.open
#顔検出用分類器の読み込み
detector = CvHaarClassifierCascade::load "./haarcascade_frontalface_alt.xml"

#取り込む画像の選択(プロ生ちゃん!)
puts "どのプロ生ちゃんにしますか?"
puts "1:ノーマル"
puts "2:サンタ"
puts "3:アニメーション"

select_pronamachan = gets.to_i

if select_pronamachan == 1 then
    pronama = IplImage.load './pronama.png'
elsif select_pronamachan == 2 then
    pronama = IplImage.load './pronamasanta.png'
elsif select_pronamachan == 3 then
    pronama=Array.new(5) { |i|  }
    pronama[0] = IplImage.load './pronama1.png'
    pronama[1] = IplImage.load './pronama2.png'
    pronama[2] = IplImage.load './pronama3.png'
    pronama[3] = IplImage.load './pronama4.png'
    pronama[4] = IplImage.load './pronama5.png'
end

puts "フレーム数は?(200まで)"

gets.to_i.times do |i|

    image = capture.query
    image = image.resize CvSize.new 480, 270

    random = 0
    if i % 5 == 0 then
        random = rand(5).to_i
    end

    #顔検出
    detector.detect_objects(image).each do |rect|
        #imageを顔検出した範囲に限定
        image.set_roi rect

        #プロ生ちゃん画像を顔検出したサイズにリサイズ
        unless select_pronamachan ==3 then
            resize_pronamachan = pronama.resize rect
        else
            resize_pronamachan = pronama[random].resize rect
        end

        #顔検出された範囲でRGB(f0,f0,f0)以外の時置き換え
        (image.rows * image.cols).times do |j|
            image[j] = resize_pronamachan[j] if resize_pronamachan[j][0] != 240.0 && resize_pronamachan[j][1] != 240.0 && resize_pronamachan[j][2] != 240.0
        end
        #範囲の限定の開放
        image.reset_roi
    end

    #生成された画像の表示
    window.show image
    #生成された画像の保存
    image.save_image("./gif/image%03d.jpg"%i.to_s)

    break if GUI::wait_key(100)
    #200回で終了
    break if i == 199
end
zsh
$ convert ./gif/*.jpg ./gif/hoge.gif

こんなgifが作れました!
output.gif
(アップロード制限回避のためにリサイズと減色してます)

まとめ

今回,ruby-opencvを軽く触ってみてプロ生ちゃんを使って遊びましたがruby-opencv,opencvは他にも色々なことが出来そうです.
興味が湧いた人はOpenCVをもっと使いこなして『俺がプロ生ちゃんだ!』しましょう!!

menphim
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away