読者です 読者をやめる 読者になる 読者になる

Natural Software

KinectなどのDepthセンサーを中心に活動しています

Kinect + Kinect SDK と Xtion + OpenNI を同時に使う

Kinect

昨日、寝る前にふと思ったんですよ。
Kinectを使って、Kinect SDKとOpenNIは共存できないけど、デバイスの違うKinect + Kinect SDK と Xtion + OpenNIなら共存できるのではないか?と
で、今朝やってみたら、できましたね。これで、いちいちPCを分けずに済みそうです...
今までそこまで頭が回らなかったw


配置はこんな感じ

ソース

やってることは単純に、KinectとXtionのカメラ画像を表示してます。
プロジェクト全体はこちらです。

XAML
&#65279;<Window x:Class="KinectAndXtion.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="312" Width="702" Closing="Window_Closing">
    <Grid>
        <Image Height="240" HorizontalAlignment="Left" Name="imageKinectSDK" Stretch="Fill" VerticalAlignment="Top" Width="320
               " Margin="0,34,0,0" />
        <Image Height="240" HorizontalAlignment="Left" Margin="360,34,0,0" Name="imageOpenNI" Stretch="Fill" VerticalAlignment="Top" Width="320" />
        <Label Content="Kinect &amp; Kinect SDK" Height="39" HorizontalAlignment="Left" Name="label1" VerticalAlignment="Top" Width="320" HorizontalContentAlignment="Center" FontSize="18" />
        <Label Content="Xtion &amp; OpenNI" Height="39" HorizontalAlignment="Right" Name="label2" VerticalAlignment="Top" Width="320" HorizontalContentAlignment="Center" FontSize="18" />
    </Grid>
</Window>
CS
using System;
using System.Windows;
using Coding4Fun.Kinect.Wpf;
using Microsoft.Research.Kinect.Nui;
using System.Threading;
using OpenNI;
using System.Windows.Threading;
using System.Windows.Media.Imaging;
using System.Windows.Media;


namespace KinectAndXtion
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private Context context;
        private ImageGenerator image;

        private Thread readerThread;
        private bool shouldRun;

        public MainWindow()
        {
            InitializeComponent();

            try {
                InitKinectSDK();
                InitOpenNI();

            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message );
                Close();
            }
        }

        private void InitOpenNI()
        {
            // ContextとImageGeneratorの作成
            ScriptNode node;
            context = Context.CreateFromXmlFile( "SamplesConfig.xml", out node );
            context.GlobalMirror = false;
            image = context.FindExistingNode( NodeType.Image ) as ImageGenerator;

            // 画像更新のためのスレッドを作成
            shouldRun = true;
            readerThread = new Thread( new ThreadStart( () =>
            {
                while ( shouldRun ) {
                    context.WaitAndUpdateAll();
                    ImageMetaData imageMD = image.GetMetaData();

                    // ImageMetaDataをBitmapSourceに変換する(unsafeにしなくてもOK!!)
                    this.Dispatcher.BeginInvoke( DispatcherPriority.Background, new Action( () =>
                    {
                        imageOpenNI.Source = BitmapSource.Create( imageMD.XRes, imageMD.YRes,
                            96, 96, PixelFormats.Rgb24, null, imageMD.ImageMapPtr,
                            imageMD.DataSize, imageMD.XRes * imageMD.BytesPerPixel );
                    } ) );
                }
            } ) );
            readerThread.Start();
        }

        private void InitKinectSDK()
        {
            // Kinectインスタンスを取得する
            Runtime kinect = Runtime.Kinects[0];
            kinect.Initialize( RuntimeOptions.UseColor );

            // RGBカメラの初期化と、イベントを登録する
            kinect.VideoStream.Open( ImageStreamType.Video, 2,
                ImageResolution.Resolution640x480, ImageType.Color );
            kinect.VideoFrameReady +=
                    new EventHandler<ImageFrameReadyEventArgs>( kinect_VideoFrameReady );
        }

        // RGBカメラのフレーム更新イベント
        void kinect_VideoFrameReady( object sender, ImageFrameReadyEventArgs e )
        {
            // RGBカメラの画像を、Imageに表示する
            // ToBitmapSource()は、Coding4Fun.Kinect.Wpfにある拡張メソッド
            imageKinectSDK.Source = e.ImageFrame.ToBitmapSource();
        }

        private void Window_Closing( object sender, System.ComponentModel.CancelEventArgs e )
        {
            shouldRun = false;
        }
    }
}

まとめ

何も特別なことをせずに、両方使えるのはいいですね:-)