11

我正在编写一个 WPF 应用程序,我需要在其中显示网络摄像头提要。我可以使用 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);

    }

这段代码真的很简单,它以 a 的形式从网络摄像头获取一个 new_frame,Bitmap我需要做的就是将其转换为 a BitmapSource,这样我就可以在 WPF 的图像帧中显示。我认为这种转换是正在发生的混乱的原因,但我不明白为什么它在计算机中有效而在其他计算机中无效。

计算机规格几乎相同,处理器相同,系统内存也相同。

我的问题是关于性能的,一台计算机中的这段代码运行流畅,并且网络摄像头的提要按原样呈现,当我将它移植到另一台 PC 时,这不会发生。

4

4 回答 4

22

这是基于本文的工作代码

(1)下载并安装最后一个 AForge 框架。(我用的是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)重新构建项目,它的工作原理!

注意:我们默认使用第一个检测到的网络摄像头。确保您已安装网络摄像头驱动程序并且网络摄像头正常工作...... :)

于 2013-02-08T18:39:57.333 回答
6

我知道原始帖子已经超过 3 年了,但我一直在试图弄清楚如何使用这段代码。我发现Dimi给出的答案几乎是一个功能齐全的代码。但是,我发现在某些计算机上存在内存泄漏和帧无法可靠渲染的问题。该代码在我更强大的开发计算机(i7、16GB RAM、Quadro Pro Graphhics 卡)上运行良好,但是当我将应用程序部署在资源更有限的计算机(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() 以便位图立即为内存转储做好准备。
  3. 将 CacheOption 更改为 OnLoad,以便所有图像内存在加载时立即转储。否则,它使用 BitmapCacheOption.Default ,即使在发出 bi.Freeze() 时,它也可以允许图像保留在内存中。这导致即使调用 Dispatcher.BeginInvoke 来渲染图像,也无法渲染帧。

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

于 2017-01-27T14:10:46.980 回答
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.

于 2010-01-05T16:40:03.190 回答
-1

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

于 2010-01-09T18:29:27.747 回答