Azure Kinect DK+Unityで点群を取ろうとして失敗したときに読む記事です。
概要
最終的にこういう点群が出ます。
やっとAzure Kinect DKで点群取れた…
— 獏星(ばくすたー) / Megumi Baxter (@baku_dreameater) 2020年4月3日
(Sensor SDK 1.4.0 + Unity 2019.3.7f1) pic.twitter.com/gBAdTkGtYG
リファレンスにする記事
こちらの2記事を読んでUnityへの導入を試します。ゴールは後者の記事に書かれた点群表示の再現です。
しかしコレで実行すると何も表示されません。
UnityかAzure Kinect SDKのバージョン差が原因で動かなくなったようです。
エラーの原因追跡
ちょっと調べると、Kinectの画像を取得するTask内で例外スローされている事が確認できます。
AzureKinectException: result = K4A_RESULT_FAILED Microsoft.Azure.Kinect.Sensor.AzureKinectException.ThrowIfNotSuccess[T] (System.Func`1[TResult] function) (at <1f5823aa499a4d77b8e0e7cd2a5615aa>:0) Microsoft.Azure.Kinect.Sensor.Image..ctor (Microsoft.Azure.Kinect.Sensor.ImageFormat format, System.Int32 widthPixels, System.Int32 heightPixels) (at <1f5823aa499a4d77b8e0e7cd2a5615aa>:0) Microsoft.Azure.Kinect.Sensor.Transformation.ColorImageToDepthCamera (Microsoft.Azure.Kinect.Sensor.Image depth, Microsoft.Azure.Kinect.Sensor.Image color) (at <1f5823aa499a4d77b8e0e7cd2a5615aa>:0) Microsoft.Azure.Kinect.Sensor.Transformation.ColorImageToDepthCamera (Microsoft.Azure.Kinect.Sensor.Capture capture) (at <1f5823aa499a4d77b8e0e7cd2a5615aa>:0) KinectScript+<KinectLoop>d__11.MoveNext () (at Assets/xxx/Scripts/KinectScript.cs:133) UnityEngine.Debug:LogException(Exception) KinectScript:OnDestroy() (at Assets/xxx/Scripts/KinectScript.cs:143)
サンプルコード中のここがエラーになります。
Image colorImage = transformation.ColorImageToDepthCamera(capture);
修正方針はいくつか考えられますが、その前にカラー画像用のImage
をStart
時点で作るように書き換えます。
これはメモリアロケーションを少し削りたいな~という程度のモチベーションです。
まずprivateフィールドに_depthColor
を追加。
//... //vertices中の何番目の点を描画するかのリスト(全部描画するけど手続き上必要) int[] indices; //座標変換(Color⇔Depth対応やDepth→xyzなど)をするためのクラス Transformation transformation; //追加: Depth用に変換された画像を保持するクラス Image _depthColor; //...
次に、InitKinect
の末尾に_depthColor
の初期化を追加。
//Kinectの初期化 private void InitKinect() { //0番目のKinectと接続 kinect = Device.Open(0); //Kinectの各種モードを設定して動作開始 kinect.StartCameras(new DeviceConfiguration { ColorFormat = ImageFormat.ColorBGRA32, ColorResolution = ColorResolution.R720p, DepthMode = DepthMode.NFOV_2x2Binned, SynchronizedImagesOnly = true, CameraFPS = FPS.FPS30 }); //座標変換(Color⇔Depth対応やDepth→xyz)のための情報を生成 transformation = kinect.GetCalibration().CreateTransformation(); //追加: depthColorの初期化。Depthの解像度ベースになることに注意 _depthColor = new Image( ImageFormat.ColorBGRA32, kinect.GetCalibration().DepthCameraCalibration.ResolutionWidth, kinect.GetCalibration().DepthCameraCalibration.ResolutionHeight ); }
初期化した_depthColor
はタスク内のループで使います。
//... //GetCaptureでKinectのデータを取得 using (Capture capture = await Task.Run(() => kinect.GetCapture()).ConfigureAwait(true)) { //Depth画像との位置・サイズ合わせ済みの画像を取得 //Image colorImage = transformation.ColorImageToDepthCamera(capture); transformation.ColorImageToDepthCamera(capture, _depthColor); //色情報のみの配列を_depthColorから取得 BGRA[] colorArray = _depthColor.GetPixels<BGRA>().ToArray(); //capture.DepthでDepth画像を取得 //...
これで再度実行するとうまくいき…ません。
今度は_depthColor
の初期化時点で例外スローされます。
AzureKinectException: result = K4A_RESULT_FAILED Microsoft.Azure.Kinect.Sensor.AzureKinectException.ThrowIfNotSuccess[T] (System.Func`1[TResult] function) (at <1f5823aa499a4d77b8e0e7cd2a5615aa>:0) Microsoft.Azure.Kinect.Sensor.Image..ctor (Microsoft.Azure.Kinect.Sensor.ImageFormat format, System.Int32 widthPixels, System.Int32 heightPixels) (at <1f5823aa499a4d77b8e0e7cd2a5615aa>:0) KinectScript.InitKinect () (at Assets/xxx/Scripts/KinectScript.cs:57) KinectScript.Start () (at Assets/xxx/Scripts/KinectScript.cs:32)
根本的なスロー箇所は最初と同じで、Image
の生成処理がエラーになっています。
ここでちょっと想像を働かせて、「Image
の別のコンストラクタを使えばいいのでは?」と考えてみます。
_depthColor
の初期化をこう書き換えます。
_depthColor = new Image( ImageFormat.ColorBGRA32, kinect.GetCalibration().DepthCameraCalibration.ResolutionWidth, kinect.GetCalibration().DepthCameraCalibration.ResolutionHeight, kinect.GetCalibration().DepthCameraCalibration.ResolutionWidth * 4 );
4つ目の引数はstride
で、画像1行ぶんのバイト数を指定します。
今回は画像フォーマットがBGRA=32bit=4byteなため、画像幅に4を掛けるだけです。
これで再度実行すると正常に動き、冒頭の画像のような点群を得られます。
やっとAzure Kinect DKで点群取れた…
— 獏星(ばくすたー) / Megumi Baxter (@baku_dreameater) 2020年4月3日
(Sensor SDK 1.4.0 + Unity 2019.3.7f1) pic.twitter.com/gBAdTkGtYG
最後に
タスク周りとか細かいとこを整形したコードを貼っておきます。
https://gist.github.com/malaybaku/59c69906e11bb9a0d008783ea4db5d08
リファレンスの記事通りにNuGetパッケージの取得とかDLLの配置を行ったうえで使うと動くはずです。最適化の観点で見るとまだまだ怪しいコードなので、実用時はご注意下さい。
Azure Kinect自体の所感としては、点群はけっこうキレイに出るので点群ビジュアライズで遊ぶのが良いのかな~と思いました。