2010-01-05 8 views
8

Estoy escribiendo una aplicación WPF en la que necesito mostrar una fuente de cámara web. Pude hacerlo fácilmente con el framework de AForge. Pero cuando cambié de una computadora a otra, el mismo código no funciona de la misma manera.Implementación de una WebCam en una aplicación WPF usando AForge.Net

En la primera, la alimentación de la cámara web funciona perfectamente, pero en la otra no ocurre, la alimentación tiene un gran retraso y la aplicación no funciona correctamente.

Aquí está el código:

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

    } 

Lo que este código es muy simple, se pone un new_frame de la cámara web en una forma de Bitmap, y lo que tengo que hacer es convertirlo en un BitmapSource , entonces puedo mostrar en el marco de la imagen del WPF. Creo que esta conversión es la responsable del desastre que está sucediendo, pero no entiendo por qué funciona en una computadora y en la otra no.

Las especificaciones de la computadora son casi las mismas, el procesador es el mismo, así como la memoria del sistema.

Mi problema aquí es acerca de rendimiento, este código en una computadora funciona sin problemas, y la alimentación de la cámara web se presenta como debería, cuando la transfiero a otra PC esto no sucede.

+0

Amigo, sin decirnos cuál es el error (incluidas las InnerExceptions y las pilas de llamadas) casi no hay posibilidad de que alguien te ayude. – Will

+0

No hay ningún error, mi problema aquí es sobre el rendimiento, este código en una computadora funciona sin problemas, y la alimentación de la cámara web se presenta como debería, cuando la transfiero a otra PC esto no sucede, la alimentación de la cámara web tiene un horrible demora y, por ejemplo, el botón Cerrar ventana no funciona. –

+0

Tienes un nuevo hombre de respuesta. Mira, por favor. –

Respuesta

2

En mi WPF MediaKit, tengo un control llamado VideoCaptureElement que renderizará una cámara web para WPF. También puede obtener acceso a las muestras enganchando en el nuevo evento de imagen y configurando EnableSampleGrabbing en el elemento.

+3

WPF MediaKit es un proyecto muerto ahora. –

-1

¿Quizás la cámara web de la otra computadora está rota/es defectuosa? O tiene una de las cámaras web que no admite la API DirectShow, que creo que se basa en AForge.

+0

Ya escribí un programa que usa Windows Forms en el que uso la API de Forgege y funciona bien. Creo que el problema aquí es en la conversión de Bitmap a BitmapSource que debe hacerse, para mostrar la imagen tomada por la cámara web. –

+0

Haga sus preguntas en comentarios por favor. –

18

Aquí está el código de trabajo basado en el artículo this.

(1) Download and install last AForge framework. (He utilizado la versión 2.2.4)

(2) Crear proyecto de aplicación WPF.

(3) Agregue referencias a esas DLL de AForge. (Se pueden encontrar en C: \ Archivos de programa (x86) \ AForge.NET \ Framework \ Release carpeta es decir)

enter image description here

(4) Construir su proyecto. (He utilizado VS 2012)

(5) Agregue el control de imagen WPF y asígnele el nombre "frameHolder".

Así que hay algo así como

<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) Añadir el código 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) Proyecto Reformado y ¡funciona!

Nota: Usamos la primera WebCam detectada de forma predeterminada. Asegúrese de tener el controlador WebCam insalled y de que WebCam funciona en general ... :)

+4

También agregue 'LocalWebCam.Stop();' en evento descargado si tiene la intención de usar esto como UserControl varias veces en su aplicación WPF. Puede haber problemas al volver a crear el control sin detener primero la cámara. De todos modos, esta solución me dio problemas durante 20 minutos hasta que noté que olvidé poner 'LocalWebCam.Start();' al final del evento Loaded :) Sí, sucede. –

2

Sé que la publicación original tiene más de 3 años, pero solo he estado tratando de descubrir cómo usar este código. Descubrí que la respuesta dada por Dimi es casi un código completamente funcional. Sin embargo, descubrí que tengo problemas con la pérdida de memoria y que el marco no se muestra de manera confiable en algunas computadoras. El código funcionó perfectamente en mi computadora de desarrollo más sólida (i7, 16 GB de RAM, tarjeta Quadro Pro Grapthics), pero cuando implementé la aplicación en una computadora con recursos más limitados (i5, 4 GB de RAM, gráficos Intel integrados), el marco desaparece una vez un tiempo y el programa también se bloqueará después de que se agote la memoria del sistema. Después de buscar en Internet por un tiempo, creo que finalmente repasé un código de trabajo basado en todos los comentarios que la gente tenía. Sé que la otra computadora es capaz de ejecutar la captura de marcos desde la cámara web porque tengo una aplicación WinForm C# que escribí usando AForge.NET y no tiene problemas para renderizar la imagen de manera confiable y sin pérdida de memoria. Lamentablemente, WPF no maneja los gráficos de la misma manera que WinForm y tenemos que hacer este truco para que AForge.NET trabaje con él.

Básicamente, el código es el mismo que el de Dimi, excepto el método 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 
     } 

    } 

Los cambios que se hicieron son los siguientes:

  1. Encerrando el mapa de bits de manipulación con Uso de alcance a fin de que cualquier memoria no utilizada se limpia inmediatamente después del final de alcance.
  2. Mover el bi.BeginInit() antes de tratar con la secuencia de memoria para que el mapa de bits esté listo para el volcado de memomory de inmediato.
  3. Cambiando CacheOption a OnLoad para que toda la memoria de imágenes se descargue en la carga. De lo contrario, utiliza BitmapCacheOption.Default, que podría permitir que la imagen se mantenga en la memoria incluso cuando se emite bi.Freeze(). Esto causó que el marco no se renderizara incluso con el Dispatcher.BeginInvoke es invocado para renderizar la imagen.

Hasta ahora ha funcionado bien, pero si alguien más detecta otros problemas, por favor haga un comentario para que sepamos cómo solucionarlo.

+0

Hay un pequeño error en el código. Si inicia su aplicación, la imagen no se muestra. Podría resolverse agregando 'ms.Seek (0, SeekOrigin.Begin);' después de 'bitmap.Save (ms, ImageFormat.Bmp);' como lo hizo Dmitry. – daniel59

Cuestiones relacionadas