ruby-opencvでプロ生ちゃん！

#はじめに
こんばんは．
このエントリーは [プロ生ちゃん Advent Calendar 2014](http://qiita.com/advent-calendar/2014/pronama-chan) の第25日目の記事です．

#環境
+ Mac OSX 10.10.1 Yosemite
+ Ruby 2.0.0p481
<br>

#目的
+ Rubyで顔認識したい
+ ruby-opencvなるものがあるらしい
* ruby-opencvで自分の顔をプロ生ちゃんにしよう！
* gifアニメーションも作りたい！
<br>

#使うもの
+ [ruby-opencv](https://github.com/ruby-opencv/ruby-opencv)
+ [ImageMagick](http://www.imagemagick.org/)
+ [プロ生ちゃん アイコンジェネレーター](http://pronama.azurewebsites.net/icon-generator/)
<br>

#環境構築
+ ruby-opencvの導入

```zsh:zsh
$ brew tap homebrew/science
$ brew install opencv
$ gem install ruby-opencv -- --with-opencv-dir=/path/to/opencvdir
```
今回は使いませんが[ruby-opencv](https://github.com/ruby-opencv/ruby-opencv)をcloneして遊ぶと勉強になります

+ ImageMagickの導入<br>
以下のリンク先のパッケージインストーラーを用いてインストール<br>
[ImageMagick installer for Mac OS X](http://cactuslab.com/imagemagick/)

<br>

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

```zsh:zsh
$ cp /usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml ./haarcascade_frontalface_alt.xml
```
僕のソースコードをそのまま使ってみる人は

```zsh:zsh
$ mkdir gif
```
[ruby-opencv](https://github.com/ruby-opencv/ruby-opencv)のサンプル，[face_detect.rb](https://github.com/ruby-opencv/ruby-opencv/blob/master/examples/face_detect.rb)を参考に開発していきます．
これをそのまま動かすだけで顔を検出して赤い線で囲みます！すごい！
当初の顔検出したい願望が叶ってしまった！
<br>

##やりたいこと① 自分の顔とプロ生ちゃんの顔を置き換えたい
検出した顔の領域と[プロ生ちゃん アイコンジェネレーター](http://pronama.azurewebsites.net/icon-generator/)で作ったアイコンを置き換えてみましょう！

```ruby
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](https://qiita-image-store.s3.amazonaws.com/0/55217/d6908884-2ae6-8851-21d1-9562229123a2.jpeg)
ちゃんと置き換わりました！
<br>

##やりたいこと② アイコンの背景を透過させたい
今回，[プロ生ちゃん アイコンジェネレーター](http://pronama.azurewebsites.net/icon-generator/)で簡単に背景の色を変えられるので，背景を使われてなさそうな色(今回はRGB(f0,f0,f0))にしてその色の時は置き換えないという手法で透過．


```ruby
(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](https://qiita-image-store.s3.amazonaws.com/0/55217/ee155459-261e-7115-3f4e-3172f6262c0e.jpeg)
背景透過ができました！
メリークリスマス！
<br>

##やりたいこと③ gifアニメーションをつくりたい
生成された画像を000〜999の数字を振って保存．
(読みながら実装している人は保存しすぎに注意)

```ruby
#生成された画像の保存
image.save_image("./gif/image%03d.jpg"%i.to_s)
```
その後，ImageMagickの以下のコマンドで変換して保存

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

結果は最後に！
<br>

#まとめると

```ruby: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:zsh
$ convert ./gif/*.jpg ./gif/hoge.gif
```

こんなgifが作れました！
![output.gif](https://qiita-image-store.s3.amazonaws.com/0/55217/4f452e6f-58ec-a046-1cd3-b9013607c2f0.gif)
(アップロード制限回避のためにリサイズと減色してます)
<br>


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