LoginSignup
6
3

More than 3 years have passed since last update.

AzureKinectでグリーンバック無しでクロマキー的な何か

Last updated at Posted at 2019-12-13

3D Sensor Advent Calendar 2019 の13日目の記事です。

はじめに

LIVを使ってBeatSaberのMR動画を撮影してるときに、「これ自分でも実装できるんじゃないか??」と思ったのをきっかけに挑戦してみました。
2時間くらい頑張ったらサクッと出来たので記事を書いてみます。

出来たこと

環境

・Unity 2019.2.11.f
・Azure Kinect (Amazonで買った)

手順(ざっくり)

1.ポイントクラウド表示

こちらの素晴らしいブログを参照してください。
 C#で始めるAzure Kinect開発⑥:Unity+C#でPoint Cloud表示

こんな感じに表示できるはず
K4A_NoGreenBack - AzureKinectSample - PC, Mac & Linux Standalone - Unity 2019.2.11f1 Personal_ _OpenGL ES 3.2_ 2019-12-13 12-59-09_Moment.jpg

2.クロマキー的な何か

今回のクロマキー的な何かはオブジェクトが重なった部分を描画しないようにして実現しました。
人物抽出ではなくて背景除去になります。

背景のみが映っている状態でポイントクラウドを複製、後述のシェーダーを適用したマテリアルに変更。
複製したポイントクラウドのPointSizeを少し大きくして、背景のポイントクラウドを覆うとこんな感じに。
K4A_NoGreenBack - AzureKinectSample - PC, Mac & Linux Standalone - Unity 2019.2.11f1 Personal_ _OpenGL ES 3.2_ 2019-12-13 12-59-09_Moment(3).jpg

シェーダー素人なので、こちらの記事を参考にしました。
 【Unityシェーダ入門】オブジェクトが重なった部分をくり抜く

ポイントクラウド用に色々書き替えたのが以下です。

ColorutoutPoint.shader
Shader "Custom/ColorutoutPoint" {
    Properties{
     _Size("ShaderSize", Float) = 1.000000
     _PointSize("PointSize", Float) = 5.0
     _Color("Color", Color) = (1,1,1,1)

    }
        SubShader{
         Tags {"Queue" = "Geometry-1"}

         Pass {
                        Zwrite On
                        ColorMask 0

        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #pragma target 2.0
        #include "UnityCG.cginc"
        #pragma multi_compile_fog
        #define USING_FOG (defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2))

        float _Size;
        float _PointSize;

        // uniforms
        // vertex shader input data
        struct appdata {
          float3 pos : POSITION;
          half4 color : COLOR;
          UNITY_VERTEX_INPUT_INSTANCE_ID
        };

        // vertex-to-fragment interpolators
        struct v2f {
          float psize : PSIZE;
          fixed4 color : COLOR0;
          #if USING_FOG
            fixed fog : TEXCOORD0;
          #endif
          float4 pos : SV_POSITION;
          UNITY_VERTEX_OUTPUT_STEREO
        };

        // vertex shader
        v2f vert(appdata IN) {
            IN.pos.xyz = IN.pos.xyz * _Size;

          v2f o;
          UNITY_SETUP_INSTANCE_ID(IN);
          UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
          half4 color = IN.color;
          float3 eyePos = mul(UNITY_MATRIX_MV, float4(IN.pos,1)).xyz;
          half3 viewDir = 0.0;
          o.color = saturate(color);
          // compute texture coordinates
          // fog
          #if USING_FOG
            float fogCoord = length(eyePos.xyz); // radial fog distance
            UNITY_CALC_FOG_FACTOR_RAW(fogCoord);
            o.fog = saturate(unityFogFactor);
          #endif
            // transform position
            o.pos = UnityObjectToClipPos(IN.pos);
            o.psize = _PointSize;
            return o;
          }

        // fragment shader
        fixed4 frag(v2f IN) : SV_Target {
          fixed4 col;
          col = IN.color;
          // fog
          #if USING_FOG
            col.rgb = lerp(unity_FogColor.rgb, col.rgb, IN.fog);
          #endif
          return col;
        }
        ENDCG
         }
    }
}
PointCloud.cs
        //背景除去用メッシュ生成
        if (Input.GetKeyDown(KeyCode.Space))
        {
            if (GameObject.Find("CutoutMesh"))
            {
                GameObject obj = GameObject.Find("CutoutMesh");
                Destroy(obj);
            }
            verticesGreenBack = vertices;
            greenBack = new GameObject();
            greenBack.name = "CutoutMesh";
            greenBack.AddComponent<MeshFilter>();
            meshRendererG = greenBack.AddComponent<MeshRenderer>();

            meshG = new Mesh();

            //65535点以上描画する際に下記を記述
            meshG.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;

            //頂点座標と色をmeshに渡す
            meshG.vertices = verticesGreenBack;

            //リストに格納した番号の頂点座標を点として描画
            meshG.SetIndices(indices, MeshTopology.Points, 0);

            //メッシュをこのオブジェクトのMeshFilterに適用
            greenBack.GetComponent<MeshFilter>().mesh = meshG;

            meshRendererG.material = materialG;
        }

        // 削除
        if (Input.GetKey(KeyCode.Backspace))
        {
            GameObject obj = GameObject.Find("CutoutMesh");
            Destroy(obj);
        }

3.おもむろにカメラの前へ。

いい感じに人だけ映る。

さいごに

明日はtakminさんの「kalibrを使ってカメラ/IMUキャリブレーション」です。

6
3
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
6
3