読者です 読者をやめる 読者になる 読者になる

ForgeVision Engineer Blog

フォージビジョン エンジニア ブログ

HTC ViveのMixedReality Captureをクロマキー布無しで実現する

こんにちは! VR事業部のizmです。普段は段ボールを解体したり、発泡スチロールを砕いたり、クロマキー布にアイロンを掛ける仕事をしています。

概要

HMDを使ったVR体験の様子を外から見た人にも分かりやすく、おもしろさを伝えるという試みとして、HTC Viveでは3本目のコントローラから見た三人称視点のゲーム映像と、実世界のカメラをクロマキーで抜いたMixed reality Captureが多く用いられています。

f:id:izm_11:20170317183049p:plain

Making High Quality Mixed Reality VR Trailers and Videos — KERT GARTNER

日本語でのセットアップ方法や仕組みは以下サイトが詳しいです。

framesynthesis.jp

ちゃんとした展示ならクロマキー布を用意すれば良いのですが、毎回洗濯してアイロンを掛けるのも手間ですし、ブース設営時に3面グリーンという制約は邪魔だなあと思ったので、別の解決方法を考えてみました。

このエントリでは以下のような仕組みでクロマキー布を使わないMixed Reality Captureの合成を行う方法を提案します。

f:id:izm_11:20170317184701p:plain

普通の背景除去

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

上記コードの後、メインループでは

  1. 前景を抜き出し
  2. 2値化をした画像をマスクとして使用
  3. 元画像を切り抜き
  4. 背景部分は緑色に塗っています。(OBSのクロマキーフィルタを適用して、ゲーム画面と合成する為)

と言う感じの処理を毎フレーム行っています。

仮想のウェブカメラ映像ストリーム生成

ここが今回のキモだと思います。先の背景除去済みの映像を映像キャプチャデバイスとしてOBSに認識させなければいけません。 通常であればDirectShowフィルタとして登録したり、UVCとして振る舞うような仮想デバイスドライバを作ったりします。

f:id:izm_11:20170317185118p:plain

この部分を真面目に書くとDirectshowフィルタのサンプルコード等と睨めっこする事になって大変そうですが やざわラボさんのycaptureというライブラリが仮想のウェブカメラとして振る舞う事ができます。丁度今回の用途にぴったりなので、ありがたく使わせていただきます。

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上でクロマキー布なしでクロマキー合成っぽいことが出来そうです。

今後の展望

何も考えずにベタで処理を書いたら背景除去だけでCPUをほとんど使い切ってしまいました。これだとViveで遊んでいるゲーム自体の処理が重くなってしまいそうです。 なので、BackgroundSubtractorMOG2をGPUにオフロードする、縮退して背景除去してからマスク伸長する、などで負荷を軽減したいです。

今回は照明の変化に対して強いかなあという理由で動的に背景データを更新していくアルゴリズムを採用しましたが、遊んでいる最中にプレーヤーがじっとしていると背景と誤認識してしまうことがあります。 いっそのこと、背景除去が得意なKinect v2などでカメラを置き換えるのも良いかもしれません。

実際に使って良い感じであれば、今回のソフトウェアを公開します。(まだちゃんと試してないので…ごめんなさい)

Tips

  • ycaptureを32bitビルドした場合、OBSは32bit版を起動すること(64bit版だと映像キャプチャデバイス欄に出てこない)
  • オートフォーカスを無効化出来るウェブカメラを使うと良い(Logicool製のウェブカメラはそういった自動制御を抑制するユーティリティソフトがあります)