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

时间:2022-10-01 15:59:29

I'm writing an WPF application where I need to show a Webcam feed. I was able to do this easly with the AForge framework.But when I've changed from a computer to a another computer the same code doesn't work the same way.

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

In the first one the webcam feed works perfectly, but in the other one this does't occur, the feed has a lot of delay, and the application doesn't work properly.

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

Here is the code:

这是代码:

    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);

    }

What this code is really simple, it gets a new_frame from the webcam in a form of a Bitmap, and what I need to do is to convert it to a BitmapSource, so I can show in the image frame of the WPF. I think this conversion is the responsible of the mess that is happening, but I don't understand why it works in a computer and in the other doesn't.

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

The computer specs are almost the same, the processor is the same, as well the system memory.

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

My problem here is about performance, this code in one computer runs smoothly, and the webcam feed is presented as it should, when I port it to another PC this doesn't happen.

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

4 个解决方案

#1


18  

Here is working code based on this article.

这是基于本文的工作代码。

(1) Download and install last AForge framework. (I have used version 2.2.4)

(1)下载并安装最后一个AForge框架。 (我使用的是2.2.4版本)

(2) Create WPF Application project.

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

(3) Add references to those AForge DLLs. (You can find them under C:\Program Files (x86)\AForge.NET\Framework\Release folder i.e.)

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

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

(4) Build your project. (I have used VS 2012)

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

(5) Add WPF Image control and name it "frameHolder".

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

So you have something like

所以你有类似的东西

<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) Add C# code:

(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) Re-Build project and it works!

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

Note: We use first detected WebCam by default. Make sure you have WebCam driver insalled and WebCam is working in general... :)

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

#2


2  

In my WPF MediaKit, I have a control called VideoCaptureElement that will render a webcam to WPF. You can also get access to the samples by hooking into the new image event and setting the EnableSampleGrabbing on the element.

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

#3


2  

I know the original post is over 3 years old, but I just have been trying to figure out how to use this code. I found that the answer given by Dimi is nearly a fully functional code. However, I found that I have issues with memory leaking and the frame not being render reliably on some computers. The code worked perfectly on my beefier development computer (i7, 16GB RAM, Quadro Pro Grapthics card), but when I deployed the app on a computer with more limited resources (i5, 4GB RAM, Integrated Intel graphics), the frame disappears once in a while and the program would also crash after the system memory runs out. After searching the internet for a while, I think I finally patched together a working code based on all the feedback people had. I know that the other computer is capable of running frame capture from the webcam because I have a WinForm C# app that I wrote using AForge.NET and it has no issues rendering the frame reliably and with no memory leak. Unfortunately WPF doesn't handle graphics the same way as WinForm and we have to do this hack to get AForge.NET to work with it.

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

Basically, the code is the same as Dimi's except for the Cam_NewFrame method.

基本上,除了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
        }

    } 

The changes that were made are the following:

所做的更改如下:

  1. Enclosing the bitmap handling with Using scope so that any unused memory is cleaned up right away after the end of scope.
  2. 使用范围封闭位图处理,以便在范围结束后立即清除任何未使用的内存。
  3. Moving the bi.BeginInit() before dealing with the memory stream so that the bitmap is ready for the memomory dump right away.
  4. 在处理内存流之前移动bi.BeginInit(),以便位图立即为memomory转储做好准备。
  5. Changing the CacheOption to OnLoad so that all the image memory gets dump right at the loading. Otherwise, it uses BitmapCacheOption.Default which could allow the image to hold on to the memory even when bi.Freeze() is issued. This caused the frame to not be rendered even with the Dispatcher.BeginInvoke is called to render the image.
  6. 将CacheOption更改为OnLoad,以便所有图像内存在加载时立即转储。否则,它使用BitmapCacheOption.Default,即使发出bi.Freeze(),也可以让图像保留在内存中。这导致即使使用Dispatcher.BeginInvoke渲染图像也不会渲染帧。

So far it's been working well but if anyone else spot other issues please make a comment so we know how to fix it.

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

#4


-1  

Maybe the webcam on the other computer is broken/faulty? Or has one of the webcams that doesnt support the DirectShow api, which i think AForge builds on.

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

#1


18  

Here is working code based on this article.

这是基于本文的工作代码。

(1) Download and install last AForge framework. (I have used version 2.2.4)

(1)下载并安装最后一个AForge框架。 (我使用的是2.2.4版本)

(2) Create WPF Application project.

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

(3) Add references to those AForge DLLs. (You can find them under C:\Program Files (x86)\AForge.NET\Framework\Release folder i.e.)

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

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

(4) Build your project. (I have used VS 2012)

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

(5) Add WPF Image control and name it "frameHolder".

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

So you have something like

所以你有类似的东西

<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) Add C# code:

(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) Re-Build project and it works!

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

Note: We use first detected WebCam by default. Make sure you have WebCam driver insalled and WebCam is working in general... :)

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

#2


2  

In my WPF MediaKit, I have a control called VideoCaptureElement that will render a webcam to WPF. You can also get access to the samples by hooking into the new image event and setting the EnableSampleGrabbing on the element.

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

#3


2  

I know the original post is over 3 years old, but I just have been trying to figure out how to use this code. I found that the answer given by Dimi is nearly a fully functional code. However, I found that I have issues with memory leaking and the frame not being render reliably on some computers. The code worked perfectly on my beefier development computer (i7, 16GB RAM, Quadro Pro Grapthics card), but when I deployed the app on a computer with more limited resources (i5, 4GB RAM, Integrated Intel graphics), the frame disappears once in a while and the program would also crash after the system memory runs out. After searching the internet for a while, I think I finally patched together a working code based on all the feedback people had. I know that the other computer is capable of running frame capture from the webcam because I have a WinForm C# app that I wrote using AForge.NET and it has no issues rendering the frame reliably and with no memory leak. Unfortunately WPF doesn't handle graphics the same way as WinForm and we have to do this hack to get AForge.NET to work with it.

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

Basically, the code is the same as Dimi's except for the Cam_NewFrame method.

基本上,除了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
        }

    } 

The changes that were made are the following:

所做的更改如下:

  1. Enclosing the bitmap handling with Using scope so that any unused memory is cleaned up right away after the end of scope.
  2. 使用范围封闭位图处理,以便在范围结束后立即清除任何未使用的内存。
  3. Moving the bi.BeginInit() before dealing with the memory stream so that the bitmap is ready for the memomory dump right away.
  4. 在处理内存流之前移动bi.BeginInit(),以便位图立即为memomory转储做好准备。
  5. Changing the CacheOption to OnLoad so that all the image memory gets dump right at the loading. Otherwise, it uses BitmapCacheOption.Default which could allow the image to hold on to the memory even when bi.Freeze() is issued. This caused the frame to not be rendered even with the Dispatcher.BeginInvoke is called to render the image.
  6. 将CacheOption更改为OnLoad,以便所有图像内存在加载时立即转储。否则,它使用BitmapCacheOption.Default,即使发出bi.Freeze(),也可以让图像保留在内存中。这导致即使使用Dispatcher.BeginInvoke渲染图像也不会渲染帧。

So far it's been working well but if anyone else spot other issues please make a comment so we know how to fix it.

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

#4


-1  

Maybe the webcam on the other computer is broken/faulty? Or has one of the webcams that doesnt support the DirectShow api, which i think AForge builds on.

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