影絵メーカー製作過程四方山話

先日、影絵メーカーというのを公開しまして、製作にあたって色々と苦労も多かったんですが、それなりに勉強になった事も多かったので、自分用の記録も兼ねてダラダラと製作過程を書いてみようかなと思います。

Flash部分の画面デザインについて悩む

いつも、「アイデアはある。機能実装もだいたいはできた。でも、デザインが…。」っていう事が多くて、今回もFlash部分の画面をどう組み立てるか悩んでしまいました。

で、Webカメラを使ったFlashのサンプルを探していたところ、シン石丸さんのところのサンプルが非常に素晴らしく使い勝手が良さげだったので、かなりパク…オマージュさせて頂きました。

Webカメラの画像を色調反転させるFlashを作った: シン石丸の電脳芸事ニッキ

他のFlashのサンプルも大いに参考にさせて頂きました。多謝。m(_ _)m

Webカメラの映像から影絵を生成する実装について悩む

"Webカメラを使って影絵を作れるサービス"というアイデアを思い付いた後に、具体的な実装をどうするかは結構試行錯誤がありました。どんな試行錯誤があったのか、ずらずらと書いてみたいと思います。

ライブクロマキーを使って抜き出した形状の部分だけ黒くする方法

最初に考え付いたのは、「川崎さんが公開しているライブクロマキーの技術を使って、手の部分だけうまく抜き出して影絵にできないかな?」という案でした。

で、ひとまずライブクロマキーのサンプルを試してみたんですが、川崎さんがブログで書かれている通り、どうもWebカメラの自動補正のせいでうまく抽出処理ができない模様…。しかも自分が使っているWebカメラの自動補正機能の設定方法が分からない!

という訳で、この案はボツに…。

閾値を利用した特定色の抜き出しを利用する方法

次に考えたのが、「手袋かなんかを付けて、その色の部分だけ抜き出す事ができれば、手で影絵が作れるんじゃね?」という案でした。

これは、クロマキーと同じやり方で、特定の色の部分だけ黒くして、それ以外を白くすればいい訳で、シン石丸さんのところにちょうどクロマキーのサンプルがあったので、そちらを参考にさせてもらいつつ、実装してみました。

WEBカメラの映像をクロマキー処理するFlashを作った: シン石丸の電脳芸事ニッキ

が、実際にやってみると、抜き出したい部分の色がかなり単一色に近くないとダメで、手袋みたいな材質のものだと、見た目以上に結構色ムラが多くて、思い通りに形を抜き出す事ができず…これもダメ…。

特定の色に近い色の部分だけを黒くする方法

クロマキー方式だと、"RGBの各値がある値以上"みたいな指定の仕方になる為に、"ある色に近い色"というような抜き出し方が難しいので、今度は色距離を利用する方法を試してみました。

ある色とある色が似ているかどうかは、色のRGB値を座標として三次元空間に投影した際の、2つの色の空間距離で表す事ができます。

var distance:Number = Math.sqrt((color1.red - color2.red)^2 + (color1.green - color2.green)^2 + (color1.blue - color2.blue)^2);

ActionScriptで書くと、こんな感じですね。

これを使って、キャプチャされたカメラ画像を1ピクセルずつ走査して、目的の色との距離がある値以下の場合ピクセルを黒く、そうじゃない場合は白く描画する…という事を全ピクセルに行えば、ある色に近い色の部分だけ黒くできるはずです。

で、やってみたんですが、パッと見単色っぽいものでも、色距離を取ってみると案外ばらつきが出てしまうようで、うまい事特定の色だけを抜き出す事はできませんでした。

ただ、方向性としては間違っていないんじゃないかと思い色々調べていくと、どうやら人間の目で見た時に色が似ているかどうかを数値として表す場合は、RGB値ではなく、HSV値というものの方が有効らしい…という情報を入手しました。

という訳で、WikipediaのHSV値の項目やら諸々を参考にしながら、HSV値を用いて色距離を計算するようにしてみました。

が…これも期待通りの結果が得られず…。なおかつ、かなり重い! まぁ、1ピクセルずつHSV値に変換しながら処理しているので当然と言えば当然なんですが、実用に堪えないので、この案はボツ…。

肌色検出を利用した方法

HSV値について調べていく内に、"肌色検出"という方法に行き当りました。以下のサイトによると、肌色は概ね、HSV値の内のH値が6〜38あたりに収まるという事らしい…。

http://www.ai.kyutech.ac.jp/~toshi/kiso_2/ensyu/color/skin.html

「という事は、H値が6〜38の部分だけ黒くなるようにすれば、手袋なんか使わなくても、手で作った形が影絵っぽく抜き出せるんじゃね?」と思い、試してみました。

「あいかわらず重たいし、とってもギザギザしてるけど、手の形がちゃんと取れてる!」*1

という事で、やっと核となる実装の目処が立ってきました。

その後、更に肌色検出について調べていたところ、以下のサイトで、もっとシンプルな実装を発見したので試してみました。

http://psyark.jp/?entry=20050828020502

こちらは、1ピクセルずつの計算ではなくフィルタとして一括して処理されるので、非常に速い! という事で、速度の問題についてもクリアする事ができました。

ギザギザが何とかできないか悩む

ここまでできたら、後は影絵のギザギザをどうにかしたいところ…。

これについては、ConvolutionFilterを使って、うまく境界線をぼかせばいいかなと思ったんですが、効果はいまいち…。

結局、肌色検出のフィルタを掛ける前に、BlurFilterを掛けてWebカメラの映像を軽くぼかしてやる、という極めて単純な方法で、それなりにいい感じに仕上がったので、これでよしとする事にしました。


という訳で、色々と苦労はあったんですが、"Webカメラを使って作った何かをサーバに投稿"という一連の流れを知る事ができて、なかなかに楽しかったですね。

Webカメラとかマイクとかを使った投稿系のサービスは、色々と面白い事ができそうなので、また何か作ってみたいですね。

さて、今度は何を作ろうかなと…。

*1:"肌色検出"なので顔の形も一緒に取れているのはご愛敬。