1

我正在从事一个项目,该项目涉及从 Kinect 相机的颜色和深度帧中提取特征。我面临的问题是,每当我尝试显示 2 个图像时,UI 都会挂起。当我尝试调试时,depthFrame 和 colorFrame 为空。如果只启用颜色流,那么 colorImage 和 featureImage1 都会正确显示,如果我只启用深度流,它应该可以正常工作。但是当我同时启用它们时,用户界面就会挂起。我不知道是什么导致了这个问题。我的 Kinect 应用程序有以下代码。这个问题的原因是什么,我该如何解决?配置:Windows 8 Pro 64bit,2Ghz Core2Duo,VisualStudio 2012 Ultimate,EmguCV 2.4.0。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Kinect;
using Emgu.CV;
using Emgu.CV.WPF;
using Emgu.CV.Structure;
using Emgu.Util;
namespace features
{
public partial class MainWindow : Window
{  
    public MainWindow()
    {
        InitializeComponent();
    }
    private Image<Bgra, Byte> cvColorImage;
    private Image<Gray, Int16> cvDepthImage;
    private int colorWidth = 640;
    private int colorHeight = 480;
    private int depthWidth = 640;
    private int depthHeight = 480;
    private static readonly int Bgr32BytesPerPixel = (PixelFormats.Bgr32.BitsPerPixel + 7) / 8;
    private byte[] colorPixels;
    private byte[] depthPixels;
    private short[] rawDepthData;
    private bool first = true;
    private bool firstDepth = true;
    Image<Bgra, byte> image2;
    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        kinectSensorChooser.KinectSensorChanged += new DependencyPropertyChangedEventHandler(kinectSensorChooser_KinectSensorChanged);
    }
    void kinectSensorChooser_KinectSensorChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        KinectSensor oldSensor = (KinectSensor)e.OldValue;
        KinectStop(oldSensor);
        KinectSensor _sensor = (KinectSensor)e.NewValue;
        _sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
        _sensor.DepthStream.Enable(DepthImageFormat.Resolution640x480Fps30);
        _sensor.DepthFrameReady += new EventHandler<DepthImageFrameReadyEventArgs>(_sensor_DepthFrameReady);
        _sensor.ColorFrameReady += new EventHandler<ColorImageFrameReadyEventArgs>(_sensor_ColorFrameReady);
        _sensor.DepthStream.FrameHeight);
        try
        {
            _sensor.Start();
        }
        catch
        {
            kinectSensorChooser.AppConflictOccurred();
        }
    }
    void KinectStop(KinectSensor sensor)
    {
        if (sensor != null)
        {
            sensor.Stop();
        }
    }

    private void Window_Closed(object sender, EventArgs e)
    {
        KinectStop(kinectSensorChooser.Kinect);
    }

    void _sensor_ColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
    {
        using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
        {
            if (colorFrame == null) return;
            if (first)
            {
                this.colorPixels = new Byte[colorFrame.PixelDataLength];
                first = false;
            }
            colorFrame.CopyPixelDataTo(this.colorPixels); //raw data in bgrx format
            processColor();
        }
    }
    void _sensor_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e)
    {
        using (DepthImageFrame depthFrame = e.OpenDepthImageFrame())
        {
            if (depthFrame == null) return;
            if (firstDepth)
            {
                this.rawDepthData = new short[depthFrame.PixelDataLength];
                firstDepth = false;
            }
            depthFrame.CopyPixelDataTo(rawDepthData);
            processDepth();
        }
    }
    private void processColor(){...}
    private void processDepth(){...}
}
}

processDepth 函数如下。我只是从 RAW 深度数据制作图像。

private void processDepth() {
    GCHandle pinnedArray = GCHandle.Alloc(this.rawDepthData, GCHandleType.Pinned);
    IntPtr pointer = pinnedArray.AddrOfPinnedObject();
    cvDepthImage = new Image<Gray, Int16>(depthWidth, depthHeight, depthWidth << 1, pointer);
    pinnedArray.Free();
    depthImage.Source = BitmapSourceConvert.ToBitmapSource(cvDepthImage.Not().Bitmap);
}

processColor 函数如下。这里只是为了它,我试图显示克隆的图像而不是提取特征,只是为了检查滞后。当两个流都启用(颜色和深度)时,以下函数会正确显示 colorImage,但是一旦我取消注释注释行,UI 就会挂起。

private void processColor() {
    GCHandle handle = GCHandle.Alloc(this.colorPixels, GCHandleType.Pinned);
    Bitmap image = new Bitmap(colorWidth, colorHeight, colorWidth<<2, System.Drawing.Imaging.PixelFormat.Format32bppRgb, handle.AddrOfPinnedObject());
    handle.Free();
    cvColorImage = new Image<Bgra, byte>(image);
    image.Dispose();
    BitmapSource src = BitmapSourceConvert.ToBitmapSource(cvColorImage.Bitmap);
    colorImage.Source = src;
    //image2 = new Image<Bgra, byte>(cvColorImage.ToBitmap()); //uncomment and it hangs
    //featureImage1.Source = BitmapSourceConvert.ToBitmapSource(image2.Bitmap); //uncomment and it hangs
}
4

1 回答 1

1

我看到代码在事件处理程序中做了很多工作。我几乎可以肯定在 GUI 线程中调用了处理程序。我建议您将代码提取到后台线程例程中。
不要忘记更新表单的控件(depthImagecontrolImage)应该使用BeginInvoke父表单的方法来完成,

于 2012-10-20T19:06:57.197 回答