通過Kinect SDK v2預覽版,取得BodyIndex(人體區域)的方法和示例代碼。
上一節,介紹了從Kinect v2預覽版用Kinect SDK v2預覽版獲取Depth數據的方法。
這一節,介紹從Kinect取得BodyIndex(人體區域)的方法。
BodyIndex
基於從Kinect取得的Depth數據(傳感器的距離信息)獲取人體區域。
因為人體區域基於Depth數據,同時也依賴Depth傳感器的分辨率。像上一節介紹的一樣,
因為Kinect v2
預覽版(512×424)的Depth傳感器的分辨率大幅提高,
和Kinect v1相比,
手指等細小部分的人體區域
也變得可以准確的取得。
但是,
能檢測出的人體區域
的數量還是6個人這一點沒有發生改變。
關於人體區域,在Kinect SDK v1里被稱為
「Player」,
不過到了
Kinect SDK v2
預覽版里更名為
「BodyIndex」。
這一節,介紹取得
「BodyIndex」的方法。

圖1 Kinect SDK v2預覽版的示例程序(BodyBasics)
把
BodyIndex在Color坐標的位置匹配截取,
手指等細小部分都可以清晰得在人體
身上保留下來了。
(注:因為Color和Depth的Camera位置不同,所以需要進行坐標空間的轉換)
樣品程序
使用Kinect SDK v2預覽版取得BodyIndex,把每個人體用顏色區分出來並顯示的示例程序展示。第2節有介紹的取得數據的階段
摘錄解說。這個示例程序的全部內容,
在下面的github里公開。

圖2 Kinect SDK v2預覽版的數據取得流程(重發)
「Sensor」
取得「Sensor」
// Sensor IKinectSensor* pSensor; ……1 HRESULT hResult = S_OK; hResult = GetDefaultKinectSensor( &pSensor ); ……2 if( FAILED( hResult ) ){ std::cerr << "Error : GetDefaultKinectSensor" << std::endl; return -1; } hResult = pSensor->Open(); ……3 if( FAILED( hResult ) ){ std::cerr << "Error : IKinectSensor::Open()" << std::endl; return -1; }
列表1.1 相當於圖1「Source」的部分
1 處理Kinect v2預覽版的Sensor接口。
2 取得默認的
Sensor。
3 打開Sensor。
「Source」
從「Sensor」取得「Source」。
// Source IBodyIndexFrameSource* pBodyIndexSource; ……1 hResult = pSensor->get_BodyIndexFrameSource( &pBodyIndexSource ); ……2 if( FAILED( hResult ) ){ std::cerr << "Error : IKinectSensor::get_BodyIndexFrameSource()" << std::endl; return -1; }
列表1.2
相當於圖1「Source」的部分
1 取得BodyIndex Frame的Source接口。
2 從Sensor取得
Source。
「Reader」
「Source」從打開「Reader」。
// Reader IBodyIndexFrameReader* pBodyIndexReader; ……1 hResult = pBodyIndexSource->OpenReader( &pBodyIndexReader ); ……2 if( FAILED( hResult ) ){ std::cerr << "Error : IBodyIndexFrameSource::OpenReader()" << std::endl; return -1; }
列表1.3 相當於圖1「Reader」的部分
1 取得BodyIndex Frame的Reader接口。
2 從Source打開Reader。
「Frame」~「Data」
從「Reader」取得最新的「Frame」。
int width = 512; ……1 int height = 424; ……1 cv::Mat bodyIndexMat( height, width, CV_8UC3 ); ……2 cv::namedWindow( "BodyIndex" ); // Color Table cv::Vec3b color[6]; ……3 color[0] = cv::Vec3b( 255, 0, 0 ); color[1] = cv::Vec3b( 0, 255, 0 ); color[2] = cv::Vec3b( 0, 0, 255 ); color[3] = cv::Vec3b( 255, 255, 0 ); color[4] = cv::Vec3b( 255, 0, 255 ); color[5] = cv::Vec3b( 0, 255, 255 ); while( 1 ){ // Frame IBodyIndexFrame* pBodyIndexFrame = nullptr; ……4 hResult = pBodyIndexReader->AcquireLatestFrame( &pBodyIndexFrame ); ……5 if( SUCCEEDED( hResult ) ){ unsigned int bufferSize = 0; unsigned char* buffer = nullptr; hResult = pBodyIndexFrame->AccessUnderlyingBuffer( &bufferSize, &buffer ); ……6 if( SUCCEEDED( hResult ) ){ for( int y = 0; y < height; y++ ){ for( int x = 0; x < width; x++ ){ unsigned int index = y * width + x; if( buffer[index] != 0xff ){ bodyIndexMat.at<cv::Vec3b>( y, x ) = color[buffer[index]]; ……7 } else{ bodyIndexMat.at<cv::Vec3b>( y, x ) = cv::Vec3b( 0, 0, 0 ); ……7 } } } } } SafeRelease( pBodyIndexFrame ); // Show Window cv::imshow( "BodyIndex", bodyIndexMat ); if( cv::waitKey( 30 ) == VK_ESCAPE ){ break; } }
列表1.4 相當於圖1「Frame」,「Data」的部分
1 BodyIndex的尺寸(512×424)。
這里為了簡化說明,畫像尺寸用硬代碼來設定,示例程序可以Source取得着Frame信息。
2 為了從BodyIndex獲得人體區域來繪制,使用OpenCV的cv::Mat。
3 繪制人體區域的color table。
4 取得BodyIndex用的Frame接口。
5 從Reader取得最新的Frame。
6 從Frame取得BodyIndex。
取得保存BodyIndex數組的指針。
7 繪制BodyIndex的人體區域。
每個BodyIndex參照color table着色。
如果可以從取得「Frame」的里獲取BodyIndex的數據。
取出的BodyIndex的數據,
像圖3一樣,
把人體區域
和非人體區域
的按各自對應的值來填入。
Kinect SDK v1的「Player」是按人體區域是
「1」~「6」(因為是6個人),
非人體區域
「0」來填入;
Kinect SDK v2
預覽版的「BodyIndex」是按照人體區域
「0」~「5」,非人體領域
「255(0xff)」來填入(圖1)。

圖3 BodyIndex數據
Kinect SDK v1 | Kinect SDK v2預覽版 | |
---|---|---|
名稱 | Player | BodyIndex |
檢測支持人數 | 6人 | 6人 |
人體領域的値 | 1~6 | 0~5 |
非人體領域的値 | 0 | 255(0xff) |
表1 Kinect SDK v1和Kinect SDK v2預覽版的人體區域(Player,BodyIndex)的比較
示例程序是,把
BodyIndex的值,
在人體區域
用
color table的顏色
(=「cv::Vec3b(B,
G,
R )」),
在非人體區域
用黑色
(=「cv::Vec3b(0,
0,
0)」)
進行着色來實現可視化。
運行結果
運行這個示例程序,就像圖4一樣,從v2
預覽版取得的人體區域
被着色顯示。

圖4 運行結果
手指的細小形狀可以清楚的分割取出。
總結
這一節是使用
Kinect SDK v2
預覽版取得
BodyIndex的示例程序的介紹,下一節是取得
Body(人體
姿勢)的示例程序的介紹。