[Azure Kinect DK] Quickstart: Build your first Azure Kinect application (C#版)

Azure Kinect DK,C#,Microsoft Azure,Microsoft Visual Studio,Mixed Reality

ソリューション開発部 中川です。

Azure Kinect DK がいよいよ日本でも 2020年3月27日(金) に発売されました。
早速ソリューション開発部でも入手し、技術調査を始めています。

本体を入手したらまずはAzure Kinect DK documentationを読み込むところから始まります。クイックスタートとしてQuickstart: Build your first Azure Kinect applicationが用意されていますが、英語のみ、かつCのコードしか掲載されていません。

Azure Kinect Sensor SDK はC#対応に更新されている(一部の機能を除く)ので、今回は「 Quickstart: Build your first Azure Kinect application 」をC#コードでまとめてみます。

Azure Kinectアプリのプロジェクト作成を行い、 Azure Kinect との接続、Azure Kinectカメラからカラー画像を取得・保存するところがゴールです。

Quickstart: Build your first Azure Kinect application C#版

Azure Kinect DKを使い始めたい? このクイックスタートでデバイスを起動してみよう!
(本文ではAzureサブスクリプションを作成するよう促していますが、とりあえず起動するだけなら不要です。)

以下のFunctionをカバーしています:

  • Microsoft.Azure.Kinect.Sensor.Device.GetInstalledCount()
  • Microsoft.Azure.Kinect.Sensor.Device.Open()
  • Microsoft.Azure.Kinect.Sensor.Device.StartCameras()
  • Microsoft.Azure.Kinect.Sensor.Device.StopCameras()

前提条件

  1. Azure Kinect DK をセットアップしてください
  2. Azure Kinect Sensor SDKをダウンロードしてインストールしてください。

Visual Studio プロジェクトの準備

Visual Studioからコンソールアプリの新規プロジェクトを作成してください。
「 ツール 」 ⇒ 「 Nugetパッケージマネージャー 」 ⇒ 「 パッケージマネージャーコンソール 」 を開いてください。

Azure Kinect Sensor SDKの追加

PM> Install-Package Microsoft.Azure.Kinect.Sensor -Version 1.4.0

System.Drauwingの追加 (Kinectから取得した画像処理のため)

PM> Install-Package System.Drawing.Common -Version 4.7.0

ヘッダー

using Microsoft.Azure.Kinect.Sensor;

Azure Kinect DK デバイスを見つける

複数の Azure Kinect DK デバイスを接続できます。まず最初に何台接続されているかを Microsoft.Azure.Kinect.Sensor.Device.GetInstalledCount() を使用して確認します。

このメソッドは特別なセットアップはなしですぐに動作します。

int count = Device.GetInstalledCount();

デバイスが接続されていることが確認出来たら、Microsoft.Azure.Kinect.Sensor.Device.Open() を使用して接続します。その際、接続する機器のIndexを指定できます。1台目に接続する場合は、0 を指定します。

//1台目に接続
Device device = Device.Open(0);

デバイスをOpen したあと、不要になったら忘れずに破棄するようにしましょう。

device.Dispose();

カメラを起動する

デバイスに接続したら、Microsoft.Azure.Kinect.Sensor.DeviceConfigurationオブジェクトでカメラ設定を定義する必要があります。カメラ設定にはさまざまなオプションがあるので、用途に合った設定を選びましょう。

//カメラを起動する
device.StartCameras(new DeviceConfiguration
{
    ColorFormat = ImageFormat.ColorBGRA32,      //RGBカラーイメージ
    ColorResolution = ColorResolution.R720p,    //解像度720p
    DepthMode = DepthMode.NFOV_Unbinned,        //深度モード:NFOV Unbinned
    SynchronizedImagesOnly = true,              //DepthイメージとColorイメージのシンクロされたイメージを取得
});

// ...Camera capture and application specific code would go here...

// カメラを停止する
device.StopCameras();

エラーハンドリング

注)この部分は原文の翻訳ではありません。
SDKを確認した限り用意されているExceptionは以下の通りです。

AzureKinectOpenDeviceException
AzureKinectStartCamerasException
AzureKinectStartImuException
AzureKinectException

OpenDevice, StartCameras, StartImu はそれぞれの操作に対応しています。その他のErrorはAzureKinectExceptionで返されるのではないかと思われます。

まだ十分に確認できていませんが、Exceptionに含まれるDescriptionは「 K4A_FAILED 」としか書かれていないことも多く、うまくいかなかった時の原因の特定が難しい印象です。

この辺は今後の拡充に期待したいところです。

StartCameras() 後に適切にStopCameras() しないままエラーなどでプロセスが落ちてしまうと、Kinectカメラが起動したままになってしまい、他のプロセスからアクセスできなくなりUSBケーブルを抜き差しする必要があるので注意しましょう。

カメラからRGBイメージを取得する

注)この部分は原文の翻訳ではありません。
原文は「// …Camera capture and application specific code would go here…」と省略されており、カメラを起動して停止するだけのコードとなっています。

でもこれだけでは寂しいので、KinectからRGBイメージを取得してローカルディスクに保存するコードを追加します。

Kinect.ImageからBitMapへの変換はtks_yoshinagaさんの下記のブログ記事を参考にさせていただきました。

tks_yoshinagaさんの「 C#で始めるAzure Kinect開発 」シリーズはとても読みやすくわかりやすいのでおススメです。

コード

            //カラー画像を取得して保存
            var transform = device.GetCalibration().CreateTransformation();
            var colorWidth = device.GetCalibration().ColorCameraCalibration.ResolutionWidth;
            var colorHeight = device.GetCalibration().ColorCameraCalibration.ResolutionHeight;

            Console.WriteLine("Get Capture.");
            using (var transformedDepth = new Image(ImageFormat.Depth16, colorWidth, colorHeight, colorWidth * sizeof(UInt16)))
            using (Capture capture = device.GetCapture())
            {
                Console.WriteLine("Captured !!");
                transform.DepthImageToColorCamera(capture, transformedDepth);

                unsafe
                {
                    //カラー画像を取得
                    var colorImage = capture.Color;

                    //画像のメモリのアドレスを取得
                    using (System.Buffers.MemoryHandle pin = colorImage.Memory.Pin())
                    {

                        try
                        {
                            //Bitmap画像を作成
                            var colorBitmap = new System.Drawing.Bitmap(
                                 colorImage.WidthPixels, //カラー画像の横幅
                                 colorImage.HeightPixels,//カラー画像の縦幅
                                 colorImage.StrideBytes, //横一列のバイト数(width*4)
                                 System.Drawing.Imaging.PixelFormat.Format32bppArgb,//カラーフォーマット(RGBA)
                                 (IntPtr)pin.Pointer); //各ピクセルの色情報

                            //ファイルに保存
                            colorBitmap.Save(@"保存したいパス\" + System.DateTime.Now.ToString("yyyyMMddhhmmss") + ".png", System.Drawing.Imaging.ImageFormat.Png);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("Failed to Save Image!");
                            Console.WriteLine(ex.Message);
                            Console.WriteLine(ex.StackTrace.ToString());
                        }
                    }
                }
            }

unsafeコードを使用するので、プロジェクトでアンセーフビルドを許可する設定を行います。プロジェクトプロパティの「ビルド」タブにて「アンセーフコードの許可(E)」にチェックを入れます。

プロジェクトのビルドオプションの「アンセーフコードの許可」にチェック

FullCode

using System;
using Microsoft.Azure.Kinect.Sensor;

namespace SensorQuickStart
{
    class Program
    {
        static void Main(string[] args)
        {
            //接続されている機器の数をチェック
            int count = Device.GetInstalledCount();
            if (Device.GetInstalledCount() == 0)
            {
                Console.WriteLine("No k4a devices attached!");
                Console.ReadKey();
                return;
            }

            Device device = null;
            // Open the first plugged in Kinect device
            try
            {
                //1台目に接続
                device = Device.Open(0);
            }
            catch (AzureKinectOpenDeviceException ex)
            {
                Console.WriteLine("Failed to open k4a device!!");
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace.ToString());
                Console.ReadKey();
                return;
            }

            //カメラを起動
            try
            {
                device.StartCameras(new DeviceConfiguration
                {
                    ColorFormat = ImageFormat.ColorBGRA32,      //RGBカラーイメージ
                    ColorResolution = ColorResolution.R720p,        //解像度720p
                    DepthMode = DepthMode.NFOV_Unbinned,    //深度モード:NFOV Unbinned
                    SynchronizedImagesOnly = true,                     //DepthイメージとColorイメージのシンクロされたイメージを取得
                });
            }
            catch (AzureKinectStartCamerasException ex)
            {
                Console.WriteLine("Failed to open k4a device!!");
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace.ToString());
                device.Dispose();
                Console.ReadKey();
                return;
            }

            //カラー画像を取得して保存
            var transform = device.GetCalibration().CreateTransformation();
            var colorWidth = device.GetCalibration().ColorCameraCalibration.ResolutionWidth;
            var colorHeight = device.GetCalibration().ColorCameraCalibration.ResolutionHeight;

            Console.WriteLine("Get Capture.");
            using (var transformedDepth = new Image(ImageFormat.Depth16, colorWidth, colorHeight, colorWidth * sizeof(UInt16)))
            using (Capture capture = device.GetCapture())
            {
                Console.WriteLine("Captured !!");
                transform.DepthImageToColorCamera(capture, transformedDepth);

                unsafe
                {
                    //カラー画像を取得
                    var colorImage = capture.Color;

                    //画像のメモリのアドレスを取得
                    using (System.Buffers.MemoryHandle pin = colorImage.Memory.Pin())
                    {

                        try
                        {
                            //Bitmap画像を作成
                            var colorBitmap = new System.Drawing.Bitmap(
                                 colorImage.WidthPixels, //カラー画像の横幅
                                 colorImage.HeightPixels,//カラー画像の縦幅
                                 colorImage.StrideBytes, //横一列のバイト数(width*4)
                                 System.Drawing.Imaging.PixelFormat.Format32bppArgb,//カラーフォーマット(RGBA)
                                 (IntPtr)pin.Pointer); //各ピクセルの色情報

                            //ファイルに保存
                            colorBitmap.Save(@"保存したいパス\" + System.DateTime.Now.ToString("yyyyMMddhhmmss") + ".png", System.Drawing.Imaging.ImageFormat.Png);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("Failed to Save Image!");
                            Console.WriteLine(ex.Message);
                            Console.WriteLine(ex.StackTrace.ToString());
                        }
                    }
                }
            }

            // Shut down the camera when finished with application logic
            device.StopCameras();
            device.Dispose();
        }
    }
}

デフォルトの構成オプション「AnyCPU」では動作できないので、「x64」に切り替えて実行してください。指定したパスにpng画像ファイルが保存されます。

Next Step

これでAzure Kinectアプリの基本中の基本を実装できることができました。次のステップとしておススメなのは、公式のGitHubに公開されているサンプルを読み込むことです。

build2019/csharp 」の下にC#でのサンプルが用意されています。

次回は Azure Kinect Body Tracking SDK を使用して、「Quickstart: Build an Azure Kinect body tracking application」のC#版を投稿します。

  • 株式会社アークシステムの来訪管理・会議室予約システム BRoomHubs
  • 低コスト・短納期で提供するまるごとおまかせZabbix