Shogo's Blog

Oct 3, 2012 - 1 minute read - Comments -

リアルタイムにテンションを上げてみた

昨日,Twitterで猫型さんアイコンのテンションが上がっている話をしていたら, こんな無茶ぶりをされたんですよ.

いいだろう,その挑戦受けてやる!

WebRTCって?

WebRTCというのはブラウザ上で Real Time Communication を行うAPI群のことことです.

  • ローカルデバイス(Webカメラとかマイクとか)へのアクセス
  • ブラウザ同士が(サーバを介さずに)直接通信

なんてことができるようになるらしいです. つまり WebRTCを使えば Skype っぽいものをプラグインのインストールなしにブラウザ上で実現できるってわけですね. Chrome の最新安定版で、ウェブの最先端に触れてみようから いろいろなWebRTCを使ったデモを見ることができます. 僕も似顔絵描いてもらったりしてみました.

getUserMedia API を使ってみる

まだまだ仕様策定中で対応ブラウザがほとんどない状況ですが, 2012年10月現在,最新版の Chrome 21 で前者のローカルデバイスへアクセスするAPIである getUserMedia API が使えるようです. 早速遊んでみましょう.

navigator.getUserMedia(
    {video: true}, // constrains: 接続先のデバイス
    function successCallback(stream) {
        // アクセス成功
        // stream に LocalMediaStream オブジェクトが入ってる

        // <video id="video"></video> 要素を取ってくる
        var video = document.getElementById('video');
        
        // BlobURLに変換してsrcに入れる
        video.src = URL.createObjectURL(stream);
        
        // 再生
        video.autoplay = true;
    },
    function errorCallback() {
        // エラー!!
    }
);

簡単ですね!

現在のところgetUserMediaとURLにはベンタープレフィックスが必要なようです.

エフェクトを加える

表示しただけじゃつまらないのでエフェクトをかけてみます. videoタグに対してCSSで変形することもできるはずですが, もっと自由度が欲しいのでCanvasを使います.

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
requestAnimationFrame(function render() {
    context.drawImage(video, 0, 0, width, height);
    requestAnimationFrame(render);
});

Canvasに画像を描画するのと全く同じ方法でカメラ映像も描画できます. しかし,drawImageでは一コマしか描画されないので,requestAnimationFrameを使って常に最新のコマが表示されるようにしています. requestAnimationFrame を使うとブラウザの描画タイミングに合わせて呼び出してくれたり, 軽かったりするらしいです. ベンダープレフィックスが必要なので適宜つけてあげて.

Canvasに描画できてしまえば,あとはなんでもし放題! strokeやfillで落書きしてみたり,drawImageで画像をオーバレイしみたり, getImageData + putImageDataを使えばピクセル単位でいろいろいじったりだってできます.

顔認識

さて,テンションを上げるには顔部分をブレさせる必要があります. 顔検出が必要ですね.

javascriptの顔検出ライブラリといえばccvというのが有名らしいので,これを使ってみます. レポジトリ中のccv.jsとface.jsを読み込んで,

var comp = ccv.detect_objects({
    canvas :ccv.grayscale(detection_canvas),
    cascade : cascade,
    interval : 5,
    min_neighbors : 1 });

とすると,[{x:0, y:0, width:100, height:100}]みたいな感じで顔の場所を取得できます.

組み合わせる

組み合わせるとこんな感じ リアルタイムにテンション上げる

元の位置から少しずれた場所に顔画像を重ねることでブレた感じにしてます. 周りの人からテンションの上がり具合が足りないと言われてしましました. もっといいテンションのあげ方があったら教えてください.

参考