1

Kinect カメラの色と深度フレームから特徴を抽出するプロジェクトに取り組んでいます。私が直面している問題は、2 つの画像を表示しようとするたびに UI がハングすることです。デバッグを試みたところ、depthFrame と colorFrame が null になっていました。カラー ストリームのみを有効にすると、colorImage と featureImage1 の両方が適切に表示され、深度ストリームのみを有効にすると、正常に動作します。しかし、両方を有効にすると、UI がハングします。何が問題を引き起こしているのかわかりません。Kinect アプリケーション用に次のコードがあります。この問題の原因は何ですか?どうすれば修正できますか? 構成: Windows 8 Pro 64 ビット、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スレッドでハンドラが呼び出されることはほぼ確実です。コードをバックグラウンド スレッド ルーチンに抽出することをお勧めします。フォームのコントロール (および)の更新は、親フォームのメソッドを使用して行う必要がある
ことを忘れないでください。depthImagecontrolImageBeginInvoke

于 2012-10-20T19:06:57.197 に答える