欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C# 利用AForge进行摄像头信息采集

程序员文章站 2022-04-09 15:47:10
AForge.NET是一个专门为开发者和研究者基于C#框架设计的,提供了不同的类库和关于类库的资源,还有很多应用程序例子,包括计算机视觉与人工智能,图像处理,神经网络,遗传算法,机器学习,机器人等领域。本文主要讲解利用AForge进行图像采集的相关内容【包括拍照,视频录制】,仅供学习分享使用。 ......

概述

aforge.net是一个专门为开发者和研究者基于c#框架设计的,提供了不同的类库和关于类库的资源,还有很多应用程序例子,包括计算机视觉与人工智能,图像处理,神经网络,遗传算法,机器学习,机器人等领域。本文主要讲解利用aforge进行图像采集的相关内容【包括拍照,视频录制】,仅供学习分享使用。

aforge.net相关类库介绍

  • aforge.dll 是框架的核心基础类库,为其他类库提供服务。
  • aforge.controls.dll 包含aforge.net的ui控件,主要用于页面显示。
  • aforge.imaging.dll 主要是框架中用于图像处理的类库,主要负责图像的处理
  • aforge.video.dll 主要是框架中对视频处理的类库。
  • aforge.video.directshow.dll 主要是通过directshow接口访问视频资源的类库。
  • aforge.video.ffmpeg.dll 是一个还未正式发布的类库,通过ffmpeg类库对视频进行读写。

通过nuget管理器引入aforge类库

项目名称右键-->管理nuget程序包,打卡nuget包管理器  如下所示:

C# 利用AForge进行摄像头信息采集

示例效果图

本示例主要包括打开,关闭摄像头,拍照,连续拍照,开始录制视频,暂停录制视频,停止录视频,退出等功能。

如下所示:左侧为摄像头投影区域,右侧为图像控件,显示拍照所得的图片

C# 利用AForge进行摄像头信息采集

核心代码

获取视频设备列表以及设备对应的分辨率

 1 /// <summary>
 2         /// 页面加载摄像头设备
 3         /// </summary>
 4         /// <param name="sender"></param>
 5         /// <param name="e"></param>
 6         private void frmmain_load(object sender, eventargs e)
 7         {
 8             try
 9             {
10                 this.lbltime.text = "";
11                 // 枚举所有视频输入设备
12                 videodevices = new filterinfocollection(filtercategory.videoinputdevice);
13                 if (videodevices.count == 0)
14                 {
15                     lblstatus.text = "no local capture devices";
16                 }
17                 foreach (filterinfo device in videodevices)
18                 {
19                     int i = 1;
20                     cmbdevices.items.add(device.name);
21                     lblstatus.text = ("摄像头" + i + "初始化完毕..." + "\n");
22                     i++;
23                 }
24                 cmbdevices.selectedindex = 0;
25             }
26             catch (applicationexception)
27             {
28                 this.lblstatus.text = "no local capture devices";
29                 videodevices = null;
30             }
31         }
32 
33         private void cmbdevices_selectedindexchanged(object sender, eventargs e)
34         {
35             this.cmbresolution.items.clear();
36             videosource = new videocapturedevice(videodevices[cmbdevices.selectedindex].monikerstring);
37             foreach(var cap in videosource.videocapabilities) {
38                 this.cmbresolution.items.add(string.format("({0},{1})",cap.framesize.width,cap.framesize.height));
39             }
40             if (this.cmbresolution.items.count > 0)
41             {
42                 this.cmbresolution.selectedindex = 0;
43             }
44         }

打开视频设备和关闭视频设备

 1    /// <summary>
 2         /// 设备打开
 3         /// </summary>
 4         /// <param name="sender"></param>
 5         /// <param name="e"></param>
 6         private void btnopen_click(object sender, eventargs e)
 7         {
 8             int index = this.cmbresolution.selectedindex;
 9             videosource = new videocapturedevice(videodevices[cmbdevices.selectedindex].monikerstring);
10             videosource.videoresolution = videosource.videocapabilities[index]; 
11             this.vsplayer.videosource = videosource;
12             //设置对应的事件
13             videosource.newframe += new newframeeventhandler(videosource_newframe);
14             this.vsplayer.start();
15         }
16 
17         /// <summary>
18         /// 产生新帧的触发事件
19         /// </summary>
20         /// <param name="sender"></param>
21         /// <param name="eventargs"></param>
22         public void videosource_newframe(object sender, newframeeventargs eventargs)
23         {
24             lock (objlock)
25             {
26                 bitmap bmp = null;
27                 if (ismultiphoto)
28                 {
29                     bmp = (system.drawing.bitmap)eventargs.frame.clone();
30                     string imgfolder = common.getimagepath();
31                     string picname = string.format("{0}\\{1}.jpg", imgfolder, datetime.now.tostring("yyyymmddhhmmss"));
32                     common.saveimage(picname, bmp);
33                 }
34                 //write videos
35                 if (isrecordvideo)
36                 {
37                     bmp = (system.drawing.bitmap)eventargs.frame.clone();
38                     videowriter.writevideoframe(bmp);
39                 }
40             }
41         }
42 
43         /// <summary>
44         /// 设备关闭
45         /// </summary>
46         /// <param name="sender"></param>
47         /// <param name="e"></param>
48         private void btnclose_click(object sender, eventargs e)
49         {
50             this.vsplayer.signaltostop();
51             this.vsplayer.waitforstop();
52         }

拍照

 1 /// <summary>
 2         /// 拍照
 3         /// </summary>
 4         /// <param name="sender"></param>
 5         /// <param name="e"></param>
 6         private void btncapture_click(object sender, eventargs e)
 7         {
 8             try
 9             {
10                 if (this.vsplayer.isrunning)
11                 {
12                     bitmap bitmap = this.vsplayer.getcurrentvideoframe();
13                     this.pbimage.image = bitmap;
14                     //设置图片相对控件的大小
15                     this.pbimage.sizemode = pictureboxsizemode.stretchimage;
16                 }
17             }
18             catch (exception ex)
19             {
20                 messagebox.show("摄像头异常:" + ex.message);
21             }
22         }

连拍功能

连拍主要是同时视频控件的一个帧触发事件,在事件中对图像进行保存,达到连拍的效果,如下所示:

1  //设置对应的事件
2 videosource.newframe += new newframeeventhandler(videosource_newframe);

视频录制

视频录制,是采用videofilewriter对获取到的每一帧进行写入到视频文件中,如下所示:

 1  /// <summary>
 2         /// 开始录视频
 3         /// </summary>
 4         /// <param name="sender"></param>
 5         /// <param name="e"></param>
 6         private void btnstartvideo_click(object sender, eventargs e)
 7         {
 8             try
 9             {
10                 //创建一个视频文件
11                 string vdopath = common.getvideopath();
12                 string vdoname = string.format("{0}\\{1}.avi", vdopath, datetime.now.tostring("yyyymmdd hh-mm-ss"));
13                 
14                 this.timer1.enabled = true;//是否执行system.timers.timer.elapsed事件;
15                 this.lblstatus.text="录制中...\n";
16                 ticknum = 0;
17                 videowriter = new videofilewriter();
18                 if (this.vsplayer.isrunning)
19                 {
20                     videowriter.open(vdoname, vdowidth, vdoheight, framerate, videocodec.mpeg4);
21                     isrecordvideo = true;
22                 }
23                 else
24                 {
25                     messagebox.show("没有视频源输入,无法录制视频。", "错误", messageboxbuttons.ok, messageboxicon.error);
26                 }
27             }
28             catch (exception ex)
29             {
30                 messagebox.show("摄像头异常:" + ex.message);
31             }
32         }
33 
34         /// <summary>
35         /// 停止录视频
36         /// </summary>
37         /// <param name="sender"></param>
38         /// <param name="e"></param>
39         private void btnstopvideo_click(object sender, eventargs e)
40         {
41             this.isrecordvideo = false;
42             this.videowriter.close();
43             this.timer1.enabled = false;
44             ticknum = 0;
45             this.lblstatus.text="录制停止!\n";
46         }
47 
48         /// <summary>
49         /// 定时器
50         /// </summary>
51         /// <param name="sender"></param>
52         /// <param name="e"></param>
53         private void timer1_tick(object sender, eventargs e)
54         {
55             ticknum++;
56             int temp = ticknum;
57             string tick = common.gettimespan(temp);
58             this.lbltime.text = tick;
59         }
60 
61         /// <summary>
62         /// 暂停录制
63         /// </summary>
64         /// <param name="sender"></param>
65         /// <param name="e"></param>
66         private void btnpausevideo_click(object sender, eventargs e)
67         {
68             if (this.btnpausevideo.text.trim() == "暂停录像")
69             {
70                 isrecordvideo = false;
71                 this.btnpausevideo.text = "恢复录像";
72                 this.timer1.enabled = false;    //暂停计时
73                 return;
74             }
75             if (this.btnpausevideo.text.trim() == "恢复录像")
76             {
77                 isrecordvideo = true;
78                 this.btnpausevideo.text = "暂停录像";
79                 this.timer1.enabled = true;     //恢复计时
80             }
81         }

注意事项

1. 由于视频录制是采用ffmpeg类库进行处理,所以除了需要aforge.video.ffmpeg.dll以外,还需要ffmpeg类库(c++),位于【aforge.net framework-2.2.5\externals\ffmpeg\bin】目录下,copy到应用程序目下即可,如下图所示:

C# 利用AForge进行摄像头信息采集

 

2. 由于aforge.video.ffmpeg.dll类库只支持.netframework2.0,所以需要采用混合模式,app.config配置如下:

1 <?xml version="1.0" encoding="utf-8"?>
2 <configuration>
3     <startup  uselegacyv2runtimeactivationpolicy="true"> 
4     <supportedruntime version="v4.0" sku=".netframework,version=v4.6.1"/></startup>
5     <supportedruntime version="v2.0.50727"/>
6 </configuration>

3. 由于ffmpeg只支持x86模式,不支持混合模式,所以需要在配置管理器进行配置x86平台,如下所示:

C# 利用AForge进行摄像头信息采集

 

4. 由于视频帧频率过快,所以需要进行加锁控制,否则会造成【读写受保护的内存】错误。

经过以上4步,才可以进行视频录制。如果是进行拍照,则不需要。

备注

心有猛虎,细嗅蔷薇。