Captura de imágenes con cámara USB usando AForge en WPF

Para implementar la funcionalidad de captura de imágenes en una aplicación WPF, se puede emplear la biblioteca AForge.Video.DirectShow. Esta opción resulta adecuada para la adquisición directa desde dispositivos de video, a diferencia de otras librerías que se limitan a capturar contenido de pantalla.

El procedimiento requieer inocrporar las siguientes referencias en el proyecto:

  • DLLs de AForge.Controls y AForge.Video.DirectShow
  • System.Drawing
  • System.Windows.Forms
  • WindowsFormsIntegration

En el archivo de marcado XAML, es necesario definir los espacios de nombres para la integración con Windows Forms y los controles de AForge:

<Window x:Class="CameraApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wfi="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
        xmlns:aforge="clr-namespace:AForge.Controls;assembly=AForge.Controls"
        Title="Captura de Video" Height="600" Width="900">
    <Grid>
        <wfi:WindowsFormsHost Width="500" Height="350" HorizontalAlignment="Left" VerticalAlignment="Top">
            <aforge:VideoSourcePlayer x:Name="videoPreview" Width="640" Height="480"/>
        </wfi:WindowsFormsHost>
        <Button Content="Iniciar Cámara" HorizontalAlignment="Left" Margin="50,380,0,0" VerticalAlignment="Top" Width="120" Click="OnStartCamera"/>
        <Button Content="Capturar Imagen" HorizontalAlignment="Left" Margin="190,380,0,0" VerticalAlignment="Top" Width="120" Click="OnCaptureImage"/>
        <Button Content="Detener" HorizontalAlignment="Left" Margin="330,380,0,0" VerticalAlignment="Top" Width="120" Click="OnStopCamera"/>
        <Image x:Name="previewImage" HorizontalAlignment="Left" Margin="570,50,0,0" VerticalAlignment="Top" Width="250" Height="200"/>
    </Grid>
</Window>

La lógica de manejo de cámara se encapsula en una clase separada que gestiona el dipsositivo de video:

using AForge.Video.DirectShow;
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Media.Imaging;

namespace CameraApp
{
    public class CameraManager
    {
        private FilterInfoCollection _dispositivosVideo;
        private VideoCaptureDevice _fuenteVideo;
        
        public void DetectarDispositivos()
        {
            _dispositivosVideo = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            if (_dispositivosVideo.Count > 0)
            {
                Console.WriteLine($"Dispositivos encontrados: {_dispositivosVideo.Count}");
            }
        }
        
        public void ConectarCamara(VideoSourcePlayer reproductor, int indiceDispositivo = 0)
        {
            if (_dispositivosVideo == null || _dispositivosVideo.Count == 0)
            {
                throw new InvalidOperationException("No se detectaron cámaras disponibles");
            }
            
            _fuenteVideo = new VideoCaptureDevice(
                _dispositivosVideo[indiceDispositivo].MonikerString);
            reproductor.VideoSource = _fuenteVideo;
            _fuenteVideo.Start();
            reproductor.Start();
        }
        
        public string CapturarImagen(VideoSourcePlayer reproductor)
        {
            if (reproductor.VideoSource == null) return null;
            
            try
            {
                using (Image fotograma = reproductor.GetCurrentVideoFrame())
                {
                    string nombreArchivo = $"captura_{DateTime.Now:yyyyMMdd_HHmmss}.jpg";
                    fotograma.Save(nombreArchivo, ImageFormat.Jpeg);
                    return nombreArchivo;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error en captura: {ex.Message}");
                return null;
            }
        }
        
        public void Desconectar(VideoSourcePlayer reproductor)
        {
            if (_fuenteVideo != null && _fuenteVideo.IsRunning)
            {
                reproductor.Stop();
                _fuenteVideo.SignalToStop();
                _fuenteVideo.WaitForStop();
                _fuenteVideo = null;
            }
        }
        
        public BitmapImage ConvertirBitmap(string rutaArchivo)
        {
            using (var flujo = new MemoryStream(File.ReadAllBytes(rutaArchivo)))
            {
                var imagen = new BitmapImage();
                imagen.BeginInit();
                imagen.CacheOption = BitmapCacheOption.OnLoad;
                imagen.StreamSource = flujo;
                imagen.EndInit();
                imagen.Freeze();
                return imagen;
            }
        }
    }
}

El código de la ventana principal coordina la interacción del usuario con los controles y el administrador de cámara:

using System.Windows;
using System.Windows.Media.Imaging;

namespace CameraApp
{
    public partial class MainWindow : Window
    {
        private readonly CameraManager _gestorCamara = new CameraManager();
        
        public MainWindow()
        {
            InitializeComponent();
            _gestorCamara.DetectarDispositivos();
        }
        
        private void OnStartCamera(object sender, RoutedEventArgs e)
        {
            try
            {
                _gestorCamara.ConectarCamara(videoPreview);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        
        private void OnCaptureImage(object sender, RoutedEventArgs e)
        {
            string archivo = _gestorCamara.CapturarImagen(videoPreview);
            if (archivo != null)
            {
                BitmapImage imagenPreview = _gestorCamara.ConvertirBitmap(archivo);
                previewImage.Source = imagenPreview;
            }
        }
        
        private void OnStopCamera(object sender, RoutedEventArgs e)
        {
            _gestorCamara.Desconectar(videoPreview);
        }
        
        protected override void OnClosed(EventArgs e)
        {
            _gestorCamara.Desconectar(videoPreview);
            base.OnClosed(e);
        }
    }
}

Este enfoque utiliza flujos de memoria para evitar bloqueos de archivos y genera nombres únicos para cada captura. La integración con WPF se realiza mediante el control WindowsFormsHost que aloja el reproductor de video de AForge.

Etiquetas: AForge WPF USB Camera Video Capture Image Processing

Publicado el 6-18 18:14