cpubbs论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

LabVIEW+单片机学习套件全套教程资料下载[免费]LabVIEW论坛精华列表贴USB0816数据采集卡《LabVIEW宝典》
LabWindows/CVI论坛精华贴NET0816以太网数据采集卡RC0210远程设备授权系统 关闭关停锁定打开设备 户外分布式数据采集
NET1624低速高精度以太网数据采集卡WIFI0824SD无线WIFI网络数据采集卡脱机运行 SD存储 小尺寸微型 串口采集远程采集 安卓 手持移动采集 纪录仪
查看: 6108|回复: 12

基于.NET控件DirectX.Capture.dll的摄像头视频AVI录制

[复制链接]
发表于 2008-10-24 17:43:42 | 显示全部楼层 |阅读模式
基于.NET控件DirectX.Capture.dll的摄像头视频AVI录制
简单做了下,高级功能我也搞不定。
现在可以实现录制AVI,preview的预览功能没有做成

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2008-10-24 18:18:02 | 显示全部楼层
版主果然牛人~~ym一下~~
发表于 2008-10-24 21:26:14 | 显示全部楼层
发表于 2008-10-24 22:21:06 | 显示全部楼层
兄弟又有好东西了,呵呵!收录到精华贴中再说!
 楼主| 发表于 2008-10-30 14:28:41 | 显示全部楼层
 楼主| 发表于 2010-3-17 21:12:55 | 显示全部楼层
 楼主| 发表于 2010-3-17 21:36:37 | 显示全部楼层
DirectX.Capture Class Library(By Brian Low.)是我在codeproject上寻找的类库,它完全由C#编写,基于directshow.net类库,用于实现音频和视频的捕捉,并且可以保存为avi文件,你可以很方便的在codeproject上下载到这两个类库的源文件。
该类库的主要特点:

可以列举和选择所有音视频的硬件设备

可以设置音频和视频相关属性,例如帧速率,大小,采样频率等
支持音视频压缩编码

支持视频预览
支持电视接口

支持混音

可以显示硬件驱动的属性

包含了标准的MSDN式的帮助文档
使用该类库的时候必须同时引入DirectX.Capture.dll和DShowNET.dll,到你的项目里。


例程1:

using DirectX.Capture

// 此时使用默认的音视频的首选设备进行捕获

Capture capture = new Capture( Filters.VideoInputDevices[0],
Filters.AudioInputDevices[0] );

// Start capturing
capture.Start();

// Stop capturing
capture.Stop();


例程2:


Capture capture = new Capture( Filters.VideoInputDevices[0],
Filters.AudioInputDevices[1] );

//这里可以设置使用哪种压缩编码方式
capture.VideoCompressor = Filters.VideoCompressors[0];
capture.AudioCompressor = Filters.AudioCompressors[0];

capture.FrameRate = 29.997;                 // NTSC
capture.FrameSize = new Size( 640, 480 );   // 640x480
capture.AudioSamplingRate = 44100;          // 44.1 kHz
capture.AudioSampleSize = 16;               // 16-bit
capture.AudioChannels = 1;                  // Mono

capture.Filename = "C:MyVideo.avi";

capture.Start();
...
capture.Stop();


例程3:关于预览


// Start preview
capture.PreviewWindow = myPanelControl;

// Stop preview
capture.PreviewWindow = null;


该类库每次都会从设备的驱动程序中更新最新支持的属性,因此你完全没有必要理会,设备到底是不是支持特定属性,只要从支持的属性中选择即可


当然该类库,也有一些问题,比如说关于电视卡的支持并不是很好,但是如果你不用的话,仅仅操作普通的视频和音频设备,该类库还是非常好用的,



---------------------原文如下------------------------------
Introduction
This article presents a class library for capturing audio and video to AVI files in .NET. Some of the features of this library:

List and select hardware devices
Access to common audio and video settings (e.g. frame rate, size)
Support audio and video compression codecs
Support video preview
Support TV tuners
Support crossbars and audio mixers
Retrieve device capabilities
Show property pages exposed by drivers
MSDN-style documentation included
Using the Code
The Capture class is the core of this library. Here is a simple example:

// Remember to add a reference to DirectX.Capture.dll
using DirectX.Capture
// Capture using the first video
// and audio devices available
Capture capture = new Capture( Filters.VideoInputDevices[0],
Filters.AudioInputDevices[0] );
// Start capturing
capture.Start();
// Stop capturing
capture.Stop();
Remember to add a reference in your project to DirectX.Capture.dll. This DLL requires DShowNET.dll, so make sure they are both in the same directory. Once you add the reference, Visual Studio .NET should take care of the copying for you.

This example will capture video and audio using the first video and audio devices installed on the system. To capture video only, pass a null as the second parameter to the constructor.

The class is initialized to a valid temporary file in the Windows temp folder. To capture to a different file, set the Capture.Filename property before you begin capturing.

A Second Example
This next example shows how to change video and audio settings. Properties such as Capture.FrameRate and Capture.AudioSampleSize allow you to programmatically adjust the capture. Use Capture.VideoCaps and Capture.AudioCaps to determine valid values for these properties.

Capture capture = new Capture( Filters.VideoInputDevices[0],
Filters.AudioInputDevices[1] );
capture.VideoCompressor = Filters.VideoCompressors[0];
capture.AudioCompressor = Filters.AudioCompressors[0];
capture.FrameRate = 29.997;                 // NTSC
capture.FrameSize = new Size( 640, 480 );   // 640x480
capture.AudioSamplingRate = 44100;          // 44.1 kHz
capture.AudioSampleSize = 16;               // 16-bit
capture.AudioChannels = 1;                  // Mono
capture.Filename = "C:\MyVideo.avi";
capture.Start();
...
capture.Stop();
The example above also shows the use of video and audio compressors. In most cases, you will want to use compressors. Uncompressed video can easily consume over 1GB of disk space per minute. Whenever possible, set the Capture.VideoCompressor and Capture.AudioCompressor properties as early as possible. Changing them requires the internal filter graph to be rebuilt which often causes most of the other properties to be reset to default values.

Behind the Scenes
This project uses 100% DirectShow to capture video. Once a capture is started, DirectShow spawns another thread and handles retrieving/moving all the video and audio data itself. That means you should be able to capture at the same speed and quality as an application written in C.

DirectShow is implemented as a set of COM components and we use .NET Interop to access them. The pioneering work on this was done by NETMaster with the DShowNET project. This Capture library uses DShowNET for the interop layer with only a few extensions. This is the DShowNET.dll mentioned earlier.

Sitting on top of all of this is the Capture class library. The center of any DirectShow app is the filter graph and the filter graph manager. For a good overview, see The Filter Graph and Its Components from the MSDN.

The Least Work Possible
The library tries at all times to do the least amount of work possible. The problem is: DirectShow is very flexible, but has few firm standards for driver developers and I have limited hardware to test with. As a result, the class tries to avoid doing any work that may not be necessary, hopefully avoiding potential incompatibilities in the process.

One example is video preview. You can start and stop preview with:

// Start preview
capture.PreviewWindow = myPanelControl;
// Stop preview
capture.PreviewWindow = null;
Hopefully this is simple to use. Internally, DirectShow does a lot of work: add required upstream filters for WDM devices, search for preview pins, use the Overlay Manager for video ports (hardware overlays), insert SmartTee filters when a separate preview pin is not available and more. Instead of rendering the preview stream as soon as the class is created, the class waits until the PreviewWindow property is set.

For developers who don't need preview, none of this work will ever be done. That means your application is more likely to work on a wider range of hardware. For developers that do need preview, this makes it easier to locate the cause of the problem and fix it or handle it gracefully.

Performance Tips
Many of the properties on the Capture class are retrieved directly from the underlying DirectShow COM components. If you need to refer to the property repeatedly in a block of code, take a copy of the value and use your copy.

// AudioSampleSize is retrieved from DirectShow each iteration
for ( int c = 0; c < 32; c++ )
{
if ( c == capture.AudioSampleSize )
MessageBox.Show( "Found!" );
}
// A faster solution
int x = capture.AudioSampleSize;
for ( int c = 0; c < 32; c++ )
{
if ( c == x )
MessageBox.Show( "Found!" );
}
Why doesn't the class simply cache the value internally? We don't know when the filter (device driver) will change this value, so we have to retrieve the value every time. This means you will always get the real value of the property.

Credits
The DirectShow interop layer was developed by NETMaster in the DShowNET project. The MDSN-style documentation was generated from the source code using nDoc.

Troubleshooting
I have tested this with an Asus v7700 (NVidia GeForce2, reference drivers) and my onboard sound card. I can't guarantee any other hardware will work. However, I expect most video capture cards and sound cards will work. You may have trouble with TV Tuner cards and DV devices (Firewire camcorders) though they should be solvable.

Try the AMCap sample from the DirectX SDK (DX9\Samples\C++\DirectShow\Bin\AMCap.exe) or Virtual VCR, a free DirectShow capture application.

This class library uses COM Interop to access the full capabilities of DirectShow, so if there is another application that can successfully use a hardware device then it should be possible to modify this class library to use the device. Please post your experiences, good or bad, in the forum below.

User Enhancements
The following enhancements have been posted to the discussion board:

Frequency Overrides for the Tuner class by fdaupias
Radio Tuning for the Tuner class by dauboro
Thanks to fdaupias and dauboro for their submissions. I have not had time to post a tested, updated version with these enhancements. If anyone wants to make an updated download zip, mail it to me and I will added it to this page. Keep the enhancements coming.

DirectX.Capture Wiki
A Wiki for this project is available here. This Wiki can be edited by anyone, no registration is required. I hope this Wiki will allow interested users to more easily collaborate on this project. New versions, enhancements, tips and tricks can be posted on the Wiki.


License
This article, along with any associated source code and files, is licensed under A Public Domain dedication

About the Author
 楼主| 发表于 2010-3-17 21:37:41 | 显示全部楼层
 楼主| 发表于 2010-3-17 21:42:04 | 显示全部楼层
随着Windows操作系统的不断演变,用于捕获视频的API接口也在进化,微软提供了VFW、DirectShow和MediaFoundation这三代接口。其中VFW早已被DirectShow取代,而最新的MediaFoundation被Windows Vista和Windows 7所支持。可惜的是,上述接口基于COM技术且灵活性很大,在.net中并不方便直接使用。

  .net封装

  老外有很多活雷锋,他们奉献了不少的开源项目,DirectShow.net是对DirectShow的封装,而MediaFoundation.net是对MediaFoundation的封装。它们都能在http://sourceforge.net上找到。这两个封装之后的类库基本上跟原来的COM是一一对应的关系,可以用于视频捕获,但是用起来还是不够简便。

  通过不断的google搜索,我认为以下类库对视频捕获封装得不错,它们是:DirectX.Capture、OpenCv、EmguCv和AForge。

  DirectX.Capture

  DirectX.Capture是发表在CodeProject上的一个项目,它能很方便的捕获视频和音频,在窗口预览,并将结果保存到文件。使用DirectX.Capture的示例如下:

  DirectX.Capture

Capture capture = new Capture( Filters.VideoInputDevices[0],
                Filters.AudioInputDevices[1] );
capture.Filename = "C:\MyVideo.avi";
capture.Start();
//...
capture.Stop();

  但是,它没有提供单独获取某帧内容的方法。如果您只是需要预览并保存视频,它很好用。

OpenCv

  OpenCv对VFW和DirectShow的视频捕获部分进行了很好的封装,能够很方便的获取到某帧的内容,也可以将结果保存到视频文件中。使用OpenCv的示例如下:

  OpenCv

IntPtr ptrCapture = CvInvoke.cvCreateCameraCapture(param.deviceInfo.Index);
      while (!stop)
      {
        IntPtr ptrImage = CvInvoke.cvQueryFrame(ptrCapture);
        lock (lockObject)
        {
          stop = stopCapture;
        }
      }
      CvInvoke.cvReleaseCapture(ref ptrCapture);

  不过OpenCv并未对音频捕获进行封装,如果需要同时录制音频,这个搞不定。

  值得注意的是,从OpenCv 1.1开始已经实现了对DirectShow的封装,这跟网上很多人所说的OpenCv使用VFW进行视频捕获效率低下这种观点不一致。关于OpenCv使用DirectShow的论据请看本文的附录。

  EmguCv

  EmguCv是对OpenCv在.net的封装,继承了OpenCv快速的优点,同时它更加好用。使用EmguCv的示例代码如下:

  EmguCv

      Capture capture = new Capture(param.deviceInfo.Index);
      while (!stop)
      {
        pbCapture.Image = capture.QueryFrame().Bitmap;
        lock (lockObject)
        {
          stop = stopCapture;
        }
      }
      capture.Dispose();

  AForge

AForge是一套纯正的.net开源图像处理类库,它的视频捕获类也是基于DirectShow的,但更加好用,功能更多,从使用和帮助来看更类似微软的类库。

  AForge

        captureAForge = new VideoCaptureDevice(cameraDevice.MonikerString);
        captureAForge.NewFrame += new NewFrameEventHandler(captureAForge_NewFrame);
        captureAForge.Start();
        //...
        captureAForge.SignalToStop();
    private void captureAForge_NewFrame(object sender, NewFrameEventArgs eventArgs)
    {
      pbCapture.Image = (Bitmap)eventArgs.Frame.Clone();
    }



  查看原图(大图)

  对比

  介绍完它们之后,我们来比较下它们。它们都是基于DirectShow的,所以性能几乎一样。实际上,我个人认为,摄像头所用的硬件和驱动程序的支持对性能影响更大。我的摄像头在Windows 7下没有专门的驱动程序,只能使用Microsoft提供的默认驱动,性能比WindowsXp要差一截。

  值得注意的是主要有几点:

  (1)只有DirectX.Capture实现了对音频的捕获;

  (2)只有DirectX.Capture不能获取单独的某帧图像;

  (3)EmguCv的免费版基于商业许可,而其他类库的许可都很宽松;

(4)AForge的示例和帮助比较好,而且功能多些。

  附录:OpenCv也用DirectShow来捕获视频

  通过分析OpenCv 2.0的源代码,我得出了OpenCv使用DirectShow来捕获视频的结论。证据如下:

  DirectShow In OpenCv

(1)
//_highgui.h line:100
#if (_MSC_VER >= 1400 || defined __GNUC__) && !defined WIN64 && !defined _WIN64
#define HAVE_VIDEOINPUT 1
#endif
(2)
//cvcap_dshow.cpp line:44
#ifdef HAVE_VIDEOINPUT
#include "videoinput.h"

/********************* Capturing video from camera via VFW *********************/

class CvCaptureCAM_DShow : public CvCapture
(3)
//cvapp.cpp line:102
CV_IMPL CvCapture * cvCreateCameraCapture (int index)
{
//.....
//line:140
 switch (domains)
 {
    #ifdef HAVE_VIDEOINPUT
    case CV_CAP_DSHOW:
      capture = cvCreateCameraCapture_DShow (index);
      if (capture)
        return capture;
      break;
    #endif

  本文完整源代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;
using AForge.Video;
using AForge.Video.DirectShow;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.UI;
using System.Threading;
namespace ImageProcessLearn
{
  public partial class FormCameraCapture : Form
  {
    private int framesCaptured; //已经捕获的视频帧数
    private int frameCount;   //需要捕获的总帧数
    private Stopwatch sw;    //计时器
    private VideoCaptureDevice captureAForge = null;  //AForge视频捕获对象
    private bool stopCapture;              //是否停止捕获视频
    private object lockObject = new object();
    public FormCameraCapture()
    {
      InitializeComponent();
      sw = new Stopwatch();
    }
    //窗体加载时,获取视频捕获设备列表
    private void FormCameraCapture_Load(object sender, EventArgs e)
    {
      FilterInfoCollection videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
      if (videoDevices != null && videoDevices.Count > 0)
      {
        int idx = 0;
        foreach (FilterInfo device in videoDevices)
        {
          cmbCaptureDevice.Items.Add(new DeviceInfo(device.Name, device.MonikerString, idx, FilterCategory.VideoInputDevice));
          idx++;
        }
        cmbCaptureDevice.SelectedIndex = 0;
      }
    }
    //当改变视频设备时,重新填充该设备对应的能力
    private void cmbCaptureDevice_SelectedIndexChanged(object sender, EventArgs e)
    {
      if (cmbCaptureDevice.SelectedItem != null)
      {
        //保存原来选择的设备能力
        Size oldFrameSize = new Size(0, 0);
        int oldMaxFrameRate = 0;
        if (cmbDeviceCapability.SelectedItem != null)
        {
          oldFrameSize = ((DeviceCapabilityInfo)cmbDeviceCapability.SelectedItem).FrameSize;
          oldMaxFrameRate = ((DeviceCapabilityInfo)cmbDeviceCapability.SelectedItem).MaxFrameRate;
        }
        //清除设备能力
        cmbDeviceCapability.Items.Clear();
        //添加新的设备能力
        int oldCapIndex = -1;  //原来选择的设备能力的新索引
        VideoCaptureDevice video = new VideoCaptureDevice(((DeviceInfo)cmbCaptureDevice.SelectedItem).MonikerString);
        for (int i = 0; i < video.VideoCapabilities.Length; i++)
        {
          VideoCapabilities cap = video.VideoCapabilities;
          DeviceCapabilityInfo capInfo = new DeviceCapabilityInfo(cap.FrameSize, cap.MaxFrameRate);
          cmbDeviceCapability.Items.Add(capInfo);
          if (oldFrameSize == capInfo.FrameSize && oldMaxFrameRate == capInfo.MaxFrameRate)
            oldCapIndex = i;
        }
        //重新选择原来的设备能力,或者选一个新的能力
        if (oldCapIndex == -1)
          oldCapIndex = 0;
        cmbDeviceCapability.SelectedIndex = oldCapIndex;
      }
    }
    //当改变设备能力时
    private void cmbDeviceCapability_SelectedIndexChanged(object sender, EventArgs e)
    {
      if (int.Parse(txtRate.Text) >= ((DeviceCapabilityInfo)cmbDeviceCapability.SelectedItem).MaxFrameRate)
        txtRate.Text = ((DeviceCapabilityInfo)cmbDeviceCapability.SelectedItem).MaxFrameRate.ToString();
    }
    //性能测试:测试获取指定帧数的视频,并将其转换成图像,所需要的时间,然后计算出FPS
    private void btnPerformTest_Click(object sender, EventArgs e)
    {
      int frameCount = int.Parse(txtFrameCount.Text);
      if (frameCount <= 0)
        frameCount = 300;
      DeviceInfo device = (DeviceInfo)cmbCaptureDevice.SelectedItem;
      btnPerformTest.Enabled = false;
      btnStart.Enabled = false;
      txtResult.Text += PerformTestWithAForge(device.MonikerString, frameCount);
      txtResult.Text += PerformTestWithEmguCv(device.Index, frameCount);
      txtResult.Text += PerformTestWithOpenCv(device.Index, frameCount);
      btnPerformTest.Enabled = true;
      btnStart.Enabled = true;
    }
    //AForge性能测试
    private string PerformTestWithAForge(string deviceMonikerString, int frameCount)
    {
      VideoCaptureDevice video = new VideoCaptureDevice(deviceMonikerString);
      video.NewFrame += new NewFrameEventHandler(PerformTest_NewFrame);
      video.DesiredFrameSize = ((DeviceCapabilityInfo)cmbDeviceCapability.SelectedItem).FrameSize;
      video.DesiredFrameRate = int.Parse(txtRate.Text);
      framesCaptured = 0;
      this.frameCount = frameCount;
      video.Start();
      sw.Reset();
      sw.Start();
      video.WaitForStop();
      double time = sw.Elapsed.TotalMilliseconds;
      return string.Format("AForge性能测试,帧数:{0},耗时:{1:F05}毫秒,FPS:{2:F02},设定({3})\r\n", frameCount, time, 1000d * frameCount / time, GetSettings());
    }
    void PerformTest_NewFrame(object sender, NewFrameEventArgs eventArgs)
    {
      framesCaptured++;
      if (framesCaptured > frameCount)
      {
        sw.Stop();
        VideoCaptureDevice video = sender as VideoCaptureDevice;
        video.SignalToStop();
      }
    }
    //EmguCv性能测试
    private string PerformTestWithEmguCv(int deviceIndex, int frameCount)
    {
      Capture video = new Capture(deviceIndex);
      video.SetCaptureProperty(CAP_PROP.CV_CAP_PROP_FRAME_WIDTH, ((DeviceCapabilityInfo)cmbDeviceCapability.SelectedItem).FrameSize.Width);
      video.SetCaptureProperty(CAP_PROP.CV_CAP_PROP_FRAME_HEIGHT, ((DeviceCapabilityInfo)cmbDeviceCapability.SelectedItem).FrameSize.Height);
      video.SetCaptureProperty(CAP_PROP.CV_CAP_PROP_FPS, double.Parse(txtRate.Text));
      sw.Reset();
      sw.Start();
      for (int i = 0; i < frameCount; i++)
        video.QueryFrame();
      sw.Stop();
      video.Dispose();
      double time = sw.Elapsed.TotalMilliseconds;
      return string.Format("EmguCv性能测试,帧数:{0},耗时:{1:F05}毫秒,FPS:{2:F02},设定({3})\r\n", frameCount, time, 1000d * frameCount / time, GetSettings());
    }
    //OpenCv性能测试
    private string PerformTestWithOpenCv(int deviceIndex, int frameCount)
    {
      IntPtr ptrVideo = CvInvoke.cvCreateCameraCapture(deviceIndex);
      CvInvoke.cvSetCaptureProperty(ptrVideo, CAP_PROP.CV_CAP_PROP_FRAME_WIDTH, ((DeviceCapabilityInfo)cmbDeviceCapability.SelectedItem).FrameSize.Width);
      CvInvoke.cvSetCaptureProperty(ptrVideo, CAP_PROP.CV_CAP_PROP_FRAME_HEIGHT, ((DeviceCapabilityInfo)cmbDeviceCapability.SelectedItem).FrameSize.Height);
      CvInvoke.cvSetCaptureProperty(ptrVideo, CAP_PROP.CV_CAP_PROP_FPS, double.Parse(txtRate.Text));
      sw.Reset();
      sw.Start();
      for (int i = 0; i < frameCount; i++)
        CvInvoke.cvQueryFrame(ptrVideo);
      sw.Stop();
      CvInvoke.cvReleaseCapture(ref ptrVideo);
      double time = sw.Elapsed.TotalMilliseconds;
      return string.Format("OpenCv性能测试,帧数:{0},耗时:{1:F05}毫秒,FPS:{2:F02},设定({3})\r\n", frameCount, time, 1000d * frameCount / time, GetSettings());
    }
    //得到设置所对应的字符串
    private string GetSettings()
    {
      return string.Format("摄像头:{0},尺寸:{1}x{2},FPS:{3}", ((DeviceInfo)cmbCaptureDevice.SelectedItem).Name,
        ((DeviceCapabilityInfo)cmbDeviceCapability.SelectedItem).FrameSize.Width,
        ((DeviceCapabilityInfo)cmbDeviceCapability.SelectedItem).FrameSize.Height,
        txtRate.Text);
    }
    //开始捕获视频
    private void btnStart_Click(object sender, EventArgs e)
    {
      //得到设置项
      DeviceInfo cameraDevice = (DeviceInfo)cmbCaptureDevice.SelectedItem;
      Size frameSize = ((DeviceCapabilityInfo)cmbDeviceCapability.SelectedItem).FrameSize;
      int rate = int.Parse(txtRate.Text);
      ThreadParam param = new ThreadParam(cameraDevice, new DeviceCapabilityInfo(frameSize, rate));
      if (rbAForge.Checked)
      {
        captureAForge = new VideoCaptureDevice(cameraDevice.MonikerString);
        captureAForge.DesiredFrameSize = frameSize;
        captureAForge.DesiredFrameRate = rate;
        captureAForge.NewFrame += new NewFrameEventHandler(captureAForge_NewFrame);
        txtResult.Text += string.Format("开始捕获视频(方式:AForge,开始时间:{0})......\r\n", DateTime.Now.ToLongTimeString());
        framesCaptured = 0;
        sw.Reset();
        sw.Start();
        captureAForge.Start();
      }
      else if (rbEmguCv.Checked)
      {
        stopCapture = false;
        Thread captureThread = new Thread(new ParameterizedThreadStart(CaptureWithEmguCv));
        captureThread.Start(param);
      }
      else if (rbOpenCv.Checked)
      {
        stopCapture = false;
        Thread captureThread = new Thread(new ParameterizedThreadStart(CaptureWithOpenCv));
        captureThread.Start(param);
      }
      btnStart.Enabled = false;
      btnStop.Enabled = true;
      btnPerformTest.Enabled = false;
    }
    private void captureAForge_NewFrame(object sender, NewFrameEventArgs eventArgs)
    {
      pbCapture.Image = (Bitmap)eventArgs.Frame.Clone();
      lock (lockObject)
      {
        framesCaptured++;
      }
    }
    //EmguCv视频捕获
    private void CaptureWithEmguCv(object objParam)
    {
      bool stop = false;
      int framesCaptured = 0;
      Stopwatch sw = new Stopwatch();
      txtResult.Invoke(new AddResultDelegate(AddResultMethod), string.Format("开始捕获视频(方式:EmguCv,开始时间:{0})......\r\n", DateTime.Now.ToLongTimeString()));
      ThreadParam param = (ThreadParam)objParam;
      Capture capture = new Capture(param.deviceInfo.Index);
      capture.SetCaptureProperty(CAP_PROP.CV_CAP_PROP_FRAME_WIDTH, param.deviceCapability.FrameSize.Width);
      capture.SetCaptureProperty(CAP_PROP.CV_CAP_PROP_FRAME_HEIGHT, param.deviceCapability.FrameSize.Height);
      capture.SetCaptureProperty(CAP_PROP.CV_CAP_PROP_FPS, param.deviceCapability.MaxFrameRate);
      sw.Start();
      while (!stop)
      {
        pbCapture.Image = capture.QueryFrame().Bitmap;
        framesCaptured++;
        lock (lockObject)
        {
          stop = stopCapture;
        }
      }
      sw.Stop();
      txtResult.Invoke(new AddResultDelegate(AddResultMethod), string.Format("捕获视频结束(方式:EmguCv,结束时间:{0},用时:{1:F05}毫秒,帧数:{2},FPS:{3:F02})\r\n",
        DateTime.Now.ToLongTimeString(), sw.Elapsed.TotalMilliseconds, framesCaptured, framesCaptured / sw.Elapsed.TotalSeconds));
      capture.Dispose();
    }
    //OpenCv视频捕获
    private void CaptureWithOpenCv(object objParam)
    {
      bool stop = false;
      int framesCaptured = 0;
      Stopwatch sw = new Stopwatch();
      txtResult.Invoke(new AddResultDelegate(AddResultMethod), string.Format("开始捕获视频(方式:OpenCv,开始时间:{0})......\r\n", DateTime.Now.ToLongTimeString()));
      ThreadParam param = (ThreadParam)objParam;
      IntPtr ptrCapture = CvInvoke.cvCreateCameraCapture(param.deviceInfo.Index);
      CvInvoke.cvSetCaptureProperty(ptrCapture, CAP_PROP.CV_CAP_PROP_FRAME_WIDTH, param.deviceCapability.FrameSize.Width);
      CvInvoke.cvSetCaptureProperty(ptrCapture, CAP_PROP.CV_CAP_PROP_FRAME_HEIGHT, param.deviceCapability.FrameSize.Height);
      CvInvoke.cvSetCaptureProperty(ptrCapture, CAP_PROP.CV_CAP_PROP_FPS, param.deviceCapability.MaxFrameRate);
      sw.Start();
      while (!stop)
      {
        IntPtr ptrImage = CvInvoke.cvQueryFrame(ptrCapture);
        MIplImage iplImage = (MIplImage)Marshal.PtrToStructure(ptrImage, typeof(MIplImage));
        Image<Bgr, byte> image = new Image<Bgr, byte>(iplImage.width, iplImage.height, iplImage.widthStep, iplImage.imageData);
        pbCapture.Image = image.Bitmap;
        //pbCapture.Image = ImageConverter.IplImagePointerToBitmap(ptrImage);
        framesCaptured++;
        lock (lockObject)
        {
          stop = stopCapture;
        }
      }
      sw.Stop();
      txtResult.Invoke(new AddResultDelegate(AddResultMethod), string.Format("捕获视频结束(方式:OpenCv,结束时间:{0},用时:{1:F05}毫秒,帧数:{2},FPS:{3:F02})\r\n",
        DateTime.Now.ToLongTimeString(), sw.Elapsed.TotalMilliseconds, framesCaptured, framesCaptured / sw.Elapsed.TotalSeconds));
      CvInvoke.cvReleaseCapture(ref ptrCapture);
    }
    //停止捕获视频
    private void btnStop_Click(object sender, EventArgs e)
    {
      if (captureAForge != null)
      {
        sw.Stop();
        if (captureAForge.IsRunning)
          captureAForge.SignalToStop();
        captureAForge = null;
        txtResult.Text += string.Format("捕获视频结束(方式:AForge,结束时间:{0},用时:{1:F05}毫秒,帧数:{2},FPS:{3:F02})\r\n",
          DateTime.Now.ToLongTimeString(), sw.Elapsed.TotalMilliseconds, framesCaptured, framesCaptured / sw.Elapsed.TotalSeconds);
      }
      lock (lockObject)
      {
        stopCapture = true;
      }
      btnStart.Enabled = true;
      btnStop.Enabled = false;
      btnPerformTest.Enabled = true;
    }
    //用于在工作线程中更新结果的委托及方法
    public delegate void AddResultDelegate(string result);
    public void AddResultMethod(string result)
    {
      txtResult.Text += result;
    }
  }
  //设备信息
  public struct DeviceInfo
  {
    public string Name;
    public string MonikerString;
    public int Index;
    Guid Category;
    public DeviceInfo(string name, string monikerString, int index) :
      this(name, monikerString, index, Guid.Empty)
    {
    }
    public DeviceInfo(string name, string monikerString, int index, Guid category)
    {
      Name = name;
      MonikerString = monikerString;
      Index = index;
      Category = category;
    }
    public override string ToString()
    {
      return Name;
    }
  }
  //设备能力
  public struct DeviceCapabilityInfo
  {
    public Size FrameSize;
    public int MaxFrameRate;
    public DeviceCapabilityInfo(Size frameSize, int maxFrameRate)
    {
      FrameSize = frameSize;
      MaxFrameRate = maxFrameRate;
    }
    public override string ToString()
    {
      return string.Format("{0}x{1} {2}fps", FrameSize.Width, FrameSize.Height, MaxFrameRate);
    }
  }
  //传递到捕获视频工作线程的参数
  public struct ThreadParam
  {
    public DeviceInfo deviceInfo;
    public DeviceCapabilityInfo deviceCapability;
    public ThreadParam(DeviceInfo deviceInfo, DeviceCapabilityInfo deviceCapability)
    {
      this.deviceInfo = deviceInfo;
      this.deviceCapability = deviceCapability;
    }
  }
}
 楼主| 发表于 2010-3-17 21:46:38 | 显示全部楼层
过了好长时间,连这个程序我自己都看不懂了。忘性特别大了。
发表于 2010-3-19 09:33:21 | 显示全部楼层
.net 技术的开拓者!go on!
发表于 2014-3-28 14:03:45 | 显示全部楼层
不好意思.请教一下,我用的是.NET 4.0,但LABVIEW的VI运行报错.是不是一定要用.NET2.0??
 楼主| 发表于 2014-6-26 11:43:28 | 显示全部楼层
floatstone 发表于 2014-3-28 14:03
不好意思.请教一下,我用的是.NET 4.0,但LABVIEW的VI运行报错.是不是一定要用.NET2.0??

需要你多测试验证下了,这个小玩意是多年前一时兴起做的,现在我都好久不玩它了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|cpubbs论坛. ( 粤ICP备09171248号 )

GMT+8, 2024-5-20 07:35 , Processed in 0.601244 second(s), 9 queries , Gzip On, File On.

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表