kinect for windows - 手势识别之一,C++实现
来源:互联网 发布:查找词语的软件 编辑:程序博客网 时间:2024/06/05 15:07
用C++来实现手势识别是比较困难的,所以在这个例子,我们只实现了握拳和松手的手势识别,其他没有实现。
先上个效果图:
在这个程序里,我们打开了kinect的RGB流,深度流,骨骼数据流和手势识别流。其中手势识别接口需要骨骼数据流和深度流来进行计算。
代码如下:
/******************************************************************* * Copyright(c) 2014-2015 传智播客 * All rights reserved. * * 文件名称: main.cpp * 简要描述: 该文件演示了Kinect for windows手势例子 * * 创建日期: 2014-01-20 * 作者: * 说明: 1.0 * * 修改日期: * 作者: * 说明: ******************************************************************/#include <Windows.h>#include <NuiApi.h>#include <KinectInteraction.h>#include <d2d1.h>#include "resource.h"#if 1// 交互客户端类,是一个纯虚类,必须继承实现纯虚函数,提供控件信息,用于交互。class CIneractionClient:public INuiInteractionClient{public: CIneractionClient() {;} ~CIneractionClient() {;} STDMETHOD(GetInteractionInfoAtLocation)(THIS_ DWORD skeletonTrackingId, NUI_HAND_TYPE handType, FLOAT x, FLOAT y, _Out_ NUI_INTERACTION_INFO *pInteractionInfo) { if(pInteractionInfo) { pInteractionInfo->IsPressTarget = false; pInteractionInfo->PressTargetControlId = 0; pInteractionInfo->PressAttractionPointX = 0.f; pInteractionInfo->PressAttractionPointY = 0.f; pInteractionInfo->IsGripTarget = false;//true; return S_OK; } return E_POINTER; //return S_OK; } STDMETHODIMP_(ULONG) AddRef() { return 2; } STDMETHODIMP_(ULONG) Release() { return 1; } STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { return S_OK; }};#endifstatic const float g_JointThickness = 3.0f;static const float g_TrackedBoneThickness = 6.0f;static const float g_InferredBoneThickness = 1.0f;// 减少全局变量,把全局变量定义在结构体里struct {DWORDwidth;DWORDheight;HWNDhWnd; // 主窗口句柄HWNDhWndColor; // rgb窗口句柄HWNDhWndDepth; // 深度图句柄HWNDhWndSkeleton; // 骨骼图显示窗口句柄HWNDhWndEdit; // 信息输出窗口句柄INuiSensor*pSensor; // kinect 设备HANDLEhEventRGB; // 色彩流通知event对象HANDLEhEventDepth; // 深度流通知event对象HANDLEhEventSkeleton; // 骨骼数据流通知event对象HANDLEhEventInteration; // 交互流数据通知event对象HANDLEhColorStream; // 色彩数据流HANDLEhDepthStream; // 深度数据流HANDLEhSkeletonStream; // 骨骼数据流INuiInteractionStream*pNuiIStream; // 交互数据流CIneractionClientnuiIClient; // 交互客户端,提供控件信息//INuiInteractionClientnuiIClient;ID2D1Factory*pD2DFactory; // direct绘图相关ID2D1HwndRenderTarget*pRenderTargetRGB; ID2D1HwndRenderTarget*pRenderTargetDepth;ID2D1HwndRenderTarget*pRenderTargetSkeleton;// RGB图显示ID2D1Bitmap*pBitmapRGB; // 用户显示色彩图的bitmap缓存BYTE*pDepthRGBBuf; // 深度图数据ID2D1Bitmap*pBitmapDepth; // 深度图缓存// 骨骼跟踪相关ID2D1SolidColorBrush* pBrushJointTracked; ID2D1SolidColorBrush* pBrushJointInferred; ID2D1SolidColorBrush* pBrushBoneTracked; ID2D1SolidColorBrush* pBrushBoneInferred; D2D1_POINT_2F Points[NUI_SKELETON_POSITION_COUNT];BOOLbNearMode; // 近模式BOOLbSeat; // 坐模式} g_data;// 简单的释放接口的封装template<class Interface>inline void SafeRelease( Interface *& pInterfaceToRelease ){ if ( pInterfaceToRelease != NULL ) { pInterfaceToRelease->Release(); pInterfaceToRelease = NULL; }}// 初始化全局数据void initGlobalData(){g_data.hWnd = NULL;g_data.pSensor = NULL;g_data.hEventRGB = NULL;g_data.hEventDepth = NULL;g_data.hEventSkeleton = NULL;g_data.bNearMode = FALSE;g_data.bSeat = FALSE;g_data.hColorStream = NULL;g_data.hDepthStream = NULL;g_data.hSkeletonStream = NULL;g_data.width = 640;g_data.height = 480;g_data.pDepthRGBBuf = new BYTE[g_data.width * g_data.height * 4];}// 对话框窗口的windows消息处理函数LRESULT CALLBACK DlgFunc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam){switch(uMsg){case WM_INITDIALOG:g_data.hWnd = hWnd;g_data.hWndColor = GetDlgItem(hWnd, IDC_RGB);g_data.hWndDepth = GetDlgItem(hWnd, IDC_DEPTH);g_data.hWndSkeleton = GetDlgItem(hWnd, IDC_SKELETON);g_data.hWndEdit = GetDlgItem(hWnd, IDC_MESSAGE);break;case WM_CLOSE:case WM_DESTROY:PostQuitMessage(0);break;case WM_COMMAND:#if 0if(IDC_SEAT == LOWORD(wParam)&& BN_CLICKED == HIWORD(wParam)){g_data.bSeat = !g_data.bSeat;if(g_data.pSensor){g_data.pSensor->NuiSkeletonTrackingEnable(g_data.pNextSkeletonFrame, g_data.bSeat?NUI_SKELETON_TRACKING_FLAG_ENABLE_SEATED_SUPPORT:0);}}#endifbreak;}return FALSE;}// 初始化direct画图对象HRESULT initD2D(){HRESULT hr;hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &g_data.pD2DFactory);if(FAILED(hr)) return hr;g_data.pD2DFactory->AddRef();return hr;}// 创建kinect设备对象HRESULT createSensor(){INuiSensor*& pSensor = g_data.pSensor;HRESULT hr;int sensorCount = 0;hr = NuiGetSensorCount(&sensorCount);if(FAILED(hr)) return hr;if(sensorCount < 1) return 0x80000000;for(int i=0; i<sensorCount; ++i){hr = NuiCreateSensorByIndex(i, &pSensor);if(FAILED(hr)) continue;hr = pSensor->NuiStatus();if(S_OK == hr)return S_OK;pSensor->Release();}return hr;}// 初始化kinect设备HRESULT initSensor(){HRESULT hr;INuiSensor*& pSensor = g_data.pSensor;// 要支持RGB,DEPTH,SKELETON,所以初始化设备时用了多个flaghr = pSensor->NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR | NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX | NUI_INITIALIZE_FLAG_USES_SKELETON);if(FAILED(hr)){pSensor->Release();return hr;}// 打开色彩数据流g_data.hEventRGB = CreateEvent( NULL, TRUE, FALSE, NULL );hr = pSensor->NuiImageStreamOpen( NUI_IMAGE_TYPE_COLOR,NUI_IMAGE_RESOLUTION_640x480, 0, 2, g_data.hEventRGB, &g_data.hColorStream); if( FAILED( hr ) ) { return hr; }// 打开深度数据流g_data.hEventDepth = CreateEvent( NULL, TRUE, FALSE, NULL );hr = pSensor->NuiImageStreamOpen( NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX, NUI_IMAGE_RESOLUTION_640x480, 0, 2, g_data.hEventDepth, &g_data.hDepthStream); if( FAILED( hr ) ) { return hr; }// 打开骨骼数据流g_data.hEventSkeleton = CreateEvent( NULL, TRUE, FALSE, NULL ); hr = pSensor->NuiSkeletonTrackingEnable( g_data.hEventSkeleton, NUI_SKELETON_TRACKING_FLAG_ENABLE_IN_NEAR_RANGE//| ); if( FAILED( hr ) ) { return hr; }// 打开交互数据流g_data.hEventInteration = CreateEvent( NULL,TRUE,FALSE,NULL );hr = NuiCreateInteractionStream(pSensor,(INuiInteractionClient *)&g_data.nuiIClient, &g_data.pNuiIStream); if( FAILED( hr ) ) { return hr; } hr = g_data.pNuiIStream->Enable(g_data.hEventInteration);if( FAILED( hr ) ) { return hr; }return hr;}void Cleanup(){if(g_data.hEventDepth != INVALID_HANDLE_VALUE) CloseHandle(g_data.hEventDepth);if(g_data.hEventRGB != INVALID_HANDLE_VALUE) CloseHandle(g_data.hEventRGB);if(g_data.hEventSkeleton != INVALID_HANDLE_VALUE) CloseHandle(g_data.hEventSkeleton);//DiscardResources();SafeRelease(g_data.pD2DFactory);//if(g_data.pSensor) g_data.pSensor->NuiShutdown();SafeRelease(g_data.pSensor);}void OutputMessage(LPCWSTR msg){//SetWindowTextW(g_data.hWndEdit, msg);static BOOL first = TRUE;if(!first){::SendMessageW(g_data.hWndEdit, EM_REPLACESEL, 0, (LPARAM)L"\r\n");}::SendMessageW(g_data.hWndEdit, EM_SETSEL, -1, -1);::SendMessageW(g_data.hWndEdit, EM_REPLACESEL, 0, (LPARAM)msg);first = FALSE;}HRESULT EnsureResourcesDepth(){ HRESULT hr = S_OK;if (NULL == g_data.pRenderTargetDepth) {D2D1_SIZE_U size = D2D1::SizeU(g_data.width, g_data.height); D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties(); rtProps.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE); rtProps.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE; // Create a hWnd render target, in order to render to the window set in initializehr = g_data.pD2DFactory->CreateHwndRenderTarget( rtProps,D2D1::HwndRenderTargetProperties(g_data.hWndDepth, size),&g_data.pRenderTargetDepth ); if ( FAILED(hr) ) { return hr; } // Create a bitmap that we can copy image data into and then render to the targethr = g_data.pRenderTargetDepth->CreateBitmap( size, D2D1::BitmapProperties( D2D1::PixelFormat( DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE) ),&g_data.pBitmapDepth ); if ( FAILED(hr) ) {SafeRelease(g_data.pRenderTargetDepth); return hr; } } return hr;}void DiscardResourcesDepth(){SafeRelease(g_data.pRenderTargetDepth);SafeRelease(g_data.pBitmapDepth);}// 处理色彩流,色彩流对于跟踪技术并无作用,这里只是显示罢了HRESULT DrawRGBMapDepth(BYTE* data, unsigned long size){int sourceStride = g_data.width * sizeof (long);HRESULT hr = EnsureResourcesDepth();if(FAILED(hr)) return hr;hr = g_data.pBitmapDepth->CopyFromMemory(NULL, data, sourceStride);if(FAILED(hr)) return hr;g_data.pRenderTargetDepth->BeginDraw();g_data.pRenderTargetDepth->DrawBitmap(g_data.pBitmapDepth);hr = g_data.pRenderTargetDepth->EndDraw();if(hr = D2DERR_RECREATE_TARGET){hr = S_OK;DiscardResourcesDepth();}return hr;}void DrawDepth(const NUI_LOCKED_RECT& lockedRect, BOOL bNearMode){if(lockedRect.Pitch != 0){int minDepth = (bNearMode ? NUI_IMAGE_DEPTH_MINIMUM_NEAR_MODE : NUI_IMAGE_DEPTH_MINIMUM) >> NUI_IMAGE_PLAYER_INDEX_SHIFT;int maxDepth = (bNearMode ? NUI_IMAGE_DEPTH_MAXIMUM_NEAR_MODE : NUI_IMAGE_DEPTH_MAXIMUM) >> NUI_IMAGE_PLAYER_INDEX_SHIFT;BYTE* rgbrun = g_data.pDepthRGBBuf;const NUI_DEPTH_IMAGE_PIXEL* pBufferRun = reinterpret_cast<const NUI_DEPTH_IMAGE_PIXEL *>(lockedRect.pBits);const NUI_DEPTH_IMAGE_PIXEL * pBufferEnd = pBufferRun + (g_data.width * g_data.height);while ( pBufferRun < pBufferEnd ){// discard the portion of the depth that contains only the player indexUSHORT depth = pBufferRun->depth;// To convert to a byte, we're discarding the most-significant// rather than least-significant bits.// We're preserving detail, although the intensity will "wrap."// Values outside the reliable depth range are mapped to 0 (black).// Note: Using conditionals in this loop could degrade performance.// Consider using a lookup table instead when writing production code.BYTE intensity = static_cast<BYTE>(depth >= minDepth && depth <= maxDepth ? depth % 256 : 0);// Write out blue byte 变成黑白灰的颜色了*(rgbrun++) = intensity;// Write out green byte*(rgbrun++) = intensity;// Write out red byte*(rgbrun++) = intensity;// We're outputting BGR, the last byte in the 32 bits is unused so skip it// If we were outputting BGRA, we would write alpha here.++rgbrun;// Increment our index into the Kinect's depth buffer++pBufferRun;}DrawRGBMapDepth(g_data.pDepthRGBBuf, g_data.width * g_data.height * 4);}}// 处理深度数据void ProcessDepth(){NUI_IMAGE_FRAME pImageFrame; INuiFrameTexture* pDepthImagePixelFrame;HRESULT hr = g_data.pSensor->NuiImageStreamGetNextFrame(g_data.hDepthStream, 0, &pImageFrame ); BOOL nearMode = TRUE; g_data.pSensor->NuiImageFrameGetDepthImagePixelFrameTexture(g_data.hDepthStream, &pImageFrame, &nearMode, &pDepthImagePixelFrame); INuiFrameTexture * pTexture = pDepthImagePixelFrame; NUI_LOCKED_RECT LockedRect; pTexture->LockRect( 0, &LockedRect, NULL, 0 ); DrawDepth(LockedRect, nearMode); if( LockedRect.Pitch != 0 ) {// 让交互对象去处理深度数据,交互数据由深度数据和骨骼数据计算,所以一旦有交互数据,就送到交互对象,让交互对象去计算结果HRESULT hr = g_data.pNuiIStream->ProcessDepth(LockedRect.size,PBYTE(LockedRect.pBits),pImageFrame.liTimeStamp); if( FAILED( hr ) ) {OutputMessage(L"error"); } } pTexture->UnlockRect(0); g_data.pSensor->NuiImageStreamReleaseFrame( g_data.hDepthStream, &pImageFrame );}HRESULT EnsureResourcesRGB(){ HRESULT hr = S_OK;if (NULL == g_data.pRenderTargetRGB) {//D2D1_SIZE_U size = D2D1::SizeU(g_data.width, g_data.height);D2D1_SIZE_U size = D2D1::SizeU(640, 480); D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties(); rtProps.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE); rtProps.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE; // Create a hWnd render target, in order to render to the window set in initializehr = g_data.pD2DFactory->CreateHwndRenderTarget( rtProps,D2D1::HwndRenderTargetProperties(g_data.hWndColor, size),&g_data.pRenderTargetRGB ); if ( FAILED(hr) ) { return hr; } // Create a bitmap that we can copy image data into and then render to the targethr = g_data.pRenderTargetRGB->CreateBitmap( size, D2D1::BitmapProperties( D2D1::PixelFormat( DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE) ),&g_data.pBitmapRGB ); if ( FAILED(hr) ) {SafeRelease(g_data.pRenderTargetRGB); return hr; } } return hr;}void DiscardResourcesRGB(){SafeRelease(g_data.pRenderTargetRGB);SafeRelease(g_data.pBitmapRGB);}HRESULT DrawRGBMapRGB(BYTE* data, unsigned long size){//int sourceStride = g_data.width * sizeof (long);int sourceStride = 640 * sizeof (long);HRESULT hr = EnsureResourcesRGB();if(FAILED(hr)) return hr;hr = g_data.pBitmapRGB->CopyFromMemory(NULL, data, sourceStride);if(FAILED(hr)) return hr;g_data.pRenderTargetRGB->BeginDraw();g_data.pRenderTargetRGB->DrawBitmap(g_data.pBitmapRGB);hr = g_data.pRenderTargetRGB->EndDraw();if(hr = D2DERR_RECREATE_TARGET){hr = S_OK;DiscardResourcesRGB();}return hr;}void ProcessRGB(){// 处理RGB图HRESULT hr;NUI_IMAGE_FRAME imageFrame;hr = g_data.pSensor->NuiImageStreamGetNextFrame(g_data.hColorStream, 0, &imageFrame);if(FAILED(hr)) return;INuiFrameTexture* pTexture = imageFrame.pFrameTexture;NUI_LOCKED_RECT lockedRect;pTexture->LockRect(0, &lockedRect, NULL, 0);if(lockedRect.Pitch != 0){DrawRGBMapRGB(lockedRect.pBits, lockedRect.size);}pTexture->UnlockRect(0);g_data.pSensor->NuiImageStreamReleaseFrame(g_data.hColorStream, &imageFrame);}// 处理交互数据// 当应用程序提供了足够的信息,并计算出交互数据之后,交互对象会通知程序void ProcessInteration(){NUI_INTERACTION_FRAME Interaction_Frame;auto ret = g_data.pNuiIStream->GetNextFrame( 0,&Interaction_Frame ); if( FAILED( ret ) ) { OutputMessage(L"Failed GetNextFrame"); return ; } int trackingID = 0; int event=0; // COORD pos = {0,0}; // HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // SetConsoleCursorPosition(hOut, pos); // 根据交互对象提供的数据,打印抓拳或者松手的信息 for(int i=0;i<NUI_SKELETON_COUNT;i++) { trackingID = Interaction_Frame.UserInfos[i].SkeletonTrackingId; event=Interaction_Frame.UserInfos[i].HandPointerInfos->HandEventType;WCHAR info[128]; if ( event == NUI_HAND_EVENT_TYPE_GRIP) {wsprintfW(info, L"抓拳 x=%d, y=%d", (int)Interaction_Frame.UserInfos[i].HandPointerInfos->X, Interaction_Frame.UserInfos[i].HandPointerInfos->Y);OutputMessage(info); } else if ( event == NUI_HAND_EVENT_TYPE_GRIPRELEASE) {wsprintfW(info, L"放手 x=%d, y=%d", (int)Interaction_Frame.UserInfos[i].HandPointerInfos->X, Interaction_Frame.UserInfos[i].HandPointerInfos->Y);OutputMessage(info); //OutputMessage(L"放手"); } else { // OutputMessage(L"没消息"); } } return ;}HRESULT EnsureResourcesSkeleton(){ HRESULT hr = S_OK;// If there isn't currently a render target, we need to create oneif (NULL == g_data.pRenderTargetSkeleton) { RECT rc;GetWindowRect( g_data.hWndSkeleton, &rc ); int width = rc.right - rc.left; int height = rc.bottom - rc.top; D2D1_SIZE_U size = D2D1::SizeU( width, height ); D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties(); rtProps.pixelFormat = D2D1::PixelFormat( DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE); rtProps.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE; // Create a Hwnd render target, in order to render to the window set in initializehr = g_data.pD2DFactory->CreateHwndRenderTarget( rtProps,D2D1::HwndRenderTargetProperties(g_data.hWndSkeleton, size), &g_data.pRenderTargetSkeleton ); if ( FAILED(hr) ) { return hr; } //light green g_data.pRenderTargetSkeleton->CreateSolidColorBrush(D2D1::ColorF(0.27f, 0.75f, 0.27f), &g_data.pBrushJointTracked); g_data.pRenderTargetSkeleton->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Yellow, 1.0f), &g_data.pBrushJointInferred); g_data.pRenderTargetSkeleton->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Green, 1.0f), &g_data.pBrushBoneTracked); g_data.pRenderTargetSkeleton->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Gray, 1.0f), &g_data.pBrushBoneInferred); } return hr;}void DiscardResourcesSkeleton(){SafeRelease(g_data.pRenderTargetSkeleton);SafeRelease(g_data.pBrushJointTracked); SafeRelease(g_data.pBrushJointInferred); SafeRelease(g_data.pBrushBoneTracked); SafeRelease(g_data.pBrushBoneInferred);}D2D1_POINT_2F SkeletonToScreen(Vector4 skeletonPoint, int width, int height){ LONG x, y; USHORT depth; // Calculate the skeleton's position on the screen // NuiTransformSkeletonToDepthImage returns coordinates in NUI_IMAGE_RESOLUTION_320x240 space NuiTransformSkeletonToDepthImage(skeletonPoint, &x, &y, &depth);//float screenPointX = static_cast<float>(x * width) / g_data.width;//float screenPointY = static_cast<float>(y * height) / g_data.height;float screenPointX = static_cast<float>(x * width) / 320;float screenPointY = static_cast<float>(y * height) / 240; return D2D1::Point2F(screenPointX, screenPointY);}void DrawBone(const NUI_SKELETON_DATA & skel, NUI_SKELETON_POSITION_INDEX joint0, NUI_SKELETON_POSITION_INDEX joint1){ NUI_SKELETON_POSITION_TRACKING_STATE joint0State = skel.eSkeletonPositionTrackingState[joint0]; NUI_SKELETON_POSITION_TRACKING_STATE joint1State = skel.eSkeletonPositionTrackingState[joint1]; // If we can't find either of these joints, exit if (joint0State == NUI_SKELETON_POSITION_NOT_TRACKED || joint1State == NUI_SKELETON_POSITION_NOT_TRACKED) { return; } // Don't draw if both points are inferred if (joint0State == NUI_SKELETON_POSITION_INFERRED && joint1State == NUI_SKELETON_POSITION_INFERRED) { return; } // We assume all drawn bones are inferred unless BOTH joints are tracked if (joint0State == NUI_SKELETON_POSITION_TRACKED && joint1State == NUI_SKELETON_POSITION_TRACKED) { g_data.pRenderTargetSkeleton->DrawLine(g_data.Points[joint0], g_data.Points[joint1], g_data.pBrushBoneTracked, g_TrackedBoneThickness); } else { g_data.pRenderTargetSkeleton->DrawLine(g_data.Points[joint0], g_data.Points[joint1], g_data.pBrushBoneInferred, g_InferredBoneThickness); }}void DrawSkeleton(const NUI_SKELETON_DATA& skel, int windowWidth, int windowHeight){int i;// 将关节点转化成屏幕上的坐标点 for (i = 0; i < NUI_SKELETON_POSITION_COUNT; ++i) { g_data.Points[i] = SkeletonToScreen(skel.SkeletonPositions[i], windowWidth, windowHeight); } // 画骨骼,参数1是骨骼数据,参数2和参数3是关节 DrawBone(skel, NUI_SKELETON_POSITION_HEAD, NUI_SKELETON_POSITION_SHOULDER_CENTER); // 这个是脑袋,从脑袋关节到肩膀中间 DrawBone(skel, NUI_SKELETON_POSITION_SHOULDER_CENTER, NUI_SKELETON_POSITION_SHOULDER_LEFT); // 肩膀中间到左边 DrawBone(skel, NUI_SKELETON_POSITION_SHOULDER_CENTER, NUI_SKELETON_POSITION_SHOULDER_RIGHT); // 肩膀中间到右边,下面的类似 DrawBone(skel, NUI_SKELETON_POSITION_SHOULDER_CENTER, NUI_SKELETON_POSITION_SPINE); DrawBone(skel, NUI_SKELETON_POSITION_SPINE, NUI_SKELETON_POSITION_HIP_CENTER); DrawBone(skel, NUI_SKELETON_POSITION_HIP_CENTER, NUI_SKELETON_POSITION_HIP_LEFT); DrawBone(skel, NUI_SKELETON_POSITION_HIP_CENTER, NUI_SKELETON_POSITION_HIP_RIGHT); // Left Arm DrawBone(skel, NUI_SKELETON_POSITION_SHOULDER_LEFT, NUI_SKELETON_POSITION_ELBOW_LEFT); DrawBone(skel, NUI_SKELETON_POSITION_ELBOW_LEFT, NUI_SKELETON_POSITION_WRIST_LEFT); DrawBone(skel, NUI_SKELETON_POSITION_WRIST_LEFT, NUI_SKELETON_POSITION_HAND_LEFT); // Right Arm DrawBone(skel, NUI_SKELETON_POSITION_SHOULDER_RIGHT, NUI_SKELETON_POSITION_ELBOW_RIGHT); DrawBone(skel, NUI_SKELETON_POSITION_ELBOW_RIGHT, NUI_SKELETON_POSITION_WRIST_RIGHT); DrawBone(skel, NUI_SKELETON_POSITION_WRIST_RIGHT, NUI_SKELETON_POSITION_HAND_RIGHT); // Left Leg DrawBone(skel, NUI_SKELETON_POSITION_HIP_LEFT, NUI_SKELETON_POSITION_KNEE_LEFT); DrawBone(skel, NUI_SKELETON_POSITION_KNEE_LEFT, NUI_SKELETON_POSITION_ANKLE_LEFT); DrawBone(skel, NUI_SKELETON_POSITION_ANKLE_LEFT, NUI_SKELETON_POSITION_FOOT_LEFT); // Right Leg DrawBone(skel, NUI_SKELETON_POSITION_HIP_RIGHT, NUI_SKELETON_POSITION_KNEE_RIGHT); DrawBone(skel, NUI_SKELETON_POSITION_KNEE_RIGHT, NUI_SKELETON_POSITION_ANKLE_RIGHT); DrawBone(skel, NUI_SKELETON_POSITION_ANKLE_RIGHT, NUI_SKELETON_POSITION_FOOT_RIGHT); // 画关节 for (i = 0; i < NUI_SKELETON_POSITION_COUNT; ++i) { D2D1_ELLIPSE ellipse = D2D1::Ellipse( g_data.Points[i], g_JointThickness, g_JointThickness ); if ( skel.eSkeletonPositionTrackingState[i] == NUI_SKELETON_POSITION_INFERRED ) { g_data.pRenderTargetSkeleton->DrawEllipse(ellipse, g_data.pBrushJointInferred); } else if ( skel.eSkeletonPositionTrackingState[i] == NUI_SKELETON_POSITION_TRACKED ) { g_data.pRenderTargetSkeleton->DrawEllipse(ellipse, g_data.pBrushJointTracked); } }}void DrawSkeleton1(const NUI_SKELETON_FRAME& skeletonFrame){HRESULT hr;//g_data.pSensor->NuiTransformSmooth(&skeletonFrame, NULL);hr = ::EnsureResourcesSkeleton();if(FAILED(hr)) return;g_data.pRenderTargetSkeleton->BeginDraw();g_data.pRenderTargetSkeleton->Clear();RECT rc;GetClientRect( g_data.hWndSkeleton, &rc);int width = rc.right;int height = rc.bottom;for( int i=0; i < NUI_SKELETON_COUNT; ++i){const NUI_SKELETON_TRACKING_STATE trackingState = skeletonFrame.SkeletonData[i].eTrackingState;if(NUI_SKELETON_TRACKED == trackingState) // 跟踪骨骼的,画骨骼{DrawSkeleton(skeletonFrame.SkeletonData[i], width, height);}else if(NUI_SKELETON_POSITION_ONLY == trackingState) // 跟踪位置的,只画位置{D2D1_ELLIPSE ellipse = D2D1::Ellipse(SkeletonToScreen(skeletonFrame.SkeletonData[i].Position, width, height),g_JointThickness,g_JointThickness);g_data.pRenderTargetSkeleton->DrawEllipse(ellipse, g_data.pBrushJointTracked);}}hr = g_data.pRenderTargetSkeleton->EndDraw();if(D2DERR_RECREATE_TARGET == hr)::DiscardResourcesSkeleton();}// 处理骨骼流void ProcessSkeleton(){NUI_SKELETON_FRAME SkeletonFrame = {0}; HRESULT hr = g_data.pSensor->NuiSkeletonGetNextFrame( 0, &SkeletonFrame ); if( FAILED( hr ) ) { OutputMessage(L"Get Skeleton Image Frame Failed"); return; } bool bFoundSkeleton = true; bFoundSkeleton = true; g_data.pSensor->NuiTransformSmooth(&SkeletonFrame,NULL); DrawSkeleton1(SkeletonFrame); Vector4 v; g_data.pSensor->NuiAccelerometerGetCurrentReading(&v); // m_nuiIStream->ProcessSkeleton(i,&SkeletonFrame.SkeletonData[i],&v,SkeletonFrame.liTimeStamp);// 让交互对象去处理骨骼数据,交互对象计算交互需要骨骼数据和深度数据,所以应用程序一旦收到骨骼数据// 就调用交互对象接口将数据发送过去。让交互对象做运算// 一旦交互对象得到足够的数据,就通知应用程序hr =g_data.pNuiIStream->ProcessSkeleton(NUI_SKELETON_COUNT, SkeletonFrame.SkeletonData, &v, SkeletonFrame.liTimeStamp); if( FAILED( hr ) ) { OutputMessage(L"Process Skeleton failed"); }}int Run(HINSTANCE hInst, int show){MSG msg = {0};WNDCLASS wc;ZeroMemory(&wc, sizeof(wc));wc.style = CS_HREDRAW | CS_VREDRAW;wc.cbWndExtra = DLGWINDOWEXTRA; wc.hInstance = hInst; wc.hCursor = LoadCursorW(NULL, IDC_ARROW); wc.hIcon = NULL;// LoadIconW(hInst, MAKEINTRESOURCE(IDI_APP)); wc.lpfnWndProc = DefDlgProcW; wc.lpszClassName = L"KinectInteration";if(!RegisterClass(&wc)){return -1;}g_data.hWnd = CreateDialogParamW(hInst,MAKEINTRESOURCE(IDD_DLG), NULL, (DLGPROC)DlgFunc, NULL); ShowWindow(g_data.hWnd, show);if(FAILED(initD2D())){MessageBox(g_data.hWnd, L"初始化DirectX失败", L"错误", MB_OK);return 0;}if(FAILED(createSensor())){MessageBox(g_data.hWnd, L"没有找到体感设备", L"错误", MB_OK);return 0;}if(FAILED(initSensor())) {MessageBox(g_data.hWnd, L"初始化体感设备失败", L"错误", MB_OK); return 0;}HANDLE hEvents[4];hEvents[0] = g_data.hEventDepth;hEvents[1] = g_data.hEventInteration;hEvents[2] = g_data.hEventRGB;hEvents[3] = g_data.hEventSkeleton;while(WM_QUIT != msg.message){DWORD dwEvent = MsgWaitForMultipleObjects(4, hEvents, FALSE, INFINITE, QS_ALLINPUT);if(WAIT_OBJECT_0 == WaitForSingleObject(g_data.hEventDepth, 0)){ProcessDepth();}if(WAIT_OBJECT_0 == WaitForSingleObject(g_data.hEventInteration, 0)){ProcessInteration();}if(WAIT_OBJECT_0 == WaitForSingleObject(g_data.hEventRGB, 0)){ProcessRGB();}if(WAIT_OBJECT_0 == WaitForSingleObject(g_data.hEventSkeleton, 0)){ProcessSkeleton();}if(PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)){if( g_data.hWnd != NULL && IsDialogMessageW(g_data.hWnd, &msg)){continue;}TranslateMessage(&msg);DispatchMessageW(&msg);}}Cleanup();return msg.wParam;}int APIENTRY wWinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow){initGlobalData();return Run(hInst, nCmdShow);}
0 0
- kinect for windows - 手势识别之一,kinect手势识别框架
- kinect for windows - 手势识别之一,C++实现
- Kinect for Windows SDK开发入门(十一):手势识别 下:基本手势识别
- [译]Kinect for Windows SDK开发入门(十一):手势识别 下:基本手势识别
- Kinect for Windows SDK开发入门(十一):手势识别 下:基本手势识别
- [译]Kinect for Windows SDK开发入门(十一):手势识别 下:基本手势识别
- Kinect for Windows SDK开发入门(十一):手势识别 下:基本手势识别
- Kinect Windows SDK 开发:手势识别
- 基于C++的Kinect手势识别实现
- [译]Kinect for Windows SDK开发入门(十):手势识别 上:基本概念
- Kinect for Windows SDK开发入门(十):手势识别 上:基本概念
- [译]Kinect for Windows SDK开发入门(十):手势识别 上:基本概念
- Kinect for Windows SDK开发入门(十):手势识别 上:基本概念
- [译]Kinect for Windows SDK开发入门(十):手势识别 上:基本概念
- Kinect for Windows SDK开发入门(十):手势识别 上:基本概念
- kinect+openni手势识别
- 手势识别Kinect
- Kinect 手势识别
- 品茶看<Servlet&JSP>-EL表达式
- 早起的鸟儿有虫吃-JSTL核心标签库[收藏]
- 又是星期五,小试牛刀(编写定制标签)
- 数字信号处理_沙沙在哪里?
- javaWeb之在例子中学习(过滤器Filter)
- kinect for windows - 手势识别之一,C++实现
- 小姐,你化妆了吗(请求与响应的装饰)
- 系统时钟 裸板
- Fighting for HDU 2109
- 异步处理
- Struts2用token防止表单数据重复提交
- Servlet & JSP系列文章总结
- TCP/IP_背后你有所不知的故事
- sjhzdgmzfh,