Skeletal Tracking
La funcionalidad estrella del sensor Kinect sin duda es el Skeletal tracking. Skeletal tracking significa seguimiento de esqueleto y se basa en un algoritmo que permite que el sensor pueda identificar partes del cuerpo de las personas que están en el campo de visión del sensor. Por medio de este algoritmo podemos obtener puntos que hacen referencia a las partes del cuerpo de la persona o las personas que están frente al sensor y hacer un seguimiento de éstos identificando gestos y/o posturas.
Para crear un nuevo proyecto sigas las instrucciones en el post anterior: Kinect Basics: Fundamentos y Configuración del entorno de desarrollo
Code:
1 // SkeletalTracking.cpp : Defines the entry point for the console application. 2 // 3 4 #include "stdafx.h" 5 #include <Windows.h> 6 #include <NuiApi.h> 7 #include <opencv2\opencv.hpp> 8 9 void drawSkeleton(cv::Mat m , NUI_SKELETON_DATA skeleton); 10 11 12 int _tmain(int argc, _TCHAR* argv[]){ 13 14 15 cv::setUseOptimized( true ); 16 17 18 /* 19 La función NuiCreateSensorByIndex crea una nueva Instancia de la clase INUISensor, 20 el primer parámetro corresponde al índex del sensor con el que vamos a trabajar, 21 en caso de que haya más de un sensor conectado 22 */ 23 INuiSensor* kinect; 24 HRESULT hr = NuiCreateSensorByIndex( 0, &kinect ); 25 if( FAILED( hr ) ){ 26 std::cerr << "Error : NuiCreateSensorByIndex" << std::endl; 27 return EXIT_FAILURE; 28 } 29 30 //inicializamos el sensor usando la función NuiInitialize,especificando 31 //que características queremos habilitar usando las banderas 32 //NUI_INITIALIZE_FLAG_USES_COLOR: color stream 33 //NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX: depth stream 34 //NUI_INITIALIZE_FLAG_USES_SKELETON: Sekeleton Tracking 35 hr = kinect->NuiInitialize( NUI_INITIALIZE_FLAG_USES_COLOR | NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX | NUI_INITIALIZE_FLAG_USES_SKELETON ); 36 if( FAILED( hr ) ){ 37 std::cerr << "Error : NuiInitialize" << std::endl; 38 return -1; 39 } 40 41 // Enable Skeleton Tracking 42 HANDLE hSkeletonEvent = INVALID_HANDLE_VALUE; 43 hSkeletonEvent = CreateEvent( nullptr, true, false, nullptr ); 44 hr = kinect->NuiSkeletonTrackingEnable( hSkeletonEvent, 0);//NUI_SKELETON_TRACKING_FLAG_ENABLE_SEATED_SUPPORT ); 45 if( FAILED( hr ) ){ 46 std::cerr << "Error : NuiSkeletonTrackingEnable" << std::endl; 47 return -1; 48 } 49 50 /* 51 NuiImageStreamOpen() esta función es un poco confusa, superficialmente lo que hace es inicializar un 52 HANDLE Object que podemos usar luego para obtener cada frame de video (RGB Stream/DEPTH Stream, de acuerdo a lo que hayamos definido en el primer argumento, 53 NUI_IMAGE_TYPE_COLOR para el RGB color image stream, o NUI_IMAGE_TYPE_DEPTH para el Depth image Stream) a una 54 Resolución de NUI_IMAGE_RESOLUTION_640x480. 55 */ 56 HANDLE hColorEvent = INVALID_HANDLE_VALUE; 57 HANDLE hColorHandle = INVALID_HANDLE_VALUE; 58 hColorEvent = CreateEvent( nullptr, true, false, nullptr ); 59 hr = kinect->NuiImageStreamOpen( NUI_IMAGE_TYPE_COLOR, NUI_IMAGE_RESOLUTION_640x480, 0, 2, hColorEvent, &hColorHandle ); 60 if( FAILED( hr ) ){ 61 std::cerr << "Error : NuiImageStreamOpen( COLOR )" << std::endl; 62 return -1; 63 } 64 //crea una ventana, para mostrar el skeleton 65 cv::namedWindow( "Skeleton" ); 66 67 HANDLE hEvents[2] = { hColorEvent, hSkeletonEvent }; 68 69 70 71 while (true) 72 { 73 ResetEvent( hSkeletonEvent ); 74 ResetEvent( hColorEvent ); 75 76 //WaitForSingleObject(hSkeletonEvent, INFINITE); 77 WaitForMultipleObjects( ARRAYSIZE( hEvents ), hEvents, true, INFINITE ); 78 79 // get Color Frame 80 NUI_IMAGE_FRAME pColorImageFrame = { 0 }; 81 hr = kinect->NuiImageStreamGetNextFrame( hColorHandle, 0, &pColorImageFrame ); 82 if( FAILED( hr ) ){ 83 std::cerr << "Error : NuiImageStreamGetNextFrame( COLOR )" << std::endl; 84 return -1; 85 } 86 87 88 // get Skeleton Frame 89 NUI_SKELETON_FRAME pSkeletonFrame = { 0 }; 90 hr = kinect->NuiSkeletonGetNextFrame( 0, &pSkeletonFrame ); 91 if( FAILED( hr ) ){ 92 std::cout << "Error : NuiSkeletonGetNextFrame" << std::endl; 93 return -1; 94 } 95 96 // GetColor Stream 97 INuiFrameTexture* pColorFrameTexture = pColorImageFrame.pFrameTexture; 98 NUI_LOCKED_RECT sColorLockedRect; 99 pColorFrameTexture->LockRect( 0, &sColorLockedRect, nullptr, 0 ); 100 cv::Mat m( 480, 640, CV_8UC4, reinterpret_cast<uchar*>( sColorLockedRect.pBits ) ); 101 102 103 //Get Skeleton Stream 104 cv::Point2f point; 105 for( int count = 0; count < NUI_SKELETON_COUNT; count++ ){ 106 NUI_SKELETON_DATA skeleton = pSkeletonFrame.SkeletonData[count]; 107 if( skeleton.eTrackingState == NUI_SKELETON_TRACKED ){ 108 drawSkeleton(m, skeleton); 109 } 110 } 111 112 cv::imshow( "Skeleton", m );//show Skeleton 113 114 //release color stream 115 pColorFrameTexture->UnlockRect( 0 ); kinect->NuiImageStreamReleaseFrame( hColorHandle, &pColorImageFrame ); 116 117 if( cv::waitKey( 30 ) == VK_ESCAPE ){ break;} 118 } 119 120 // Kinect 121 kinect->NuiShutdown(); kinect->NuiSkeletonTrackingDisable();CloseHandle( hColorEvent );CloseHandle( hSkeletonEvent );cv::destroyAllWindows(); 122 123 return 0; 124 } 125 126 127 //draw Join 128 void drawBone(cv::Mat m , NUI_SKELETON_DATA skeleton, NUI_SKELETON_POSITION_INDEX jointFrom,NUI_SKELETON_POSITION_INDEX jointTo ){ 129 130 NUI_SKELETON_POSITION_TRACKING_STATE jointFromState = skeleton.eSkeletonPositionTrackingState[jointFrom]; 131 132 NUI_SKELETON_POSITION_TRACKING_STATE jointToState = skeleton.eSkeletonPositionTrackingState[jointTo]; 133 134 if (jointFromState == NUI_SKELETON_POSITION_NOT_TRACKED || jointToState == NUI_SKELETON_POSITION_NOT_TRACKED){ 135 return; // nothing to draw, one of the joints is not tracked 136 } 137 138 // Don't draw if both points are inferred 139 if (jointFromState == NUI_SKELETON_POSITION_INFERRED || jointToState == NUI_SKELETON_POSITION_INFERRED){ 140 cv::Point2f pointFrom; 141 NuiTransformSkeletonToDepthImage( skeleton.SkeletonPositions[jointFrom], &pointFrom.x, &pointFrom.y, NUI_IMAGE_RESOLUTION_640x480 ); 142 cv::Point2f pointTo; 143 NuiTransformSkeletonToDepthImage( skeleton.SkeletonPositions[jointTo], &pointTo.x, &pointTo.y, NUI_IMAGE_RESOLUTION_640x480 ); 144 cv::line(m,pointFrom, pointTo, static_cast<cv::Scalar>( cv::Vec3b( 0, 0, 255 ) ),2,CV_AA); 145 cv::circle( m, pointTo, 5, static_cast<cv::Scalar>(cv::Vec3b( 0, 255, 255 )), -1, CV_AA ); 146 } 147 148 // We assume all drawn bones are inferred unless BOTH joints are tracked 149 if (jointFromState == NUI_SKELETON_POSITION_TRACKED && jointToState == NUI_SKELETON_POSITION_TRACKED) 150 { 151 cv::Point2f pointFrom; 152 NuiTransformSkeletonToDepthImage( skeleton.SkeletonPositions[jointFrom], &pointFrom.x, &pointFrom.y, NUI_IMAGE_RESOLUTION_640x480 ); 153 cv::Point2f pointTo; 154 NuiTransformSkeletonToDepthImage( skeleton.SkeletonPositions[jointTo], &pointTo.x, &pointTo.y, NUI_IMAGE_RESOLUTION_640x480 ); 155 //dibujamos una linea que entre los dos punto 156 cv::line(m,pointFrom, pointTo, static_cast<cv::Scalar>( cv::Vec3b( 0, 255, 0 ) ),2,CV_AA); 157 //en donde inicia cada linea dibujamos un circulo 158 cv::circle( m, pointTo, 5, static_cast<cv::Scalar>(cv::Vec3b( 0, 255, 255 )), -1, CV_AA ); 159 } 160 161 } 162 163 //draw the body 164 void drawSkeleton(cv::Mat m , NUI_SKELETON_DATA skeleton){ 165 //Head and Shoulders (cabeza y espalda) 166 drawBone(m , skeleton, NUI_SKELETON_POSITION_HEAD, NUI_SKELETON_POSITION_SHOULDER_CENTER); 167 drawBone(m, skeleton, NUI_SKELETON_POSITION_SHOULDER_CENTER, NUI_SKELETON_POSITION_SHOULDER_LEFT); 168 drawBone(m, skeleton, NUI_SKELETON_POSITION_SHOULDER_CENTER, NUI_SKELETON_POSITION_SHOULDER_RIGHT); 169 170 //hip(cadera) 171 drawBone(m,skeleton, NUI_SKELETON_POSITION_SHOULDER_CENTER, NUI_SKELETON_POSITION_SPINE); 172 drawBone(m,skeleton, NUI_SKELETON_POSITION_SPINE, NUI_SKELETON_POSITION_HIP_CENTER); 173 drawBone(m,skeleton, NUI_SKELETON_POSITION_HIP_CENTER, NUI_SKELETON_POSITION_HIP_LEFT); 174 drawBone(m,skeleton, NUI_SKELETON_POSITION_HIP_CENTER, NUI_SKELETON_POSITION_HIP_RIGHT); 175 176 //Knee (rodillas) 177 drawBone(m,skeleton, NUI_SKELETON_POSITION_HIP_LEFT, NUI_SKELETON_POSITION_KNEE_LEFT); 178 drawBone(m,skeleton, NUI_SKELETON_POSITION_HIP_RIGHT, NUI_SKELETON_POSITION_KNEE_RIGHT); 179 180 //Ankle (rodillas) 181 drawBone(m,skeleton, NUI_SKELETON_POSITION_KNEE_LEFT, NUI_SKELETON_POSITION_ANKLE_LEFT); 182 drawBone(m,skeleton, NUI_SKELETON_POSITION_KNEE_RIGHT, NUI_SKELETON_POSITION_ANKLE_RIGHT); 183 drawBone(m,skeleton, NUI_SKELETON_POSITION_ANKLE_LEFT, NUI_SKELETON_POSITION_FOOT_LEFT); 184 drawBone(m,skeleton, NUI_SKELETON_POSITION_ANKLE_RIGHT, NUI_SKELETON_POSITION_FOOT_RIGHT); 185 186 187 //Left Arm(brazo izquierdo) 188 drawBone(m,skeleton, NUI_SKELETON_POSITION_SHOULDER_LEFT, NUI_SKELETON_POSITION_ELBOW_LEFT); 189 drawBone(m,skeleton, NUI_SKELETON_POSITION_ELBOW_LEFT, NUI_SKELETON_POSITION_WRIST_LEFT); 190 drawBone(m,skeleton, NUI_SKELETON_POSITION_WRIST_LEFT, NUI_SKELETON_POSITION_HAND_LEFT); 191 192 //Right Arm(brazo derecho) 193 drawBone(m,skeleton, NUI_SKELETON_POSITION_SHOULDER_RIGHT, NUI_SKELETON_POSITION_ELBOW_RIGHT); 194 drawBone(m,skeleton, NUI_SKELETON_POSITION_ELBOW_RIGHT, NUI_SKELETON_POSITION_WRIST_RIGHT); 195 drawBone(m,skeleton, NUI_SKELETON_POSITION_WRIST_RIGHT, NUI_SKELETON_POSITION_HAND_RIGHT); 196 197 198 199 200 } 201 202
Resultado:
Descargar Código fuente: https://github.com/haruiz/Kinect_Blog