微软Kinect 1.7 附带ColorBasics-D2D示例程序基本解析
先安裝Kinect SDK;
如上圖;需要安裝2個安裝文件;sdk,toolkit;然后可以獲得示例代碼;
運行程序需要安裝Kinect傳感器;
?
主文件代碼;
//------------------------------------------------------------------------------ // <copyright file="ColorBasics.cpp" company="Microsoft"> // Copyright (c) Microsoft Corporation. All rights reserved. // </copyright> //------------------------------------------------------------------------------#include "stdafx.h" #include <strsafe.h> #include "ColorBasics.h" #include "resource.h"/// <summary> /// Entry point for the application /// </summary> /// <param name="hInstance">handle to the application instance</param> /// <param name="hPrevInstance">always 0</param> /// <param name="lpCmdLine">command line arguments</param> /// <param name="nCmdShow">whether to display minimized, maximized, or normally</param> /// <returns>status</returns> int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) {CColorBasics application;application.Run(hInstance, nCmdShow); }/// <summary> /// Constructor /// </summary> CColorBasics::CColorBasics() :m_pD2DFactory(NULL),m_pDrawColor(NULL),m_hNextColorFrameEvent(INVALID_HANDLE_VALUE),m_pColorStreamHandle(INVALID_HANDLE_VALUE),m_bSaveScreenshot(false),m_pNuiSensor(NULL) { }/// <summary> /// Destructor /// </summary> CColorBasics::~CColorBasics() {if (m_pNuiSensor){m_pNuiSensor->NuiShutdown();}if (m_hNextColorFrameEvent != INVALID_HANDLE_VALUE){CloseHandle(m_hNextColorFrameEvent);}// clean up Direct2D rendererdelete m_pDrawColor;m_pDrawColor = NULL;// clean up Direct2DSafeRelease(m_pD2DFactory);SafeRelease(m_pNuiSensor); }/// <summary> /// Creates the main window and begins processing /// </summary> /// <param name="hInstance">handle to the application instance</param> /// <param name="nCmdShow">whether to display minimized, maximized, or normally</param> int CColorBasics::Run(HINSTANCE hInstance, int nCmdShow) {MSG msg = {0};WNDCLASS wc;// Dialog custom window classZeroMemory(&wc, sizeof(wc));wc.style = CS_HREDRAW | CS_VREDRAW;wc.cbWndExtra = DLGWINDOWEXTRA;wc.hInstance = hInstance;wc.hCursor = LoadCursorW(NULL, IDC_ARROW);wc.hIcon = LoadIconW(hInstance, MAKEINTRESOURCE(IDI_APP));wc.lpfnWndProc = DefDlgProcW;wc.lpszClassName = L"ColorBasicsAppDlgWndClass";if (!RegisterClassW(&wc)){return 0;}// Create main application windowHWND hWndApp = CreateDialogParamW(hInstance,MAKEINTRESOURCE(IDD_APP),NULL,(DLGPROC)CColorBasics::MessageRouter, reinterpret_cast<LPARAM>(this));// Show windowShowWindow(hWndApp, nCmdShow);const int eventCount = 1;HANDLE hEvents[eventCount];// Main message loopwhile (WM_QUIT != msg.message){hEvents[0] = m_hNextColorFrameEvent;// Check to see if we have either a message (by passing in QS_ALLINPUT)// Or a Kinect event (hEvents)// Update() will check for Kinect events individually, in case more than one are signalledDWORD dwEvent = MsgWaitForMultipleObjects(eventCount, hEvents, FALSE, INFINITE, QS_ALLINPUT);// Check if this is an event we're waiting on and not a timeout or messageif (WAIT_OBJECT_0 == dwEvent){Update();}if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)){// If a dialog message will be taken care of by the dialog procif ((hWndApp != NULL) && IsDialogMessageW(hWndApp, &msg)){continue;}TranslateMessage(&msg);DispatchMessageW(&msg);}}return static_cast<int>(msg.wParam); }/// <summary> /// Main processing function /// </summary> void CColorBasics::Update() {if (NULL == m_pNuiSensor){return;}if ( WAIT_OBJECT_0 == WaitForSingleObject(m_hNextColorFrameEvent, 0) ){ProcessColor();} }/// <summary> /// Handles window messages, passes most to the class instance to handle /// </summary> /// <param name="hWnd">window message is for</param> /// <param name="uMsg">message</param> /// <param name="wParam">message data</param> /// <param name="lParam">additional message data</param> /// <returns>result of message processing</returns> LRESULT CALLBACK CColorBasics::MessageRouter(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {CColorBasics* pThis = NULL;if (WM_INITDIALOG == uMsg){pThis = reinterpret_cast<CColorBasics*>(lParam);SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));}else{pThis = reinterpret_cast<CColorBasics*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));}if (pThis){return pThis->DlgProc(hWnd, uMsg, wParam, lParam);}return 0; }/// <summary> /// Handle windows messages for the class instance /// </summary> /// <param name="hWnd">window message is for</param> /// <param name="uMsg">message</param> /// <param name="wParam">message data</param> /// <param name="lParam">additional message data</param> /// <returns>result of message processing</returns> LRESULT CALLBACK CColorBasics::DlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {switch (message){case WM_INITDIALOG:{// Bind application window handlem_hWnd = hWnd;// Init Direct2DD2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);// Create and initialize a new Direct2D image renderer (take a look at ImageRenderer.h)// We'll use this to draw the data we receive from the Kinect to the screenm_pDrawColor = new ImageRenderer();HRESULT hr = m_pDrawColor->Initialize(GetDlgItem(m_hWnd, IDC_VIDEOVIEW), m_pD2DFactory, cColorWidth, cColorHeight, cColorWidth * sizeof(long));if (FAILED(hr)){SetStatusMessage(L"Failed to initialize the Direct2D draw device.");}// Look for a connected Kinect, and create it if foundCreateFirstConnected();}break;// If the titlebar X is clicked, destroy appcase WM_CLOSE:DestroyWindow(hWnd);break;case WM_DESTROY:// Quit the main message pumpPostQuitMessage(0);break;// Handle button presscase WM_COMMAND:// If it was for the screenshot control and a button clicked event, save a screenshot next frame if (IDC_BUTTON_SCREENSHOT == LOWORD(wParam) && BN_CLICKED == HIWORD(wParam)){m_bSaveScreenshot = true;}break;}return FALSE; }/// <summary> /// Create the first connected Kinect found /// </summary> /// <returns>indicates success or failure</returns> HRESULT CColorBasics::CreateFirstConnected() {INuiSensor * pNuiSensor;HRESULT hr;int iSensorCount = 0;hr = NuiGetSensorCount(&iSensorCount);if (FAILED(hr)){return hr;}// Look at each Kinect sensorfor (int i = 0; i < iSensorCount; ++i){// Create the sensor so we can check status, if we can't create it, move on to the nexthr = NuiCreateSensorByIndex(i, &pNuiSensor);if (FAILED(hr)){continue;}// Get the status of the sensor, and if connected, then we can initialize ithr = pNuiSensor->NuiStatus();if (S_OK == hr){m_pNuiSensor = pNuiSensor;break;}// This sensor wasn't OK, so release it since we're not using itpNuiSensor->Release();}if (NULL != m_pNuiSensor){// Initialize the Kinect and specify that we'll be using colorhr = m_pNuiSensor->NuiInitialize(NUI_INITIALIZE_FLAG_USES_COLOR); if (SUCCEEDED(hr)){// Create an event that will be signaled when color data is availablem_hNextColorFrameEvent = CreateEvent(NULL, TRUE, FALSE, NULL);// Open a color image stream to receive color frameshr = m_pNuiSensor->NuiImageStreamOpen(NUI_IMAGE_TYPE_COLOR,NUI_IMAGE_RESOLUTION_640x480,0,2,m_hNextColorFrameEvent,&m_pColorStreamHandle);}}if (NULL == m_pNuiSensor || FAILED(hr)){SetStatusMessage(L"No ready Kinect found!");return E_FAIL;}return hr; }/// <summary> /// Get the name of the file where screenshot will be stored. /// </summary> /// <param name="screenshotName"> /// [out] String buffer that will receive screenshot file name. /// </param> /// <param name="screenshotNameSize"> /// [in] Number of characters in screenshotName string buffer. /// </param> /// <returns> /// S_OK on success, otherwise failure code. /// </returns> HRESULT GetScreenshotFileName(wchar_t *screenshotName, UINT screenshotNameSize) {wchar_t *knownPath = NULL;HRESULT hr = SHGetKnownFolderPath(FOLDERID_Pictures, 0, NULL, &knownPath);if (SUCCEEDED(hr)){// Get the timewchar_t timeString[MAX_PATH];GetTimeFormatEx(NULL, 0, NULL, L"hh'-'mm'-'ss", timeString, _countof(timeString));// File name will be KinectSnapshot-HH-MM-SS.wavStringCchPrintfW(screenshotName, screenshotNameSize, L"%s\\KinectSnapshot-%s.bmp", knownPath, timeString);}CoTaskMemFree(knownPath);return hr; }/// <summary> /// Handle new color data /// </summary> /// <returns>indicates success or failure</returns> void CColorBasics::ProcessColor() {HRESULT hr;NUI_IMAGE_FRAME imageFrame;// Attempt to get the color framehr = m_pNuiSensor->NuiImageStreamGetNextFrame(m_pColorStreamHandle, 0, &imageFrame);if (FAILED(hr)){return;}INuiFrameTexture * pTexture = imageFrame.pFrameTexture;NUI_LOCKED_RECT LockedRect;// Lock the frame data so the Kinect knows not to modify it while we're reading itpTexture->LockRect(0, &LockedRect, NULL, 0);// Make sure we've received valid dataif (LockedRect.Pitch != 0){// Draw the data with Direct2Dm_pDrawColor->Draw(static_cast<BYTE *>(LockedRect.pBits), LockedRect.size);// If the user pressed the screenshot button, save a screenshotif (m_bSaveScreenshot){WCHAR statusMessage[cStatusMessageMaxLen];// Retrieve the path to My PhotosWCHAR screenshotPath[MAX_PATH];GetScreenshotFileName(screenshotPath, _countof(screenshotPath));// Write out the bitmap to diskhr = SaveBitmapToFile(static_cast<BYTE *>(LockedRect.pBits), cColorWidth, cColorHeight, 32, screenshotPath);if (SUCCEEDED(hr)){// Set the status bar to show where the screenshot was savedStringCchPrintf( statusMessage, cStatusMessageMaxLen, L"Screenshot saved to %s", screenshotPath);}else{StringCchPrintf( statusMessage, cStatusMessageMaxLen, L"Failed to write screenshot to %s", screenshotPath);}SetStatusMessage(statusMessage);// toggle off so we don't save a screenshot again next framem_bSaveScreenshot = false;}}// We're done with the texture so unlock itpTexture->UnlockRect(0);// Release the framem_pNuiSensor->NuiImageStreamReleaseFrame(m_pColorStreamHandle, &imageFrame); }/// <summary> /// Set the status bar message /// </summary> /// <param name="szMessage">message to display</param> void CColorBasics::SetStatusMessage(WCHAR * szMessage) {SendDlgItemMessageW(m_hWnd, IDC_STATUS, WM_SETTEXT, 0, (LPARAM)szMessage); }/// <summary> /// Save passed in image data to disk as a bitmap /// </summary> /// <param name="pBitmapBits">image data to save</param> /// <param name="lWidth">width (in pixels) of input image data</param> /// <param name="lHeight">height (in pixels) of input image data</param> /// <param name="wBitsPerPixel">bits per pixel of image data</param> /// <param name="lpszFilePath">full file path to output bitmap to</param> /// <returns>indicates success or failure</returns> HRESULT CColorBasics::SaveBitmapToFile(BYTE* pBitmapBits, LONG lWidth, LONG lHeight, WORD wBitsPerPixel, LPCWSTR lpszFilePath) {DWORD dwByteCount = lWidth * lHeight * (wBitsPerPixel / 8);BITMAPINFOHEADER bmpInfoHeader = {0};bmpInfoHeader.biSize = sizeof(BITMAPINFOHEADER); // Size of the headerbmpInfoHeader.biBitCount = wBitsPerPixel; // Bit countbmpInfoHeader.biCompression = BI_RGB; // Standard RGB, no compressionbmpInfoHeader.biWidth = lWidth; // Width in pixelsbmpInfoHeader.biHeight = -lHeight; // Height in pixels, negative indicates it's stored right-side-upbmpInfoHeader.biPlanes = 1; // DefaultbmpInfoHeader.biSizeImage = dwByteCount; // Image size in bytesBITMAPFILEHEADER bfh = {0};bfh.bfType = 0x4D42; // 'M''B', indicates bitmapbfh.bfOffBits = bmpInfoHeader.biSize + sizeof(BITMAPFILEHEADER); // Offset to the start of pixel databfh.bfSize = bfh.bfOffBits + bmpInfoHeader.biSizeImage; // Size of image + headers// Create the file on disk to write toHANDLE hFile = CreateFileW(lpszFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);// Return if error opening fileif (NULL == hFile) {return E_ACCESSDENIED;}DWORD dwBytesWritten = 0;// Write the bitmap file headerif ( !WriteFile(hFile, &bfh, sizeof(bfh), &dwBytesWritten, NULL) ){CloseHandle(hFile);return E_FAIL;}// Write the bitmap info headerif ( !WriteFile(hFile, &bmpInfoHeader, sizeof(bmpInfoHeader), &dwBytesWritten, NULL) ){CloseHandle(hFile);return E_FAIL;}// Write the RGB Dataif ( !WriteFile(hFile, pBitmapBits, bmpInfoHeader.biSizeImage, &dwBytesWritten, NULL) ){CloseHandle(hFile);return E_FAIL;} // Close the fileCloseHandle(hFile);return S_OK; }首先看一下,包含stdafx.h,Resource.h;這是一個VC++項目;但不是MFC項目;
程序是以wWinMain入口;
Run函數(shù)里面主要是注冊窗口類;創(chuàng)建窗口,消息循環(huán);
CreateDialogParam函數(shù),根據(jù)對話框模板資源創(chuàng)建一個無模式的對話框。在顯示對話框之前,函數(shù)把一個應用程序定義的值作為WM_INITDIALOG消息IParam參數(shù)傳到對話框過程應用程序可用此值來初始化對話框控制。
在stdafx.h里,有
#include <d2d1.h>
#pragma comment ( lib, "d2d1.lib" )
也就是此程序?qū)⑹褂梦④汥irectX 2D;
在初始化對話框(WM_INITDIALOG)的時候,執(zhí)行
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);
創(chuàng)建D2D工廠;
在CreateFirstConnected函數(shù)里主要是獲取連接了幾個kinect傳感器(NuiGetSensorCount);
然后調(diào)用NuiCreateSensorByIndex創(chuàng)建傳感器對象;
主要的功能是在ProcessColor函數(shù)里;
NUI_IMAGE_FRAME imageFrame是一個圖像幀;
獲取了圖像幀以后調(diào)用D2D的功能來在窗口上進行繪制;
然后保存屏幕截圖到文件;
這是kinect的基本C++示例;
《新程序員》:云原生和全面數(shù)字化實踐50位技術專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的微软Kinect 1.7 附带ColorBasics-D2D示例程序基本解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Windows控制台程序处理消息编程实例
- 下一篇: 体感(Kinect)开发要点总结一