我希望您能协助我处理Kinect v2 SDK中的MultiSourceFrameArrived事件。
以下是相关方法:
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));
}
}
}
}
}
现在,请允许我解释:
- 当从Kinect收到特定类型的帧时,该方法运行,这个帧被获取并且我可以在using块中提取出ColorFrame和BodyFrame。
- 第一个“using”块将ColorFrame转换为WPF的WriteableBitmap(在构造函数中声明),并将用户控件的ReflectionImageSource设置为此WriteableBitmap。如果这是唯一的using块,我会看到屏幕上非常平滑的图像!
- 第二个BodyFrame using确定最近的身体,如果被跟踪,则创建一个填充有人类BodyComponents(手、脚、头等)的字典。
- 此处的foreach循环在每个BodyComponent上运行“Generate”函数,该函数设置其某些属性。例如,它设置了一个EncompassingRectangle属性,该属性是一个Int32Rect对象,旨在包含该组件。
下面就是我需要帮助的部分!
RunFunFiltering方法是一个高度密集的处理方法,运行时会创建一个阻塞语句,导致我的UI冻结。这将导致我的颜色帧视频反馈非常跳跃!RunFunFiltering方法需要设置一些BodyComponent类的属性,例如矩形应显示的颜色、ReflectionImageSource中的白色像素数以及将另一个可写位图设置为包含在矩形中的第一个ReflectionImageSource的部分。
由于此对象现在已经完成,所有属性都已设置(并且已对字典中的每个BodyComponent执行此操作),因此我在视图上运行UpdateValues方法,该方法为我显示BodyComponent类中有趣的内容。
根据@sstan在这篇文章中提供的建议:Async Await to Keep Event Firing
我添加了一个Task.Run()块。然而,这似乎没有释放我的UI,并且我仍然看到跳跃的图像。奇怪的是,在计时器示例中,它完全正常工作!我有点不知道该怎么办。
我对异步函数有点生疏,但我真的想了解您的解决方案。如果您能在代码中提供解释,我将非常感激!
更新
我已经确定获取帧的using语句在放置在Task.Run调用之外时会阻塞UI。
我不能只使整个BodyFrame using块异步运行,因为我需要第一个“Generate”函数始终发生并且不是重型线程的一部分。两个using块似乎不太优雅,而且问题被掩盖了...