none
How to set tracked skeletons in C++ such that it works RRS feed

  • Question

  • Hi,

    I'd indirectly like to report a bug that setting skeletons in C++ does not seem to work properly. The skeleton in the skeleton-frame structure that has an actual user ID will ALWAYS have only the state NUI_SKELETON_POSITION_ONLY, never NUI_SKELETON_TRACKED. Here's my code:

    (A few notes before: my goal is to have sticky skeletons, that's all. My class generates an event that ALWAYS contains two skeletons, and if less than 2 are found, the structures are filled with "all values zero" skeletons. My class has the members DWORD trackedUserIndex1 and trackedUserIndex2 that indicate the tracked user IDs of the previous frame, i.e. the value from the dwTrackingID field. I have defined NOT_TRACKED_DWORD 99999 and NOT_TRACKED -1 (for integers))

        NUI_SKELETON_FRAME skeletonFrame = {};

        if (!SUCCEEDED(kinectSensor->NuiSkeletonGetNextFrame( 0, &skeletonFrame )) ) {
            return;
        }

        if (trackedUserIndex1 != NOT_TRACKED_DWORD) {
            std::cout << "Sanity check: trackedUserIndex1=" << trackedUserIndex1 << std::endl;
        }

        //make sure that dwTrackingID (is > 0, e.g. 33 or 201, identifying the user) stays the same as long as this user is within the scene
        //indices for THIS current frame
        int trackedSkeleton1Idx = NOT_TRACKED, trackedSkeleton2Idx = NOT_TRACKED;

        //find an index where we get a "all values zero" skeleton
        int zeroSkeletonIndex = 0;
        for ( int i = 0 ; i < NUI_SKELETON_COUNT ; i++ ) {
            if( skeletonFrame.SkeletonData[i].eTrackingState == NUI_SKELETON_NOT_TRACKED ) {
                zeroSkeletonIndex = i;
                break;
            }
        }

        //check whether previously tracked users are detected in this frame, too
        if (trackedUserIndex1 != NOT_TRACKED_DWORD || trackedUserIndex2 != NOT_TRACKED_DWORD) {
            for ( int i = 0 ; i < NUI_SKELETON_COUNT ; i++ ) {
                if( skeletonFrame.SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED ) {
                    if (trackedUserIndex1 == skeletonFrame.SkeletonData[i].dwTrackingID) {
                        trackedSkeleton1Idx = i;
                        std::cout << "setting trackedSkeleton1Idx to " << trackedSkeleton1Idx << " due to earlier detection" << std::endl;
                    } else if (trackedUserIndex2 == skeletonFrame.SkeletonData[i].dwTrackingID) {
                        trackedSkeleton2Idx = i;
                        std::cout << "setting trackedSkeleton2Idx to " << trackedSkeleton2Idx << " due to earlier detection" << std::endl;
                    }
                }
            }
        }
        
        //check if there are any new skeletons detected in this frame that are not covered by the previous-frame indices
        if (trackedSkeleton1Idx == NOT_TRACKED || trackedSkeleton2Idx == NOT_TRACKED) {
            for ( int i = 0 ; i < NUI_SKELETON_COUNT ; i++ ) {
                if( skeletonFrame.SkeletonData[i].eTrackingState == NUI_SKELETON_POSITION_ONLY ) {
                    if (skeletonFrame.SkeletonData[i].dwTrackingID != trackedUserIndex1 &&
                        skeletonFrame.SkeletonData[i].dwTrackingID != trackedUserIndex2) {
                        //found NEW skeleton
                        //assign it to whichever current-frame indices are still "free"
                        if (trackedSkeleton1Idx == NOT_TRACKED) {
                            trackedSkeleton1Idx = i;
                        } else if (trackedSkeleton2Idx == NOT_TRACKED) {
                            trackedSkeleton2Idx = i;
                        }
                    }
                }
            }
        }

        DWORD nuiSelectedIDs[NUI_SKELETON_MAX_TRACKED_COUNT] = {0, 0};
        if (trackedSkeleton1Idx != NOT_TRACKED) {
            nuiSelectedIDs[0] = skeletonFrame.SkeletonData[trackedSkeleton1Idx].dwTrackingID;
            trackedUserIndex1 = skeletonFrame.SkeletonData[trackedSkeleton1Idx].dwTrackingID;

        } else {
            trackedUserIndex1 = NOT_TRACKED_DWORD;
        }
        if (trackedSkeleton2Idx != NOT_TRACKED) {
            nuiSelectedIDs[1] = skeletonFrame.SkeletonData[trackedSkeleton2Idx].dwTrackingID;
            trackedUserIndex2 = skeletonFrame.SkeletonData[trackedSkeleton2Idx].dwTrackingID;
        } else {
            trackedUserIndex2 = NOT_TRACKED_DWORD;
        }

        HRESULT result = kinectSensor->NuiSkeletonSetTrackedSkeletons(nuiSelectedIDs);
        if (FAILED(result)) {
            std::cout << "Warning: could not set tracked skeletons!" << std::endl;
        }


        //we need to give exactly 2 skeletons to the event, so even if there are none of them actually tracked, still
        //hand a zero'd skeleton over
        if (trackedSkeleton1Idx == NOT_TRACKED) {
            trackedSkeleton1Idx = zeroSkeletonIndex;
        } else if (trackedSkeleton2Idx == NOT_TRACKED) {
            trackedSkeleton2Idx = zeroSkeletonIndex;
        }


    Monday, June 11, 2012 1:36 PM

Answers

  • I think I might have found the problem. It seems that my checks that compare skeletonFrame.SkeletonData[i].eTrackingState to NUI_SKELETON_TRACKED or NUI_SKELETON_POSITION_ONLY actually need to include BOTH, i.e. both NUI_SKELETON_POSITION_ONLY  and NUI_SKELETON_TRACKED, because the SDK does not seem to follow the command to actually TRACK a skeleton "immediately" on the next frame. I.e. it seems to take some time/frames until a untracked skeleton (NUI_SKELETON_POSITION_ONLY) becomes a tracked one (NUI_SKELETON_TRACKED)

    Such behavior should be documented though...

    Monday, June 11, 2012 1:44 PM