ブログ@kaorun55

HoloLensやKinectなどのDepthセンサーを中心に書いています。

C# + WPF de OpenNI プログラミング #openni_ac

このエントリはOpenNI Advent Calendar 2011 : ATNDの12月4日分です!!
Advent Calendarでの、僕の全プロジェクトはこちらです


ちょっとWPFを触ったので、OpenNIでもWPFでやってみました。
とても簡単でびっくり。OpenNIのサンプルはWindows Formだけど、ライブラリはWPF用に作られているのではないかと思うほど...

見た目の解説

Imageを一つ貼り付けます。今度は、ツールボックスが出た。

<Window x:Class="CameraImageWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="519" Width="663" Closing="Window_Closing">
    <Grid>
        <Image Height="480" HorizontalAlignment="Left" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="640
               " />
    </Grid>
</Window>

中身の解説

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

using OpenNI;
using System.Threading;
using System.Windows.Media.Imaging;
using System;
using System.Windows.Threading;

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

        private Thread readerThread;
        private bool shouldRun;

        public MainWindow()
        {
            InitializeComponent();

            try {
                // 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( () =>
                        {
                            image1.Source = BitmapSource.Create( imageMD.XRes, imageMD.YRes,
                                96, 96, PixelFormats.Bgr24, null, imageMD.ImageMapPtr,
                                imageMD.DataSize, imageMD.XRes * imageMD.BytesPerPixel );
                        } ) );
                    }
                } ) );
                readerThread.Start();
            }
            catch ( Exception ex ) {
                MessageBox.Show( ex.Message );
            }
        }

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

特に変わらず

// ContextとImageGeneratorの作成
ScriptNode node;
context = Context.CreateFromXmlFile( "SamplesConfig.xml", out node );
context.GlobalMirror = false;
image = context.FindExistingNode( NodeType.Image ) as ImageGenerator;
データの更新

スレッドの作成までは同じ。BitmapSource.Createが、IntPtrとデータサイズを受け入れてくれるため、ImageMetaDataの内容で更新が可能です。

// 画像更新のためのスレッドを作成
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( () =>
        {
            image1.Source = BitmapSource.Create( imageMD.XRes, imageMD.YRes,
                96, 96, PixelFormats.Bgr24, null, imageMD.ImageMapPtr,
                imageMD.DataSize, imageMD.XRes * imageMD.BytesPerPixel );
        } ) );
    }
} ) );
readerThread.Start();

まとめ

このように、C#+WPFが一番すっきりかけるので、OpenNIのこの組み合わせが一番いいのかぁと思いました。