undefined

bokuweb.me

wasm化したOpenCVでカメラ入力に笑い男を加えて描画する


OpenCVで試したいことがあり、OpenCV + wasmで入門がてら顔認識を試して遊んでみました。

OpenCVのビルド

wasmへのビルドは参考になるような記事を見つけられず、いろいろ試したものの成功しなかったんですが、ビルドを成功させているリポジトリが発見でき手順通り(cloneするリポジトリ名のみ間違ってて修正しましたが)にやることでビルドできました。

github.com

例えば顔認識分類器のデータの追加変更や任意のモジュールの追加、削除などを行うことを考えると自前でビルドできないと今後きつそうなんですが、正直良くわからないってのが現状です。このあたりは課題。 ビルド筋を鍛えようにも取っ掛かりもないような状態なので、おすすめの資料などがあれば、是非教えていただけると嬉しいです。

wasm

Rustでいろいろ試しているが、その際以下の記事をよく参考にさせてもらったりしてます。

sbfl.net

具体的には以下の用な感じで事前にビルドしたopencvを読み込んで使用する。

    "use strict"
    const name = "wasm/cv-wasm";
    const Module = {
      preRun: [],
      postRun: [],
      wasmBinaryFile: `${name}.wasm`,
      print: text => console.log(text),
      printErr: text => console.error(text),
    };
    fetch(`${name}.wasm`)
      .then(res => res.arrayBuffer())
      .then(buffer => {
        Module.wasmBinary = buffer;
        const script = document.createElement("script");
        script.src = `${name}.js`;
        script.addEventListener('load', (e) => {
          const main = document.createElement('script');
          main.src = 'main.js';
          document.body.appendChild(main);
        });
        document.body.appendChild(script);
      });

入力画像の顔認識

上記のリポジトリにはありがたいことに多くのサンプル、テストが含まれており、その中の顔認識のサンプルを書き直しながら試していきました。

github.com

wasmに対応したブラウザであれば以下で試すことができます。(loadに時間かかります)

https://bokuweb.github.io/cv-wasm-face-detect-sample/index.html

検知できれば以下のように顔部分が赤枠でマークされると思います。

f:id:bokuweb:20170727205411p:plain

カメラ入力の対応と笑い男のレンダリング

ここまでできれば、あとはカメラ入力に対応するだけです。 navigator.getUserMediaで映像を取得しvideoタグに繋いで、rafvideoからcanvsに描画し、顔が検出されていれば、座標とサイズを元に笑い男を描画しています。以下から試すことができますが、雑にcustomElements.defineを使用したがために先のサンプルとは違い動くのは最新のchromeぐらいだと思います。飽きたので最大笑い男数1。

https://bokuweb.github.io/wasm-cv-with-laughing-man/ (loadに時間かかります、カメラ必要)

ちゃんと動くとこんなこんな感じ。

f:id:bokuweb:20170727210000g:plain

顔を傾けると結構認識できなかったり、服のシワをご検知したりします。精度をあげる方法はいくつかあるようでちらっと見かけはしましたが、最終目的としては顔認識したいわけではないので、ひとまずここまで。MacBook Pro (Retina 13-inch、Early 2015) 2.9 GHz Intel Core i5 RAM 8 GB + chrome 59で4FPSとかそんなもんでした。画像を200 × 200くらいにすると60FPSでてた。参考まで。