0

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

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

如果我可以将图像框动态绑定到静态方法中的属性(并以编程方式启用/禁用该绑定),我认为这将解决我的问题。但是,我尝试采用的方法可能存在其他问题。非常感谢任何代码/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 代码片段(工作):

//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.

谢谢!

4

2 回答 2

2

在这里扩展一下celsoap7 的答案是生成的 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>

我(和其他人)发现将图像编组到 UI 线程上会占用过多的 CPU,因此最好按照celsoap7 的建议将 EmguCVImageBox放入 WPFWindowsFormsHost中。

可悲的是,这可能会使您询问的那种 MVVM 绑定与您设想的结构完全不同。

于 2013-10-12T15:33:59.197 回答
2

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

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

于 2013-04-30T10:20:43.770 回答