调用AForge.video.DirectShow免费实现摄像头采集和上下左右镜像功能

By admin at 2022-07-23 • 3人收藏 • 2374人看过

这次我们使用开源免费AForge.video.DirectShow实现摄像头采集和上下左右镜像功能


前面我分享了一个收费的sharpCamera.dll程序集实现此功能, 它是个收费控件, 虽然费用也不高. 但是我们能先用免费的就不用收费的原则 , 下面来探讨下AForge的使用方法.


二楼有写好的AForge封装库下载


和sharpCamera那个类似, AForge也是异步使用picturebox来实现


image.png


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();


完整测试工程如下:

aardio工程2.zip


12 个回复 | 最后更新于 2023-11-24
2022-07-25   #1

简单封装了个AForgeVideo摄像头库:

image.png

//AForge摄像头库
import dotNet
import System.Drawing;
import System.Windows.Forms;

class AForgeVideo{
	ctor( winform ){
		this.pictureBox = ..System.Windows.Forms.CreateEmbed("PictureBox",winform); 
		this.pictureBox.BackColor = ..System.Drawing.Color.Black;
		this.pictureBox.SizeMode = ..System.Windows.Forms.PictureBoxSizeMode.StretchImage;
		this.carema = ..dotNet.load("\res\AForge.dll");
		this.AForgeCamera = this.carema.import("AForge.Video");
		this.flip = 0;
		this.videoDevice = null;
		..table.gc(this,"stop");
	};
	
	getNameList = function(){
		var videoDevices = this.AForgeCamera.DirectShow.FilterInfoCollection(this.AForgeCamera.DirectShow.FilterCategory.VideoInputDevice);
		var retTab = {};
		if(videoDevices.Count>0){
			for(i=0;videoDevices.Count-1;1){
				//压入摄像头设备号名称列表	
				..table.push(retTab , videoDevices.Item[i].MonikerString);
			}
			return retTab; 
		}
		return null;
	}
	
	getVideoCapabilitiesList = function(deviceName){
		if(deviceName!=null){
			var videoDevice = this.AForgeCamera.DirectShow.VideoCaptureDevice(deviceName);
			var videoCapabilitiesEx = videoDevice.VideoCapabilities;
			var retTab = {};
			if(videoCapabilitiesEx.LongLength>0){
				for(i=0;videoCapabilitiesEx.LongLength-1;1){
					..table.push(retTab,{
						["Width"] = videoCapabilitiesEx.Item[i].FrameSize.Width,
						["Height"] = videoCapabilitiesEx.Item[i].FrameSize.Height,
						["FrameRate"] = videoCapabilitiesEx.Item[i].FrameRate,
					});
				}
				return retTab;
			}
			return null; 
		}
		return null;
	}
	
	start = function(DeviceIndex=1,index=1){
		if(this.videoDevice){
			this.videoDevice.Stop();
		}
		
		var namelist = this.getNameList();
		if(DeviceIndex <= #namelist){
			name = namelist[DeviceIndex];
		}else {
			//超出摄像头数量,不开启
			return false;
		}	
		//设定帧率和分辨率
		var VideoCapabilities = this.getVideoCapabilitiesList(name);
		this.videoDevice = this.AForgeCamera.DirectShow.VideoCaptureDevice(name);
		
		if(VideoCapabilities!=null){
			if(index>#VideoCapabilities){
				index = 1;
			}
			this.videoDevice.DesiredFrameRate = VideoCapabilities[index].FrameRate;
			this.videoDevice.DesiredFrameSize = ..System.Drawing.Size(VideoCapabilities[index].Width,VideoCapabilities[index].Height);
			this.videoDevice.DesiredSnapshotSize = ..System.Drawing.Size(VideoCapabilities[index].Width,VideoCapabilities[index].Height);
		}
		
		this.videoDevice.NewFrame = function(sender, NewFrameEventArgs){
			var temp = NewFrameEventArgs.Frame.Clone();
    		select(this.flip) {
        		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 (this.pictureBox.Image != null)
    		{
        		this.pictureBox.Image.Dispose();
    		}
    		this.pictureBox.Image = temp;
		}
		this.videoDevice.Start();
		return true;
	}
	
	stop = function(){
		if(this.videoDevice){
			this.videoDevice.Stop();
			this.videoDevice = null;
		}
	}
	
	flipLoop = function(){
		select(this.flip) {
        	case 0 {
            	this.flip=1;
        	}
        	case 1 {
            	this.flip=2;
        	}
        	case 2 {
            	this.flip=3;
        	}
        	case 3 {
            	this.flip=0;
        	}
        	else {
        	}
    	}
	}
}

/**intellisense()
AForgeVideo = AForge摄像头库
AForgeVideo(.(winform) = 创建 摄像头 界面
AForgeVideo() = !AVideo.
end intellisense**/

/**intellisense(!AVideo)
getNameList() = 获取摄像头设备硬件DeviceName名称列表
getVideoCapabilitiesList(.(DeviceName) = 获取指定设备的 分辨率和帧率 列表,如果不存在那么返回 null
start(.(DeviceIndex,CapabilitiesIndex) = 开启摄像头\n DeviceIndex:设备序号 , CapabilitiesIndex:分辨率和帧率表序号
stop() = 关闭摄像头
flipLoop() = 循环镜像图像,调用一次改变一次镜像方向
end intellisense**/

使用的时候:

import win.ui;
/*DSG{{*/
mainForm = win.form(text="aardio工程2";right=1209;bottom=556)
mainForm.add(
button={cls="button";text="start";left=16;top=519;right=127;bottom=545;db=1;dl=1;z=2};
button2={cls="button";text="flip";left=142;top=519;right=254;bottom=545;db=1;dl=1;z=3};
button3={cls="button";text="stop";left=265;top=519;right=381;bottom=545;db=1;dl=1;z=4};
button4={cls="button";text="start";left=833;top=518;right=944;bottom=544;db=1;dr=1;z=6};
button5={cls="button";text="flip";left=959;top=518;right=1071;bottom=544;db=1;dr=1;z=7};
button6={cls="button";text="stop";left=1082;top=518;right=1198;bottom=544;db=1;dr=1;z=8};
custom={cls="custom";text="自定义控件";left=0;top=0;right=601;bottom=496;bgcolor=12639424;db=1;dl=1;dr=0.5;dt=1;z=1};
custom2={cls="custom";text="自定义控件";left=609;top=0;right=1210;bottom=496;bgcolor=12639424;db=1;dl=0.5;dr=1;dt=1;z=5}
)
/*}}*/

import AForgeVideo;
var video = AForgeVideo(mainForm.custom);

mainForm.button.oncommand = function(id,event){
	//默认开启序号1摄像头,分辨率为序号1的分辨率和帧率
	video.start();
}

mainForm.button2.oncommand = function(id,event){
	//摄像头1镜像
	video.flipLoop();
}

mainForm.button3.oncommand = function(id,event){
	//摄像头1停止
	video.stop();
}

//定义2号摄像头
var video2 = AForgeVideo(mainForm.custom2);
mainForm.button4.oncommand = function(id,event){
	//开启序号2摄像头,分辨率为序号1的分辨率和帧率
	video2.start(2);
}

mainForm.button5.oncommand = function(id,event){
	//摄像头2镜像
	video2.flipLoop();
}

mainForm.button6.oncommand = function(id,event){
	//摄像头2停止
	video2.stop();
}

mainForm.show();
return win.loopMessage();


完整示例工程和库代码如下:

AForge.zip


2022-07-26   #2

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();
        }
    }
}

WindowsFormsApp2.zip


2022-09-20   #3

更新:

给摄像头增加可移动水平辅助线和双击全屏功能

image.png

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;


2022-09-20   #4

厉害了大佬

2022-09-21   #5

2022-10-05   #6

厉害!!能不能分享一下 相机亮度 对比度 白平衡这些调节 拍照功能 怎么实现,谢谢。

2022-10-05   #7

回复#7 @user11 :

我这里只是简单的演示, 你百度下有方法的,简单的方法是调用属性

videoDevice.DisplayPropertyPage(0);

会弹出来属性窗.

至于代码的, 也能搜得到, 你自己试一试吧

2022-11-14   #8

请教一下怎么拍照保存图像到剪贴板呢?

2022-11-14   #9

回复#8 @neilyih :

提问的时候干嘛要在问题前面加上一些和代码无关的牢骚呢?(我已经帮你删掉)

win.clip.writeBitmap 图片写入剪贴板

2022-11-14   #10

2023-07-26   #11

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;

}


2023-11-24   #12

如果有两个摄像头, 软件里需要交换图像, 那么可以:

 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;
            }
        }


登录后方可回帖

登 录
信息栏
 私人小站

本站域名

ChengXu.XYZ

投诉联系:  popdes@126.com



快速上位机开发学习,本站主要记录了学习过程中遇到的问题和解决办法及上位机代码分享

这里主要专注于学习交流和经验分享.
纯私人站,当笔记本用的,学到哪写到哪.
如果侵权,联系 Popdes@126.com

友情链接
Aardio官方
Aardio资源网


才仁机械


网站地图SiteMap

Loading...