Kinect for Windows SDK v2.0入門 目次
Kinectアプリを実運用する際に、センサーがささっているかどうかは非常に重要な問題です。イベントなどでの現地で設置されるものについてアプリが動作しない場合の切り分け、コンシューマー向けにアプリを出すとしてユーザーの接続忘れ、またアプリ動作中に不意にケーブルが抜けた場合の対処や注意メッセージなどがあります。
また、Public Previewでの動作上、アプリケーション起動の際に、直前の最後のフレームが送られてくる現象があります。これを回避するためにも使用します。
Kinect for Windows SDK v1と比べても非常に簡単な実装になっているので、地味ながら確実に組み込む機能になると思います。
なお、C++での実装について、動作はしていますが、もう少しやりようもある気がしています。もっと良い実装があれば教えてもらえると嬉しいです。
環境
筆者の環境は次の通りです。
- Windows 8.1 Pro Update1 64bit
- Visual Studio 2013 Ultimate(Express for Windows Desktopでも可)
- Kinect for Windows SDK v2.0-1407
- 32bitアプリケーション
- サンプルコードのリポジトリ
実行結果
Kinectの抜き差しによって表示が変わります。
解説
今まではKinectを開くと同時にストリームを開いていました。Kinectが未接続時にも問題なく動作はするのですが、実アプリになると未接続時にはユーザーへのメッセージが必要になるかと思います。
また、先にも書いたようにPublic Previewでの動作上、アプリケーション起動の際に、直前の最後のフレームが送られてくる現象があります。これを回避するためにも使用します。
初期化
初期化の手順は次の通りです
Kinectが接続される
- Kinectの接続通知が呼ばれる
- 各種Readerなどの設定を行う
Kinectの接続については、アプリ起動中に物理的に未接続から接続になった場合も、接続された状態でアプリを起動しても同じです。
C++はWAITABLE_HANDLEというハンドルを使ってイベントを取得します(現状はポーリングです)。C#についてはイベントハンドラを登録することで、変化があった時に呼び出されます。
C++
void initialize(){
// デフォルトのKinectを取得する
ERROR_CHECK( ::GetDefaultKinectSensor( &kinect ) );
// Kinectを開く
ERROR_CHECK( kinect->Open() );
BOOLEAN isOpen = false;
ERROR_CHECK( kinect->get_IsOpen( &isOpen ) );
if ( !isOpen ){
throw std::runtime_error("Kinectが開けません");
}
// Kinectの接続確認に登録する
kinect->SubscribeIsAvailableChanged( &waitableHandle );
}
C#(デスクトップ)
private void Window_Loaded( object sender, RoutedEventArgs e ){
try {
// Kinectを開く
kinect = KinectSensor.GetDefault();
kinect.Open();
// 挿抜検出イベントを設定
kinect.IsAvailableChanged += kinect_IsAvailableChanged;
}
catch ( Exception ex ) {
MessageBox.Show( ex.Message );
Close();
}
}
C#(Windows ストアアプリ)
protected override void OnNavigatedTo( NavigationEventArgs e ){
base.OnNavigatedTo( e );
try {
// Kinectを開く
kinect = KinectSensor.GetDefault();
kinect.Open();
// 挿抜検出イベントを設定
kinect.IsAvailableChanged += kinect_IsAvailableChanged;
}
catch ( Exception ex ) {
MessageDialog dlg = new MessageDialog(ex.Message);
dlg.ShowAsync();
}
}
抜き差しの検出イベント
Kinectの抜き差しを検出すると、C++ではIsAvailableの値が変わり、C#ではイベントハンドラが呼びされます。最初にKinectが接続された時(Readerがnullの時)はReaderの初期化を行います。この処理は今までの初期化処理と同じです。
C++
void updateKinectAvailable(){
ComPtr<IIsAvailableChangedEventArgs> args;
auto ret = kinect->GetIsAvailableChangedEventData( waitableHandle, &args );
if ( ret != S_OK ) {
return;
}
BOOLEAN available = false;
args->get_IsAvailable( &available );
// 未接続→接続
if ( !isAvailable && available ){
if ( colorFrameReader == nullptr ){
// カラーリーダーを取得する
ComPtr<IColorFrameSource> colorFrameSource;
ERROR_CHECK( kinect->get_ColorFrameSource( &colorFrameSource ) );
ERROR_CHECK( colorFrameSource->OpenReader( &colorFrameReader ) );
// カラー画像のサイズを取得する
ComPtr<IFrameDescription> colorFrameDescription;
ERROR_CHECK( colorFrameSource->CreateFrameDescription(
ColorImageFormat::ColorImageFormat_Bgra, &colorFrameDescription ) );
ERROR_CHECK( colorFrameDescription->get_Width( &colorWidth ) );
ERROR_CHECK( colorFrameDescription->get_Height( &colorHeight ) );
ERROR_CHECK( colorFrameDescription->get_BytesPerPixel( &colorBytesPerPixel ) );
// バッファーを作成する
colorBuffer.resize( colorWidth * colorHeight * colorBytesPerPixel );
}
}
// 接続→未接続
else if ( isAvailable && !available ){
cv::destroyAllWindows();
}
// 状態の更新
isAvailable = available;
}
C#(デスクトップ)
void kinect_IsAvailableChanged( object sender, IsAvailableChangedEventArgs e ){
// Kinectが接続された
if ( e.IsAvailable ) {
// カラーを設定する
if ( colorFrameReader == null ) {
colorFrameReader = kinect.ColorFrameSource.OpenReader();
colorFrameReader.FrameArrived += colorFrameReader_FrameArrived;
}
TextStatus.Text = "Kinectが接続されました";
}
// Kinectが外された
else {
// イメージを初期化する
ImageColor.Source = null;
TextStatus.Text = "Kinectが外されました";
}
}
C#(Windows ストアアプリ)
void kinect_IsAvailableChanged( KinectSensor sender, IsAvailableChangedEventArgs args ){
// Kinectが接続された
if ( args.IsAvailable ) {
// カラーを設定する
if ( colorFrameReader == null ) {
// カラー画像の情報を作成する(BGRAフォーマット)
colorFrameDesc = kinect.ColorFrameSource.CreateFrameDescription( ColorImageFormat.Bgra );
colorBitmap = new WriteableBitmap( colorFrameDesc.Width, colorFrameDesc.Height );
ImageColor.Source = colorBitmap;
colorBuffer = new byte[colorFrameDesc.Width * colorFrameDesc.Height * colorFrameDesc.BytesPerPixel];
// カラーリーダーを開く
colorFrameReader = kinect.ColorFrameSource.OpenReader();
colorFrameReader.FrameArrived += colorFrameReader_FrameArrived;
}
ImageColor.Source = colorBitmap;
TextStatus.Text = "Kinectが接続されました";
}
// Kinectが外された
else {
// イメージを初期化する
ImageColor.Source = null;
TextStatus.Text = "Kinectが外されました";
}
}
まとめ
v2ではKinectの接続状態が単純に取得できるようになります。その分実装もコンパクトで非常に助かります。