こんにちは! VR事業部のizmです。普段は段ボールを解体したり、発泡スチロールを砕いたり、クロマキー布にアイロンを掛ける仕事をしています。
概要
HMDを使ったVR体験の様子を外から見た人にも分かりやすく、おもしろさを伝えるという試みとして、HTC Viveでは3本目のコントローラから見た三人称視点のゲーム映像と、実世界のカメラをクロマキーで抜いたMixed reality Captureが多く用いられています。
Making High Quality Mixed Reality VR Trailers and Videos — KERT GARTNER
日本語でのセットアップ方法や仕組みは以下サイトが詳しいです。
ちゃんとした展示ならクロマキー布を用意すれば良いのですが、毎回洗濯してアイロンを掛けるのも手間ですし、ブース設営時に3面グリーンという制約は邪魔だなあと思ったので、別の解決方法を考えてみました。
このエントリでは以下のような仕組みでクロマキー布を使わないMixed Reality Captureの合成を行う方法を提案します。
普通の背景除去
OpenCVには様々な背景除去アルゴリズムが実装されています。その中で便利そうなMixture of Gaussian Distribution法を使う BackgroundSubtractorMOG2関数 を今回は採用しました。 こんな感じにセットアップします。
cv::VideoCapture cap(0);//カメラを開いて //解像度やFPSを指定 cap.set(CV_CAP_PROP_FOURCC, CV_FOURCC('M', 'J', 'P', 'G')); cap.set(CV_CAP_PROP_FRAME_WIDTH, 1280); cap.set(CV_CAP_PROP_FRAME_HEIGHT, 720); Ptr<BackgroundSubtractorMOG2> pMOG2; float varThreshold = 16; bool bShadowDetection = true; pMOG2 = createBackgroundSubtractorMOG2(history_val, varThreshold, bShadowDetection); //MOG2 approach pMOG2->setShadowValue(4.2); // Sets the showdow color (0-black, 255-white) pMOG2->setShadowThreshold(.5); //Originally ftau? pMOG2->setVarThreshold(20); //Double pMOG2->setNMixtures(5); // Int pMOG2->setBackgroundRatio(0.7); //Double
上記コードの後、メインループでは
- 前景を抜き出し
- 2値化をした画像をマスクとして使用
- 元画像を切り抜き
- 背景部分は緑色に塗っています。(OBSのクロマキーフィルタを適用して、ゲーム画面と合成する為)
と言う感じの処理を毎フレーム行っています。
仮想のウェブカメラ映像ストリーム生成
ここが今回のキモだと思います。先の背景除去済みの映像を映像キャプチャデバイスとしてOBSに認識させなければいけません。 通常であればDirectShowフィルタとして登録したり、UVCとして振る舞うような仮想デバイスドライバを作ったりします。
この部分を真面目に書くとDirectshowフィルタのサンプルコード等と睨めっこする事になって大変そうですが やざわラボさんのycaptureというライブラリが仮想のウェブカメラとして振る舞う事ができます。丁度今回の用途にぴったりなので、ありがたく使わせていただきます。
ycapture上で送信するフレームデータとしてOpenCVのcv::Matから送る場合はBGRをRGBに変換して送ると良いです。以下は送信例です。
cv::cvtColor(image, dst, cv::COLOR_BGR2RGB); HRESULT hr = sender->Send(ms, dst.cols, dst.rows, dst.data);
実験結果
意図した通りOBS上でクロマキー布なしでクロマキー合成っぽいことが出来そうです。
OpenBroadcastStudioでクロマキーフィルタ入れてやれば、良い感じに緑で抜けそう。
— 絵麻さんを養って幸せな家庭を築く (@izm) 2017年3月17日
Mixture of Gaussian Distributionで背景抜いてるから、パラメータいじれば結構良い感じに検出してくれてます。Logicoolのウェブカメラ使用。 pic.twitter.com/AdbLZrAS74
今後の展望
何も考えずにベタで処理を書いたら背景除去だけでCPUをほとんど使い切ってしまいました。これだとViveで遊んでいるゲーム自体の処理が重くなってしまいそうです。 なので、BackgroundSubtractorMOG2をGPUにオフロードする、縮退して背景除去してからマスク伸長する、などで負荷を軽減したいです。
今回は照明の変化に対して強いかなあという理由で動的に背景データを更新していくアルゴリズムを採用しましたが、遊んでいる最中にプレーヤーがじっとしていると背景と誤認識してしまうことがあります。 いっそのこと、背景除去が得意なKinect v2などでカメラを置き換えるのも良いかもしれません。
実際に使って良い感じであれば、今回のソフトウェアを公開します。(まだちゃんと試してないので…ごめんなさい)