Kinect v2の深度センサーから取り込んだ画像を表示する
「Depth画像の表示」とは、Kinect v2センサーの「深度センサー」から画像を撮り込むことを指します。第1回目でも解説していたように、v2からはDepth画像の解像度が512×424にアップし、Kinect v1(320×240)よりも繊細な画像を表示できるようになりました。第1回目でも解説していたように「Depth画像」は、ピクセルの一つ一つが深度(距離)データを保持しています。そのため、「Color画像」と組み合わせて距離を測ったり、画像をマスクしたりするのに使用されます。今回は、Kinect v2の基本の一つである、この「深度センサー」を使って画像を撮り込む方法を解説します。まずはプロジェクトからの作成です。
プロジェクトの作成
VS 2013のメニューから[ファイル]ー[新規作成]ー[プロジェクト]と選択します。次に、「テンプレート」から「Visual Basic」を選択し、右に表示される項目名から「WPF アプリケーション」を選択します。「名前」に任意のプロジェクト名を指定します。今回は「Depth_Basic_Sample」という名前を付けています。
コントロールの配置
デザイン画面上にツールボックスからImageコントロールを1個配置し、「名前(x:Name)」に「Image1」と指定しておきます。
レイアウトは図1のようになります。
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="600" Width="800"> (1) <Grid> <Image x:Name="Image1" /> (2) </Grid> </Window>
- Window要素のHeightプロパティに「600」、Widthプロパティに「800」と指定しておきます。
- 名前がImage1というImageコントロールを配置しています。
参照設定
ソリューションエクスプローラー内の「参照設定」に、Microsoft.Kinect.dllを追加する必要があります。この手順については第1回で解説していますので、そちらを参照してください。
ロジックコードを記述する
次に、ソリューションエクスプローラー内のMainWindow.xamlを展開して表示されるMainWindow.xaml.vbをダブルクリックして、リスト2のコードを記述します。
Imports Microsoft.Kinect (1) Class MainWindow Private myKinectSensor As KinectSensor (2) Private myDepthFrameReader As DepthFrameReader = Nothing (3) Private myBytesPerPixel As Integer (4) Private DepthImageFrameData() As UShort (5) Private DepthImageBitmapRect As Int32Rect (6) Private DepthImageStride As Integer (7) Private DepthImageBitmap As WriteableBitmap (8)
- Kinectの使用を可能にするために、Microsoft.Kinect名前空間をインポートします。次は、メンバー変数を宣言します。
- Kinectセンサーを表すクラスであるKinectSensor型のメンバー変数myKinectSensorを宣言します。
- DepthFrameReaderクラス型のメンバー変数、myDepthFrameReaderを宣言します。DepthFrameReaderクラスは、深度(距離)フレームのリーダーを表わすクラスです。
- Integer型のメンバー変数myBytesPerPixelを宣言します。この変数には、深度(距離)データからのピクセル データのサイズ(ピクセルあたりのバイト)を格納します。
- UShort型の配列メンバー変数DepthImageFrameDataを宣言します。この配列変数では、DepthデータのWidthとHeightを乗算した分の配列を確保します。
- Int32Rect構造体のメンバー変数DepthImageBitmapRectを宣言します。Int32Rect構造体は、長方形の幅、高さ、および位置を表す構造体です。このメンバー変数は、Int32Rectのパラメータで初期化された新しいインスタンスを作成します。
- Integer型のメンバー変数DepthImageStrideを宣言します。この変数にはDepthのストライドを格納します。
- WriteableBitmapクラス型のメンバー変数DepthImageBitmapを宣言します。
ウインドウが読み込まれた時の処理
次に、ウインドウが読み込まれた際の処理を記述します。
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded myKinectSensor = KinectSensor.GetDefault (1) If myKinectSensor Is Nothing = False Then myDepthFrameReader = myKinectSensor.DepthFrameSource.OpenReader (2) Dim myDepthFrameDescripton As FrameDescription = myKinectSensor.DepthFrameSource.FrameDescription (3) DepthImageBitmap = New WriteableBitmap(myDepthFrameDescripton.Width, myDepthFrameDescripton.Height, 96.0, 96.0, PixelFormats.Gray8, Nothing) (4) myBytesPerPixel = myDepthFrameDescripton.BytesPerPixel (5) DepthImageFrameData = New UShort(myDepthFrameDescripton.Width * myDepthFrameDescripton.Height - 1) {} (6) DepthImageBitmapRect = New Int32Rect(0, 0, myDepthFrameDescripton.Width, myDepthFrameDescripton.Height) (7) DepthImageStride = myDepthFrameDescripton.Width * myBytesPerPixel (8) AddHandler myDepthFrameReader.FrameArrived, AddressOf myDepthFrameReader_FrameArrived (9) myKinectSensor.Open() (10) End If End Sub
- まずKinectセンサーを使用可能にします。Kinectセンサーが使用可能な状態にある場合は、以下の処理を行います。
- 深度(距離)フレームのソースを取得する、DepthFrameSourceのOpenReaderメソッドで、深度(距離)フレームのソースフレームのリーダーを開きます。
- KinectSensorからのフレームのプロパティを表わすクラスである、FrameDescriptionクラス型の変数myDepthFrameDescriptonを宣言し、myKinectSensor.DepthFrameSource.FrameDescriptionで、深度(距離)フレームソースの深度(距離)フレームのプロパティを取得します。
- 次に、WriteableBitmapのパラメータで初期化された、新しいインスタンス、DepthImageBitmapオブジェクトを作成します。WriteableBitmapの書式については、連載の第2回目を参照してください。今回はPixelFormatsに「Gray8」を指定しています。「PixelFormats.Gray8」は、ピクセルあたりのビット数が8で256段階のグレイスケール チャネルを表示する「Gray8」ピクセル形式を表します。
- メンバー変数myBytesPerPixelに、深度(距離)データからのピクセル データのサイズ(ピクセルあたりのバイト)を格納します。「2」という値が格納されます。グレイスケールは16ビットで、BytesPerPixelプロパティで、ピクセルあたりのバイト数を取得すると、16÷8の「2」が取得できます。
- 要素の個数が、深度(距離)フレームのWidthとHeightの積であるUShort型の配列を確保し、メンバー変数DepthImageFrameDataに格納します。
- Int32Rectのパラメータで初期化された、新しいインスタンスDepthImageBitmapRectオブジェクトを作成します。Int32Rectの書式については、第2回目を参照してください。
- メンバー変数myBytesPerPixelが格納している値「2」と、深度(距離)フレームのWidthである「512」を乗算した値(1024)を、メンバー変数DepthImageStrideに格納します。
- AddHandlerステートメントで、DepthFrameReaderのFrameArrivedイベントにイベントハンドラを指定します。FrameArrivedイベントは、深度(距離)フレームが到着した時に発生するイベントです。
- OpenメソッドでKinectセンサーを開きます。
深度(距離)フレームが到着した時に発生するイベント
リスト3の最後で指定したイベントハンドラの内容です。
Private Sub myDepthFrameReader_FrameArrived(sender As Object, e As DepthFrameArrivedEventArgs) Using myDepthFrame As DepthFrame = e.FrameReference.AcquireFrame (1) If myDepthFrame Is Nothing = False Then myDepthFrame.CopyFrameDataToArray(DepthImageFrameData) (2) DepthImageBitmap.WritePixels(DepthImageBitmapRect, DepthImageFrameData, DepthImageStride, 0) (3) Image1.Source = DepthImageBitmap (4) End If End Using End Sub
- e.FrameReference.AcquireFrameメソッドで深度(距離)フレームを取得し、myDepthFrameで参照します。
- CopyFrameDataToArrayメソッドで、深度(距離)フレームデータをUShort型配列にコピーします。書式は下記の通りです。
CopyFrameDataToArray(frameData)
frameDataには深度(距離)フレームデータをコピーする先の配列を指定します。この場合はUShort型の配列変数DepthImageFrameDataを指定しています。 - DepthImageBitmap(WriteableBitmapクラス)のWritePixelsメソッドで、ビットマップの指定した領域内のピクセルを更新します。WritePixelsの書式については、第2回目を参照してください。
- Image1のSourceプロパティにDepthImageBitmapオブジェクトを指定します。これで深度(距離)センサーからの画像が表示されます。
ウインドウが閉じられる時の処理
最後に、ウインドウが閉じられる際の処理を記述します。
Private Sub MainWindow_Closing(sender As Object, e As ComponentModel.CancelEventArgs) Handles Me.Closing If myDepthFrameReader Is Nothing = False Then myDepthFrameReader.Dispose() (1) myDepthFrameReader = Nothing End If If myKinectSensor Is Nothing = False Then myKinectSensor.Close() (2) myKinectSensor = Nothing End If End Sub End Class
- myDepthFrameReaderをDisposeし、全ての関連付けから解放します。
- Kinectセンサーも閉じ、全ての関連付けから解放します。
上記のプログラムを実行すると、図2のように表示されます。
次回は、赤外線画像の取り込みにチャレンジします。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- Kinect v2のIRセンサーから赤外線画像を読み込む
- Kinect v2のカメラから画像を取り込んで表示する基本プログラム
- Kinectを使って、画面上の赤い輪をくぐるサンプル
- Kinect v2を使って、机の上のリンゴをつかんで移動してみる
- Kinect v2で実現する打楽器のバーチャル演奏
- Kinectを使って、自分の手のひらに小さな分身を出現させてみる
- Kinectで結成したマイ・ダンスチームを、サンプルを見ながら実際の背景に合成してみよう
- Kinect v2の音声認識で「仮面」を選んで変身してみる
- これであなたもダンスグループの一員!?Kinectで自分を分身させるプログラムを作る
- 人体の連続した動作を音声でキャプチャするKinectのサンプルプログラム