2012年8月31日金曜日

KINECTサンプル(VB) SkeletonTracking for SDK1.5

KINECTサンプルプログラム 骨格追跡 のVB版です。

C#版と内容はほとんど同じです。

違うところは関節部分を表す円のサイズを距離によって変化するようにしてみました。


MainWindow.xaml
------------------------------------------------------------------------------

<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="519" Width="1175">
    <Grid Width="1141">
        <Canvas Height="480" HorizontalAlignment="Left" Name="canvas1" VerticalAlignment="Top" Width="640" />
        <TextBox Height="40" HorizontalAlignment="Left" Margin="743,46,0,0" Name="skelx" VerticalAlignment="Top" Width="120" FontSize="20" />
        <TextBox Height="40" HorizontalAlignment="Left" Margin="869,46,0,0" Name="skely" VerticalAlignment="Top" Width="120" FontSize="20" />
        <TextBox Height="40" HorizontalAlignment="Left" Margin="995,46,0,0" Name="skelz" VerticalAlignment="Top" Width="120" FontSize="20" />
        <TextBox Height="40" HorizontalAlignment="Left" Margin="743,95,0,0" Name="depthx" VerticalAlignment="Top" Width="120" FontSize="20" />
        <TextBox Height="40" HorizontalAlignment="Left" Margin="869,95,0,0" Name="depthy" VerticalAlignment="Top" Width="120" FontSize="20" />
        <TextBox Height="40" HorizontalAlignment="Left" Margin="995,95,0,0" Name="depthz" VerticalAlignment="Top" Width="120" FontSize="20" />
        <Label Content="Skeleton" Height="40" HorizontalAlignment="Left" Margin="646,46,0,0" Name="label1" VerticalAlignment="Top" FontSize="20" />
        <Label Content="Depth" FontSize="20" Height="40" HorizontalAlignment="Left" Margin="671,95,0,0" Name="label2" VerticalAlignment="Top" />
        <Label Content="Z" FontSize="20" Height="40" HorizontalAlignment="Left" Margin="995,0,0,0" Name="label3" VerticalAlignment="Top" Width="120" HorizontalContentAlignment="Center" />
        <Label Content="X" FontSize="20" Height="40" HorizontalAlignment="Left" Margin="743,0,0,0" Name="label4" VerticalAlignment="Top" Width="120" HorizontalContentAlignment="Center" />
        <Label Content="Y" FontSize="20" Height="40" HorizontalAlignment="Left" Margin="869,0,0,0" Name="label5" VerticalAlignment="Top" Width="120" HorizontalContentAlignment="Center" />
    </Grid>
</Window>
------------------------------------------------------------------------------
C#版と一緒です。
キャンバスとテキストボックスを配置しています。

MainWindow.xaml.cs
------------------------------------------------------------------------------

Imports Microsoft.Kinect

Class MainWindow
    Inherits Window

    Private kinect As KinectSensor
    Private skeletonData As Skeleton()


    ''' <summary>
    '''
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()

        ' この呼び出しはデザイナーで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。

        ''接続の確認
        If KinectSensor.KinectSensors.Count = 0 Then
            MessageBox.Show("KINECTが見つかりません。")
            Exit Sub
        End If

        kinect = KinectSensor.KinectSensors(0)

        ''Depthカメラを有効にする
        kinect.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30)
        ''骨格追跡を有効にする
        kinect.SkeletonStream.Enable()

        ''イベントの登録
        AddHandler kinect.AllFramesReady, AddressOf kinect_AllFramesReady

        ''KINECTのスタート
        kinect.Start()

    End Sub

    ''' <summary>
    '''
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub kinect_AllFramesReady(ByVal sender As Object, ByVal e As AllFramesReadyEventArgs)

        ''フレームデータの取得
        Using skelFrame As SkeletonFrame = e.OpenSkeletonFrame()
            Using depthFrame As DepthImageFrame = e.OpenDepthImageFrame()

                If skelFrame Is Nothing = False Then
                    ''キャンバスのクリア
                    canvas1.Children.Clear()

                    ''Skeletonデータの取得
                    skeletonData = New Skeleton(skelFrame.SkeletonArrayLength - 1) {}
                    skelFrame.CopySkeletonDataTo(skeletonData)

                    ''プレイヤーごとの描画
                    For Each skel In skeletonData
                        If skel.TrackingState = SkeletonTrackingState.Tracked Then
                            ''骨格を描画
                            For Each jt As Joint In skel.Joints
                                If jt.TrackingState <> JointTrackingState.NotTracked Then
                                    ''骨格の座標(頭)
                                    If jt.JointType = JointType.Head Then
                                        skelx.Text = jt.Position.X.ToString()
                                        skely.Text = jt.Position.Y.ToString()
                                        skelz.Text = jt.Position.Z.ToString()
                                    End If

                                    ''座標の変換(DepthFrame 640*480)
                                    Dim pt As DepthImagePoint = depthFrame.MapFromSkeletonPoint(jt.Position)

                                    ''depth座標に変換後の座標(頭)
                                    If jt.JointType = JointType.Head Then
                                        depthx.Text = pt.X.ToString()
                                        depthy.Text = pt.Y.ToString()
                                        depthz.Text = pt.Depth.ToString()
                                    End If

                                 
                                    ''円の表示
                                    If jt.TrackingState = JointTrackingState.Tracked Then
                                        Dim el As New Ellipse
                                        canvas1.Children.Add(el)
                                        With el
                                            .Margin = New Thickness(pt.X, pt.Y, 0, 0)
                                            .Fill = New SolidColorBrush(Colors.Green)
                                            .Width = CInt((4000 - pt.Depth) / 100) + 10
                                            .Height = CInt((4000 - pt.Depth) / 100) + 10
                                        End With
                                    Else
                                        Dim el As New Ellipse
                                        canvas1.Children.Add(el)
                                        With el
                                            .Margin = New Thickness(pt.X, pt.Y, 0, 0)
                                            .Fill = New SolidColorBrush(Colors.Red)
                                            .Width = CInt((4000 - pt.Depth) / 100) + 10
                                            .Height = CInt((4000 - pt.Depth) / 100) + 10
                                        End With
                                    End If
                                End If
                            Next
                        End If
                    Next


                End If

            End Using
        End Using

------------------------------------------------------------------------------
プログラムの内容はC#版を参照してください。
違うところは円を表示するところでサイズを距離に応じて変えている部分になります。
「CInt((4000 - pt.Depth) / 100)」式のうち4000はデフォルトモードでの認識最大距離4mをミリメートルとしているためです。ちょっとだけ3Dっぽく見えるはずです。


2012年8月30日木曜日

KINECTサンプル(C#) SkeletonTracking for SDK1.5

今回は骨格追跡のサンプルになります。
骨格追跡は座標系がRGBカメラやDepthカメラと全然違うので(厳密に言うとDepthもですけど)色々やらなければいけないことが増えています。

サンプルを実行すると、認識した人物の各関節部分に円を表示します。
認識できている部位は緑色で、推定している部位は赤色で表示します。
それから頭部の座標をSkeletonFrameの場合と、Depthデータとマッピングした時の場合を表示しています。

MainWindow.xaml
------------------------------------------------------------------------------
<Window x:Class="KinectSkeletonforSDK15.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="519" Width="1175">
    <Grid Width="1141">
        <Canvas Height="480" HorizontalAlignment="Left" Name="canvas1" VerticalAlignment="Top" Width="640" />
        <TextBox Height="40" HorizontalAlignment="Left" Margin="743,46,0,0" Name="skelx" VerticalAlignment="Top" Width="120" FontSize="20" />
        <TextBox Height="40" HorizontalAlignment="Left" Margin="869,46,0,0" Name="skely" VerticalAlignment="Top" Width="120" FontSize="20" />
        <TextBox Height="40" HorizontalAlignment="Left" Margin="995,46,0,0" Name="skelz" VerticalAlignment="Top" Width="120" FontSize="20" />
        <TextBox Height="40" HorizontalAlignment="Left" Margin="743,95,0,0" Name="depthx" VerticalAlignment="Top" Width="120" FontSize="20" />
        <TextBox Height="40" HorizontalAlignment="Left" Margin="869,95,0,0" Name="depthy" VerticalAlignment="Top" Width="120" FontSize="20" />
        <TextBox Height="40" HorizontalAlignment="Left" Margin="995,95,0,0" Name="depthz" VerticalAlignment="Top" Width="120" FontSize="20" />
        <Label Content="Skeleton" Height="40" HorizontalAlignment="Left" Margin="646,46,0,0" Name="label1" VerticalAlignment="Top" FontSize="20" />
        <Label Content="Depth" FontSize="20" Height="40" HorizontalAlignment="Left" Margin="671,95,0,0" Name="label2" VerticalAlignment="Top" />
        <Label Content="Z" FontSize="20" Height="40" HorizontalAlignment="Left" Margin="995,0,0,0" Name="label3" VerticalAlignment="Top" Width="120" HorizontalContentAlignment="Center" />
        <Label Content="X" FontSize="20" Height="40" HorizontalAlignment="Left" Margin="743,0,0,0" Name="label4" VerticalAlignment="Top" Width="120" HorizontalContentAlignment="Center" />
        <Label Content="Y" FontSize="20" Height="40" HorizontalAlignment="Left" Margin="869,0,0,0" Name="label5" VerticalAlignment="Top" Width="120" HorizontalContentAlignment="Center" />
    </Grid>
</Window>
------------------------------------------------------------------------------
今回はCanvasコントロールと座標データを表示するためのテキストボックスを配置しています。



MainWindow.xaml.cs
------------------------------------------------------------------------------
using System;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

using Microsoft.Kinect;

namespace KinectSkeletonforSDK15
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private KinectSensor kinect;

        /// <summary>
        ///
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
     
            //接続の確認
            if (KinectSensor.KinectSensors.Count == 0)
            {
                MessageBox.Show("KINECTがみつかりません。");
                Close();
            }

            kinect = KinectSensor.KinectSensors[0];

            //Depthカメラを有効にする
            kinect.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
            //骨格追跡を有効にする
            kinect.SkeletonStream.Enable();

            //イベントの登録
            kinect.AllFramesReady += new EventHandler<AllFramesReadyEventArgs>(kinect_AllFramesReady);
         
            //KINECTのスタート
            kinect.Start();

        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void kinect_AllFramesReady(object sender, AllFramesReadyEventArgs e)
        {
         
            using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
            using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
            {

                if (skeletonFrame != null)
                {
                    //キャンバスのクリア
                    canvas1.Children.Clear();

                    //Skeletonデータの取得
                    Skeleton[] skeletonData = new Skeleton[skeletonFrame.SkeletonArrayLength];
                    skeletonFrame.CopySkeletonDataTo(skeletonData);

                    //プレイヤーごとの描画
                    foreach (var skeleton in skeletonData)
                    {
                        if (skeleton.TrackingState == SkeletonTrackingState.Tracked)
                        {
                            //骨格を描画
                            foreach (Joint joint in skeleton.Joints)
                            {
                                if (joint.TrackingState != JointTrackingState.NotTracked)
                                {
                                    //骨格の座標(頭)
                                    if (joint.JointType == JointType.Head)
                                    {
                                        skelx.Text = joint.Position.X.ToString();
                                        skely.Text = joint.Position.Y.ToString();
                                        skelz.Text = joint.Position.Z.ToString();
                                    }

                                    //座標の変換(DepthFrame 640*480)
                                    DepthImagePoint point = depthFrame.MapFromSkeletonPoint(joint.Position);

                                    //depth座標に変換後の座標(頭)
                                    if (joint.JointType == JointType.Head)
                                    {
                                        depthx.Text = point.X.ToString();
                                        depthy.Text = point.Y.ToString();
                                        depthz.Text = point.Depth.ToString();
                                    }

                                    //円の表示
                                    if (joint.TrackingState == JointTrackingState.Tracked)
                                    {
                                        canvas1.Children.Add(new Ellipse()
                                        {
                                            Margin = new Thickness(point.X, point.Y, 0, 0),
                                            Fill = new SolidColorBrush(Colors.Green),
                                            Width = 10,
                                            Height = 10
                                        });
                                    }

                                    else
                                    {
                                        canvas1.Children.Add(new Ellipse()
                                        {
                                            Margin = new Thickness(point.X, point.Y, 0, 0),
                                            Fill = new SolidColorBrush(Colors.Red),
                                            Width = 10,
                                            Height = 10
                                        });
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
------------------------------------------------------------------------------
フレームの更新イベントが変わっています。複数タイプのフレームを同期しながら処理する場合に「AllFramesReady」を利用します。今回はDepthフレームとSkeletonフレームを使っています。
骨格追跡を行うにはDepthフレーム、Skeletonフレームはどちらも必要です。

Skeletonフレームには認識できたプレイヤーの人数分のデータが構造体として格納されています。
Skeleton構造体には各関節(Joint)の座標データやトラッキングの状態などが格納されています。

プログラムでは1人ずつのSkeleton構造体を取得してから、Joint構造体の値(座標)を取得します。
Joint構造体の座標は3次元座標(KINECTを中心にした右手系座標)なので、平面に表示するために変換が必要になります。
今回はDepthフレームに合わせて2次元座標(Depthフレームのデータは左上を原点としています)に変換しています。(MapFromSkeletonPointメソッドを使っています。)
座標の違いはテキストボックスの値を確認してください。ちなみにKINECTまでの距離(Z座標)の単位はSkeletonはメートル(m)、Depthはミリメートル(mm)です。

変換した座標を元にCanvasコントロールに円を追加して各関節部分を表示しています。

各フレームの重ね合わせの方法がいくつかあるのでまたの機会にまとめてみたいと思います。


2012年8月29日水曜日

KINECTサンプル(VB) Depthカメラ for SDK1.5

DepthサンプルのVBです。

基本的にC#版と同じです。

MainWindow.xaml
------------------------------------------------------------------------------

<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="520" Width="700">
    <Grid>
        <Image Name="DepthImg" Stretch="Uniform" Height="480" Width="640" />
    </Grid>
</Window>
------------------------------------------------------------------------------

イメージコントロールを1つ配置しています。

MainWindow.xaml.vb
------------------------------------------------------------------------------
Imports Microsoft.Kinect

Class MainWindow

    Inherits Window

    Private kinect As KinectSensor
    Private colorPixel As Byte()
    Private depthPixel As Short()

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()

        ' この呼び出しはデザイナーで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。

        ''接続の確認
        If KinectSensor.KinectSensors.Count = 0 Then
            MessageBox.Show("KINECTが見つかりません。")
            Exit Sub
        End If

    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Window_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded

        kinect = KinectSensor.KinectSensors(0)

        ''Depthカメラの設定
        kinect.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30)

        ''データ用配列の準備
        colorPixel = New Byte(kinect.DepthStream.FramePixelDataLength * 4 - 1) {}
        depthPixel = New Short(kinect.DepthStream.FramePixelDataLength - 1) {}

        ''イベントの登録
        AddHandler kinect.DepthFrameReady, AddressOf kinect_depthFrameReady

        ''KINECTのスタート
        kinect.Start()

    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub kinect_depthFrameReady(ByVal sender As Object, ByVal e As DepthImageFrameReadyEventArgs)

        Using depthFrame As DepthImageFrame = e.OpenDepthImageFrame
            If depthFrame Is Nothing = False Then
                ''Depthカメラのデータを取得
                depthFrame.CopyPixelDataTo(depthPixel)

                ''距離データから画像を生成
                Dim i As Integer
                Dim j As Integer = 0
                Dim depth As Short
                Dim dist As Byte
                For i = 0 To depthPixel.Length - 1

                    ''距離データの取り出し
                    depth = CShort(depthPixel(i) >> DepthImageFrame.PlayerIndexBitmaskWidth)

                    ''画素データに変換 SDKのサンプルを参照
                    dist = CByte((depth + 1) And Byte.MaxValue)

                    ''距離データを100分率で表現
                    ''dist = CByte(255 - (255 * depth / 4095))

                    ''//距離データ 13ビットを4ビットシフトしてから8ビット分だけ取り出す場合
                    ''dist = CByte((depth + 1) >> 4 And Byte.MaxValue)

                    ''RGBイメージに書込み
                    colorPixel(j) = dist
                    colorPixel(j + 1) = dist
                    colorPixel(j + 2) = dist
                    j = j + 4

                Next

                DepthImg.Source = BitmapSource.Create(depthFrame.Width, depthFrame.Height, 96, 96, PixelFormats.Bgr32, Nothing, colorPixel, depthFrame.Width * 4)

            End If
        End Using
    End Sub
End Class
------------------------------------------------------------------------------

C#版とは違いはありません。
Depthイメージをそのまま表示することはほとんどないでしょうが、データ構造を理解するのには知っておく必要があるのではないかと思います。

次は骨格認識の予定です。

2012年8月28日火曜日

KINECTサンプル(C#) Depthカメラ for SDK1.5

今回はDepthカメラのデータを表示してみます。

RGBカメラのデータは色情報ですので、ほぼそのまま画像データとして利用できますが、Depthカメラのデータは距離データ+αなのでそれを画像データに変換することが必要になります。

MainWindow.xaml
------------------------------------------------------------------------------

<Window x:Class="KinectDepthforSDK15.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="520" Width="700">
    <Grid>
        <Image Name="Depth" Stretch="Uniform" Height="480" Width="640" />
    </Grid>
</Window>
------------------------------------------------------------------------------

RGBカメラの時と同様にイメージコントロールを一つ配置しています。


MainWindow.xaml.cs
------------------------------------------------------------------------------

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

using Microsoft.Kinect;

namespace KinectDepthforSDK15
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        KinectSensor kinect;

        public MainWindow()
        {
            InitializeComponent();

            //接続の確認
            if (KinectSensor.KinectSensors.Count == 0)
            {
                MessageBox.Show("KINECTが見つかりません。");
                Close();
            }

            kinect = KinectSensor.KinectSensors[0];

            //Depthカメラの設定
            kinect.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);

            //イベントの登録
            kinect.DepthFrameReady += new EventHandler<DepthImageFrameReadyEventArgs>(kinect_DepthFrameReady);

            //KINECTのスタート
            kinect.Start();

        }

        void kinect_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
        {
            using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
            {
                if (depthFrame != null)
                {
                    //Depthカメラの深度データ
                    short[] depthPixel = new short[depthFrame.PixelDataLength];
                    depthFrame.CopyPixelDataTo(depthPixel);

                    //表示用画像データ配列(画像データは4チャンネル必要なので要素数は4倍になる)
                    byte[] colorPixel = new byte[depthFrame.Width*depthFrame.Height * 4];

                    //距離データから画像を生成するループ
                    int j = 0;

                    for (int i = 0; i < depthPixel.Length; i++)
                    {
                        //距離データの取り出し
                        short depth = (short)( depthPixel[i] >> DepthImageFrame.PlayerIndexBitmaskWidth);

                        //画素データに変換(距離データのうち下位1バイトで表現している)
                        //SDKのDepthサンプルを参考
                        byte dist = (byte)((depth + 1) & byte.MaxValue);    //byte.MaxValue=255

                        //距離データ(0-4095)を100分率で表現するなら次の式で
                        //byte dist = (byte)(255 - (255 * depth / 4095));

                        //距離データ 13ビットを4ビットシフトしてから8ビット分だけ取り出す場合
                        //byte dist = (byte)(depth + 1 >> 4 & byte.MaxValue);

                        //RGBイメージ配列に書込み
                        colorPixel[j] = dist;
                        colorPixel[j + 1] = dist;
                        colorPixel[j + 2] = dist;
                        j += 4;
                    }

                    //イメージコントロールに設定
                    Depth.Source = BitmapSource.Create(depthFrame.Width, depthFrame.Height, 96, 96, PixelFormats.Bgr32, null, colorPixel, depthFrame.Width * 4);

                }
            }
        }

    }
}


------------------------------------------------------------------------------

プログラムの前半はRGBカメラの時とほとんど変わりません。

Depthカメラからのデータは1ピクセルあたり2バイト(16ビット)になりますのでshort型配列に取り込みます。

表示用のイメージデータはBGR32タイプになるので画像サイズ(640*480)の4倍必要になります。

距離データは16ビット中上位13ビットで標準モードの場合0-4095(mm)の距離を表します。残り3ビットは認識しているプレイヤーのIDが入るのですが、今回は骨格認識を有効にしていないので利用できません。

 「depthPixel[i] >> DepthImageFrame.PlayerIndexBitmaskWidth」で3ビット右にシフトして距離データを取り出しています。

距離データは0-4095の値になるのでこれを0-255(画素データは8ビット)に収まるようにすれば距離に応じたイメージデータを得ることができます。
SDKのサンプルでは取り出した距離データに1を足して(計測できない距離データが-1になるのでそれを補正しているのだと思います。)から下位8ビットデータを取り出して画素データとしています。
ほかにもいろいろ表現の仕方はあると思います。

得られた画像を見てみると人物などに影ができていますが、これはDepthカメラの仕様(赤外線を利用している)でどうしてもできてしまうようです。





2012年8月26日日曜日

KINECTサンプル(VB) RGBカメラ for SDK1.5

KINECTのサンプル VB版です。

C#と同じ内容です。

開発環境は

Windows7 Ultimate 64bit SP1
Visual Basic 2010 Express
KINECT SDK 1.5
KINECT for Windows

となります。

WPFアプリケーションです。

プロジェクトの参照の追加で「Microsoft.Kinect」を追加するようにしてください。


MainWindow.xaml
------------------------------------------------------------------------------

<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="520" Width="700">
    <Grid>
        <Image Name="Rgb" Stretch="Uniform" Height="480" Width="640" />
    </Grid>
</Window>
------------------------------------------------------------------------------

C#とまったく同じです。イメージコントロールを1つ配置しています。


MainWindow.xaml.vb
------------------------------------------------------------------------------
Imports Microsoft.Kinect

Class MainWindow

    Inherits Window

    Private kinect As KinectSensor
    Private colorPixel As Byte()

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub New()

        ' この呼び出しはデザイナーで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。

        ''接続の確認
        If KinectSensor.KinectSensors.Count = 0 Then
            MessageBox.Show("KINECTが見つかりません。")
            Exit Sub
        End If

    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub Window_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded

        kinect = KinectSensor.KinectSensors(0)

        ''RGBデータ用配列の初期化
        colorPixel = New Byte(kinect.ColorStream.FramePixelDataLength - 1) {}

        ''RGBカメラの設定
        kinect.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30)

        ''イベントの登録
        AddHandler kinect.ColorFrameReady, AddressOf kinect_colorFrameReady

        ''KINECTのスタート
        kinect.Start()

    End Sub

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub kinect_colorFrameReady(ByVal sender As Object, ByVal e As ColorImageFrameReadyEventArgs)

        Using colorFrame As ColorImageFrame = e.OpenColorImageFrame
            If colorFrame Is Nothing = False Then

                colorFrame.CopyPixelDataTo(colorPixel)

                Rgb.Source = BitmapSource.Create(colorFrame.Width, colorFrame.Height, 96, 96, PixelFormats.Bgr32, Nothing, colorPixel, colorFrame.Width * colorFrame.BytesPerPixel)

            End If
        End Using

    End Sub
End Class
------------------------------------------------------------------------------

C#と比べてほとんど違いはありません。NullがNothingになるのをよく間違えますけど^^;

画像データを生成している箇所の説明を少しします。
イメージコントロールのソースを「BitmapSource.Create」で行っていますが、構文は

BitmapSource.Create( 
               画像の幅、
               画像の高さ、
               表示するDPIのX値(通常は96に固定)、
               表示するDPIのY値(通常は96に固定)、
               ビットマップのピクセル形式(BGR32が推奨?)、
               ビットマップのパレット(使わない?)、
               ビットマップを表すバイト配列(KINECTのRGBデータ)、
               ストライド(ビットマップの幅×1ピクセル当りのバイト数 32ビットなので4バイト)
               )

となります。

KINECTからのRGBデータ(バイト配列)を加工することによっていろいろな画像表示が可能になります。




2012年8月25日土曜日

KINECTサンプル(C#) RGBカメラ for SDK1.5

以前の投稿から時間が過ぎてしまいましたが、ここ最近また色々プログラムを書いているので備忘録として基本的なサンプルプログラムを掲載します。

開発環境は

Windows7 Ultimate 64bit SP1
Visual C# 2010 Express
KINECT SDK 1.5
KINECT for Windows

となります。

KINECT SDKは最新版をそのままインストールしているだけです。

サンプルはWPFアプリケーションです。

RGBカメラの画像を表示するサンプルです。

------------------------------------------------------------------------------
追記(2012/08/26)

プロジェクトの参照設定で「Microsoft.Kinect」を追加してください。
------------------------------------------------------------------------------


MainWindow.xaml
------------------------------------------------------------------------------

<Window x:Class="KinectRGBforSDK15.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="520" Width="700">
    <Grid>
        <Image Name="Rgb" Stretch="Uniform" Height="480" Width="640" />
    </Grid>
</Window>
------------------------------------------------------------------------------

イメージコントロールを1つだけ配置しています。

MainWindows.xaml.cs
------------------------------------------------------------------------------
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

using Microsoft.Kinect;

namespace KinectRGBforSDK15
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        KinectSensor kinect;

        public MainWindow()
        {
            InitializeComponent();

            //接続の確認
            if (KinectSensor.KinectSensors.Count == 0)
            {
                MessageBox.Show("KINECTが見つかりません。");
                Close();
            }

            kinect = KinectSensor.KinectSensors[0];

            //RGBカメラの設定
            kinect.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);

            //イベントの登録
            kinect.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(kinect_colorFrameReady);

            //KINECTのスタート
            kinect.Start();

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void kinect_colorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
            {
                if (colorFrame != null)
                {
                    //RGBカメラのビットイメージデータ
                    byte[] colorPixel = new byte[colorFrame.PixelDataLength];
                    colorFrame.CopyPixelDataTo(colorPixel);

                    //ビットマップイメージの作成
                    Rgb.Source = BitmapSource.Create(colorFrame.Width, colorFrame.Height, 96, 96, PixelFormats.Bgr32, null, colorPixel, colorFrame.Width * colorFrame.BytesPerPixel);

                }
            }
        }

    }
}
------------------------------------------------------------------------------
エラー処理などは省略していますが、RGBカメラの画像を表示するだけならこれだけの記述でできます。

イベント内で取り出しているKINECTからのデータは32ビットのカラーイメージ(BGR8ビット+αチャンネル8ビット。ただしαチャンネルは0で固定  空きチャンネル8ビット)です。

これは640*480の画像1ピクセルを4バイトで表現していることになります。
WPFのイメージコントロールであつかえるビットマップイメージはBRG32形式に対応しているのでKINECTからのカラーイメージデータを元にそのままビットマップイメージを作ることができます。