Microsoft Visual C++ 2012 Express
 Direct3D 11.0
 Kinect for Windows SDK v1.7
 DirectXTex texture processing library

■Kinect RGBカメラ Top Next
関連ページ:Direct3D 自作の共通ライブラリ


今回から Kinect やります。まあKinectは他のサイトで紹介されているようなので、最新情報がほしい人はそっちを参考にしてください。うちはマイペース更新なので。
Kinectはゲームだけでなく医療関係でも使用されているので今回やることにしました。


さて始める前にライセンスについて説明します。 リンク先のライセンス表記のとおり、2013/6/23現在、Kinect for Windows アプリケーションに関連して Kinect for Xbox 360 センサーを使用する場合、設計、開発、およびテストが可能ですが、 エンドユーザーが使用することはできません。開発したアプリケーションを配信する場合ご注意ください。
ちなみに当サイトではKinect for Xbox 360 センサーを使用しています。Kinect for Windows センサーでのテストは行っておりません。


次に開発環境を構築します。まず今回から最新であるMicrosoft Visual C++ 2012 Expressを使用するので、ダウンロードしてインストールしてください。

Kinect for Windows SDK v1.7 をダウンロードしてインストールしてください。
Kinect for Windows SDK用インクルードファイルのパス C:\Program Files\Microsoft SDKs\Kinect\v1.7\inc
Kinect for Windows SDK用ライブラリファイルのパス C:\Program Files\Microsoft SDKs\Kinect\v1.7\lib\x86

パスは環境によって変わる場合があるので、適当に脳内補完してください。


次にサンプル作成で参考にした書籍を紹介します。Kinect for Windows SDK C++編です。 この書籍ではレンダリングに OpenCV を使用していますが、当サイトは DirectX がメインなので、DirectX に変更します。 とはいえ OpenCV のほうが圧倒的に楽ちんなので、Kinect プログラミングに専念したい方は OpenCV を使うのも手です。


いよいよソースを見ていきます。

UCommon.h 共通で使用するヘッダファイル
UException.h 例外処理クラスのヘッダファイル
UDirect3D11.h Direct3Dクラスのヘッダーファイル
UDirect3D11.cpp Direct3Dクラスのソースファイル
UGraphicsPipeline.h グラフィックパイプラインクラスのヘッダーファイル
UGraphicsPipeline.cpp グラフィックパイプラインクラスのソースファイル
UMesh.h メッシュの抽象クラスのヘッダーファイル
UMesh.cpp メッシュの抽象クラスのソースファイル
Sample01.hlsl hlslファイル
UPlane01.h メッシュクラスのヘッダーファイル
UPlane01.cpp メッシュクラスのソースファイル
UKinect01.h Kinectクラスのヘッダーファイル
UKinect01.cpp Kinectクラスのソースファイル
main.cpp main関数のソースファイル

---Sample01.hlsl---  ↑


// テクスチャー
Texture2D g_Tex : register( t0 );

// サンプラーステート
SamplerState  g_Sampler : register( s0 );

// 頂点シェーダーの入力パラメータ
struct VS_IN
{
   float3 pos   : POSITION;   // 頂点座標
   float2 texel : TEXCOORD;   // テクセル
};

// 頂点シェーダーの出力パラメータ
struct VS_OUT_PS_IN
{
   float4 pos    : SV_POSITION;
   float2 texel  : TEXCOORD0;
};

// 頂点シェーダー
VS_OUT_PS_IN VS_Main( VS_IN In )
{
   VS_OUT_PS_IN Out = { float4( In.pos, 1.0f ), In.texel };
   return Out;
}

// ピクセルシェーダ
float4 PS_Main( VS_OUT_PS_IN In ) : SV_TARGET
{
   // BGRAの並びらしい
   return g_Tex.Sample( g_Sampler, In.texel ).bgra;
}

---UPlane01.h---  ↑

#ifndef UPLANE_H
#define UPLANE_H

#include "../../Common/Header/UCommon.h"
#include <NuiApi.h>
#include "../../Common/Header/UException.h."
#include "../../Common/Header/UMesh.h"
#include "../../Common/Header/UDirect3D11.h"

class UCPlane01 : public UIMesh
{
private:
   // 頂点定義
   typedef struct _VERTEX
   {
      // 頂点座標
      float x, y, z;
      // テクセル
      float tu, tv;
   }VERTEX;

   // 頂点バッファ
   ID3D11Buffer* m_pVertexBuffer;

   // インデックスバッファ
   ID3D11Buffer* m_pIndexBuffer;

   // シェーダーリソースビュー
   ID3D11ShaderResourceView* m_pSRView;

   // サンプラーステート
   ID3D11SamplerState* m_pSamplerState;
public:
   UCPlane01();
   ~UCPlane01();
   void Invalidate();
   void CreateMesh( ID3D11Device* pD3DDevice, UINT Width, UINT Height );
   void NextFrame( ID3D11DeviceContext* pD3DDeviceContext, NUI_LOCKED_RECT ColorData );
   void Render( ID3D11DeviceContext* pD3DDeviceContext );
};

#endif

---UPlane01.cpp---  ↑

#include "UPlane01.h"

UCPlane01::UCPlane01()
{
   m_pVertexBuffer = nullptr;
   m_pIndexBuffer = nullptr;
   m_pSRView = nullptr;
   m_pSamplerState = nullptr;
}

UCPlane01::~UCPlane01()
{
   Invalidate();
}

void UCPlane01::Invalidate()
{
   SAFE_RELEASE( m_pSamplerState );
   SAFE_RELEASE( m_pSRView );
   SAFE_RELEASE( m_pIndexBuffer );
   SAFE_RELEASE( m_pVertexBuffer );
}

void UCPlane01::CreateMesh( ID3D11Device* pD3DDevice, UINT Width, UINT Height )
{
   // 頂点データを格納する
   VERTEX v[] = { 
       1,  1, 0.0f, 1.0f, 0.0f,
      -1,  1, 0.0f, 0.0f, 0.0f,
       1, -1, 0.0f, 1.0f, 1.0f,
      -1, -1, 0.0f, 0.0f, 1.0f,
   };
      
   // 頂点バッファを作成する
   m_pVertexBuffer = CreateVertexBuffer( pD3DDevice, v, sizeof( v ), 0 );

   UINT Index[] = { 0, 1, 2, 3 };

   // インデックスバッファを作成する。
   m_pIndexBuffer = CreateIndexBuffer( pD3DDevice, Index, sizeof( Index ), 0 );

   // 空のデカールマップ用シェーダーリソースビューを作成する
   // GPU (読み取りのみ) と CPU (書き込みのみ) によるアクセスが可能なリソースとして作成する設定
   m_pSRView = CreateSRViewForDecalMap( pD3DDevice, Width, Height, UD3D11_FORMAT, UEACCESS_FLAG::UPDATE_SUBRESOURCE );

   // サンプラーステートを作成する
   m_pSamplerState = CreateSamplerState( pD3DDevice, D3D11_TEXTURE_ADDRESS_WRAP );
}

void UCPlane01::NextFrame( ID3D11DeviceContext* pD3DDeviceContext, NUI_LOCKED_RECT ColorData )
{
   ID3D11Resource* pResource = nullptr;

   __try
   {
      // シェーダーリソースビューからテクスチャーを取得する
      m_pSRView->GetResource( &pResource );

      // シェーダーリソースビューに色情報を設定する
      pD3DDeviceContext->UpdateSubresource( pResource, 0, nullptr, ColorData.pBits, ColorData.Pitch, 0 );
   }
   __finally
   {
      SAFE_RELEASE( pResource );
   }
}

void UCPlane01::Render( ID3D11DeviceContext* pD3DDeviceContext )
{
   // 頂点バッファ設定
   UINT stride = sizeof( UCPlane01::VERTEX );
   UINT offset = 0;
   pD3DDeviceContext->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &stride, &offset );

   // インデックスバッファ設定
   pD3DDeviceContext->IASetIndexBuffer( m_pIndexBuffer, DXGI_FORMAT_R32_UINT, 0 );

   // プリミティブ タイプおよびデータの順序に関する情報を設定
   pD3DDeviceContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );

   // ピクセルシェーダーのサンプラーステートを設定する
   pD3DDeviceContext->PSSetSamplers( 0, 1, &m_pSamplerState );

   // デカールマップを設定する
   pD3DDeviceContext->PSSetShaderResources( 0, 1, &m_pSRView );

   // 定数バッファを無効にする
   ID3D11Buffer* pNull[1] = { nullptr };
   pD3DDeviceContext->VSSetConstantBuffers( 0, _countof( pNull ), pNull );
   pD3DDeviceContext->PSSetConstantBuffers( 0, _countof( pNull ), pNull );

   // インデックスバッファを使用した描画
    pD3DDeviceContext->DrawIndexed( 4, 0, 0 );
}

---UKinect01.h---  ↑

#ifndef KINECT01_H
#define KINECT01_H

#include "../../Common/Header/UCommon.h"
#include <NuiApi.h>
#include "../../Common/Header/UException.h"

// Kinect用ライブラリ
#pragma comment( lib, "Kinect10.lib" )

class UCKinect01
{
private:
   INuiSensor* m_pKinectSensor;
   HANDLE m_ImageStreamHandle;
   NUI_IMAGE_FRAME m_ImageFrame;
public:
   UCKinect01();
   ~UCKinect01();
   void CreateKinect( DWORD& pWidth, DWORD& pHeight );
   NUI_LOCKED_RECT CreateColorDataAndNextFrame();
   void ReleaseColorData();
};

#endif

---UKinect01.cpp---  ↑

#include "../../Common/Header/UKinect01.h"

UCKinect01::UCKinect01()
{
   m_pKinectSensor = nullptr;
}

UCKinect01::~UCKinect01()
{
   if( m_pKinectSensor != nullptr )
      m_pKinectSensor->NuiShutdown();

   SAFE_RELEASE( m_pKinectSensor );
}

void UCKinect01::CreateKinect( DWORD& pWidth, DWORD& pHeight )
{
   HRESULT hr = E_FAIL;
   int count = 0;

   pWidth = 0;
   pHeight = 0;

   // マシンに接続されている Kinectセンサー 数を取得する。
   if( FAILED( hr = ::NuiGetSensorCount( &count ) ) )
      throw( UCException( hr, _T("UCKinect01::CreateKinect()でエラーが発生しました。接続されているKinectセンサーの数を取得できません。") ) );

   if( count == 0 )
      throw( UCException( -1, _T("UCKinect01::CreateKinect()でエラーが発生しました。Kinectセンサーが接続されていません。") ) );

   // 指定したインデックスの INuiSensor のインスタンスを作成する
   // ここでは 0 番目のインスタンスのみ作成する
   if( FAILED( hr = ::NuiCreateSensorByIndex( 0, &m_pKinectSensor ) ) )
      throw( UCException( hr, _T("UCKinect01::CreateKinect()でエラーが発生しました。Kinectセンサーが接続されていません。") ) );

   HRESULT status = E_FAIL;

   for( int i=0; i<50; i++ )
   {
      TCHAR msg[256];

      // Kinectセンサー の接続状態を取得する
      status = m_pKinectSensor->NuiStatus();
   
      // 正常
      if( status == S_OK )
         break;
      // Kinectセンサーが接続されているが、初期化中
      // Kinectセンサー接続直後にアプリを起動するとこの状態になるときがある
      else if( status == S_NUI_INITIALIZING )
      {
         _stprintf_s( msg, _T("■□■HRESULT:0x%x [ %s ]\n"), hr, _T(":Kinectセンサーが接続されているが、初期化中\n") );
         OutputDebugString( msg );
      }
      // Kinectセンサーが接続されているが、エラーが発生
      // Kinectセンサー接続直後にアプリを起動するとこの状態になるときがある
      else
      {
         _stprintf_s( msg, _T("■□■HRESULT:0x%x [ %s ]\n"), hr, _T(":Kinectセンサーが接続されているが、エラーが発生\n") );
         OutputDebugString( msg );
      }

      Sleep( 1000 );
   }
   if( status != S_OK )
      throw( UCException( -1, _T("UCKinect01::CreateKinect()でエラーが発生しました。Kinectセンサーが接続されているが、初期化が完了しなかった") ) );

   // Kinectを初期化する。ここでは RGBカメラ 機能を使用する。
   if( FAILED( hr = m_pKinectSensor->NuiInitialize( NUI_INITIALIZE_FLAG_USES_COLOR ) ) )
      throw( UCException( -1, _T("UCKinect01::CreateKinect()でエラーが発生しました。Kinectセンサーが接続されているが、初期化が完了しなかった") ) );

   // RGBカメラでサポートしている設定は NUI_IMAGE_RESOLUTION_640x480, NUI_IMAGE_RESOLUTION_1280x960 の2パターン
   NUI_IMAGE_RESOLUTION imageResolution = NUI_IMAGE_RESOLUTION_640x480;

   // イメージストリームをオープンする
   if( FAILED( hr = m_pKinectSensor->NuiImageStreamOpen( 
                                 NUI_IMAGE_TYPE_COLOR,                   // カラーストリームからカラーデータを取得する
                                 imageResolution,                        // イメージストリームの解像度を指定する
                                 0, 2, nullptr, 
                                 &m_ImageStreamHandle                    // 開始されたイメージストリームのハンドル
                                 ) ) )
      throw( UCException( hr, _T("UCKinect01::CreateKinect()でエラーが発生しました。イメージストリームをオープンできなかった") ) );

   // NUI_IMAGE_RESOLUTION列挙型の値から実際の解像度値を取得する
   ::NuiImageResolutionToSize( imageResolution, pWidth, pHeight );
}

NUI_LOCKED_RECT UCKinect01::CreateColorDataAndNextFrame()
{
   HRESULT hr = E_FAIL;
   NUI_LOCKED_RECT colorData;

   // 指定されたイメージストリームから次のイメージフレームを取得する
   if( FAILED( hr = m_pKinectSensor->NuiImageStreamGetNextFrame( m_ImageStreamHandle, INFINITE, &m_ImageFrame ) ) )
      throw( UCException( hr, _T("UCKinect01::GetColorData()でエラーが発生しました。次のイメージフレームを取得できなかった") ) );

   // イメージフレームからカラーデータを取得する
   if( FAILED( hr = m_ImageFrame.pFrameTexture->LockRect( 0, &colorData, nullptr, 0 ) ) )
      throw( UCException( hr, _T("UCKinect01::CreateColorData()でエラーが発生しました。イメージフレームからカラーデータを取得できなかった") ) );

   return colorData;
}

void UCKinect01::ReleaseColorData()
{
   HRESULT hr = E_FAIL;

   // ロックを解除する
   if( FAILED( hr = m_ImageFrame.pFrameTexture->UnlockRect( 0 ) ) )
      throw( UCException( hr, _T("UCKinect01::ReleaseColorData()でエラーが発生しました。ロックを解除できなかった") ) );

   // イメージストリームから取得したイメージフレームを解放する
   if( FAILED( hr = m_pKinectSensor->NuiImageStreamReleaseFrame( m_ImageStreamHandle, &m_ImageFrame ) ) )
      throw( UCException( hr, _T("UCKinect01::ReleaseColorData()でエラーが発生しました。イメージストリームから取得したイメージフレームを解放できなかった") ) );
}

Kinect用のAPIのリファレンスを確認できるようにリンクを張っているので、必ず仕様を確認してください。面倒なので説明はしません。

---main.cpp---  ↑

#include "../../Common/Header/UCommon.h"
#include "../../Common/Header/UException.h"
#include "../../Common/Header/UDirect3D11.h"
#include "../../Common/Header/UGraphicsPipeline.h"
#include "../../Common/Header/UKinect01.h"
#include "UPlane01.h"
#include <NuiApi.h>

// シェーダーオブジェクトを作成するとき、ファイルから読むか、メモリから読むかを切り替える
#if defined(DEBUG) || defined(_DEBUG)
   #define UNCOMPILED_SHADER     // ファイルを読み込んでコンパイルする
#else
   #include "../../Common/HLSL/Sample01_VS_Main.h"
   #include "../../Common/HLSL/Sample01_PS_Main.h"
#endif

// アプリケーション名
TCHAR* AppName = _T("Kinect_Tutrial01");

// Direct3D関連の自作クラス
UCDirect3D11* g_pDirect3D11 = nullptr;

// グラフィックパイプライン関連の自作クラス
UCGraphicsPipeline* g_pGraphicsPipeline = nullptr;

// Kinectセンサーオブジェクト
UCKinect01* g_pKinect01 = nullptr;

// 平面オブジェクト
UCPlane01* g_pPlane01 = nullptr;

// メモリ解放
void Invalidate()
{
   SAFE_DELETE( g_pKinect01 );
   SAFE_DELETE( g_pPlane01 );
   SAFE_DELETE( g_pGraphicsPipeline );
   SAFE_DELETE( g_pDirect3D11 );
}

// ウィンドウプロシージャ
LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, UINT wParam, LONG lParam )
{
   switch( msg )
   {
   case WM_KEYUP:
      // アプリ終了
      if( wParam == VK_ESCAPE )
         ::DestroyWindow( hWnd );
      break;

   case WM_DESTROY:
      ::PostQuitMessage(0);
      break;

   default:
      return ::DefWindowProc( hWnd, msg, wParam, lParam );
   }

   return 0L;
}

// Direct3Dの作成
void CreateDirect3D( HINSTANCE hInstance, DWORD Width, DWORD Height )
{
   DXGI_MODE_DESC* pModeDescArray = nullptr;

   __try
   {
      DXGI_MODE_DESC  ModeDesc;
      UINT num;

      // ディスプレイモード一覧の数を取得する
      g_pDirect3D11->GetDisplayMode( nullptr, &num );

      pModeDescArray = NEW DXGI_MODE_DESC[num];
      // ディスプレイモード一覧を取得する
      g_pDirect3D11->GetDisplayMode( pModeDescArray, &num );

      bool find = false;
      for( UINT i=0; i<num; i++ )
      {
         // 適切な解像度のディスプレイモードを検索する
         if( pModeDescArray[i].Width == Width && pModeDescArray[i].Height == Height )
         {
            find = true;
            ::CopyMemory( &ModeDesc, &pModeDescArray[i], sizeof( DXGI_MODE_DESC ) );
            break;
         }
      }

      if( find == false )
         throw( UCException( -1, _T("InitDirect3D()でエラーが発生しました。適切なディスプレイモードの解像度を取得できません。") ) );

      // ウィンドウの作成およびDirect3D の作成
      g_pDirect3D11->CreateDirect3D11( AppName, hInstance, WndProc, &ModeDesc, TRUE, TRUE );
   }
   __finally
   {
      SAFE_DELETE_ARRAY( pModeDescArray );
   }
}

void CreateGraphicePipeline()
{
   D3D11_INPUT_ELEMENT_DESC layout[] = {
         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT,    0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
   };

   // シェーダーを作成する
#if defined(DEBUG) || defined(_DEBUG)
   g_pGraphicsPipeline->CreateVertexShaderFromFile( g_pDirect3D11->m_pD3DDevice, _T("../../Common/HLSL/Sample01.hlsl"), "VS_Main", layout, _countof( layout ) );
   g_pGraphicsPipeline->CreatePixelShaderFromFile(  g_pDirect3D11->m_pD3DDevice, _T("../../Common/HLSL/Sample01.hlsl"), "PS_Main" );
#else
   g_pGraphicsPipeline->CreateVertexShaderFromMemory( g_pDirect3D11->m_pD3DDevice, (LPBYTE)g_VS_Main, sizeof( g_VS_Main ), layout, _countof( layout ) );
   g_pGraphicsPipeline->CreatePixelShaderFromMemory(  g_pDirect3D11->m_pD3DDevice, (LPBYTE)g_PS_Main, sizeof( g_PS_Main ) );
#endif

   // ラスタライザーステートを作成する
   g_pGraphicsPipeline->CreateRasterizerState( g_pDirect3D11->m_pD3DDevice, D3D11_CULL_MODE::D3D11_CULL_BACK );

   // 深度ステンシルステートを作成する
   g_pGraphicsPipeline->CreateDepthStencilState( g_pDirect3D11->m_pD3DDevice, FALSE, D3D11_DEPTH_WRITE_MASK::D3D11_DEPTH_WRITE_MASK_ALL );

   // ブレンドステートを作成する
   UCGraphicsPipeline::UEBLEND_STATE BlendStateType[1] = { UCGraphicsPipeline::UEBLEND_STATE::NONE };
   g_pGraphicsPipeline->CreateBlendState( g_pDirect3D11->m_pD3DDevice, BlendStateType, 1 );
}

// 各種リソースを作成する
void CreateMesh( DWORD Width, DWORD Height )
{
   g_pPlane01->CreateMesh( g_pDirect3D11->m_pD3DDevice, Width, Height );
}

void NextFrame()
{
   NUI_LOCKED_RECT rect = g_pKinect01->CreateColorDataAndNextFrame();
   g_pPlane01->NextFrame( g_pDirect3D11->m_pD3DDeviceContext, rect );
   g_pKinect01->ReleaseColorData();
}

// 描画処理
HRESULT Render()
{
   float ClearColor[4] = { 0.0f, 0.125f, 0.6f, 1.0f }; // RGBA

   // バックバッファをクリアする。
   g_pDirect3D11->ClearBackBuffer( ClearColor ); 

   // 深度バッファをクリアする。
   g_pDirect3D11->ClearDepthStencilView( D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 );

   // グラフィックパイプラインの設定
   {
      g_pGraphicsPipeline->SetVertexShader( g_pDirect3D11->m_pD3DDeviceContext );
      g_pGraphicsPipeline->SetPixelShader( g_pDirect3D11->m_pD3DDeviceContext );
      g_pGraphicsPipeline->SetRasterizerState( g_pDirect3D11->m_pD3DDeviceContext );
      g_pGraphicsPipeline->SetDepthStencilState( g_pDirect3D11->m_pD3DDeviceContext );
      g_pGraphicsPipeline->SetBlendState( g_pDirect3D11->m_pD3DDeviceContext );
   }

   // レンダリング
   {
      g_pPlane01->Render( g_pDirect3D11->m_pD3DDeviceContext );
   }

   // レンダリングされたイメージをユーザーに表示。
   return g_pDirect3D11->Present( 0, 0 );
}
 
// メイン関数
int APIENTRY _tWinMain( HINSTANCE hInstance,
                        HINSTANCE /*hPrevInstance*/,
                        LPTSTR    /*lpCmpLine*/,
                        INT       /*nCmdShow*/ )
{
   // メモリリーク検出
   _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_CHECK_EVERY_1024_DF);

   MSG msg = {0};

   try
   {
      // Direct3D 関連自作クラスのインスタンスを作成
      // CreateDirect3D()関数内でインスタンスの作成を行うと、C2712 エラーが発生するのでここで行う。
      g_pDirect3D11 = NEW UCDirect3D11();
      g_pGraphicsPipeline = NEW UCGraphicsPipeline();
      g_pPlane01 = NEW UCPlane01();
      g_pKinect01 = NEW UCKinect01();

      DWORD Width = 0, Height = 0;

      // Kinectセンサーオブジェクトを作成
      g_pKinect01->CreateKinect( Width, Height );

      // Direct3Dの作成
      CreateDirect3D( hInstance, Width, Height );

      // グラフィックパイプラインリソースの作成
      CreateGraphicePipeline();

      // リソースの作成
      CreateMesh( Width, Height );

      ::ShowWindow( g_pDirect3D11->m_hWnd, SW_SHOW );
      ::UpdateWindow( g_pDirect3D11->m_hWnd );

      // メッセージループ
      do
      { 
        if( ::PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
        {
          ::TranslateMessage(&msg); 
          ::DispatchMessage(&msg); 
        }
        else
        {
          NextFrame();
          Render();
        }
      }while( msg.message != WM_QUIT );
   }
   catch( UCException ex )
   {
      ::MessageBox( nullptr, ex.m_pErrorStr, _T("エラー"), MB_OK );
   }

   Invalidate();
   ::UnregisterClass( AppName, hInstance );

   return msg.wParam;
}

Direct3D に関してはここでは説明しませんが、よくわからないという人はまず Direct3D を勉強してください。またすでに説明しましたが OpenCV 使ったほうがレンダリングは簡単に実装できます。 Direct3D がわからないという人はKinect for Windows SDK C++編をもとに OpenCV で実装してみてください。

そんなこんなで今回のサンプルを実行すると Kinectセンサー のカメラから読み取った映像をウィンドウ上に表示することができます。 自分の部屋をネット上に流したくないのでサンプル画像はありません。汚いからというわけではないよ。


web拍手 by FC2

Top Next

inserted by FC2 system