Kinect開發學習筆記之(八)彩色、深度、骨骼和使用者摳圖結合

查志強發表於2016-08-02

【原文:http://blog.csdn.net/zouxy09/article/details/8163265

Kinect開發學習筆記之(八)彩色、深度、骨骼和使用者摳圖結合

zouxy09@qq.com

http://blog.csdn.net/zouxy09

 

我的Kinect開發平臺是:

Win7 x86 + VS2010 + Kinect for Windows SDK v1.6 + OpenCV2.3.0

開發環境的搭建見上一文:

http://blog.csdn.net/zouxy09/article/details/8146055

 

本學習筆記以下面的方式組織:程式設計前期分析、程式碼與註釋和重要程式碼解析三部分。

 

要實現目標:整合前面所說的彩色影象、深度影象和骨骼影象,就是實現和SDK自帶的那個SkeletonView例程差不多的功能。另外,再增加使用者摳圖功能,這個功能和SDK自帶的那個Green Screen功能差不多。我們通過OpenCV來顯示。

 

一、程式設計前期分析

       這裡因為是整合前面幾個學習筆記提到的功能,所以要了解的東西前面都已經瞭解了,這裡就不贅述了。這裡唯一有一個新的點就是使用者摳圖,我們再學習學習。

       那麼叫摳圖啊?用過Photoshop或者AE等一般的影象或者視訊處理軟體的人應該不會陌生。所謂摳圖,就是把圖片或影像的某一部分從原始圖片或影像中分離出來成為單獨的圖層。主要功能是為了後期的合成做準備。如果還不瞭解的話,我們看過科幻電影或者一個特效視訊吧?某個人在恐龍旁邊、某個人在懸崖邊打架、某個人在天上飛等等,這些場景大家有沒有想過它是怎樣實現的啊?難道真的是實景拍的?你都會說了“怎麼可能!”。實際上很大一部分就是採用摳圖這個技術的,如果搞視訊特效處理的話,這個技術行業內好像叫“鍵控”。它在電視製作和電影製作中很常見,這種技術叫做綠屏摳像,就是演員或者播音員站在綠色底板前,然後錄完節目後,綠色背景摳出,換成其他場景,在一些科幻電影中演員不可能在實景中表演時常採用的造景手法。

       在Kinect中我們也可以達到類似的效果。Kinect SDK使得這個很容易實現。這實際上就是現實增強的一個基本例子,現實增強應用非常有趣而且能夠獲得非常好的使用者體驗。許多藝術家使用Kinect來進行現實增強互動展覽。另外,這種技術也通常作為廣告和營銷的工具。

 

二、程式碼與註釋

[cpp] view plain copy
  1. #include <windows.h>  
  2. #include <iostream>   
  3. #include <NuiApi.h>  
  4. #include <opencv2/opencv.hpp>  
  5.   
  6. using namespace std;  
  7. using namespace cv;  
  8.   
  9. bool tracked[NUI_SKELETON_COUNT]={FALSE};   
  10. CvPoint skeletonPoint[NUI_SKELETON_COUNT][NUI_SKELETON_POSITION_COUNT]={cvPoint(0,0)};   
  11. CvPoint colorPoint[NUI_SKELETON_COUNT][NUI_SKELETON_POSITION_COUNT]={cvPoint(0,0)};   
  12.    
  13. void getColorImage(HANDLE &colorEvent, HANDLE &colorStreamHandle, Mat &colorImage);   
  14. void getDepthImage(HANDLE &depthEvent, HANDLE &depthStreamHandle, Mat &depthImage);   
  15. void getSkeletonImage(HANDLE &skeletonEvent, Mat &skeletonImage, Mat &colorImage, Mat &depthImage);   
  16. void drawSkeleton(Mat &image, CvPoint pointSet[], int witchone);   
  17. void getTheContour(Mat &image, int whichone, Mat &mask);  
  18.   
  19. int main(int argc, char *argv[])  
  20. {  
  21.     Mat colorImage;  
  22.     colorImage.create(480, 640, CV_8UC3);   
  23.     Mat depthImage;  
  24.     depthImage.create(240, 320, CV_8UC3);   
  25.     Mat skeletonImage;  
  26.     skeletonImage.create(240, 320, CV_8UC3);   
  27.     Mat mask;  
  28.     mask.create(240, 320, CV_8UC3);   
  29.    
  30.     HANDLE colorEvent = CreateEvent( NULL, TRUE, FALSE, NULL );   
  31.     HANDLE depthEvent = CreateEvent( NULL, TRUE, FALSE, NULL );   
  32.     HANDLE skeletonEvent = CreateEvent( NULL, TRUE, FALSE, NULL );   
  33.    
  34.     HANDLE colorStreamHandle = NULL;   
  35.     HANDLE depthStreamHandle = NULL;   
  36.    
  37.     HRESULT hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR | NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX | NUI_INITIALIZE_FLAG_USES_SKELETON);     
  38.     if( hr != S_OK )     
  39.     {     
  40.         cout<<"NuiInitialize failed"<<endl;     
  41.         return hr;     
  42.     }   
  43.    
  44.     hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480, NULL, 4, colorEvent, &colorStreamHandle);   
  45.     if( hr != S_OK )     
  46.     {     
  47.         cout<<"Open the color Stream failed"<<endl;   
  48.         NuiShutdown();   
  49.         return hr;     
  50.     }   
  51.     hr = NuiImageStreamOpen(NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX, NUI_IMAGE_RESOLUTION_320x240, NULL, 2, depthEvent, &depthStreamHandle);   
  52.     if( hr != S_OK )     
  53.     {     
  54.         cout<<"Open the depth Stream failed"<<endl;   
  55.         NuiShutdown();   
  56.         return hr;     
  57.     }   
  58.     hr = NuiSkeletonTrackingEnable( skeletonEvent, 0 );//開啟骨骼跟蹤事件     
  59.     if( hr != S_OK )     
  60.     {     
  61.         cout << "NuiSkeletonTrackingEnable failed" << endl;     
  62.         NuiShutdown();   
  63.         return hr;     
  64.     }   
  65.     
  66.     namedWindow("mask", CV_WINDOW_AUTOSIZE);  
  67.     namedWindow("colorImage", CV_WINDOW_AUTOSIZE);  
  68.     namedWindow("depthImage", CV_WINDOW_AUTOSIZE);  
  69.     namedWindow("skeletonImage", CV_WINDOW_AUTOSIZE);  
  70.       
  71.     while (1)   
  72.     {   
  73.         if(WaitForSingleObject(colorEvent, 0)==0)   
  74.             getColorImage(colorEvent, colorStreamHandle, colorImage);   
  75.         if(WaitForSingleObject(depthEvent, 0)==0)   
  76.             getDepthImage(depthEvent, depthStreamHandle, depthImage);   
  77.         //這裡使用INFINITE是為了避免沒有啟用skeletonEvent而跳過此程式碼出現colorimage頻閃的現象   
  78.         if(WaitForSingleObject(skeletonEvent, INFINITE)==0)  
  79.             getSkeletonImage(skeletonEvent, skeletonImage, colorImage, depthImage);   
  80.             
  81.         for (int i=0; i<6; i++)    
  82.         {   
  83.             if(tracked[i] == TRUE)   
  84.             {   
  85.                 mask.setTo(0);  
  86.                 getTheContour(depthImage, i, mask);   
  87.                 tracked[i] = FALSE;   
  88.                 break;   
  89.             }   
  90.         }   
  91.    
  92.         imshow("mask", mask);   
  93.         imshow("colorImage", colorImage);   
  94.         imshow("depthImage", depthImage);   
  95.         imshow("skeletonImage", skeletonImage);   
  96.    
  97.         if(cvWaitKey(1)==27)   
  98.             break;   
  99.     }   
  100.    
  101.     NuiShutdown();   
  102.     return 0;   
  103. }  
  104.   
  105.   
  106. void getColorImage(HANDLE &colorEvent, HANDLE &colorStreamHandle, Mat &colorImage)   
  107. {   
  108.     const NUI_IMAGE_FRAME *colorFrame = NULL;   
  109.    
  110.     NuiImageStreamGetNextFrame(colorStreamHandle, 0, &colorFrame);   
  111.     INuiFrameTexture *pTexture = colorFrame->pFrameTexture;     
  112.    
  113.     NUI_LOCKED_RECT LockedRect;   
  114.     pTexture->LockRect(0, &LockedRect, NULL, 0);     
  115.    
  116.     if( LockedRect.Pitch != 0 )   
  117.     {   
  118.         for (int i=0; i<colorImage.rows; i++)   
  119.         {  
  120.             uchar *ptr = colorImage.ptr<uchar>(i);  //第i行的指標                    
  121.             //每個位元組代表一個顏色資訊,直接使用uchar  
  122.             uchar *pBuffer = (uchar*)(LockedRect.pBits) + i * LockedRect.Pitch;  
  123.             for (int j=0; j<colorImage.cols; j++)   
  124.             {   
  125.                 ptr[3*j] = pBuffer[4*j];  //內部資料是4個位元組,0-1-2是BGR,第4個現在未使用   
  126.                 ptr[3*j+1] = pBuffer[4*j+1];   
  127.                 ptr[3*j+2] = pBuffer[4*j+2];   
  128.             }   
  129.         }   
  130.     }   
  131.     else   
  132.     {   
  133.         cout<<"捕捉色彩影象出現錯誤"<<endl;   
  134.     }  
  135.   
  136.     pTexture->UnlockRect(0);   
  137.     NuiImageStreamReleaseFrame(colorStreamHandle, colorFrame );  
  138. }   
  139.    
  140. void getDepthImage(HANDLE &depthEvent, HANDLE &depthStreamHandle, Mat &depthImage)   
  141. {   
  142.     const NUI_IMAGE_FRAME *depthFrame = NULL;   
  143.    
  144.     NuiImageStreamGetNextFrame(depthStreamHandle, 0, &depthFrame);   
  145.     INuiFrameTexture *pTexture = depthFrame->pFrameTexture;     
  146.    
  147.     NUI_LOCKED_RECT LockedRect;   
  148.     pTexture->LockRect(0, &LockedRect, NULL, 0);     
  149.    
  150.     RGBQUAD q;   
  151.   
  152.     if( LockedRect.Pitch != 0 )   
  153.     {   
  154.         for (int i=0; i<depthImage.rows; i++)   
  155.         {   
  156.             uchar *ptr = depthImage.ptr<uchar>(i);   
  157.             uchar *pBuffer = (uchar*)(LockedRect.pBits) + i * LockedRect.Pitch;  
  158.             USHORT *pBufferRun = (USHORT*) pBuffer;   
  159.               
  160.             for (int j=0; j<depthImage.cols; j++)   
  161.             {   
  162.                 int player = pBufferRun[j]&7;   
  163.                 int data = (pBufferRun[j]&0xfff8) >> 3;   
  164.                    
  165.                 uchar imageData = 255-(uchar)(256*data/0x0fff);   
  166.                 q.rgbBlue = q.rgbGreen = q.rgbRed = 0;   
  167.    
  168.                 switch(player)   
  169.                 {   
  170.                     case 0:     
  171.                         q.rgbRed = imageData / 2;     
  172.                         q.rgbBlue = imageData / 2;     
  173.                         q.rgbGreen = imageData / 2;     
  174.                         break;     
  175.                     case 1:      
  176.                         q.rgbRed = imageData;     
  177.                         break;     
  178.                     case 2:     
  179.                         q.rgbGreen = imageData;     
  180.                         break;     
  181.                     case 3:     
  182.                         q.rgbRed = imageData / 4;     
  183.                         q.rgbGreen = q.rgbRed*4;  //這裡利用乘的方法,而不用原來的方法可以避免不整除的情況   
  184.                         q.rgbBlue = q.rgbRed*4;  //可以在後面的getTheContour()中配合使用,避免遺漏一些情況   
  185.                         break;     
  186.                     case 4:     
  187.                         q.rgbBlue = imageData / 4;    
  188.                         q.rgbRed = q.rgbBlue*4;     
  189.                         q.rgbGreen = q.rgbBlue*4;     
  190.                         break;     
  191.                     case 5:     
  192.                         q.rgbGreen = imageData / 4;    
  193.                         q.rgbRed = q.rgbGreen*4;     
  194.                         q.rgbBlue = q.rgbGreen*4;     
  195.                         break;     
  196.                     case 6:     
  197.                         q.rgbRed = imageData / 2;     
  198.                         q.rgbGreen = imageData / 2;      
  199.                         q.rgbBlue = q.rgbGreen*2;     
  200.                         break;     
  201.                     case 7:     
  202.                         q.rgbRed = 255 - ( imageData / 2 );     
  203.                         q.rgbGreen = 255 - ( imageData / 2 );     
  204.                         q.rgbBlue = 255 - ( imageData / 2 );   
  205.                 }      
  206.                 ptr[3*j] = q.rgbBlue;   
  207.                 ptr[3*j+1] = q.rgbGreen;   
  208.                 ptr[3*j+2] = q.rgbRed;   
  209.             }   
  210.         }   
  211.     }   
  212.     else   
  213.     {   
  214.         cout << "捕捉深度影象出現錯誤" << endl;   
  215.     }   
  216.       
  217.     pTexture->UnlockRect(0);  
  218.     NuiImageStreamReleaseFrame(depthStreamHandle, depthFrame);    
  219. }   
  220.    
  221. void getSkeletonImage(HANDLE &skeletonEvent, Mat &skeletonImage, Mat &colorImage, Mat &depthImage)   
  222. {   
  223.     NUI_SKELETON_FRAME skeletonFrame = {0};  
  224.     bool bFoundSkeleton = false;    
  225.    
  226.     if(NuiSkeletonGetNextFrame( 0, &skeletonFrame ) == S_OK )     
  227.     {     
  228.         forint i = 0 ; i < NUI_SKELETON_COUNT ; i++ )     
  229.         {     
  230.             if( skeletonFrame.SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED )   
  231.             {     
  232.                 bFoundSkeleton = true;     
  233.                 break;   
  234.             }     
  235.         }     
  236.     }   
  237.     else   
  238.     {   
  239.         cout << "沒有找到合適的骨骼幀" << endl;   
  240.         return;    
  241.     }   
  242.    
  243.     if( !bFoundSkeleton )     
  244.     {     
  245.         return;    
  246.     }     
  247.    
  248.     NuiTransformSmooth(&skeletonFrame, NULL);//平滑骨骼幀,消除抖動     
  249.     skeletonImage.setTo(0);     
  250.       
  251.     forint i = 0 ; i < NUI_SKELETON_COUNT ; i++ )     
  252.     {     
  253.         if( skeletonFrame.SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED &&     
  254.             skeletonFrame.SkeletonData[i].eSkeletonPositionTrackingState[NUI_SKELETON_POSITION_SHOULDER_CENTER] != NUI_SKELETON_POSITION_NOT_TRACKED)     
  255.         {     
  256.             float fx, fy;     
  257.    
  258.             for (int j = 0; j < NUI_SKELETON_POSITION_COUNT; j++)//所有的座標轉化為深度圖的座標     
  259.             {     
  260.                 NuiTransformSkeletonToDepthImage(skeletonFrame.SkeletonData[i].SkeletonPositions[j], &fx, &fy );     
  261.                 skeletonPoint[i][j].x = (int)fx;     
  262.                 skeletonPoint[i][j].y = (int)fy;     
  263.             }     
  264.    
  265.             for (int j=0; j<NUI_SKELETON_POSITION_COUNT ; j++)     
  266.             {     
  267.                 if (skeletonFrame.SkeletonData[i].eSkeletonPositionTrackingState[j] != NUI_SKELETON_POSITION_NOT_TRACKED)//跟蹤點一用有三種狀態:1沒有被跟蹤到,2跟蹤到,3根據跟蹤到的估計到     
  268.                 {     
  269.                     LONG colorx, colory;   
  270.                     NuiImageGetColorPixelCoordinatesFromDepthPixel(NUI_IMAGE_RESOLUTION_640x480, 0,    
  271.                         skeletonPoint[i][j].x, skeletonPoint[i][j].y, 0,&colorx, &colory);   
  272.                     colorPoint[i][j].x = int(colorx);  
  273.                     colorPoint[i][j].y = int(colory); //儲存座標點   
  274.                     circle(colorImage, colorPoint[i][j], 4, cvScalar(0, 255, 255), 1, 8, 0);   
  275.                     circle(skeletonImage, skeletonPoint[i][j], 3, cvScalar(0, 255, 255), 1, 8, 0);   
  276.    
  277.                     tracked[i] = TRUE;   
  278.                 }   
  279.             }   
  280.    
  281.             drawSkeleton(colorImage, colorPoint[i], i);    
  282.             drawSkeleton(skeletonImage, skeletonPoint[i], i);   
  283.         }   
  284.     }     
  285. }   
  286.    
  287. void drawSkeleton(Mat &image, CvPoint pointSet[], int whichone)   
  288. {   
  289.     CvScalar color;   
  290.     switch(whichone) //跟蹤不同的人顯示不同的顏色   
  291.     {   
  292.     case 0:   
  293.         color = cvScalar(255);   
  294.         break;   
  295.     case 1:   
  296.         color = cvScalar(0,255);   
  297.         break;   
  298.     case 2:   
  299.         color = cvScalar(0, 0, 255);   
  300.         break;   
  301.     case 3:   
  302.         color = cvScalar(255, 255, 0);   
  303.         break;   
  304.     case 4:   
  305.         color = cvScalar(255, 0, 255);   
  306.         break;   
  307.     case 5:   
  308.         color = cvScalar(0, 255, 255);   
  309.         break;   
  310.     }   
  311.    
  312.     if((pointSet[NUI_SKELETON_POSITION_HEAD].x!=0 || pointSet[NUI_SKELETON_POSITION_HEAD].y!=0) &&   
  313.         (pointSet[NUI_SKELETON_POSITION_SHOULDER_CENTER].x!=0 || pointSet[NUI_SKELETON_POSITION_SHOULDER_CENTER].y!=0))   
  314.         line(image, pointSet[NUI_SKELETON_POSITION_HEAD], pointSet[NUI_SKELETON_POSITION_SHOULDER_CENTER], color, 2);   
  315.     if((pointSet[NUI_SKELETON_POSITION_SHOULDER_CENTER].x!=0 || pointSet[NUI_SKELETON_POSITION_SHOULDER_CENTER].y!=0) &&   
  316.         (pointSet[NUI_SKELETON_POSITION_SPINE].x!=0 || pointSet[NUI_SKELETON_POSITION_SPINE].y!=0))   
  317.         line(image, pointSet[NUI_SKELETON_POSITION_SHOULDER_CENTER], pointSet[NUI_SKELETON_POSITION_SPINE], color, 2);   
  318.     if((pointSet[NUI_SKELETON_POSITION_SPINE].x!=0 || pointSet[NUI_SKELETON_POSITION_SPINE].y!=0) &&   
  319.         (pointSet[NUI_SKELETON_POSITION_HIP_CENTER].x!=0 || pointSet[NUI_SKELETON_POSITION_HIP_CENTER].y!=0))   
  320.         line(image, pointSet[NUI_SKELETON_POSITION_SPINE], pointSet[NUI_SKELETON_POSITION_HIP_CENTER], color, 2);   
  321.    
  322.     //左上肢   
  323.     if((pointSet[NUI_SKELETON_POSITION_SHOULDER_CENTER].x!=0 || pointSet[NUI_SKELETON_POSITION_SHOULDER_CENTER].y!=0) &&   
  324.         (pointSet[NUI_SKELETON_POSITION_SHOULDER_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_SHOULDER_LEFT].y!=0))   
  325.         line(image, pointSet[NUI_SKELETON_POSITION_SHOULDER_CENTER], pointSet[NUI_SKELETON_POSITION_SHOULDER_LEFT], color, 2);   
  326.     if((pointSet[NUI_SKELETON_POSITION_SHOULDER_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_SHOULDER_LEFT].y!=0) &&   
  327.         (pointSet[NUI_SKELETON_POSITION_ELBOW_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_ELBOW_LEFT].y!=0))   
  328.         line(image, pointSet[NUI_SKELETON_POSITION_SHOULDER_LEFT], pointSet[NUI_SKELETON_POSITION_ELBOW_LEFT], color, 2);   
  329.     if((pointSet[NUI_SKELETON_POSITION_ELBOW_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_ELBOW_LEFT].y!=0) &&   
  330.         (pointSet[NUI_SKELETON_POSITION_WRIST_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_WRIST_LEFT].y!=0))   
  331.         line(image, pointSet[NUI_SKELETON_POSITION_ELBOW_LEFT], pointSet[NUI_SKELETON_POSITION_WRIST_LEFT], color, 2);   
  332.     if((pointSet[NUI_SKELETON_POSITION_WRIST_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_WRIST_LEFT].y!=0) &&   
  333.         (pointSet[NUI_SKELETON_POSITION_HAND_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_HAND_LEFT].y!=0))   
  334.         line(image, pointSet[NUI_SKELETON_POSITION_WRIST_LEFT], pointSet[NUI_SKELETON_POSITION_HAND_LEFT], color, 2);   
  335.    
  336.     //右上肢   
  337.     if((pointSet[NUI_SKELETON_POSITION_SHOULDER_CENTER].x!=0 || pointSet[NUI_SKELETON_POSITION_SHOULDER_CENTER].y!=0) &&   
  338.         (pointSet[NUI_SKELETON_POSITION_SHOULDER_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_SHOULDER_RIGHT].y!=0))   
  339.         line(image, pointSet[NUI_SKELETON_POSITION_SHOULDER_CENTER], pointSet[NUI_SKELETON_POSITION_SHOULDER_RIGHT], color, 2);   
  340.     if((pointSet[NUI_SKELETON_POSITION_SHOULDER_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_SHOULDER_RIGHT].y!=0) &&   
  341.         (pointSet[NUI_SKELETON_POSITION_ELBOW_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_ELBOW_RIGHT].y!=0))   
  342.         line(image, pointSet[NUI_SKELETON_POSITION_SHOULDER_RIGHT], pointSet[NUI_SKELETON_POSITION_ELBOW_RIGHT], color, 2);   
  343.     if((pointSet[NUI_SKELETON_POSITION_ELBOW_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_ELBOW_RIGHT].y!=0) &&   
  344.         (pointSet[NUI_SKELETON_POSITION_WRIST_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_WRIST_RIGHT].y!=0))   
  345.         line(image, pointSet[NUI_SKELETON_POSITION_ELBOW_RIGHT], pointSet[NUI_SKELETON_POSITION_WRIST_RIGHT], color, 2);   
  346.     if((pointSet[NUI_SKELETON_POSITION_WRIST_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_WRIST_RIGHT].y!=0) &&   
  347.         (pointSet[NUI_SKELETON_POSITION_HAND_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_HAND_RIGHT].y!=0))   
  348.         line(image, pointSet[NUI_SKELETON_POSITION_WRIST_RIGHT], pointSet[NUI_SKELETON_POSITION_HAND_RIGHT], color, 2);   
  349.    
  350.     //左下肢   
  351.     if((pointSet[NUI_SKELETON_POSITION_HIP_CENTER].x!=0 || pointSet[NUI_SKELETON_POSITION_HIP_CENTER].y!=0) &&   
  352.         (pointSet[NUI_SKELETON_POSITION_HIP_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_HIP_LEFT].y!=0))   
  353.         line(image, pointSet[NUI_SKELETON_POSITION_HIP_CENTER], pointSet[NUI_SKELETON_POSITION_HIP_LEFT], color, 2);   
  354.     if((pointSet[NUI_SKELETON_POSITION_HIP_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_HIP_LEFT].y!=0) &&   
  355.         (pointSet[NUI_SKELETON_POSITION_KNEE_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_KNEE_LEFT].y!=0))   
  356.         line(image, pointSet[NUI_SKELETON_POSITION_HIP_LEFT], pointSet[NUI_SKELETON_POSITION_KNEE_LEFT], color, 2);   
  357.     if((pointSet[NUI_SKELETON_POSITION_KNEE_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_KNEE_LEFT].y!=0) &&   
  358.         (pointSet[NUI_SKELETON_POSITION_ANKLE_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_ANKLE_LEFT].y!=0))   
  359.         line(image, pointSet[NUI_SKELETON_POSITION_KNEE_LEFT], pointSet[NUI_SKELETON_POSITION_ANKLE_LEFT], color, 2);   
  360.     if((pointSet[NUI_SKELETON_POSITION_ANKLE_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_ANKLE_LEFT].y!=0) &&    
  361.         (pointSet[NUI_SKELETON_POSITION_FOOT_LEFT].x!=0 || pointSet[NUI_SKELETON_POSITION_FOOT_LEFT].y!=0))   
  362.         line(image, pointSet[NUI_SKELETON_POSITION_ANKLE_LEFT], pointSet[NUI_SKELETON_POSITION_FOOT_LEFT], color, 2);   
  363.    
  364.     //右下肢   
  365.     if((pointSet[NUI_SKELETON_POSITION_HIP_CENTER].x!=0 || pointSet[NUI_SKELETON_POSITION_HIP_CENTER].y!=0) &&   
  366.         (pointSet[NUI_SKELETON_POSITION_HIP_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_HIP_RIGHT].y!=0))   
  367.         line(image, pointSet[NUI_SKELETON_POSITION_HIP_CENTER], pointSet[NUI_SKELETON_POSITION_HIP_RIGHT], color, 2);   
  368.     if((pointSet[NUI_SKELETON_POSITION_HIP_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_HIP_RIGHT].y!=0) &&   
  369.         (pointSet[NUI_SKELETON_POSITION_KNEE_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_KNEE_RIGHT].y!=0))   
  370.         line(image, pointSet[NUI_SKELETON_POSITION_HIP_RIGHT], pointSet[NUI_SKELETON_POSITION_KNEE_RIGHT],color, 2);   
  371.     if((pointSet[NUI_SKELETON_POSITION_KNEE_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_KNEE_RIGHT].y!=0) &&   
  372.         (pointSet[NUI_SKELETON_POSITION_ANKLE_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_ANKLE_RIGHT].y!=0))   
  373.         line(image, pointSet[NUI_SKELETON_POSITION_KNEE_RIGHT], pointSet[NUI_SKELETON_POSITION_ANKLE_RIGHT], color, 2);   
  374.     if((pointSet[NUI_SKELETON_POSITION_ANKLE_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_ANKLE_RIGHT].y!=0) &&   
  375.         (pointSet[NUI_SKELETON_POSITION_FOOT_RIGHT].x!=0 || pointSet[NUI_SKELETON_POSITION_FOOT_RIGHT].y!=0))   
  376.         line(image, pointSet[NUI_SKELETON_POSITION_ANKLE_RIGHT], pointSet[NUI_SKELETON_POSITION_FOOT_RIGHT], color, 2);   
  377. }   
  378.    
  379.  //根據給定的深度資料的關係(在getDepthImage()中的)確定不同的跟蹤目標   
  380. void getTheContour(Mat &image, int whichone, Mat &mask)  
  381. {   
  382.     for (int i=0; i<image.rows; i++)   
  383.     {   
  384.         uchar *ptr = image.ptr<uchar>(i);   
  385.         uchar *ptrmask = mask.ptr<uchar>(i);    
  386.         for (int j=0; j<image.cols; j++)   
  387.         {   
  388.             if (ptr[3*j]==0 && ptr[3*j+1]==0 && ptr[3*j+2]==0) //都為0的時候予以忽略   
  389.             {   
  390.                 ptrmask[3*j]=ptrmask[3*j+1]=ptrmask[3*j+2]=0;   
  391.             }else if(ptr[3*j]==0 && ptr[3*j+1]==0 && ptr[3*j+2]!=0)//ID為1的時候,顯示綠色   
  392.             {   
  393.                 ptrmask[3*j] = 0;   
  394.                 ptrmask[3*j+1] = 255;   
  395.                 ptrmask[3*j+2] = 0;   
  396.             }else if (ptr[3*j]==0 && ptr[3*j+1]!=0 && ptr[3*j+2]==0)//ID為2的時候,顯示紅色   
  397.             {   
  398.                 ptrmask[3*j] = 0;   
  399.                 ptrmask[3*j+1] = 0;   
  400.                 ptrmask[3*j+2] = 255;   
  401.             }else if (ptr[3*j]==ptr[3*j+1] && ptr[3*j]==4*ptr[3*j+2])//ID為3的時候   
  402.             {   
  403.                 ptrmask[3*j] = 255;   
  404.                 ptrmask[3*j+1] = 255;   
  405.                 ptrmask[3*j+2] = 0;   
  406.             }else if (4*ptr[3*j]==ptr[3*j+1] && ptr[3*j+1]==ptr[3*j+2])//ID為4的時候   
  407.             {   
  408.                 ptrmask[3*j] = 255;   
  409.                 ptrmask[3*j+1] = 0;   
  410.                 ptrmask[3*j+2] = 255;   
  411.             }else if (ptr[3*j]==4*ptr[3*j+1] && ptr[3*j]==ptr[3*j+2])//ID為5的時候   
  412.             {   
  413.                 ptrmask[3*j] = 0;   
  414.                 ptrmask[3*j+1] = 255;   
  415.                 ptrmask[3*j+2] = 255;   
  416.             }else if (ptr[3*j]==2*ptr[3*j+1] && ptr[3*j+1]==ptr[3*j+2])//ID為6的時候   
  417.             {   
  418.                 ptrmask[3*j] = 255;   
  419.                 ptrmask[3*j+1] = 255;   
  420.                 ptrmask[3*j+2] = 255;   
  421.             }else if (ptr[3*j]==ptr[3*j+1] && ptr[3*j]==ptr[3*j+2])//ID為7的時候或者ID為0的時候,顯示藍色   
  422.             {   
  423.                 ptrmask[3*j] = 255;   
  424.                 ptrmask[3*j+1] = 0;   
  425.                 ptrmask[3*j+2] = 0;   
  426.             }else   
  427.             {   
  428.                 cout <<"如果輸出這段程式碼,說明有遺漏的情況,請查詢getTheContour函式" << endl;   
  429.             }   
  430.         }   
  431.     }   
  432. }  

 

三、程式碼解析

       這裡,在對前面所說的彩色影象、深度影象和骨骼影象的整合功能的實現上,就是通過整合前面工作的程式碼而已(請參考之前的博文)。然後唯一有一個新的東西就是摳圖,我們需要把使用者扣出來,顯示與背景不一樣的顏色,具體的函式就是:

void getTheContour(Mat &image, int whichone, Mat &mask);

       呼叫它的時候,傳入的是深度影象image,我們在深度影象處理的時候,也就是getDepthImage 函式裡面對深度資料已經做了處理,已經將玩家的ID資料轉換為RGBQUAD 格式的資料了,所以使用者的ID資料已經隱含的在深度影象的每個畫素中表示了,所以這裡我們只需要分析每個畫素的RGB值就可以對應的知道是哪個ID了,那麼屬於某個ID的畫素我們就用某種顏色來表示,其他背景畫素我們就用藍色來表示。這樣就完成了摳圖。

       實際上,我們之前提到的getDepthImage 函式就是處理深度資料的每一個畫素,如果屬於同一個使用者的ID,那麼畫素就標為同種顏色,不同的使用者,其ID不一樣,顏色的標示也不一樣,如果不屬於某個使用者的畫素,那麼就採用原來的深度值,而getTheContour函式實際上就是這裡不一樣而已。“如果不屬於某個使用者的畫素,那麼就採用原來的深度值”,這裡改為“如果不屬於某個使用者的畫素,那麼就將畫素值賦值為藍色”。

既然你都把使用者扣出來了,那麼把他弄到你給定的一個圖片場景裡面應該不難了吧。呵呵,相信大家都有各種辦法的。

       至此,本文的目標就達到了,下面是結果。其實右邊是彩色影象,在彩色影象裡面使用者的骨架也是被標註出來的,只是本人不宜拋頭露面,所以就拋棄這部分的截圖了。

 

        另外,感覺到這裡,Kinect SDK能提供的基本資料我們會獲取了,也就是勉勉強強把地基打好了,那麼後面的工作就是在上面創造屬於你的世界了。我們後面會學習基於Kinect的姿態、手勢識別等等的內容,通過他們去構建良好的人機互動程式。當然,Kinect還包含有語音識別的功能,這裡暫時就不涉及了。


相關文章