调用AForge.video.DirectShow免费实现摄像头采集和上下左右镜像功能
By
admin
at 2022-07-23 • 3人收藏 • 2454人看过
这次我们使用开源免费的AForge.video.DirectShow实现摄像头采集和上下左右镜像功能
前面我分享了一个收费的sharpCamera.dll程序集实现此功能, 它是个收费控件, 虽然费用也不高. 但是我们能先用免费的就不用收费的原则 , 下面来探讨下AForge的使用方法.
二楼有写好的AForge封装库下载
和sharpCamera那个类似, AForge也是异步使用picturebox来实现
import win.ui; /*DSG{{*/ mainForm = win.form(text="aardio工程2";right=959;bottom=564) mainForm.add( button={cls="button";text="start";left=307;top=527;right=418;bottom=553;db=1;dl=1;z=2}; button2={cls="button";text="stop";left=430;top=527;right=542;bottom=553;db=1;dl=1;dr=1;z=3}; button3={cls="button";text="flip";left=553;top=527;right=669;bottom=553;db=1;dr=1;z=4}; combobox={cls="combobox";left=53;top=527;right=286;bottom=553;db=1;dl=1;edge=1;items={};mode="dropdownlist";z=5}; custom={cls="custom";text="自定义控件";left=0;top=0;right=960;bottom=520;bgcolor=12639424;db=1;dl=1;dr=1;dt=1;z=1} ) /*}}*/ import dotNet import System.Drawing; import System.Windows.Forms; var pictureBox1 = System.Windows.Forms.CreateEmbed("PictureBox",mainForm.custom); pictureBox1.BackColor = System.Drawing.Color.Black; pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; dotNet.reference({ "AForge" = "\res\AForge.dll"; }) var carema = dotNet.load("AForge"); var AForgeCamera = carema.import("AForge.Video"); var videoDevices = AForgeCamera.DirectShow.FilterInfoCollection(AForgeCamera.DirectShow.FilterCategory.VideoInputDevice); //默认取第一个序号的摄像头 var videoDevice = AForgeCamera.DirectShow.VideoCaptureDevice(videoDevices.Item[0].MonikerString); //摄像头包含的可用帧率和分辨率 var videoCapabilitiesEx = videoDevice.VideoCapabilities; for(i=0;videoCapabilitiesEx.LongLength-1;1){ mainForm.combobox.add("分辨率: "++videoCapabilitiesEx.Item[i].FrameSize.Width++"*"++videoCapabilitiesEx.Item[i].FrameSize.Height ++ " 帧率: " ++ videoCapabilitiesEx.Item[i].FrameRate); } if(mainForm.combobox.count){ mainForm.combobox.selIndex = 1; } var flip1 = 0; videoDevice.NewFrame = function(sender, NewFrameEventArgs){ var temp = NewFrameEventArgs.Frame.Clone(); select(flip1) { case 0 { } case 1 { temp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipX); } case 2 { temp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipXY); } case 3 { temp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipY); } else { } } if (pictureBox1.Image != null) { pictureBox1.Image.Dispose(); } pictureBox1.Image = temp; } mainForm.button.oncommand = function(id,event){ videoDevice.Stop(); if(mainForm.combobox.count){ //设定帧率和分辨率 videoDevice.DesiredFrameRate = videoCapabilitiesEx.Item[mainForm.combobox.selIndex-1].FrameRate; videoDevice.DesiredFrameSize = videoCapabilitiesEx.Item[mainForm.combobox.selIndex-1].FrameSize; videoDevice.DesiredSnapshotSize = videoCapabilitiesEx.Item[mainForm.combobox.selIndex-1].FrameSize; videoDevice.Start(); } } mainForm.button2.oncommand = function(id,event){ videoDevice.Stop(); } mainForm.button3.oncommand = function(id,event){ select(flip1) { case 0 { flip1=1; } case 1 { flip1=2; } case 2 { flip1=3; } case 3 { flip1=0; } else { } } } mainForm.onClose = function(hwnd,message,wParam,lParam){ videoDevice.Stop(); } mainForm.show(); return win.loopMessage();
完整测试工程如下:
12 个回复 | 最后更新于 2023-11-24
C#工程中使用Aforge摄像头
using AForge; using AForge.Video; using AForge.Video.DirectShow; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApp2 { public partial class Form1 : Form { VideoCaptureDevice VideoDevice; public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { FilterInfoCollection VideoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice); //默认取第一个序号的摄像头 VideoDevice = new VideoCaptureDevice(VideoDevices[0].MonikerString); foreach (var VideoCapabilitie in VideoDevice.VideoCapabilities) { Console.WriteLine(VideoCapabilitie.AverageFrameRate); Console.WriteLine(VideoCapabilitie.FrameSize); } VideoDevice.VideoResolution = VideoDevice.VideoCapabilities[4]; VideoDevice.NewFrame += OnNewFrame; VideoDevice.Start(); } void OnNewFrame(object sender, NewFrameEventArgs eventArgs) { //var temp = eventArgs.Frame.Clone(); if (pictureBox1.Image != null) { pictureBox1.Image.Dispose(); } pictureBox1.Image = (Bitmap)eventArgs.Frame.Clone(); } private void button1_Click(object sender, EventArgs e) { VideoDevice.Stop(); } private void button2_Click(object sender, EventArgs e) { VideoDevice.Start(); } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { VideoDevice.Stop(); } } }
更新:
给摄像头增加可移动水平辅助线和双击全屏功能
import win.ui; /*DSG{{*/ var winform = win.form(text="aardio form";right=739;bottom=499) winform.add( video_line={cls="plus";left=0;top=205;right=740;bottom=206;bgcolor=65280;dl=1;dr=1;z=1} ) /*}}*/ import AForgeVideo; var video = AForgeVideo(winform); //禁用清除背景 winform.onEraseBkgnd = lambda() 0; try{//防止意外报错 video.start(1/*摄像头序号*/,1/*分辨率序号*/); video.flip = 1/*水平镜像*/; } catch(e) { winform.msgboxErr("摄像头打开失败!") } //使辅助线显示在摄像头上 winform.video_line.setParent(winform) //双击全屏 video.pictureBox.MouseDoubleClick = function(sender, e){ if(winform.parent){ winform.parent.fullscreen(); }else { winform.fullscreen(); } } //单击移动线 video.pictureBox.MouseClick = function(sender, e){ var x,y = win.getMessagePos(); x,y = win.toClient(winform.hwnd,x,y); winform.video_line.setPos(0,y); } winform.onClose = function(hwnd,message,wParam,lParam){ video.stop(); } winform.show(); win.loopMessage(); return winform;
c# 的winform界面中给摄像头画面增加功能:
鼠标点击画面, 在点击点位置绘制一条斜线 , 双击鼠标隐藏
难点:
摄像头的分辨率和界面上的picturebox的大小并不是一致的, 摄像头图片会被拉伸填充满画面, 那么你在picturebox点击的位置就需要对应的进行缩放, 这样在真实摄像头画面图片里面绘制的线才是真正的位置, 要不然你点击的位置绘线会出现很大偏差.
解决办法就是: 对应点进行比例缩放即可. 这样绘制到图片内的线在picturebox里无论怎么拉伸都是实际位置了.
FilterInfoCollection VideoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice); //默认取第一个序号的摄像头 VideoDevice1 = new VideoCaptureDevice(VideoDevices[端口1].MonikerString); VideoDevice1.VideoResolution = VideoDevice1.VideoCapabilities[分辨率1]; VideoDevice1.NewFrame += OnNewFrame1; VideoDevice1.Start(); bool video1_clickFlag = false; int video1_clickX; int video1_clickY; private void video1_MouseClick(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { video1_clickX = e.X; video1_clickY = e.Y; video1_clickFlag = true; } else if (e.Button == MouseButtons.Right) { Form fm1 = new jiaodu(); fm1.ShowDialog(); } } private void video1_MouseDoubleClick(object sender, MouseEventArgs e) { video1_clickFlag = false; } void OnNewFrame1(object sender, NewFrameEventArgs eventArgs) { var temp = (Bitmap)eventArgs.Frame.Clone(); switch (flip1) { case 0: break; case 1: temp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipX); break; case 2: temp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipY); break; case 3: temp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipXY); break; default: break; } if (video1_clickFlag) { using (var graphics = Graphics.FromImage(temp)) using (var pen = new Pen(Color.Lime, 1)) { var bili_X = temp.Width * 1.0 / video1.Width; var bili_Y = temp.Height * 1.0 / video1.Height; int Mdian_X = (int)(video1_clickX * bili_X); int Mdian_Y = (int)(video1_clickY * bili_Y); var p1 = new Point(Mdian_X, Mdian_Y); //计算直线上的端点P0 var x0 = (int)(Mdian_X - Mdian_Y / Math.Tan(GlobalVar.jiaodu * Math.PI / 180)); //计算直线上的端点P2 var x2 = (int)(Mdian_X + (temp.Height - Mdian_Y) / Math.Tan(GlobalVar.jiaodu * Math.PI / 180)); var p0 = new Point(x0, 0); var p2 = new Point(x2, temp.Height); //在Bitmap上绘制直线 graphics.DrawLine(pen, p0, p1); graphics.DrawLine(pen, p1, p2); var p3 = new Point(0, Mdian_Y); var p4 = new Point(temp.Width, Mdian_Y); //在Bitmap上绘制直线 graphics.DrawLine(pen, p3, p1); graphics.DrawLine(pen, p1, p4); } } if (video1.Image != null) { video1.Image.Dispose(); } video1.Image = temp; }
如果有两个摄像头, 软件里需要交换图像, 那么可以:
VideoDevice1.NewFrame -= OnNewFrame1; VideoDevice2.NewFrame -= OnNewFrame2; VideoDevice1.NewFrame += OnNewFrame2; VideoDevice2.NewFrame += OnNewFrame1;
当窗口关闭的时候记得释放掉:
private void Form1_FormClosing(object sender, FormClosingEventArgs e) { try { VideoDevice1.Stop(); VideoDevice2.Stop(); VideoDevice1.NewFrame -= OnNewFrame1; VideoDevice2.NewFrame -= OnNewFrame2; } catch (Exception) { // throw; } }
登录后方可回帖
简单封装了个AForgeVideo摄像头库:
使用的时候:
完整示例工程和库代码如下: