2015-03-05 2 views
0

Я работаю в VS 2012, мой проект является # WPF приложения C с .NetFramework 4,0Получить текущий кадр с веб-камеры - DirectShowLib

Моя цель - Нужно показать живой веб-камера в пользовательский элемент управления и обработки тока (как растровое изображение) на каждые 2 секунды.

Что я достиг - Я могу инициализировать веб-камеру и передавать потоковое видео в DirectShowLib. Я использовал пример this.

Что мне нужно - Я не могу получить рамку (как растровое изображение). Есть ли какие-либо методы по умолчанию для получения текущего кадра в DirectShow? Нужна ли какая-либо реализация в моем User Control (WebCamControl2, как указано в примере). Есть ли какой-нибудь пример для моей потребности?

Спасибо.

Update:

Вот код, я использую:

using System; 
using System.Diagnostics; 
using System.Drawing; 
using System.Runtime.InteropServices; 
using System.Windows.Forms; 
using DirectShowLib; 
using System.Runtime.InteropServices.ComTypes; 

namespace WebCamControl2 
{ 
    [Guid("43878F19-1E0E-42d2-B72B-88A94418A302"), 
    ComVisible(true)] 
    public partial class WebCamControl2 : UserControl 
    { 
     public enum PlayState : int 
     { 
      Stopped, 
      Paused, 
      Running, 
      Init 
     }  

     private PlayState CurrentState = PlayState.Stopped; 
     private int WM_GRAPHNOTIFY = Convert.ToInt32("0X8000", 16) + 1; 
     private IVideoWindow videoWindow = null; 
     private IMediaControl mediaControl = null; 
     private IMediaEventEx mediaEventEx = null; 
     private IGraphBuilder graphBuilder = null; 
     private ICaptureGraphBuilder2 captureGraphBuilder = null; 

     public WebCamControl2() 
     { 
      InitializeComponent();   
     } 

     private void WebCamControl_Load(object sender, System.EventArgs e) 
     { 
      this.Resize += new System.EventHandler(WebCamControl_Resize);    
      CaptureVideo(); 
     } 

     private void InitializeComponent() 
     { 
      components = new System.ComponentModel.Container(); 
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
      System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(WebCamControl2)); 

      this.Load += new System.EventHandler(WebCamControl_Load); 
     } 

     private void CaptureVideo() 
     { 
      int hr = 0; 
      IBaseFilter sourceFilter = null; 
      try 
      { 
       // create the necessary DirectShow interfaces 
       GetInterfaces(); 

       hr = this.captureGraphBuilder.SetFiltergraph(this.graphBuilder); 
       DsError.ThrowExceptionForHR(hr); 

       sourceFilter = FindCaptureDevice(); 

       hr = this.graphBuilder.AddFilter(sourceFilter, "WebCamControl Video"); 
       DsError.ThrowExceptionForHR(hr); 

       hr = this.captureGraphBuilder.RenderStream(PinCategory.Preview, MediaType.Video, sourceFilter, null, null); 
       Debug.WriteLine(DsError.GetErrorText(hr)); 
       DsError.ThrowExceptionForHR(hr); 

       Marshal.ReleaseComObject(sourceFilter); 

       SetupVideoWindow(); 

       hr = this.mediaControl.Run(); 
       DsError.ThrowExceptionForHR(hr); 

       this.CurrentState = PlayState.Running; 
      } 
      catch (Exception ex) 
      { 
       MessageBox.Show("An unrecoverable error has occurred.\r\n" + ex.ToString()); 
      } 
     } 

     private void GetInterfaces() 
     { 
      this.graphBuilder = (IGraphBuilder)(new FilterGraph()); 
      this.captureGraphBuilder = (ICaptureGraphBuilder2)(new CaptureGraphBuilder2()); 
      this.mediaControl = (IMediaControl)this.graphBuilder; 
      this.videoWindow = (IVideoWindow)this.graphBuilder; 
      this.mediaEventEx = (IMediaEventEx)this.graphBuilder; 

      // send notification messages to the control window 
      int hr = this.mediaEventEx.SetNotifyWindow(this.Handle, WM_GRAPHNOTIFY, IntPtr.Zero); 

      DsError.ThrowExceptionForHR(hr); 
     } 

     private IBaseFilter FindCaptureDevice() 
     { 
      UCOMIEnumMoniker classEnum = null; 
      UCOMIMoniker[] moniker = new UCOMIMoniker[1]; 
      object source = null; 

      ICreateDevEnum devEnum = (ICreateDevEnum)(new CreateDevEnum()); 
      int hr = devEnum.CreateClassEnumerator(FilterCategory.VideoInputDevice, out classEnum, CDef.None); 
      DsError.ThrowExceptionForHR(hr); 
      Marshal.ReleaseComObject(devEnum); 

      if (classEnum == null) 
      { 
       throw new ApplicationException("No video capture device was detected.\\r\\n\\r\\n" + "This sample requires a video capture device, such as a USB WebCam,\\r\\nto be installed and working properly. The sample will now close."); 
      } 

      int none = 0; 

      if (classEnum.Next(moniker.Length, moniker, out none) == 0) 
      { 
       Guid iid = typeof(IBaseFilter).GUID; 
       moniker[0].BindToObject(null, null, ref iid, out source); 
      } 
      else 
      { 
       throw new ApplicationException("Unable to access video capture device!"); 
      } 

      Marshal.ReleaseComObject(moniker[0]); 
      Marshal.ReleaseComObject(classEnum); 

      return (IBaseFilter)source; 
     } 

     private void SetupVideoWindow() 
     { 
      int hr = 0; 

      //set the video window to be a child of the main window 
      //putowner : Sets the owning parent window for the video playback window. 
      hr = this.videoWindow.put_Owner(this.Handle); 
      DsError.ThrowExceptionForHR(hr); 


      hr = this.videoWindow.put_WindowStyle(WindowStyle.Child | WindowStyle.ClipChildren); 
      DsError.ThrowExceptionForHR(hr); 

      //Use helper function to position video window in client rect of main application window 
      WebCamControl_Resize(this, null); 



      //Make the video window visible, now that it is properly positioned 
      //put_visible : This method changes the visibility of the video window. 
      hr = this.videoWindow.put_Visible(OABool.True); 
      DsError.ThrowExceptionForHR(hr); 
     } 

     //protected override void WndProc(ref Message m) 
     //{ 
     // if (m.Msg == WM_GRAPHNOTIFY) 
     // { 
     //  HandleGraphEvent(); 
     // } 
     // if (this.videoWindow != null) 
     // { 
     //  this.videoWindow.NotifyOwnerMessage(m.HWnd, m.Msg, m.WParam.ToInt32(), m.LParam.ToInt32()); 
     // } 
     // base.WndProc(ref m); 
     //}   

     private void HandleGraphEvent() 
     { 
      int hr = 0; 
      EventCode evCode = 0; 
      int evParam1 = 0; 
      int evParam2 = 0; 

      while (this.mediaEventEx != null && this.mediaEventEx.GetEvent(out evCode, out evParam1, out evParam2, 0) == 0) 
      { 
       // Free event parameters to prevent memory leaks associated with 
       // event parameter data. While this application is not interested 
       // in the received events, applications should always process them. 
       hr = this.mediaEventEx.FreeEventParams(evCode, evParam1, evParam2); 
       DsError.ThrowExceptionForHR(hr); 

       // Insert event processing code here, if desired (see http://msdn2.microsoft.com/en-us/library/ms783649.aspx) 
      } 
     }  

     private void ReleaseInterfaces() 
     { 
      if (this.mediaControl != null) 
       this.mediaControl.StopWhenReady(); 

      this.CurrentState = PlayState.Stopped; 

      // stop notifications of events 
      if (this.mediaEventEx != null) 
       this.mediaEventEx.SetNotifyWindow(IntPtr.Zero, WM_GRAPHNOTIFY, IntPtr.Zero); 

      //// Relinquish ownership (IMPORTANT!) of the video window. 
      //// Failing to call put_Owner can lead to assert failures within 
      //// the video renderer, as it still assumes that it has a valid 
      //// parent window. 
      if (this.videoWindow != null) 
      { 
       this.videoWindow.put_Visible(OABool.False); 
       this.videoWindow.put_Owner(IntPtr.Zero); 
      } 

      // Release DirectShow interfaces 
      Marshal.ReleaseComObject(this.mediaControl); 
      this.mediaControl = null; 

      Marshal.ReleaseComObject(this.mediaEventEx); 
      this.mediaEventEx = null; 

      Marshal.ReleaseComObject(this.videoWindow); 
      this.videoWindow = null; 

      Marshal.ReleaseComObject(this.graphBuilder); 
      this.graphBuilder = null; 

      Marshal.ReleaseComObject(this.captureGraphBuilder); 
      this.captureGraphBuilder = null; 
     } 

     private void WebCamControl_Resize(object sender, System.EventArgs e) 
     { 
      //Resize the video preview window to match owner window size 
      if (this.videoWindow != null) 
       this.videoWindow.SetWindowPosition(0, 0, this.Width, this.ClientSize.Height); 
     } 
    } 
} 
+0

Почему вы не использовали EMGU и Opencv? –

+0

Извините @HazemAbdullah. , Я не знаю об этих библиотеках. Есть ли демо-приложение, использующее библиотеки. Пожалуйста, дайте мне знать, чтобы я мог понять, поможет ли это мне в этом. Спасибо – Gopichandar

ответ

1

Попробуйте использовать EMGU или OpenCV

http://www.emgu.com/wiki/index.php/Main_Page

И это пример, как захватить кадры от вас видео (кулачок) http://www.emgu.com/wiki/index.php?title=Camera_Capture

1-Добавить Emgu DLLs к приложению 2- Это пример

private Capture _capture; 
Image<Gray, Byte> frame; 

//0 is the default camera 
_capture = new Capture(0); 

//here how you can get the frames from your video 
Image<Bgr, Byte> frame = _capture.QueryFrame(); 
+0

Спасибо. Позвольте мне попытаться обновить вас. – Gopichandar

+0

Добро пожаловать, я отредактировал свой ответ, который может вам помочь –

+0

Я попытался запустить демонстрационное приложение по ссылке, предоставленной вами. Это ошибка. 'Необработанное исключение типа« System.TypeInitializationException »произошло в Emgu.CV.dll Дополнительная информация: Инициализатор типа для« Emgu.CV.CvInvoke »выбрал исключение.« После нажатия «Начать захват». Я что-то пропустил? – Gopichandar

0

Вы найдете целый ряд вопросов, решение указанной проблемы, например,

Есть два решения. Вы либо отбираетесь от компонента, который визуализирует видео (рендеринга видео), либо добавляете Sample Grabber или аналогичный фильтр в конвейер и захватываете его обратный вызов. Оба способа получения данных вы можете использовать для инициализации вашего растрового изображения .NET, но не совсем растрового изображения. То есть вы должны сделать шаг преобразования (inspiring Q on this).

Возможно, вы можете использовать библиотеки CV, которые, однако, являются огромным излишеством для такой простой задачи, и их захват видео может оказаться негибким, если вам нужно добавить что-то еще.

+0

Спасибо @Roman , , Я обновил свой пример кода. Можете ли вы посоветовать мне, как я могу добавить образец grabber или filter, чтобы получить растровое изображение текущего кадра. – Gopichandar

+0

Где вы делаете RenderStream, создайте SampleGrabber, AddFilter it, инициализируйте, чтобы работать только как 24 или 32 бит RGB. Подключите свой вход к вашему источнику, а затем RenderStream. Затем вы можете предоставить обратный вызов для приема кадров через вызов SampleCB. Поиск по указанным ключевым словам, и у вас будет много фрагментов кода для использования. –

+0

Позвольте мне попробовать. Спасибо за информацию. – Gopichandar

0

Я преодолел эту проблему, сняв снимок экрана вместо того, чтобы снимать кадр с видео. Вот код, который помог мне

//Create a new bitmap. 
var bmpScreenshot = new System.Drawing.Bitmap(Screen.PrimaryScreen.Bounds.Width, 
               Screen.PrimaryScreen.Bounds.Height, 
               System.Drawing.Imaging.PixelFormat.Format32bppArgb); 

// Create a graphics object from the bitmap. 
var gfxScreenshot = System.Drawing.Graphics.FromImage(bmpScreenshot); 

// Take the screenshot from the upper left corner to the right bottom corner. 
gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, 
               Screen.PrimaryScreen.Bounds.Y, 
               0, 
               0, 
               Screen.PrimaryScreen.Bounds.Size, 
               System.Drawing.CopyPixelOperation.SourceCopy); 

Я знаю, что это неправильный путь. Однако это дает мне решение для моей потребности. Я пробовал с SampleGrabber и EMGU, но я не могу получить решение, как ожидалось. Я чувствую, что мое решение достаточно просто для моей потребности и может помочь кому-то.

Спасибо.

Смежные вопросы