C++でFaceTrackerの基本的な部分をやってみました。こちらにあったものを少し日本語にした程度ですが。
必要な変数
IFTFaceTracker* pFT; // 顔追跡する人FT_CAMERA_CONFIG videoCameraConfig; // RGBカメラの設定
FT_CAMERA_CONFIG depthCameraConfig; // 距離カメラの設定
IFTResult* pFTResult; // 顔追跡結果
IFTImage* pColorFrame; // 顔追跡用のRGBデータ
IFTImage* pDepthFrame; // 顔追跡用の距離データ
FT_SENSOR_DATA sensorData; // Kinectセンサーデータ
std::vector<unsigned char> colorCameraFrameBuffer;
std::vector<unsigned char> depthCameraFrameBuffer;
顔追跡の基本機能の初期化
やることは次の通りです。
// FaceTrackerのインスタンスを生成するpFT = ::FTCreateFaceTracker();
if( !pFT ) {
throw std::runtime_error( "ERROR:FTCreateFaceTracker" );
}
// RGBカメラおよび距離カメラの設定を行う
videoCameraConfig.Width = width;
videoCameraConfig.Height = height;
videoCameraConfig.FocalLength =
NUI_CAMERA_COLOR_NOMINAL_FOCAL_LENGTH_IN_PIXELS * (width / 640);
depthCameraConfig.Width = width;
depthCameraConfig.Height = height;
depthCameraConfig.FocalLength =
NUI_CAMERA_DEPTH_NOMINAL_FOCAL_LENGTH_IN_PIXELS * (width / 320);
// FaceTrackerを初期化する
HRESULT hr = pFT->Initialize( &videoCameraConfig, &depthCameraConfig, 0, 0) ;
if( FAILED(hr) ) {
throw std::runtime_error( "ERROR:Initialize" );
}
// FaceTrackerの結果を格納先を生成する
hr = pFT->CreateFTResult( &pFTResult );
if(FAILED(hr)) {
throw std::runtime_error( "ERROR:CreateFTResult" );
}
顔追跡用のRGBおよび距離データ情報の作成
やることは次の通りです。
- IFTImageのインスタンスをRGBおよび距離について、それぞれ生成する
- IFTImageにRGBおよび距離のデータを格納するためのバッファを関連付ける
- FT_SENSOR_DATAにそれぞれのIFTImageを設定する
// FaceTrackerで利用するRGBおよび距離データのインスタンスを生成するpColorFrame = FTCreateImage();
pDepthFrame = FTCreateImage();
if( !pColorFrame || !pDepthFrame ) {
throw std::runtime_error( "ERROR:FTCreateImage" );
}
// RGBおよび距離データのバッファサイズを設定する
// RGBは1pixelあたり4バイト。距離は1pixelあたり2バイト
colorCameraFrameBuffer.resize( width*4 * height );
depthCameraFrameBuffer.resize( width*2 * height );
// フレームデータにバッファを設定する
// You can also use Allocate() method in which case
// IFTImage interfaces own their memory.
// In this case use CopyTo() method to copy buffers
// CopyToでもOK?
pColorFrame->Attach(width, height, &colorCameraFrameBuffer[0],
FTIMAGEFORMAT_UINT8_B8G8R8X8, width*4);
pDepthFrame->Attach(width, height, &depthCameraFrameBuffer[0],
FTIMAGEFORMAT_UINT16_D13P3, width*2);
// センサーデータを作成する
sensorData.pVideoFrame = pColorFrame;
sensorData.pDepthFrame = pDepthFrame;
sensorData.ZoomFactor = 1.0f; // Not used must be 1.0
sensorData.ViewOffset.x = 0; // Not used must be (0,0)
sensorData.ViewOffset.y = 0; // Not used must be (0,0)
顔の追跡を行う
顔の追跡はIFTFaceTracker::StartTracking()およびIFTFaceTracker::ContinueTracking()で行います。この2つは顔の追跡状態によって使い分け、追跡を開始するときはIFTFaceTracker::StartTracking()を、追跡を開始した後に継続する場合にはIFTFaceTracker::ContinueTracking()を呼び出します。
これらを呼び出す前には、初期化時に作成したcolorCameraFrameBufferおよびdepthCameraFrameBufferにKinectから取得された最新のデータを設定してください。
結果はIFTResultに格納され、IFTResult::GetStatus()で処理結果を、IFTResult::GetFaceRect()で検出した顔の矩形領域をそれぞれ取得します。またIFTResultのほかのメソッドを利用することで、2Dや3Dでの部位の位置を取得することもできるようです。
// 追跡中、未追跡によって処理が変わるif(!isFaceTracked) {
// FaceTrakingを開始する
auto hr = pFT->StartTracking(&sensorData, NULL, NULL, pFTResult);
if(SUCCEEDED(hr) && SUCCEEDED(pFTResult->GetStatus())) {
// 顔を見つけたので、追跡状態へ遷移
::OutputDebugString( L"StartTracking\n" );
isFaceTracked = true;
// 顔の領域を取得する
pFTResult->GetFaceRect( &faceRect );
}
else {
// 顔を見失ったので、未追跡状態のまま
isFaceTracked = false;
::OutputDebugString( L"StartTracking failed\n" );
}
}
else {
// FaceTrakingを継続する
auto hr = pFT->ContinueTracking(&sensorData, NULL, pFTResult);
if(SUCCEEDED(hr) && SUCCEEDED(pFTResult->GetStatus())) {
// 顔を見つけたので、追跡状態のまま
::OutputDebugString( L"ContinueTracking\n" );
// 顔の領域を取得する
pFTResult->GetFaceRect( &faceRect );
}
else {
// 顔を見失ったので、未追跡状態へ遷移
::OutputDebugString( L"ContinueTracking failed\n" );
isFaceTracked = false;
}
}
後片づけ
それぞれのRelease()を呼びます。
pFTResult->Release();pColorFrame->Release();
pDepthFrame->Release();
pFT->Release();
こんな感じで顔を検出することができます。
FaceTrackerのライブラリを見てみると、Kinect SDKからは独立したライブラリになっていること、入力フォーマットがいくつか設定できることから、Kinect SDK以外(具体的にはOpenNI)でも使えるような気がします(想像ですけど)。
[amazon asin='9784798033709']