• Microsoft Kinect SDK中的Event Model


    Microsoft Kinect SDK在初始化的时候,需要设置一个ManualReset的Event Handle丢进NuiImageStreamOpen里。

    1         hNextColor = CreateEvent(NULL, TRUE, FALSE, NULL);
    2     
    3         hr = m_pNuiSensor->NuiImageStreamOpen(
    4         NUI_IMAGE_TYPE_COLOR,
    5         NUI_IMAGE_RESOLUTION_640x480, 0, 2, 
    6         hNextColor, 
    7         &hColorStream);

    但在处理的时候,没有任何地方调用ResetEvent来重置hNextColor。看微软提供的SkeletonViewer里面的有一段函数:第18行,调用一次WaitForMultipleObjects后,又在41/50/55行再次调用WaitForSingleObject来确认当前是否有Depth/Color/Skeleton帧。

     1 DWORD WINAPI CSkeletalViewerApp::Nui_ProcessThread( )
     2 {
     3     const int numEvents = 4;
     4     HANDLE hEvents[numEvents] = { m_hEvNuiProcessStop, m_hNextDepthFrameEvent, m_hNextColorFrameEvent, m_hNextSkeletonEvent };
     5     int    nEventIdx;
     6     DWORD  t;
     7 
     8     m_LastDepthFPStime = timeGetTime( );
     9 
    10     // Blank the skeleton display on startup
    11     m_LastSkeletonFoundTime = 0;
    12 
    13     // Main thread loop
    14     bool continueProcessing = true;
    15     while ( continueProcessing )
    16     {
    17         // Wait for any of the events to be signalled
    18         nEventIdx = WaitForMultipleObjects( numEvents, hEvents, FALSE, 100 );
    19 
    20         // Timed out, continue
    21         if ( nEventIdx == WAIT_TIMEOUT )
    22         {
    23             continue;
    24         }
    25 
    26         // stop event was signalled 
    27         if ( WAIT_OBJECT_0 == nEventIdx )
    28         {
    29             continueProcessing = false;
    30             break;
    31         }
    32 
    33         // Wait for each object individually with a 0 timeout to make sure to
    34         // process all signalled objects if multiple objects were signalled
    35         // this loop iteration
    36 
    37         // In situations where perfect correspondance between color/depth/skeleton
    38         // is essential, a priority queue should be used to service the item
    39         // which has been updated the longest ago
    40 
    41         if ( WAIT_OBJECT_0 == WaitForSingleObject( m_hNextDepthFrameEvent, 0 ) )
    42         {
    43             //only increment frame count if a frame was successfully drawn
    44             if ( Nui_GotDepthAlert() )
    45             {
    46                 ++m_DepthFramesTotal;
    47             }
    48         }
    49 
    50         if ( WAIT_OBJECT_0 == WaitForSingleObject( m_hNextColorFrameEvent, 0 ) )
    51         {
    52             Nui_GotColorAlert();
    53         }
    54 
    55         if (  WAIT_OBJECT_0 == WaitForSingleObject( m_hNextSkeletonEvent, 0 ) )
    56         {
    57             Nui_GotSkeletonAlert( );
    58         }

    若无ResetEvent的话,势必会造成下次调用WaitForMultipleObjects/WaitForSingleObject仍能成功,于是会导致重复帧。但实际情况上不会出现重复帧,于是猜测是在用户手动调用NuiImageStreamGetNextFrame更新FrameHandle时,这个函数在SDK内部将当前的 hNextColor重置。

    模拟函数如下:

     1 #include <iostream>
     2 #include <Windows.h>
     3 using namespace std;
     4 
     5 HANDLE hNextRgb;
     6 int timestamp = 0;
     7 
     8 void FakeNuiSkeletonGetNextFrame()
     9 {
    10     // HRESULT NuiImageStreamGetNextFrame(HANDLE hStream,DWORD dwMillisecondsToWait,const NUI_IMAGE_FRAME **ppcImageFrame)
    11     // update rgb stream handle : "HANDLE hStream" and reset next rgb event
    12     ResetEvent(hNextRgb);
    13 }
    14 
    15 DWORD WINAPI RgbCaptureThread(LPVOID lpParameter) 
    16 { 
    17     while(1)   
    18     { 
    19         Sleep(30); // assume rgb frame is update 30ms/frame
    20         timestamp++;
    21         cout << "+ ";
    22         SetEvent(hNextRgb);
    23     }
    24     return 0; 
    25 } 
    26 
    27 DWORD WINAPI MyProcssThread(LPVOID lpParameter) 
    28 { 
    29     while(1)   
    30     { 
    31         if ( WAIT_OBJECT_0 == WaitForSingleObject(hNextRgb,INFINITE) )
    32         {
    33             FakeNuiSkeletonGetNextFrame();
    34             cout<< timestamp <<endl;
    35             {
    36                 // copy the rgb frame, run your own algorithm
    37                 // if your process time is beyond 30ms, you will lose some rgb frames
    38                 int ProcessTime = 30;  
    39                 Sleep(ProcessTime);
    40             }            
    41         }
    42     }
    43     return 0; 
    44 }
    45 
    46 void simulateKinect()
    47 { 
    48     hNextRgb = CreateEvent(NULL,TRUE,FALSE,NULL); 
    49 
    50     HANDLE hThrd[2];
    51     hThrd[0] =  CreateThread(NULL,0,MyProcssThread,NULL,0,NULL); 
    52     // hThrd[1] is hidden in SDK, there should be a rgb/depth thread that continues update kinect rgb/depth camera
    53     hThrd[1] =  CreateThread(NULL,0,RgbCaptureThread,NULL,0,NULL); 
    54 
    55     WaitForMultipleObjects(2, hThrd, TRUE, INFINITE);
    56     CloseHandle(hThrd[0]); 
    57     CloseHandle(hThrd[1]);   
    58     CloseHandle(hNextRgb);
    59 } 
    60 
    61 int main(){
    62     simulateKinect();
    63     return 0;
    64 }

    可以看到,如果用户在MyProcessThread中处理一帧的时间过长,超过30ms,就会导致错过下一帧的更新。

    eg:ProcessTime = 40时,每更新4个Frame,只处理3个Frame,程序输出如下:

    为了证实想法的正确性,搜了一下MSDN,发现如下描述:

    http://msdn.microsoft.com/en-us/library/hh973076.aspx

    Event Model

    The event model supports the ability to integrate retrieval of a skeleton frame into an application engine with more flexibility and more accuracy.

    In this model, C++ code passes an event handle to NuiImageStreamOpen to open a color or depth stream. The event handle should be a manual-reset event handle, created by a call to the Windows CreateEvent API. When a new frame of color or depth data is ready, the event is signaled. Any thread waiting on the event handle wakes and gets the frame of color or depth data by calling NuiImageStreamGetNextFrame or skeleton data by calling NuiSkeletonGetNextFrameDuring this time, the event is reset by the NUI Image Camera API.

    后话:Microsoft Kinect SDK目前的内部同步(RGB/DEPTH/SKELETON)仍然做的不是特别精准,所以下一步将要考虑如何设置缓存,并根据timestamp手工同步这三组数据。

    下一篇文章,先测试下NuiSetFrameEndEvent~

  • 相关阅读:
    JDK和TOMCAT的安装与配置环境变量
    jsp_类的封装_集合的应用
    eclipse的安装
    动态JSP的了解
    Xamarin GitHub 下载的源码运行不了
    VS2017 移动开发(Android and IOS) 序
    C# 移动开发 MasterDetailPage 侧滑
    C# 获取本机IP(优化项目实际使用版)
    C# 调用第三方DLL缓冲区溢出导致的异常
    后台安装 SQL Server 无人值守 安装
  • 原文地址:https://www.cnblogs.com/lucantang/p/2678990.html
Copyright © 2020-2023  润新知