SharpDX と KinectV2 を使ってカメラ画像を表示する
About
遅ればせながら Kinect-V2 と KinectSDK-2.0 とを入手したので、SharpDX でカメラ画像の表示をしてみました。Kinect-V2 では解像度が格段に向上しているので、画像処理などを含めたアプリケーションを作りたい場合には、シェーダないし、DirectCompute の形で GPU を活用することになりそうです。
- サンプルは Gist にアップしました。
SharpDX や KinectV2 の詳細についてはここで解説しません。 SDK のバージョンアップによって仕様が変更されたり、ソースコードの配布先を変更したり停止したりする可能性が十分にあります。
簡単な解説
Kinect-V1 と比較して設定が可能な項目は増えていますが、最小のソースコードはむしろシンプルになった印象を受けます。
フィールドに Kinect への参照を用意しておいて、GetDefault メソッドによってインスタンスを取得、代入します。次いで Open メソッドによって Kinect の動作を開始します。
private KinectSensor kinect; … this.kinect = KinectSensor.GetDefault(); this.kinect.Open();
Kinect-V2 になってもイベントドリブン型とポーリング型と実装形態は2パターンあります。ただし SharpDX ではポーリング型を利用する方が良いです。これはカメラ画像などを表示するために利用する Texture2D のインスタンスを生成する際に、GPU 領域を用意することに起因します。これについては続く項目で解説します。
厳密には SharpDX でかつ DirectX 10 以降を利用する場合です。さらに SharpDX.Toolkit を使わない場合にはこの限りではありません。
カメラから取得したデータを流し込むテクスチャを用意しておきます。Texture2D のインスタンスを更新の度に毎回生成することは良くありません。Texture2D のインスタンスの生成時に、GPU(VRAM) にそのインスタンスが必要とする領域を確保してしまうからです。特に少ない VRAM の場合には、解放が追いつかずにすぐにアクセス違反が発生します。したがって、予めテクスチャを用意して、その領域を更新する手法を取ります。
そのテクスチャの更新ですが、ポーリングによって行われるべきです。イベントドリブン型で実装してしまうと、VRAM の書き換え中に、描画命令が発生する可能性があり、やはりアクセス違反が発生します。
protected override void LoadContent() { this.spriteBatch = new SpriteBatch(GraphicsDevice); this.tex2d_ColorImage = Texture2D.New(this.GraphicsDevice, this.colorFrameDescription.Width, this.colorFrameDescription.Height, PixelFormat.B8G8R8A8.UNorm); base.LoadContent(); }
というわけで、Update メソッド内で Kinect からデータを受け取り、テクスチャを更新します。データが含まれている ColorFrame を取得するには、ColorFrameReader を取得します。予め ColorFrameReader への参照をフィールドあたりに用意しておくのも良いです。ここでは分かり易さのために、Update メソッド内で取得しています。AcquireLatestFrame メソッドによって、ColorFrame を取得します。
protected override void Update(GameTime gameTime) { ColorFrame colorFrame = this.kinect.ColorFrameSource.OpenReader().AcquireLatestFrame(); if (colorFrame == null) { return; } byte[] colorDataArray = new byte[colorFrameDescription.Width * colorFrameDescription.Height * colorFrameDescription.BytesPerPixel]; colorFrame.CopyConvertedFrameDataToArray(colorDataArray, ColorImageFormat.Bgra); this.tex2d_ColorImage.SetData<byte>(colorDataArray); colorFrame.Dispose(); base.Update(gameTime); }
取得した ColorFrame からカメラ画像を取得します。カメラ画像は byte 配列として取得します。予めデータを受け取るのに必要な領域(配列)を用意しておき、CopyConvertedFrameDataToArray メソッドによってその領域に複製します。メソッド名の通り、変換先のフォーマットも指定しています。ここでは Bgra です。
後は受け取ったデータを用意したテクスチャに流して、このテクスチャを描画すれば良いです。