一、 效果展示
二、NuGet安装 AForge.Video、AForge.Video.DirectShow
三、核心代码
引用dll
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
using AForge.Video;
using AForge.Video.DirectShow;
using AForge.Video.FFMPEG;
Form2.cs
namespace WinFormsApp4
{
public partial class Form2 : Form
{
// 启动摄像头按钮点击事件
private VideoCaptureDevice videoSource;
private FilterInfoCollection videoDevices;
private VideoFileWriter videoWriter;
private Bitmap currentFrame;
public Form2()
{
InitializeComponent();
InitializeCameraList();
}
// 初始化摄像头列表
private void InitializeCameraList()
{
try
{
videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
foreach (FilterInfo device in videoDevices)
{
cmbCameras.Items.Add(device.Name);
}
if (cmbCameras.Items.Count > 0)
{
cmbCameras.SelectedIndex = 0;
}
else
{
MessageBox.Show("未检测到摄像头设备");
}
}
catch (Exception ex)
{
MessageBox.Show(#34;初始化摄像头失败: {ex.Message}");
}
}
/// <summary>
/// 启动摄像头按钮点击事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStart_Click(object sender, EventArgs e)
{
if (videoDevices == null || videoDevices.Count == 0) return;
try
{
videoSource = new VideoCaptureDevice(videoDevices[cmbCameras.SelectedIndex].MonikerString);
videoSource.NewFrame += new NewFrameEventHandler(VideoSource_NewFrame);
videoSource.Start();
btnStart.Enabled = false;
btnStop.Enabled = true;
btnCapture.Enabled = true;
btVideoStart.Enabled= true;
btVideoStop.Enabled= true;
}
catch (Exception ex)
{
MessageBox.Show(#34;摄像头启动失败: {ex.Message}");
}
}
// 实时视频帧处理
private void VideoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
try
{
currentFrame = (Bitmap)eventArgs.Frame.Clone();
// 跨线程更新UI
if (videoPreview.InvokeRequired)
{
videoPreview.Invoke(new Action(() =>
{
videoPreview.Image?.Dispose();
videoPreview.Image = currentFrame;
}));
}
else
{
videoPreview.Image = currentFrame;
}
}
catch (Exception ex)
{
Console.WriteLine(#34;帧处理错误: {ex.Message}");
}
}
// 拍照按钮点击事件
private void btnCapture_Click(object sender, EventArgs e)
{
if (currentFrame != null)
{
using (SaveFileDialog saveDialog = new SaveFileDialog())
{
saveDialog.Filter = "JPEG图片|*.jpg|PNG图片|*.png|BMP图片|*.bmp";
saveDialog.Title = "保存图片";
saveDialog.FileName = #34;Capture_{DateTime.Now:yyyyMMddHHmmss}";
if (saveDialog.ShowDialog() == DialogResult.OK)
{
try
{
ImageFormat format = ImageFormat.Jpeg;
switch (Path.GetExtension(saveDialog.FileName).ToLower())
{
case ".png":
format = ImageFormat.Png;
break;
case ".bmp":
format = ImageFormat.Bmp;
break;
}
currentFrame.Save(saveDialog.FileName, format);
MessageBox.Show("照片保存成功!");
}
catch (Exception ex)
{
MessageBox.Show(#34;保存失败: {ex.Message}");
}
}
}
}
}
// 停止摄像头按钮点击事件
private void btnStop_Click(object sender, EventArgs e)
{
try
{
if (videoSource != null && videoSource.IsRunning)
{
videoSource.SignalToStop();
videoSource.NewFrame -= VideoSource_NewFrame;
videoSource = null;
}
btnStart.Enabled = true;
btnStop.Enabled = false;
btnCapture.Enabled = false;
btVideoStart.Enabled = false;
btVideoStop.Enabled = false;
}
catch (Exception ex)
{
MessageBox.Show(#34;停止摄像头时发生错误: {ex.Message}");
}
}
protected void videoStart()
{
// 初始化视频写入对象
videoWriter = new VideoFileWriter();
var width = videoSource.VideoResolution.FrameSize.Width;
var height = videoSource.VideoResolution.FrameSize.Height;
var fps = videoSource.VideoResolution.AverageFrameRate;
videoWriter.Open("output.mp4", width, height, fps, VideoCodec.MPEG4); // 输出MP4格式:ml-citation{ref="5,7" data="citationList"}
// 注册帧捕获回调
videoSource.NewFrame += (sender, eventArgs) =>
{
Bitmap frame = (Bitmap)eventArgs.Frame.Clone();
videoWriter.WriteVideoFrame(frame); // 写入视频帧:ml-citation{ref="5" data="citationList"}
frame.Dispose(); // 释放资源避免内存泄漏
};
}
private void btVideoStart_Click(object sender, EventArgs e)
{
videoStart();
// 启动摄像头和录像
videoSource.Start();
}
private void btVideoStop_Click(object sender, EventArgs e)
{
// 停止录像时释放资源
if (videoSource != null && videoSource.IsRunning)
{
videoSource.SignalToStop();
videoSource.WaitForStop();
}
videoWriter?.Close();
videoWriter?.Dispose();
}
// 窗体关闭时释放资源
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
base.OnFormClosing(e);
btnStop_Click(null, EventArgs.Empty);
currentFrame?.Dispose();
}
}
}
Form2.Designer.cs
using System.Windows.Forms;
namespace WinFormsApp4
{
partial class Form2
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
splitContainer1 = new SplitContainer();
btVideoStop = new Button();
btVideoStart = new Button();
cmbCameras = new ComboBox();
btnStart = new Button();
btnStop = new Button();
btnCapture = new Button();
videoPreview = new PictureBox();
panel1 = new Panel();
((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit();
splitContainer1.Panel1.SuspendLayout();
splitContainer1.Panel2.SuspendLayout();
splitContainer1.SuspendLayout();
((System.ComponentModel.ISupportInitialize)videoPreview).BeginInit();
SuspendLayout();
//
// splitContainer1
//
splitContainer1.Dock = DockStyle.Fill;
splitContainer1.Location = new Point(0, 0);
splitContainer1.Name = "splitContainer1";
splitContainer1.Orientation = Orientation.Horizontal;
//
// splitContainer1.Panel1
//
splitContainer1.Panel1.Controls.Add(btVideoStop);
splitContainer1.Panel1.Controls.Add(btVideoStart);
splitContainer1.Panel1.Controls.Add(cmbCameras);
splitContainer1.Panel1.Controls.Add(btnStart);
splitContainer1.Panel1.Controls.Add(btnStop);
splitContainer1.Panel1.Controls.Add(btnCapture);
//
// splitContainer1.Panel2
//
splitContainer1.Panel2.Controls.Add(videoPreview);
splitContainer1.Panel2.Controls.Add(panel1);
splitContainer1.Size = new Size(1149, 687);
splitContainer1.SplitterDistance = 140;
splitContainer1.TabIndex = 0;
//
// btVideoStop
//
btVideoStop.Enabled = false;
btVideoStop.Location = new Point(842, 63);
btVideoStop.Margin = new Padding(4, 5, 4, 5);
btVideoStop.Name = "btVideoStop";
btVideoStop.Size = new Size(112, 38);
btVideoStop.TabIndex = 9;
btVideoStop.Text = "停止录视频";
btVideoStop.UseVisualStyleBackColor = true;
btVideoStop.Click += btVideoStop_Click;
//
// btVideoStart
//
btVideoStart.Enabled = false;
btVideoStart.Location = new Point(705, 63);
btVideoStart.Margin = new Padding(4, 5, 4, 5);
btVideoStart.Name = "btVideoStart";
btVideoStart.Size = new Size(112, 38);
btVideoStart.TabIndex = 8;
btVideoStart.Text = "开始录视频";
btVideoStart.UseVisualStyleBackColor = true;
btVideoStart.Click += btVideoStart_Click;
//
// cmbCameras
//
cmbCameras.Dock = DockStyle.Top;
cmbCameras.FormattingEnabled = true;
cmbCameras.Location = new Point(0, 0);
cmbCameras.Margin = new Padding(4, 5, 4, 5);
cmbCameras.Name = "cmbCameras";
cmbCameras.Size = new Size(1149, 28);
cmbCameras.TabIndex = 4;
//
// btnStart
//
btnStart.Location = new Point(95, 63);
btnStart.Margin = new Padding(4, 5, 4, 5);
btnStart.Name = "btnStart";
btnStart.Size = new Size(112, 38);
btnStart.TabIndex = 5;
btnStart.Text = "启动";
btnStart.UseVisualStyleBackColor = true;
btnStart.Click += btnStart_Click;
//
// btnStop
//
btnStop.Enabled = false;
btnStop.Location = new Point(393, 63);
btnStop.Margin = new Padding(4, 5, 4, 5);
btnStop.Name = "btnStop";
btnStop.Size = new Size(112, 38);
btnStop.TabIndex = 7;
btnStop.Text = "停止";
btnStop.UseVisualStyleBackColor = true;
btnStop.Click += btnStop_Click;
//
// btnCapture
//
btnCapture.Enabled = false;
btnCapture.Location = new Point(246, 63);
btnCapture.Margin = new Padding(4, 5, 4, 5);
btnCapture.Name = "btnCapture";
btnCapture.Size = new Size(112, 38);
btnCapture.TabIndex = 6;
btnCapture.Text = "拍照";
btnCapture.UseVisualStyleBackColor = true;
btnCapture.Click += btnCapture_Click;
//
// videoPreview
//
videoPreview.Dock = DockStyle.Fill;
videoPreview.Location = new Point(0, 0);
videoPreview.Margin = new Padding(4, 5, 4, 5);
videoPreview.Name = "videoPreview";
videoPreview.Size = new Size(1149, 543);
videoPreview.SizeMode = PictureBoxSizeMode.Zoom;
videoPreview.TabIndex = 5;
videoPreview.TabStop = false;
//
// panel1
//
panel1.Dock = DockStyle.Fill;
panel1.Location = new Point(0, 0);
panel1.Name = "panel1";
panel1.Size = new Size(1149, 543);
panel1.TabIndex = 6;
//
// Form2
//
AutoScaleDimensions = new SizeF(9F, 20F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(1149, 687);
Controls.Add(splitContainer1);
Name = "Form2";
Text = "Form2";
FormClosing += Form2_FormClosing;
splitContainer1.Panel1.ResumeLayout(false);
splitContainer1.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)splitContainer1).EndInit();
splitContainer1.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)videoPreview).EndInit();
ResumeLayout(false);
}
#endregion
private SplitContainer splitContainer1;
private ComboBox cmbCameras;
private Button btnStart;
private Button btnStop;
private Button btnCapture;
private PictureBox videoPreview;
private Panel panel1;
private Button btVideoStart;
private Button btVideoStop;
}
}
功能特点:
- 自动检测可用摄像头
- 实时视频预览
- 支持保存为JPG/PNG/BMP格式
- 自动生成带时间戳的文件名
- 完善的异常处理
- 资源自动释放
AForge.NET 框架概述
AForge.NET 是一个基于 C# 的开源框架,专注于计算机视觉、图像处理和视频采集领域。其核心模块包含视频输入设备控制、图像算法处理、多媒体文件编解码等功能,适用于摄像头实时采集、视频录制、图像分析等场景
模块介绍
AForge.NET是一个专门为开发者和研究者基于C#框架设计的,他包括计算机视觉与人工智能,图像处理,神经网络,遗传算法,机器学习,模糊系统,机器人控制等领域。
主要架构
这个框架由一系列的类库组成。主要包括有:
AForge.Imaging —— 一些日常的图像处理和过滤器
AForge.Vision —— 计算机视觉应用类库
AForge.Neuro —— 神经网络计算库AForge.Genetic -进化算法编程库
AForge.MachineLearning —— 机器学习类库
AForge.Robotics —— 提供一些机器人的工具类库
AForge.Video —— 一系列的视频处理类库
AForge.Fuzzy —— 模糊推理系统类库
AForge.Controls—— 图像,三维,图表显示控件
模块特点
该框架架构合理,易于扩展,涉及多个较前沿的技术模块,可以为相关开发人员或科研人员的工作提供极大便利。该框架使用LGPLv3 协议,2.0以前版本遵循GPLv3 协议,如果对于协议有协商需要可以联系项目作者。