LoginSignup
22
23

More than 5 years have passed since last update.

「コワすぎ」るカメラアプリ2~地獄だぞ編~【Unity × OpenCV × Dlib】

Last updated at Posted at 2016-08-18

※(2017/04/27)公開しているデモアプリをUnityの新しいバージョンでビルドしたものに変更
(WebGL対応については「OpenCV for Unity」AssetのWebGL対応がやって来たヤァ!ヤァ!ヤァ!を参照してください)

はじめに

前回の記事に引き続いて今回もUnityとOpneCVとDlibを利用したカメラアプリのサンプルを作成してみたいと思います。
「コワすぎ」るカメラアプリ1~歪む顔編~【Unity × OpenCV × Dlib】とのシリーズ記事になります。)

元ネタ

今回の元ネタ映像は白石晃士監督の初期名作「オカルト」から。
クライマックスで「白石く~ん、助けてぇ~~~!」と江野君が叫ぶシーン。
物語の根幹に関わる重要なシーンなので詳細な説明はしませんが、ある種のリアリティ満ちた衝撃的な映像体験が味わえる名シーンです。
とにかく素晴らしい奇跡の連続のような映画なので、未見の人はぜひ作品を観てください。

qiita_kowasugirucamera2_1.jpg

せっかくなので同じく白石監督作品である「コワすぎ!」や他作品にも頻出する異世界空間(ファンの間では「白石空間」とも呼ばれている)のイメージも融合させることにしました。

制作のポイント

顔器官検出の情報を基に頭部の領域だけを白く塗りつぶしたマスク画像を作成して別の背景に合成するところが制作のポイントになります。
また、人物ごとに色を変えたり、口の開閉度に応じて顔の大きさを変えたりする演出を加えることにしました。

qiita_kowasugirucamera2_2.jpg

Assetsのセットアップと顔検出をトラッキングしてから顔器官検出までの流れは前記事と同じです。

マスク画像作成

ここでもFaceSwapperSampleのコードが大いに参考になりました。

KowasugiruJigokuCamera.cs
        //マスクに顔の輪郭を描画
        private void drawMaskByFacePoints(Mat maskMat, Point[] points)
        {
            Imgproc.fillConvexPoly(maskMat, new MatOfPoint(points), new Scalar(255));


        }

        //マスクの縁をぼかす
        private void featherMask(Mat maskMat, OpenCVForUnity.Rect rect, Size feather_amount)
        {
            using (Mat maskMat_rect = new Mat(maskMat, rect))
            {
                Imgproc.erode(maskMat_rect, maskMat_rect, Imgproc.getStructuringElement(Imgproc.MORPH_RECT, feather_amount), new Point(-1, -1), 1, Core.BORDER_CONSTANT, new Scalar(0));
                Imgproc.blur(maskMat_rect, maskMat_rect, feather_amount, new Point(-1, -1), Core.BORDER_CONSTANT);
            }
        }

髪の毛部分をマスクに追加する処理
(頭頂部付近の髪の毛っぽい色を色域比較で抽出しているだけなので、撮影環境によって上手くいかないことがある。改良が必要)

KowasugiruJigokuCamera.cs
        //色域比較により髪の毛を抽出してマスクに加える
        private void drawHeadContourMask(Mat frameMat, Mat maskMat, OpenCVForUnity.Rect rect)
        {

            using (Mat frameMat_rect = new Mat(frameMat, rect))
            using (Mat maskMat_rect = new Mat(maskMat, rect))
            {

                //RGBA形式で色域比較
                byte[] data  = new byte[4];
                frameMat_rect.get(rect.height / 5, rect.width / 2, data);

                Core.inRange(frameMat_rect, new Scalar(data[0] - 30, data[2] - 30, data[2] - 30, 255), new Scalar(data[0] + 10, data[2] + 10, data[2] + 10, 255), maskMat_rect);

                //クロージング処理
                Imgproc.morphologyEx(maskMat_rect, maskMat_rect, Imgproc.MORPH_CLOSE, new Mat(),new Point(-1,-1), 3);

                //首以下のマスクを塗りつぶして除外
                Imgproc.rectangle(maskMat_rect, new Point(0, rect.height * 0.95f), new Point(rect.width, rect.height), Scalar.all(0),-1);

            }

デモアプリ(歪む顔編、地獄だぞ編共通)

※要求するカメラ入力サイズによってシーンをを切り替えて試せるように(640x480 or 320x240)デモアプリを修正しました。

  • Android (Unity5.5.1p4)

  • WebGL_asm.jp (Unity5.6.0f3)(WebGL対応のブラウザで実行可能)

  • WebGL_webassembly (Unity5.6.0f3)(WebGL対応かつwebassemblyが有効なブラウザならより高速に実行可能)

動作画面

映像素材:MovieTips

(動画はiPhone6実機からキャプチャして8fpsのGIF動画に変換したもの)

qiita_kowasugirucamera2_3.jpg
サンプルアプリで被写体をを撮影すると、
KowasugiruJigokuCamera_cap1.gif
このような映像になります。(口を大きく開くと顔が拡大される)

qiita_kowasugirucamera2_4.jpg
撮影環境や検出設定によっては髪の毛も綺麗に抽出できます。

qiita_kowasugirucamera2_5.jpg
もちろん複数人の撮影にも対応しています。
(カメラ入力サイズ640x480のシーンでは高速化のために1/2にダウンサンプリングした画像に対して顔器官検出を行っているので検出精度が少し犠牲になっています)

まとめ

まさに「生首だけでやれんのか!?」状態。
撮影者は田代君ごっこ、映る側は江野君ごっこ遊びが捗ります。(映像的には「オカルト」より「コワすぎ!」に近くなりましたが)
複数人でワイワイ映ることで更にカオスな映像が楽しめます。

関連記事

22
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
23