2010-01-05 37 views
8

Tôi đang viết một ứng dụng WPF nơi tôi cần hiển thị nguồn cấp dữ liệu Webcam. Tôi đã có thể làm điều này một cách dễ dàng với khuôn khổ AForge.Nhưng khi tôi đã thay đổi từ một máy tính sang một máy tính khác, cùng một mã không hoạt động theo cùng một cách.Triển khai WebCam trên ứng dụng WPF bằng AForge.Net

Trong lần đầu tiên, nguồn cấp dữ liệu webcam hoạt động hoàn hảo, nhưng trong trường hợp khác, điều này không xảy ra, nguồn cấp dữ liệu có nhiều sự chậm trễ và ứng dụng không hoạt động đúng cách.

Đây là mã:

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

    } 

gì mã này là thực sự đơn giản, nó được một new_frame từ webcam trong một hình thức của một Bitmap, và những gì tôi cần làm là để chuyển đổi nó vào một BitmapSource , vì vậy tôi có thể hiển thị trong khung hình của WPF. Tôi nghĩ sự chuyển đổi này là trách nhiệm của sự lộn xộn đang xảy ra, nhưng tôi không hiểu tại sao nó lại hoạt động trong máy tính và cái kia thì không.

Thông số kỹ thuật máy tính gần như giống nhau, bộ xử lý giống nhau, cũng như bộ nhớ hệ thống.

Vấn đề của tôi ở đây là khoảng hiệu suất, mã này trong một máy tính chạy trơn tru và nguồn cấp dữ liệu webcam được trình bày như khi cần, khi tôi chuyển sang máy tính khác, điều này không xảy ra.

+0

Dude, không cho chúng tôi biết lỗi là gì (bao gồm bất kỳ InnerExceptions và ngăn xếp cuộc gọi nào) hầu như không có ai có thể giúp bạn. – Will

+0

Không có lỗi, vấn đề của tôi ở đây là về hiệu suất, mã này trong một máy tính chạy trơn tru, và nguồn cấp dữ liệu webcam được trình bày như nó cần, khi tôi chuyển nó sang máy tính khác, điều này không xảy ra. sự chậm trễ, và ví dụ nút đóng cửa sổ không hoạt động. –

+0

Bạn đã có một người trả lời mới. Vui lòng xem. –

Trả lời

2

Trong số WPF MediaKit của tôi, tôi có một điều khiển gọi là VideoCaptureElement sẽ hiển thị webcam cho WPF. Bạn cũng có thể truy cập vào các mẫu bằng cách gắn vào sự kiện hình ảnh mới và thiết lập EnableSampleGrabbing trên phần tử.

+3

WPF MediaKit bây giờ là một dự án đã chết. –

-1

Có thể webcam trên máy tính khác bị hỏng/lỗi? Hoặc có một trong những webcam không hỗ trợ api DirectShow, mà tôi nghĩ rằng AForge được xây dựng trên đó.

+0

Tôi đã viết một chương trình bằng Windows Forms, trong đó tôi sử dụng API Aforge và nó hoạt động tốt. Tôi nghĩ rằng vấn đề ở đây là trong việc chuyển đổi Bitmap thành BitmapSource mà cần phải được thực hiện, để hiển thị hình ảnh được chụp bởi webcam. –

+0

Hãy đặt câu hỏi của bạn trong phần bình luận. –

18

Đây là mã hoạt động dựa trên this bài viết.

(1) Download and install last AForge framework. (Tôi đã sử dụng phiên bản 2.2.4)

(2) Tạo dự án Ứng dụng WPF.

(3) Thêm tham chiếu đến các DLL AForge đó. (Bạn có thể tìm thấy chúng trong C: \ Program Files (x86) \ AForge.NET \ Framework \ phát hành thư mục ví dụ)

enter image description here

(4) Xây dựng dự án của bạn. (Tôi đã sử dụng VS 2012)

(5) Thêm điều khiển hình ảnh WPF và đặt tên là "frameHolder".

Vì vậy, bạn có một cái gì đó giống như

<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) Thêm mã 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) Dự án Re-Xây dựng và nó hoạt động!

Lưu ý: Chúng tôi sử dụng WebCam được phát hiện đầu tiên theo mặc định. Đảm bảo rằng bạn có trình điều khiển WebCam bị mất tích và WebCam đang hoạt động nói chung ... :)

+4

Cũng thêm 'LocalWebCam.Stop();' vào sự kiện Unloaded nếu bạn dự định sử dụng điều này như UserControl nhiều lần trong ứng dụng WPF của bạn. Có thể có vấn đề khi tạo điều khiển một lần nữa mà không dừng máy ảnh trước. Dù sao, giải pháp này đã cho tôi gặp rắc rối trong 20 phút cho đến khi tôi nhận thấy tôi quên đặt 'LocalWebCam.Start();' ở phần cuối của sự kiện được tải :) Vâng, điều đó xảy ra. –

2

Tôi biết bài đăng gốc đã hơn 3 tuổi nhưng tôi đã cố gắng tìm hiểu cách sử dụng mã này. Tôi thấy rằng câu trả lời được đưa ra bởi Dimi gần như là một mã đầy đủ chức năng. Tuy nhiên, tôi thấy rằng tôi có vấn đề với rò rỉ bộ nhớ và khung không được hiển thị đáng tin cậy trên một số máy tính. Mã hoạt động hoàn hảo trên máy tính phát triển của tôi (i7, RAM 16GB, thẻ Quadro Pro Grapthics), nhưng khi tôi triển khai ứng dụng trên máy tính có nhiều tài nguyên giới hạn hơn (i5, RAM 4GB, đồ họa Intel tích hợp), khung biến mất một lần một thời gian và chương trình cũng sẽ sụp đổ sau khi bộ nhớ hệ thống hết. Sau khi tìm kiếm trên Internet trong một thời gian, tôi nghĩ cuối cùng tôi đã vá một mã làm việc dựa trên tất cả những phản hồi mà mọi người có. Tôi biết rằng các máy tính khác có khả năng chạy chụp khung hình từ webcam bởi vì tôi có một ứng dụng WinForm C# mà tôi đã viết bằng cách sử dụng AForge.NET và nó không có vấn đề dựng khung hình một cách đáng tin cậy và không bị rò rỉ bộ nhớ. Thật không may WPF không xử lý đồ họa theo cùng một cách như WinForm và chúng tôi phải làm điều này hack để có được AForge.NET để làm việc với nó.

Về cơ bản, mã này giống với mã của Dimi ngoại trừ phương pháp Cam_NewFrame.

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 
     } 

    } 

Những thay đổi đã được thực hiện như sau:

  1. Đưa các bitmap xử lý với sử dụng phạm vi để cho bất kỳ bộ nhớ không sử dụng được làm sạch lên ngay lập tức sau khi kết thúc phạm vi.
  2. Di chuyển bi.BeginInit() trước khi xử lý luồng bộ nhớ để bitmap sẵn sàng cho bản ghi nhớ ngay lập tức.
  3. Thay đổi CacheOption thành OnLoad để tất cả bộ nhớ hình ảnh được đổ ngay tại tải. Nếu không, nó sử dụng BitmapCacheOption.Default có thể cho phép hình ảnh giữ trên bộ nhớ ngay cả khi bi.Freeze() được phát hành. Điều này khiến khung không được hiển thị ngay cả với Dispatcher.BeginInvoke được gọi để hiển thị hình ảnh.

Cho đến giờ nó vẫn hoạt động tốt nhưng nếu có ai khác phát hiện sự cố khác, vui lòng đưa ra nhận xét để chúng tôi biết cách khắc phục.

+0

Có một lỗi nhỏ trong mã. Nếu bạn khởi động ứng dụng của bạn, hình ảnh sẽ không được hiển thị. Nó có thể được giải quyết bằng cách thêm 'ms.Seek (0, SeekOrigin.Begin);' sau 'bitmap.Save (ms, ImageFormat.Bmp);' như Dmitry đã làm. – daniel59

Các vấn đề liên quan