使用AForge.Net在WPF应用程序上实现WebCam

问题描述 投票:9回答:4

我正在写一个WPF应用程序,我需要显示一个Webcam feed。我能够使用AForge框架轻松完成这项工作。但是当我从计算机更改为另一台计算机时,相同的代码不能以相同的方式工作。

在第一个网络摄像头提供工作完美,但在另一个,这不会发生,饲料有很多延迟,应用程序无法正常工作。

这是代码:

    private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
    {
        Bitmap img = (Bitmap)eventArgs.Frame.Clone();

        this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, (SendOrPostCallback)delegate
            {
                IntPtr hBitmap = img.GetHbitmap();
                System.Windows.Media.Imaging.BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    hBitmap,
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());

                DeleteObject(hBitmap);

                img.Dispose();
                GC.Collect();
                image1.Source = bitmapSource;

            }, null);

    }

这段代码非常简单,它以Bitmap的形式从网络摄像头获取一个new_frame,我需要做的是将它转换为BitmapSource,所以我可以在WPF的图像框架中显示。我认为这种转换是造成这种混乱的原因,但我不明白为什么它在计算机中起作用而在另一种情况下却不起作用。

计算机规格几乎相同,处理器是相同的,以及系统内存。

我的问题是关于性能,这个代码在一台计算机上运行顺畅,网络摄像头提供应该呈现,当我将它移植到另一台PC时,这不会发生。

wpf webcam aforge
4个回答
19
投票

这是基于this文章的工作代码。

(1)Download and install last AForge framework。 (我使用的是2.2.4版本)

(2)创建WPF应用程序项目。

(3)添加对那些AForge DLL的引用。 (您可以在C:\ Program Files(x86)\ AForge.NET \ Framework \ Release文件夹下找到它们,即)

(4)建立你的项目。 (我用过VS 2012)

(5)添加WPF Image控件并将其命名为“frameHolder”。

所以你有类似的东西

<Window x:Class="WpfApplication1.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 HorizontalAlignment="Stretch" Name="frameHolder"  VerticalAlignment="Stretch"  Stretch="Fill"/>
    </Grid>
</Window>

(6)添加C#代码:

using AForge.Video;
    using AForge.Video.DirectShow;
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading;
    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;

/////

namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            VideoCaptureDevice LocalWebCam;
            public FilterInfoCollection LoaclWebCamsCollection; 

        void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            try
            {
                System.Drawing.Image img = (Bitmap)eventArgs.Frame.Clone();

                MemoryStream ms = new MemoryStream();
                img.Save(ms, ImageFormat.Bmp);
                ms.Seek(0, SeekOrigin.Begin);
                BitmapImage bi = new BitmapImage();
                bi.BeginInit();
                bi.StreamSource = ms;
                bi.EndInit();

                bi.Freeze();
                Dispatcher.BeginInvoke(new ThreadStart(delegate
                {
                    frameHolder.Source = bi;
                }));
            }
            catch (Exception ex)
            {
            }
        } 

        public MainWindow()
        {
            InitializeComponent();
            Loaded += MainWindow_Loaded;
        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            LoaclWebCamsCollection = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            LocalWebCam = new VideoCaptureDevice(LoaclWebCamsCollection[0].MonikerString);
            LocalWebCam.NewFrame += new NewFrameEventHandler(Cam_NewFrame);

            LocalWebCam.Start();
        }
    }
}

(7)重建项目,它的工作原理!

注意:我们默认使用第一个检测到的WebCam。确保你安装了WebCam驱动程序并且WebCam正常工作...... :)


2
投票

在我的WPF MediaKit中,我有一个名为VideoCaptureElement的控件,它将向WPF呈现网络摄像头。您还可以通过挂钩到新图像事件并在元素上设置EnableSampleGrabbing来访问示例。


2
投票

我知道原帖已超过3年了,但我一直在试图弄清楚如何使用这段代码。我发现Dimi给出的答案几乎是一个功能齐全的代码。但是,我发现存在内存泄漏问题,而且某些计算机上的帧无法可靠地呈现。该代码在我更强大的开发计算机(i7,16GB RAM,Quadro Pro Grapthics卡)上运行得非常完美,但是当我在具有更多资源(i5,4GB RAM,集成Intel图形)的计算机上部署应用程序时,框架就会消失一次一段时间后,程序也会在系统内存耗尽后崩溃。在网上搜索了一段时间之后,我想我最终根据人们的反馈拼凑了一份工作代码。我知道另一台计算机能够从网络摄像头运行帧捕获,因为我有一个使用AForge.NET编写的WinForm C#应用程序,并且没有问题可靠地渲染帧并且没有内存泄漏。不幸的是,WPF不像WinForm那样处理图形,我们必须这样做才能让AForge.NET使用它。

基本上,除了Cam_NewFrame方法之外,代码与Dimi相同。

void Cam_NewFrame(object sender, NewFrameEventArgs eventArgs)
    {
        try
        {
            BitmapImage bi;
            using(var bitmap = (Bitmap)eventArgs.Frame.Clone())
            {
                bi = new BitmapImage();
                bi.BeginInit();
                MemoryStream ms = new MemoryStream();
                bitmap.Save(ms, ImageFormat.Bmp);
                bi.StreamSource = ms;
                bi.CacheOption = BitmapCacheOption.OnLoad;
                bi.EndInit();
            }
            bi.Freeze();
            Dispatcher.BeginInvoke(new ThreadStart(delegate { frameHolder.Source = bi; }));


        }
        catch (Exception ex)
        {
            //catch your error here
        }

    } 

所做的更改如下:

  1. 使用范围封闭位图处理,以便在范围结束后立即清除任何未使用的内存。
  2. 在处理内存流之前移动bi.BeginInit(),以便立即为memomory转储做好准备。
  3. 将CacheOption更改为OnLoad,以便所有图像内存在加载时立即转储。否则,它使用BitmapCacheOption.Default,即使发出bi.Freeze(),也可以让图像保留在内存中。这导致即使使用Dispatcher.BeginInvoke渲染图像也不会渲染帧。

到目前为止,它一直运作良好,但如果其他人发现其他问题,请发表评论,以便我们知道如何解决它。


-1
投票

也许另一台计算机上的网络摄像头坏了/有故障?或者有一个不支持DirectShow api的网络摄像头,我认为AForge建立在其上。

© www.soinside.com 2019 - 2024. All rights reserved.