WPF,使用Binding显示Emgu图像

时间:2013-01-10 16:07:30

标签: wpf design-patterns binding emgucv

我熟悉在WPF图像框中显示Emgu图像的基本代码,当所有源代码都在MainWindow.xaml.cs代码隐藏中时。

但是我试图将我的Emgu相关代码(包括“ProcessFrame”事件/ Queryframe片段)放入一个单独的静态方法类中,以便以后可以重用它们。我这样做是因为虽然我希望能够在以后阶段从同一台相机中获取图像,但我也希望能够灵活地在不同的图像框中显示这些图像。我在这一步遇到了麻烦。

如果我可以动态地将Image框绑定到静态方法中的属性(并且还以编程方式启用/禁用该绑定),我认为这将解决我的问题。但是,我尝试采取的方法可能还有其他一些问题。任何代码/ xaml修改都非常感谢。

以下代码有效,但不能令人满意,因为它迫使我将ProcessFrame方法捆绑到MainWindow代码中:

XAML(工作):

<Window x:Class="EmguWPF_Test.MainWindow"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     Title="MainWindow" Height="350" Width="525">
     <Grid>
       <Image Height="215" HorizontalAlignment="Left" Margin="62,66,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="224"  />
     </Grid>
</Window>

MainWindow Code Snippet(正常工作):

//using statements etc
public partial class MainWindow : Window
{
private Image<Bgr, Byte> image; 
private Capture capture = null;

private void button1_Click(object sender, RoutedEventArgs e)
{
    InitializeCameras();
    timer = new DispatcherTimer();
    timer.Tick+=new EventHandler(ProcessFrame);
    timer.Interval = new TimeSpan(0, 0, 0, 0, 10);
    timer.Start();            
}

private void InitializeCameras()
    {
        if (capture == null)
        {
            try
            {
                capture = new Capture(0);
            }
            catch // etc 
        }
    }

private void ProcessFrame(object sender, EventArgs arg)
    {
        image = capture.QueryFrame();
        image1.Source = BitmapSourceConvert.ToBitmapSource(image);
    }
}

public static class BitmapSourceConvert
{
   [DllImport("gdi32")]
    private static extern int DeleteObject(IntPtr o);

    public static BitmapSource ToBitmapSource(IImage image)
    {
        using (System.Drawing.Bitmap source = image.Bitmap)
        {
            IntPtr ptr = source.GetHbitmap(); //obtain the Hbitmap

            BitmapSource bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                ptr,
                IntPtr.Zero,
                Int32Rect.Empty,
                System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());

            DeleteObject(ptr); //release the HBitmap
            return bs;
        }
    }
}

以下代码是我需要帮助的地方:

XAML(与之前相同)

<Window x:Class="EmguWPF_Test.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">

<Grid>
    <Image Height="215" HorizontalAlignment="Left" Margin="62,66,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="224"  />
</Grid>
</Window>

ViewModel Snippet(是的 - 可能过于雄心勃勃,无法尝试设计模式):

public ViewModel()
    {    
        CaptureMethods.InitializeCameras();
        timer = new DispatcherTimer();
        timer.Tick += new EventHandler(CaptureMethods.ProcessFrame);
        timer.Interval = new TimeSpan(0, 0, 0, 0, 10);
        timer.Start(); 
    }

CaptureMethods类,不按照我想要的方式作为单独的类工作。您会注意到我现在在此类中定义捕获字段,而不是在ViewModel类中定义:

class CaptureMethods
{
    private static Capture capture = null;

    public static void InitializeCameras()
    {
        if (capture == null)
        {
            try
            {
                capture = new Capture(0);
            }
            catch // etc 
        }
    }

public static void ProcessFrame(object sender, EventArgs arg)
    {
        image = capture.QueryFrame();
        image1.Source = BitmapSourceConvert.ToBitmapSource(image); // this is my problem line
    }
}

// BitmapSourceConvert class not repeated here to avoid duplication.

谢谢!

2 个答案:

答案 0 :(得分:2)

我的建议不是使用WPF Image Box,而是使用Emgu的ImageBox(Emgu.CV.UI.ImageBox)。它是一个更完整的控件,它旨在与框架一起使用。

唯一的问题是控件类型仅适用于Windows窗体,但您始终可以使用Emgu的Image Box创建WinForms用户控件,并在WindowsFormsHost中的WPF中使用它。

答案 1 :(得分:2)

要在celsoap7's answer上展开一点,这就是生成的XAML的样子:

<Window x:Class="WPFEmguCV.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:emui="clr-namespace:Emgu.CV.UI;assembly=Emgu.CV.UI"
        Title="MainWindow" Height="521" Width="1274">
    <Grid>
        <WindowsFormsHost>
            <emui:ImageBox x:Name="CapturedImageBox" Width="409" Height="353" />
        </WindowsFormsHost>
    </Grid>
</Window>

我(and others)发现将图像封送到UI线程会占用太多CPU,所以你最好不要像celsoap7 suggests那样把一个EmguCV ImageBox放在WPF中{ {1}}。

可悲的是,这可能会使你所要求的那种MVVM绑定与你想象的结构完全不同。