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

时间:2010-01-05 12:47:48

标签: wpf webcam aforge

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

在第一个网络摄像头Feed中,网络摄像头输入效果很好,但在另一个网络摄像头输入中,这种情况不会发生,导致延迟很多,并且应用程序无法正常工作。

以下是代码:

    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时,这种情况不会发生。

4 个答案:

答案 0 :(得分: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文件夹下找到它们。)

enter image description here

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

(5)添加WPF图像控件并将其命名为“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正常工作......:)

答案 1 :(得分:2)

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

答案 2 :(得分: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渲染图像也不会渲染帧。
  4. 到目前为止,它一直运作良好,但如果其他人发现其他问题,请发表评论,以便我们知道如何解决它。

答案 3 :(得分:-1)

也许其他电脑上的网络摄像头坏了/有故障?或者有一个不支持DirectShow api的网络摄像头,我认为AForge是基于它的。