これであなたもダンスグループの一員!?Kinectで自分を分身させるプログラムを作る

前ページからの続きです。
Kinectの画像をビットマップデータに書き出す処理
Byte型の配列変数bytePlayerをInt32Rect構造体の高さにscreenImageStrideで乗算した値で初期化します。640*1280=819200-1の値で初期化するのと同じです。
各分身は、バッファに保存してある0.5秒前、1秒前のデータをそれぞれが参照することで、時差表示を可能にしています。1秒で30フレームなので、0.5秒の場合はその半分の15フレームとなり、変数frameを15で初期化しておきます。
繰り返し変数iで0からメンバ定数変数myPlayer(7)-1分、反復処理を行います。
整数型変数iframeを宣言し、反復変数iが0の場合は、iframe変数にRingBuffer構造体のbuffer_indexプロパティの値(リングバッファ内のインデックス値)を指定します。このbuffer_indexは次のフレームに移動するたびに加算される値で、リングバッファ内のインデックス値になります。
iが0以外の場合は、RingBuffer構造体のbuffer_indexプロパティに、15フレームにi-1の値を乗算した値が加算され格納されます。i-1した値を乗算しないと、背景が白で切り抜かれたプレイヤーが1人分余分に表示されますので注意してください。
Byte型のcolorPixelData配列変数に、RingBuffer構造体のget_rgb_frame関数を使って、iframeに該当する、リングバッファ内のRGBカメラのデータ値を取得します。整数型の配列変数PlayerInexに、RingBuffer構造体のget_PlayerIndexData関数を使って、iframeに該当するリングバッファ内のプレイヤーインデックス値を取得します。
変数indexの値が、colorPixelData変数の値の長さより小さい場合は以下の処理を繰り返します。
4バイトずつ加算される変数indexに該当するPlayerIndexの値が0より大きい場合、つまりプレイヤーが存在する場合は、プレイヤーを描画します。indexに対応する、Byte型の配列変数である距離データを画像化していきます。
Kinectの画像をビットマップデータに書き出します。WriteableBitmap型の変数overrayBitmapにWritePixelsメソッドで、byteからビットマップへ書き出します。ビットマップの指定した領域内に更新したデータを格納します。書式は下記の通りです。このoverrayBitmapプロパティの値を、Nameがhuman_image1というImageコントロールのSourceプロパティに指定します。
WritePixels(更新するWriteableBitmapの四角形,ビットマップの更新に使用するピクセル配列,pixel内の更新領域のストライド,入力バッファのオフセット)
Private Sub RenderScreen2()
If screenImageStride = 0 Then
Return
End If
Dim bytePlayer As Byte() = New Byte(CInt(myImageSize.Height) * screenImageStride - 1) {}
Dim frame As Integer = 15
For i As Integer = 0 To myPlayer - 1
Dim iframe As Integer
If i = 0 Then
iframe = myRingBuffer.buffer_index
Else
iframe = myRingBuffer.buffer_index + (frame * i - 1)
End If
Dim colorPixelData As Byte() = myRingBuffer.get_rgb_frame(iframe)
Dim PlayerIndex As Integer() = myRingBuffer.get_PlayerIndexData(iframe)
If colorPixelData Is Nothing Then
Continue For
End If
Dim index As Integer = 0
While index < colorPixelData.Length
If PlayerIndex(index) > 0 Then
bytePlayer(index) = colorPixelData(index)
bytePlayer(index + 1) = colorPixelData(index + 1)
bytePlayer(index + 2) = colorPixelData(index + 2)
bytePlayer(index + 3) = colorPixelData(index + 3)
End If
index = index + BytesPerPixel
End While
Next
overrayBitmap.WritePixels(myScreenImageRect, bytePlayer, screenImageStride, 0)
human_image1.Source = overrayBitmap
End Sub
ウィンドウが閉じられる時の処理
Kinectセンサーの動作を停止してリソースを解放する、StopKinectプロシージャを実行します。
Private Sub MainWindow_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Me.Closing StopKinect() End Sub End Class
RingBufferLib.dllのソースコード(Class1.vb)
リングバッファ内にRGB配列のコピー、Depth配列のコピー、PlayerIndex配列のコピー等を行っています。
Option Strict On
Public Class Kinect_RingBuffer
Public Structure RingBufferData
Public Property ColorPixelData() As Byte()
Public Property DepthPixelData() As Short()
Public Property PlayerIndexData() As Integer()
Public Sub InitArray(ColorStream_FramePixelDataLength As Integer, DepthStream_FramePixelDataLength As Integer)
ColorPixelData = New Byte(ColorStream_FramePixelDataLength - 1) {}
DepthPixelData = New Short(DepthStream_FramePixelDataLength - 1) {}
PlayerIndexData = New Integer(ColorStream_FramePixelDataLength - 1) {}
End Sub
Public Sub copy_framedata(ByRef value As Byte())
System.Array.Copy(value, ColorPixelData, value.Length)
End Sub
Public Sub copymyDepthPixelData(value As Short())
System.Array.Copy(value, DepthPixelData, value.Length)
End Sub
Public Sub copy_PlayerIndexData(value As Integer())
System.Array.Copy(value, PlayerIndexData, value.Length)
End Sub
End Structure
Public Structure RingBuffer
Dim myRingBufferData As RingBufferData()
Property max_buffer_frame() As Integer
Property buffer_index() As Integer
Private Function get_index(frameNo As Integer) As Integer
Dim no As Integer
If frameNo < max_buffer_frame Then
no = frameNo
Else
no = frameNo - max_buffer_frame
End If
If frameNo < 0 Then
no = max_buffer_frame + frameNo
End If
Return no
End Function
Public Function get_rgb_frame(frameNo As Integer) As Byte()
If myRingBufferData Is Nothing Then
Return Nothing
End If
Return myRingBufferData(get_index(frameNo)).ColorPixelData
End Function
Public Function get_depth_frame(frameNo As Integer) As Short()
If myRingBufferData Is Nothing Then
Return Nothing
End If
Return myRingBufferData(get_index(frameNo)).DepthPixelData
End Function
Public Function get_PlayerIndexData(frameNo As Integer) As Integer()
If myRingBufferData Is Nothing Then
Return Nothing
End If
Return myRingBufferData(get_index(frameNo)).PlayerIndexData
End Function
Public Function init_ringbuffer(buffer_sec As Integer, ColorStream_FramePixelDataLength As Integer, DepthStream_FramePixelDataLength As Integer) As Boolean
Try
buffer_index = 0
max_buffer_frame = 30 * buffer_sec
myRingBufferData = New RingBufferData(max_buffer_frame - 1) {}
For i As Integer = 0 To max_buffer_frame - 1
myRingBufferData(i) = New RingBufferData()
myRingBufferData(i).InitArray(ColorStream_FramePixelDataLength, DepthStream_FramePixelDataLength)
Next
Return True
Catch ex As Exception
Return False
End Try
End Function
Public Sub save_framedata(value As Byte())
myRingBufferData(buffer_index).copy_framedata(value)
End Sub
Public Sub save_depthdata(value As Short())
myRingBufferData(buffer_index).copymyDepthPixelData(value)
End Sub
Public Sub save_playerIndexdata(value As Integer())
myRingBufferData(buffer_index).copy_PlayerIndexData(value)
End Sub
Public Sub set_nextframe()
If buffer_index >= max_buffer_frame - 1 Then
buffer_index = 0
Else
buffer_index = buffer_index + 1
End If
End Sub
End Structure
End Class
以上で今回のサンプルは終了です。
ダンスグループの一員になれるKinectサンプル
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- Kinectで結成したマイ・ダンスチームを、サンプルを見ながら実際の背景に合成してみよう
- Kinectの音声認識を使って、プレイヤーを分離、結合させるデモを試してみる
- Kinectを使って、画面上の赤い輪をくぐるサンプル
- Kinectを使って、自分の手のひらに小さな分身を出現させてみる
- 人体の連続した動作を音声でキャプチャするKinectのサンプルプログラム
- プレイヤーの身体パーツを判別するKinectサンプル
- Kinectで距離カメラの値を取得して、指定した距離で人物が背景に溶け込むサンプル
- 人物を切り抜いて画面に表示するKinectサンプル
- Kinectを使って、顔の動きを認識して画面に表示する
- Kinectによる深度データの取得・表示と、モーターを動かすサンプル


