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

SourceChord

C#とXAML好きなプログラマの備忘録。最近はWPF系の話題が中心です。

KinectでカメラのRGBデータ取得

C# WPF Kinect

Kinectプログラミング、はじめの一歩として、RGBカメラの画像を表示してみました。



手順

  1. プロジェクトの参照に以下を追加
    1. Microsoft.Kinect.dll
  2. コード
    1. WindowのLoadイベントで以下の処理を行う
      1. Kinectが接続されているかチェック
      2. ColorStreamのEnableメソッドを呼び出し、ストリームを有効にする
      3. ColorFrameReadyイベントハンドラの設定。フレームの更新の通知を受けるイベント
    2. WindowのCloseイベント
      1. KinectSensorのStopメソッド呼び出し
    3. ColorFrameReadyイベント
      1. イベント引数からフレームを取得し、画面表示用のWriteableBitmapにコピーする

Kinectの画像データを格納するWriteableBitmapは、DependencyPropertyにしておき、XAML側からバインドしました。

取得するColorImageの種類

ColorStreamのEnableメソッドに渡す引数で、取得する画像の種類を指定できます。
取得できる画像の種類は以下の列挙体で定義されています。
ColorImageFormat Enumeration


全コードは以下の通り。

MainWindow.xaml
<Window x:Class="KinectTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" Closing="Window_Closing">
    <Grid>
        <Image Source="{Binding ColorBitmap}"/>
    </Grid>
</Window>
MainWindow.xaml.cs
using Microsoft.Kinect;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

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

        public WriteableBitmap ColorBitmap
        {
            get { return (WriteableBitmap)GetValue(ColorBitmapProperty); }
            set { SetValue(ColorBitmapProperty, value); }
        }
        // Using a DependencyProperty as the backing store for ColorBitmap.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ColorBitmapProperty =
            DependencyProperty.Register("ColorBitmap", typeof(WriteableBitmap), typeof(MainWindow), new PropertyMetadata(null));


        private byte[] colorPixels;

        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = this;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            if (KinectSensor.KinectSensors.Count <= 0)
            {
                MessageBox.Show("Kinectが接続されていません。");
                Close();
            }
            this.sensor = KinectSensor.KinectSensors.FirstOrDefault(x => x.Status == KinectStatus.Connected);

            if (this.sensor != null)
            {
                this.sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
                this.colorPixels = new byte[this.sensor.ColorStream.FramePixelDataLength];
                this.ColorBitmap = new WriteableBitmap(this.sensor.ColorStream.FrameWidth, this.sensor.ColorStream.FrameHeight, 96, 96, PixelFormats.Bgr32, null);
                this.sensor.ColorFrameReady += sensor_ColorFrameReady;
            }

            try
            {
                this.sensor.Start();
            }
            catch (IOException)
            {
                this.sensor = null;
            }

            if (this.sensor == null)
            {
                MessageBox.Show("使用可能なKinectが見つかりません");
            }
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (this.sensor != null)
            {
                this.sensor.Stop();
            }
        }

        void sensor_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
        {
            using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
            {
                if (colorFrame != null)
                {
                    var bmp = this.ColorBitmap;
                    colorFrame.CopyPixelDataTo(this.colorPixels);
                    bmp.WritePixels(
                        new Int32Rect(0, 0, bmp.PixelWidth, bmp.PixelHeight),
                        this.colorPixels,
                        bmp.PixelWidth * sizeof(int),
                        0);
                }
            }
        }
    }
}