最近一个项目需要,控制usb摄像头进行拍摄,特别是支持摄像头自身的快照按钮进行快速拍摄,项目是用C#写的,在网上看了一些资料,选择了AForge库来调用摄像头,看了下AForge的帮助文档,正好支持硬件的快照功能。
AForge库
AForge库网上有资源,需要下载以下几个dll。将它们添加引用后,using AForge.Video.DirectShow 就行了,然后在工具箱中添加AForge.Controls的控件。
窗体效果图
窗体这里就没弄设备选择 分辨率这些东西,功能上支持软件按钮拍摄和硬件按钮拍摄。
硬件快照按钮事件
AForge是支持设备快照的,想详细了解的朋友可以看AForge.Video.DirectShow的帮助文档,链接: VideoCaptureDevice成员.
两行代码就行了。一个开启,一个绑定快照帧事件,OK。事件里面根据需求自己写。
//允许摄像头快照按键
videoDevice.ProvideSnapshots = true;
videoDevice.SnapshotFrame += new AForge.Video.NewFrameEventHandler(videoDevice_SnapShoot);
代码
在软件上拍照很简单,网上也有很多资料,直接上代码。
// An highlighted block
private FilterInfoCollection videoDevices;//所有摄像设备
private VideoCaptureDevice videoDevice;//摄像设备
private VideoCapabilities[] videoCapabilities;//摄像头分辨率
private void FrmTakePhoto_Load(object sender, EventArgs e)
{
//窗体关闭绑定事件 关闭摄像头和释放资源
this.FrmTakePhoto_FormClosing += new FormClosedEventHandler(FrmTakePhoto_FormClosing);
this.FormClosed += new FormClosedEventHandler(FrmTakePhoto_FormClosed);
videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);//得到机器所有接入的摄像设备
if (videoDevices.Count != 0)
{
//获取摄像头
videoDevice = new VideoCaptureDevice(videoDevices[0].MonikerString);
//获得摄像头的分辨率
videoCapabilities = videoDevice.VideoCapabilities;//设备的摄像头分辨率数组
if ((videoCapabilities != null) && (videoCapabilities.Length != 0))
{
videoDevice.VideoResolution = videoCapabilities[videoCapabilities.Length - 1];//摄像头分辨率
//允许摄像头一键拍摄
videoDevice.ProvideSnapshots = true;
videoDevice.SnapshotFrame += new AForge.Video.NewFrameEventHandler(videoDevice_SnapShoot);
vispShoot.VideoSource = videoDevice;//把摄像头赋给控件
vispShoot.Start();//开启摄像头
EnableControlStatus(false);
}
else
{
msg.MsgDivShow("未获取摄像头分辨率!", 3);
}
}
else
{
msg.MsgDivShow("未找到摄像头设备!", 5);
}
}
//快照触发事件
private void videoDevice_SnapShoot(object sender, AForge.Video.NewFrameEventArgs eventArgs)
{
picbPreview.Image = (Bitmap)eventArgs.Frame.Clone();
//这里修改控件需要跨线程,用Invoke,如果不需要则忽略
MethodInvoker mi = new MethodInvoker(() =>
{
btnCheck.Enabled = true;
});
this.BeginInvoke(mi);
}
//控件的显示切换
private void EnableControlStatus(bool status)
{
btnPic.Enabled = !status;
btnCheck.Enabled = status;
btnYes.Enabled = status;
}
//拍照按钮事件
private void btnPic_Click(object sender, EventArgs e)
{
//Bitmap img = //拍照
picbPreview.Image = vispShoot.GetCurrentVideoFrame();
btnCheck.Enabled = true;
}
private void FrmTakePhoto_FormClosing(object sender, FormClosingEventArgs e)
{
DisConnect();//关闭并释放
}
//关闭并释放
private void DisConnect()
{
if (vispShoot.VideoSource != null)
{
vispShoot.SignalToStop();
vispShoot.WaitForStop();
vispShoot.VideoSource = null;
}
}
private void btnCheck_Click(object sender, EventArgs e)
{
//这里可以根据情况,把照片存到某个路径下
if (!Directory.Exists(filePath))
{
Directory.CreateDirectory(filePath);
}
string fileName = "photo_" + imgPara + basicStepId.ToString() + order.ToString() + ".jpg";
try
{
Image img = picbPreview.Image;
img.Save(filePath + fileName, ImageFormat.Jpeg);
img.Dispose();
}
catch (Exception ex)
{
msg.MsgDivShow("图片本地保存失败",2);
}
//也可以上传到数据库 代码就不写了
}
private void btnYes_Click(object sender, EventArgs e)
{
//关闭该页面
this.Close();
}
//释放资源
private void FrmTakePhoto_FormClosed(object sender, FormClosedEventArgs e)
{
this.Dispose();
}
注意点:在实测过程中,通用的usb摄像头需要在启动后2~3秒后才能触发硬件快照事件,具体原因还不清楚,软件拍摄不影响,实际使用的时候请注意,我的解决方法是采用软件加载延时来避免这一情况,大家有更好的方法可以分享一下哈。