Kinect SDK v2預覽版的主要功能的使用介紹,基本上完成了。這次,是關於取得Body(人體姿勢)方法的說明。
上一節,是使用
Kinect SDK v2
預覽版從
Kinect v2
預覽版取得
BodyIndex(人體區域
)的方法。
這一節, 介紹從Kinect取得Body(人體姿勢 )的方法。
Body
到目前為止,
Kinect能取得Depth(通過傳感器的距離信息)和BodyIndex(人體區域
)。並且,
基於這些數據可以取得人體姿勢
。
Kinect的人體姿勢,是向
學習了
基於
龐大數量的姿勢信息的識別器里,輸入人體區域
的信息來推定的(注:因為男女老少高矮胖瘦體形各不相同,
所以必須
基於神經網絡的數據庫才能准確識別人體
)。詳細還請參考
Microsoft Research發表的論文。
這個論文在IEEE CVPR 2011(計算機視覺 及模式認識領域的首位會議)發表, 獲獎Best Paper。
Microsoft Research“Real-Time Human Pose Recognition in Parts from a Single Depth Image”
背景技術說不定很復雜,不過開發者通過
Kinect SDK可以簡單地取得和使用
人體姿勢。
人體的姿勢數據,可以得到頭,手,腳等3維的位置,基於這些可以實現姿勢的識別。
這個人體區域,在Kinect SDK v1被稱為「Skeleton」,不過,在Kinect SDK v2預覽版里更名為「Body」。
這一節,介紹取得Body的方法。
示例程序
使用
Kinect SDK
v2
預覽版取得
Body
和
Color圖像疊加顯示為
「●(圓點)」的示例程序展示。還有,
基於
Body數據,
Hand State(手的狀態)也做了顯示。
第2節有介紹取得數據的階段
摘錄解說,這個示例程序的全部內容,
在下面的github里公開。

圖1 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 IBodyFrameSource* pBodySource; ……1 hResult = pSensor->get_BodyFrameSource( &pBodySource ); ……2 if( FAILED( hResult ) ){ std::cerr << "Error : IKinectSensor::get_BodyFrameSource()" << std::endl; return -1; }
列表1.2
相當於圖1「Source」的部分
1 Body Frame的Source接口。
2 從Sensor取得
Source。
這里只是關於取得Body的源代碼解說,不過,為了案例程序的顯示,也同時取得了Color。
「Reader」
「Source」從打開「Reader」。
// Reader IBodyFrameReader* pBodyReader; ……1 hResult = pBodySource->OpenReader( &pBodyReader ); ……2 if( FAILED( hResult ) ){ std::cerr << "Error : IBodyFrameSource::OpenReader()" << std::endl; return -1; }
列表1.3 相當於圖1「Reader」的部分
1 Body Frame的Reader接口。
2 從Source打開Reader。
「Frame」~「Data」
從「Reader」取得最新的「Frame」(列表1.5)。
在這之前,為了可以和從傳感器取得的坐標匹配,取得
ICoordinateMapper的接口(列表
1.4
),由於
Color照相機和Depth傳感器的位置是分開的,
因此需要把b
ody數據和Color圖像的位置進行匹配。
// Coordinate Mapper ICoordinateMapper* pCoordinateMapper; ……1 hResult = pSensor->get_CoordinateMapper( &pCoordinateMapper ); ……2 if( FAILED( hResult ) ){ std::cerr << "Error : IKinectSensor::get_CoordinateMapper()" << std::endl; return -1; }
列表1.4,坐標匹配接口的取得
1 Frame之間的坐標匹配的接口。
2 從Sensor獲取坐標匹配的接口。
接下來的列表1.5,是和連載第2節一樣的方法,表示的是Color圖形的取得。
int width = 1920; int height = 1080; unsigned int bufferSize = width * height * 4 * sizeof( unsigned char ); cv::Mat bufferMat( height, width, CV_8UC4 ); cv::Mat bodyMat( height / 2, width / 2, CV_8UC4 ); cv::namedWindow( "Body" ); // Color Table cv::Vec3b color[6]; 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 ){ // Color Frame ……1 IColorFrame* pColorFrame = nullptr; hResult = pColorReader->AcquireLatestFrame( &pColorFrame ); if( SUCCEEDED( hResult ) ){ hResult = pColorFrame->CopyConvertedFrameDataToArray( bufferSize, reinterpret_cast<BYTE*>( bufferMat.data ), ColorImageFormat_Bgra ); if( SUCCEEDED( hResult ) ){ cv::resize( bufferMat, bodyMat, cv::Size(), 0.5, 0.5 ); } } SafeRelease( pColorFrame ); /* Body部分在列表1.6 */ // Show Window cv::imshow( "Body", bodyMat ); if( cv::waitKey( 10 ) == VK_ESCAPE ){ break; } }
列表1.5,相當於圖1「Frame」,「Data」的部分(第1部分)
1 為了顯示Body數據取得Color圖像,詳細見第2節。
列表1.5中的Body部分的代碼,在下面的列表1.6里顯示。
// Body Frame IBodyFrame* pBodyFrame = nullptr; ……1 hResult = pBodyReader->AcquireLatestFrame( &pBodyFrame ); ……2 if( SUCCEEDED( hResult ) ){ IBody* pBody[BODY_COUNT] = { 0 }; ……3 hResult = pBodyFrame->GetAndRefreshBodyData( BODY_COUNT, pBody ); ……3 if( SUCCEEDED( hResult ) ){ for( int count = 0; count < BODY_COUNT; count++ ){ BOOLEAN bTracked = false; ……4 hResult = pBody[count]->get_IsTracked( &bTracked ); ……4 if( SUCCEEDED( hResult ) && bTracked ){ Joint joint[JointType::JointType_Count]; ……5 hResult = pBody[count]->GetJoints( JointType::JointType_Count, joint ); ……5 if( SUCCEEDED( hResult ) ){ // Left Hand State HandState leftHandState = HandState::HandState_Unknown; ……6 hResult = pBody[count]->get_HandLeftState( &leftHandState ); ……6 if( SUCCEEDED( hResult ) ){ ColorSpacePoint colorSpacePoint = { 0 }; ……7 hResult = pCoordinateMapper->MapCameraPointToColorSpace( joint[JointType::JointType_HandLeft].Position, &colorSpacePoint ); ……7 if( SUCCEEDED( hResult ) ){ int x = static_cast<int>( colorSpacePoint.X ); int y = static_cast<int>( colorSpacePoint.Y ); if( ( x >= 0 ) && ( x < width ) && ( y >= 0 ) && ( y < height ) ){ if( leftHandState == HandState::HandState_Open ){ ……8 cv::circle( bufferMat, cv::Point( x, y ), 75, cv::Scalar( 0, 128, 0 ), 5, CV_AA ); } else if( leftHandState == HandState::HandState_Closed ){ ……8 cv::circle( bufferMat, cv::Point( x, y ), 75, cv::Scalar( 0, 0, 128 ), 5, CV_AA ); } else if( leftHandState == HandState::HandState_Lasso ){ ……8 cv::circle( bufferMat, cv::Point( x, y ), 75, cv::Scalar( 128, 128, 0 ), 5, CV_AA ); } } } } // Right Hand State /* 和左手一樣,獲取右手Hand State繪制狀態。 */ // Joint ……9 for( int type = 0; type < JointType::JointType_Count; type++ ){ ColorSpacePoint colorSpacePoint = { 0 }; pCoordinateMapper->MapCameraPointToColorSpace( joint[type].Position, &colorSpacePoint ); int x = static_cast< int >( colorSpacePoint.X ); int y = static_cast< int >( colorSpacePoint.Y ); if( ( x >= 0 ) && ( x < width ) && ( y >= 0 ) && ( y < height ) ){ cv::circle( bufferMat, cv::Point( x, y ), 5, static_cast<cv::Scalar>( color[count] ), -1, CV_AA ); } } } } } cv::resize( bufferMat, bodyMat, cv::Size(), 0.5, 0.5 ); } } SafeRelease( pBodyFrame );
列表1.6,
相當於圖1「Frame」,「Data」的部分(第2部分)
1 Body的Frame接口。
2 從Reader里取得最新的Frame。
3 從Frame取得Body。
后面,是從人體取得數據。
4 確認能着追蹤到人體。
5
取得人體Joint(關節)。
6 取得Hand State。
7 為了繪制,把Body座標向Color座標的坐標匹配。
匹配的坐標是否超出繪制范圍
(這里Color圖像的尺寸是1920×1080)的檢查。
(注:因為兩個Camera位置、FOV和分辨率的不同,在匹配時不可能完全一一對應,所以必須檢查坐標的有效性)
8 對應狀態繪制相應顏色的○(圓型)做Hand State的可視化。
用各自對應Open(打開:布),Closed(關閉:拳),Lasso(套索:剪)的顏色繪制。如果檢查不出狀態就不繪制。
9 對應人體的Joint參照color table的顏色做繪制。
和Hand State一樣,Body坐標向Color坐標坐標匹配來繪制●(圓點)。
使用Kinect SDK v1從人體區域
中檢測獲取的詳細人體姿勢
最多支持2個人。
Kinect SDK v2
預覽版可以檢測獲取全部人體區域
(6人)的詳細人體姿勢
。
另外,
Kinect SDK v1能取得的Joint是全身20個,
Kinect SDK v2
預覽版是追加了
「脖子(=NECK)」,
「指尖(=HAND_TIP_LEFT,
HAND_TIP_RIGHT)」,
「大拇指(=THUMB_LEFT,
THUMB_RIGHT)」5個,
一共25個Joint。
示例程序里,根據
Joint位置參考color table的顏色繪制成
「●(圓點)」來可視化
。
Kinect SDK v1(Kinect Developer Toolkit/Kinect Interaction)可以取得的Hand State,
有「Open(打開)」和「Closed(關閉)」的2種類型。
Kinect SDK v2
預覽版,
在
「Open」「Closed」基礎上又增加了
「Lasso(=套索)」這個狀態的取得。
「Lasso」能檢查出豎起兩個手指的狀態。想象為
「猜拳的(拳頭,
剪刀,
布)」就好了。這里還有一個鏈接擴展閱讀,
我之后會翻譯。
現在,6個人中可以同時獲取其中2個人的
Hand State。
示例程序里,可以通過手的
Joint位置的狀態來着色
「○(圓環)」的繪制做可視化。
「Open」綠色(=「cv::Scalar(0,
128,
0)」),
「Closed」是紅色(=「cv::Scalar(0,
0,
128)」),
「Lasso」用淡藍色(=「cv::Scalar(128,
128,
0)」)表現。
Kinect SDK v1 | Kinect SDK v2預覽版 | |
---|---|---|
名稱 | Skeleton | Body |
人體姿勢可以取得的人數 | 2人 | 6人 |
Joint(關節) | 20處 | 25處 |
Hand State(手的狀態) | 2種類 | 3種類 |
Hand State可以取得的人數 | 2人 | 2人 |
表1 Kinect SDK v1和Kinect SDK v2預覽版的人體姿勢(Skeleton,Body)的比較

圖2 Kinect v1和Kinect v2預覽版的可以取得的Joint
運行結果
運行這個示例程序,就像圖3一樣,從v2
預覽版取得的人體姿勢
和手的狀態被可視化了。

圖3 運行結果
Joint用●(圓點)來顯示,
Hand State用來
○(圓環)來顯示。

圖4 Hand State的識別結果
「Open」是綠色,「Closed」是紅色,「Lasso」淺藍色的○(
圓環
)來顯示。 手的狀態可以清晰的識別。
總結
這一節是使用
Kinect SDK v2
預覽版取得Body的示例程序的介紹。現在,
Kinect SDK v2
預覽版實現的主要功能基本上都被介紹了。
不過,
Kinect SDK v2
預覽版,
在RTM版的發布之前預計會有2~3次的更新。近日,
第1次更新被預定公開給早期提供程序的參與者。一旦
SDK v2
預覽版有公開更新,
本連載就會追加新的功能介紹。