Kinect Frame Arrived Asynchronous

坚强是说给别人听的谎言 提交于 2019-12-19 03:33:28

问题


I am looking for some help with my MultiSourceFrameArrived event in the Kinect v2 SDK.

The following is the method in question:

    private async void _reader_MultiSourceFrameArrived(object sender, MultiSourceFrameArrivedEventArgs e)
    {
        MultiSourceFrame multiSourceFrame = e.FrameReference.AcquireFrame();

        using (var colorFrame = multiSourceFrame.ColorFrameReference.AcquireFrame())
        {
            if (colorFrame != null)
            {
                _writeableBitmap.Lock();
                colorFrame.CopyConvertedFrameDataToIntPtr(
                    _writeableBitmap.BackBuffer,
                    (uint)(_colorFrameDescription.Width * _colorFrameDescription.Height * _colorFrameDescription.BytesPerPixel),
                    ColorImageFormat.Bgra);
                _writeableBitmap.AddDirtyRect(new Int32Rect(0, 0, _writeableBitmap.PixelWidth, _writeableBitmap.PixelHeight));
                _writeableBitmap.Unlock();
                reflectionOverlayControl.ReflectionImageSource = _writeableBitmap;
            }
        }

        using (var bodyFrame = multiSourceFrame.BodyFrameReference.AcquireFrame())
        {
            if (bodyFrame != null)
            {
                Body body = JointHelpers.FindClosestBody(bodyFrame);

                if (body != null)
                {
                    if (body.IsTracked)
                    {
                        Dictionary<BodyComponentType, BodyComponent> bodyComponentDictionary = BuildBodyComponentDictionary(body);

                        foreach (BodyComponent bodyComponent in bodyComponentDictionary.Values.OrderBy(x => x.BodyComponentType))
                        {
                            bodyComponent.Generate(_writeableBitmap, _coordinateMapper, FrameType.Color, 25);
                            if (!_isRunningFiltering)
                            {
                                _isRunningFiltering = true;
                                try
                                { 
                                    await Task.Run(() =>
                                        {
                                            bodyComponent.RunFunFiltering();
                                        });
                                }
                                finally
                                {
                                    _isRunningFiltering = false;
                                }
                            }
                        }
                        reflectionOverlayControl.UpdateValues(
                               bodyComponentDictionary,
                               GetFullBodyComponent(body));
                    }
                }
            }
        }
    }

Now, allow me to explain:

  • The method runs when a particular kind of frame arrives from the Kinect, this is acquired and I can extract the ColorFrame and BodyFrame out of it in the using blocks.
  • The first "using" block turns the ColorFrame into a WPF WriteableBitmap (declared in the constructor) and sets a user control's ReflectionImageSource set equal to this WriteableBitmap. If this were the only using block, I would see a very smooth feed on the screen!
  • The second BodyFrame using determines the closest body, if it is tracked and then creates a Dictionary populated with a persons BodyComponents (hands, feet, head etc.)
  • The foreach loop here runs the "Generate" function on each BodyComponent, which sets a few of it's properties. For example, it sets an EncompassingRectangle property which is an Int32Rect object designed to encompass the component.

The next bit is where I need help!

The method RunFunFiltering is a heavily intensive processing method which, when run, would create a blocking statement that freezes up my UI. This would have the effect of making my color frame video feed very jumpy! This RunFunFiltering method needs to set some of the BodyComponent class's properties, such as the colour that the rectangle should be displayed, the number of white pixels in it's ReflectionImageSource and to set another writeable bitmap with the part of the first ReflectionImageSource which is contained in the rectangle.

Since this object is now complete, with all properties set (and this has been done for each of the BodyComponent's in the dictionary) I run an UpdateValues method on the view, which displays the interesting stuff in the BodyComponent class on the screen for me.

Following some advice from @sstan in this post: Async Await to Keep Event Firing

I threw in a Task.Run() block. However, this doesn't seem to be releasing my UI and I still see a jumpy image. The weird thing is in that timer example, that it works perfectly! I'm at a bit of a loss here to know what to do.

I'm a bit of a beginner with asynchronous functions but I would really like to understand your solutions. If you can provide an explanation with your code I'd be extremely grateful!

Update

I have been able to identify that the using statement which acquires the frame blocks the UI when it is placed outside of the Task.Run call.

I can't just make the whole BodyFrame using block run asynchronously because I need the first "Generate" function to always happen and not be part of the heavy processing thread. Two using blocks seems inelegant and is rather pushing my question under the carpet...


回答1:


From your comment I understand the following:

  • You have an async function that is called when a frame arrives
  • If no RunFunFiltering task is running start one
  • If such a task is running, don't start a new one
  • If RunFunFiltering is finished Process the result

.

Task taskFunFiltering = null;

private async Task ProcessFrame(...)
{   // a new frame is arrived
    DoSomeProcessing(...);
    // only start a new run fun filtering if previous one is finished
    if (taskFunFiltering == null || taskFunFiltering.IsCompleted)
    {   // start a new fun filtering
        // don't wait for the result
        taskFunFiltering = Task.Run( () => ...);
    }
}

private async Task RunFunFiltering(...)
{
    // do the filtering and wait until finished
    var filterResult = await DoFiltering(...);
    DisplayResult(filterResult);
}


来源:https://stackoverflow.com/questions/32074055/kinect-frame-arrived-asynchronous

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!