关于在C#中实现多相机的使用方法
- 前言
- 了解一些概念
- C#多相机的调用与实现
前言
当我们在布置自己的视觉软件时,难免会遇到需要多工位检测的时候。针对于多相机的控制与显示如何实现,相信对于新手来说是一个十分复杂的问题。但相信经过我的分析,大家能够轻松搞定。
了解一些概念
首先,我们要知道,基于SDK的相机开发其实是用户通过相机厂家提供的函数包,以实现客户想要的功能。也就是说,并没有想象的那么复杂,函数别人已经给你写好了,你只要会使用就好了。在这之前,我们需要安装相机的驱动器,以获取开放的SDK,这里我们以大华相机为例。你可以在官网下载驱动器,或者在资源:中下载安装大华相机的驱动器。
然后,我们可以在驱动器的安装目录下得到SDK开发包。
C#多相机的调用与实现
资源:
首先,将相机的功能封装在Camera
类中,其代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ThridLibray;
using System.Diagnostics;
namespace MultiCSDemo
{
class DahuaCamera
{
public static List<DahuaCamera> m_vecs = new List<DahuaCamera>();
IDevice m_dev;
CameraOperator m_cameraOperator;
public enum EStatus
{
eStatusOK = 0,
eStatusFailed = -1,
eStatusNullPtr = -2,
eStatusDisconnect = -3,
eStatusAlreadyDone = -4,
eStatusTimeout = -5,
eStatusNotAvailable = -6,
};
//搜索所有相机
public static int EnumCameras()
{
List<IDeviceInfo> deviceInfoListCnt = Enumerator.EnumerateDevices();
if (deviceInfoListCnt.Count <= 0)
return -1;
//做多支持四个相机
for(int i=0; i<deviceInfoListCnt.Count; i++)
{
if(i >= 4)
{
break;
}
IDevice dev = Enumerator.GetDeviceByIndex(i);
Trace.WriteLine(dev.DeviceInfo.DeviceType + "\n");
m_vecs.Add(new DahuaCamera(dev));
}
return deviceInfoListCnt.Count;
}
#region 属性设置和获取函数
/*SDK有六种属性类型,对应六种通用属性设置方法,属性类型和名称可以通过MVviewer查看
注意,部分属性在开始采图后不能设置,对应MVviewer可以看到该栏属性名称变暗,但可以获取该属性*/
/*整型属性*/
public int setIntegerAttr(string attrName, long nValue)
{
if ((m_dev == null) || (!m_dev.IsOpen))
return -1;
using (IIntegraParameter p = m_dev.ParameterCollection[new IntegerName(attrName)])
{
if (false == p.SetValue(nValue))
{
return -1;
}
}
return 0;
}
public long getIntegerAttr(string attrName)
{
if ((m_dev == null) || (!m_dev.IsOpen))
{
return -1;
}
long nValue = -1;
using (IIntegraParameter p = m_dev.ParameterCollection[new IntegerName(attrName)])
{
/*获取失败失败返回0*/
nValue = p.GetValue();
}
return nValue;
}
/*浮点型属性*/
public int setFloatAttr(string attrName, double dValue)
{
if ((m_dev == null) || (!m_dev.IsOpen))
return -1;
using (IFloatParameter p = m_dev.ParameterCollection[new FloatName(attrName)])
{
if (false == p.SetValue(dValue))
{
return -1;
}
}
return 0;
}
public double getFloatAttr(string attrName)
{
if ((m_dev == null) || (!m_dev.IsOpen))
return -1.0;
double dValue = -1.0;
using (IFloatParameter p = m_dev.ParameterCollection[new FloatName(attrName)])
{
/*获取失败失败返回0.0*/
dValue = p.GetValue();
}
return dValue;
}
/*布尔型属性*/
public int setBoolAttr(string attrName, bool bValue)
{
if ((m_dev == null) || (!m_dev.IsOpen))
return -1;
using (IBooleanParameter p = m_dev.ParameterCollection[new BooleanName(attrName)])
{
if (false == p.SetValue(bValue))
{
return -1;
}
}
return 0;
}
public bool getBoolAttr(string attrName)
{
if ((m_dev == null) || (!m_dev.IsOpen))
return false;
bool bValue = false;
using (IBooleanParameter p = m_dev.ParameterCollection[new BooleanName(attrName)])
{
bValue = p.GetValue();
}
return bValue;
}
/*枚举类型*/
public int setEnumAttr(string attrName, string sValue)
{
if ((m_dev == null) || (!m_dev.IsOpen))
return -1;
using (IEnumParameter p = m_dev.ParameterCollection[new EnumName(attrName)])
{
if (false == p.SetValue(sValue))
{
return -1;
}
}
return 0;
}
public string getEnumAttr(string attrName)
{
if ((m_dev == null) || (!m_dev.IsOpen))
return null;
string sValue = null;
using (IEnumParameter p = m_dev.ParameterCollection[new EnumName(attrName)])
{
sValue = p.GetValue();
}
return sValue;
}
/*字符串类型*/
public int setStringAttr(string attrName, string sValue)
{
if ((m_dev == null) || (!m_dev.IsOpen))
return -1;
using (IStringParameter p = m_dev.ParameterCollection[new StringName(attrName)])
{
if (false == p.SetValue(sValue))
{
return -1;
}
}
return 0;
}
public string getStringAttr(string attrName)
{
if ((m_dev == null) || (!m_dev.IsOpen))
return null;
string sValue = null;
using (IStringParameter p = m_dev.ParameterCollection[new StringName(attrName)])
{
sValue = p.GetValue();
}
return sValue;
}
/*命令型属性*/
public int executeCommand(string attrName)
{
if ((m_dev == null) || (!m_dev.IsOpen))
return -1;
using (ICommandParameter p = m_dev.ParameterCollection[new CommandName(attrName)])
{
if (false == p.Execute())
{
return -1;
}
}
return 0;
}
#endregion
public DahuaCamera(IDevice dev)
{
m_dev = dev;
}
~DahuaCamera() { }
public EStatus Open()
{
if (m_dev == null)
return EStatus.eStatusNullPtr;
if (m_dev.IsOpen)
return EStatus.eStatusAlreadyDone;
if (false == m_dev.Open())
return EStatus.eStatusFailed;
return EStatus.eStatusOK;
}
public EStatus Close()
{
if (m_dev == null)
return EStatus.eStatusNullPtr;
if (false == m_dev.IsOpen)
return EStatus.eStatusAlreadyDone;
StopGrabbing();
if (false == m_dev.Close())
return EStatus.eStatusFailed;
return EStatus.eStatusOK;
}
public EStatus StartGrabbing()
{
if (m_dev == null)
return EStatus.eStatusNullPtr;
if (false == m_dev.IsOpen)
return EStatus.eStatusDisconnect;
if (m_dev.IsGrabbing)
return EStatus.eStatusAlreadyDone;
//注册回调函数
m_dev.StreamGrabber.ImageGrabbed += m_cameraOperator.OnImageGrabbed;
if (false == m_dev.GrabUsingGrabLoopThread())
return EStatus.eStatusFailed;
return EStatus.eStatusOK;
}
public EStatus StopGrabbing()
{
if (m_dev == null)
return EStatus.eStatusNullPtr;
if (false == m_dev.IsOpen)
return EStatus.eStatusDisconnect;
if (false == m_dev.IsGrabbing)
return EStatus.eStatusAlreadyDone;
m_dev.StreamGrabber.ImageGrabbed -= m_cameraOperator.OnImageGrabbed;
if (false == m_dev.ShutdownGrab())
return EStatus.eStatusFailed;
return EStatus.eStatusOK;
}
public bool isOpen()
{
return m_dev.IsOpen;
}
public void SetCameraOperator(CameraOperator cameraOperator)
{
m_cameraOperator = cameraOperator;
}
public bool SetTriggerClose()
{
if (m_dev == null || !m_dev.IsOpen)
return false;
return m_dev.TriggerSet.Close();
}
public bool SetTriggerMode(bool bValue)
{
if (m_dev == null || !m_dev.IsOpen)
return false;
string str = (bValue==true?TriggerSourceEnum.Software : TriggerSourceEnum.Line1);
return m_dev.TriggerSet.Open(str);
}
public bool TriggerOnce()
{
if (m_dev == null || !m_dev.IsOpen)
return false;
if (false == m_dev.ExecuteSoftwareTrigger())
return false;
return true;
}
}
}
其中,如需要其他功能参见相机开发手册,然后再在其中添加即可,开发手册连接:
为了事项多相机控制,在这里,我们需要专门创建一个控制相机的类CameraOperator
,在该类中,我们要实现相机参数与窗体控件之间的交互。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ThridLibray;
using System.Diagnostics;
using System.Threading;
using System.Drawing;
using System.Drawing.Imaging;
namespace MultiCSDemo
{
class CameraOperator
{
DahuaCamera m_camera;
List<IGrabbedRawData> m_frameList = new List<IGrabbedRawData>(); // 图像缓存列表 | frame data list
Thread renderThread = null; // 显示线程 | image display thread
bool m_bShowLoop = true; // 线程控制变量 | thread looping flag
Mutex m_mutex = new Mutex(); // 锁,保证多线程安全 | mutex
private Graphics _g = null;
System.Windows.Forms.PictureBox m_pictureBox;
int m_index;
public delegate int GrabDelegate();
public CameraOperator(int i,System.Windows.Forms.PictureBox pictureBox)
{
m_index = i;
m_camera = DahuaCamera.m_vecs[i];
m_camera.SetCameraOperator(this);
m_pictureBox = pictureBox;
m_stopWatch.Start();
}
~CameraOperator()
{
}
private void ShowThread()
{
while (m_bShowLoop)
{
if (m_frameList.Count == 0)
{
Thread.Sleep(10);
continue;
}
// 图像队列取最新帧
// always get the latest frame in list
m_mutex.WaitOne();
IGrabbedRawData frame = m_frameList.ElementAt(m_frameList.Count - 1);
m_frameList.Clear();
m_mutex.ReleaseMutex();
// 主动调用回收垃圾
// call garbage collection
GC.Collect();
// 控制显示最高帧率为25FPS
// control frame display rate to be 25 FPS
if (false == isTimeToDisplay())
{
continue;
}
try
{
// 图像转码成bitmap图像
// raw frame data converted to bitmap
var bitmap = frame.ToBitmap(false);
// 使用GDI绘图
// create graphic object
if (_g == null)
{
_g = m_pictureBox.CreateGraphics();
}
_g.DrawImage(bitmap, new Rectangle(0, 0, m_pictureBox.Width, m_pictureBox.Height),
new Rectangle(0, 0, bitmap.Width, bitmap.Height), GraphicsUnit.Pixel);
bitmap.Dispose();
}
catch (Exception exception)
{
Catcher.Show(exception);
}
}
}
const int DEFAULT_INTERVAL = 40;
Stopwatch m_stopWatch = new Stopwatch();
private bool isTimeToDisplay()
{
m_stopWatch.Stop();
long m_lDisplayInterval = m_stopWatch.ElapsedMilliseconds;
if (m_lDisplayInterval <= DEFAULT_INTERVAL)
{
m_stopWatch.Start();
return false;
}
else
{
m_stopWatch.Reset();
m_stopWatch.Start();
return true;
}
}
public DahuaCamera.EStatus Open()
{
return m_camera.Open();
}
public DahuaCamera.EStatus Close()
{
return m_camera.Close();
}
public DahuaCamera.EStatus StartGrabbing()
{
m_bShowLoop = true;
if (null == renderThread)
{
renderThread = new Thread(new ThreadStart(ShowThread));
renderThread.Start();
}
return m_camera.StartGrabbing();
}
public DahuaCamera.EStatus StopGrabbing()
{
m_bShowLoop = false;
renderThread.Join();
renderThread = null;
return m_camera.StopGrabbing();
}
public void OnImageGrabbed(Object sender, GrabbedEventArgs e)
{
Trace.WriteLine("the"+ m_index +"camera blockid is " + e.GrabResult.BlockID + "\n");
m_mutex.WaitOne();
m_frameList.Add(e.GrabResult.Clone());
m_mutex.ReleaseMutex();
}
public int SetExposureTime(double dValue)
{
return m_camera.setFloatAttr("ExposureTime", dValue);
}
public bool SetTriggerClose()
{
return m_camera.SetTriggerClose();
}
public bool SetTriggerMode(bool bValue)
{
return m_camera.SetTriggerMode(bValue);
}
public bool TriggerOnce()
{
return m_camera.TriggerOnce();
}
}
}
因此,我们在窗体中的实现如下:
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;
using System.Threading;
using ThridLibray;
using System.Diagnostics;
namespace MultiCSDemo
{
public partial class Form1 : Form
{
//CameraOperator xx;
//CameraOperator xx2;
int m_index = 0;
bool[] m_cbVec = { false, false, false, false };
CameraOperator[] m_cameraVec = new CameraOperator[4];
List<PictureBox> m_pictureBoxVec = new List<PictureBox>();
bool isGrabbing = false;
string[] m_strVec = new string[4];
public Form1()
{
InitializeComponent();
/*窗口置于屏幕中央*/
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
m_pictureBoxVec.Add(pictureBox1);
m_pictureBoxVec.Add(pictureBox2);
m_pictureBoxVec.Add(pictureBox3);
m_pictureBoxVec.Add(pictureBox4);
deviceListAcquire();
//ShowInfo("hello");
}
private void deviceListAcquire()
{
DahuaCamera.EnumCameras();
for(int i=0; i<DahuaCamera.m_vecs.Count; i++)
{
/*获取一个相机对象*/
IDevice dev = Enumerator.GetDeviceByIndex(i);
if (dev.DeviceInfo.DeviceType == 0)
{
cbBoxSelect.Items.Add("GigE: " + dev.DeviceInfo.ManufactureInfo + " " + dev.DeviceInfo.Model + " (" + dev.DeviceInfo.SerialNumber + ")");
}
else if (dev.DeviceInfo.DeviceType == 1)
{
cbBoxSelect.Items.Add("USB: " + dev.DeviceInfo.ManufactureInfo + " " + dev.DeviceInfo.Model + " (" + dev.DeviceInfo.SerialNumber + ")");
}
m_strVec[i] = dev.DeviceInfo.SerialNumber;
m_cameraVec[i] = new CameraOperator(i, m_pictureBoxVec[i]);
}
if (DahuaCamera.m_vecs.Count != 0)
cbBoxSelect.SelectedIndex = 0;
}
public void ShowInfo(string info)
{
textBox1.AppendText(info);
textBox1.AppendText(Environment.NewLine);
textBox1.ScrollToCaret();
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
for (int i = 0; i < DahuaCamera.m_vecs.Count; i++)
{
if(isGrabbing)
{
m_cameraVec[i].StopGrabbing();
}
m_cameraVec[i].Close();
}
}
private void btnOpenCam_Click(object sender, EventArgs e)
{
for (int i = 0; i < DahuaCamera.m_vecs.Count; i++)
{
if(DahuaCamera.EStatus.eStatusOK != m_cameraVec[i].Open())
{
ShowInfo(DateTime.Now + " Camera " + m_strVec[i] + " Open fail");
}
else
{
ShowInfo(DateTime.Now + " Camera " + m_strVec[i] + " Open success");
}
if (checkBoxMode.Checked)
{
m_cameraVec[i].SetTriggerMode(false);
}
else
{
m_cameraVec[i].SetTriggerClose();
}
}
}
private void btnCloseCam_Click(object sender, EventArgs e)
{
for (int i = 0; i < DahuaCamera.m_vecs.Count; i++)
{
if(DahuaCamera.EStatus.eStatusOK != m_cameraVec[i].Close())
{
ShowInfo(DateTime.Now + " Camera " + m_strVec[i] + " Close fail");
}
else
{
ShowInfo(DateTime.Now + " Camera " + m_strVec[i] + " Close success");
}
}
}
private void btnStartGrab_Click(object sender, EventArgs e)
{
for (int i = 0; i < DahuaCamera.m_vecs.Count; i++)
{
if(DahuaCamera.EStatus.eStatusOK != m_cameraVec[i].StartGrabbing())
{
ShowInfo(DateTime.Now + " Camera " + m_strVec[i] + " StartGrabbing fail");
}
else
{
ShowInfo(DateTime.Now + " Camera " + m_strVec[i] + " StartGrabbing success");
}
}
isGrabbing = true;
}
private void btnStopGrab_Click(object sender, EventArgs e)
{
for (int i = 0; i < DahuaCamera.m_vecs.Count; i++)
{
if (DahuaCamera.EStatus.eStatusOK != m_cameraVec[i].StopGrabbing())
{
ShowInfo(DateTime.Now + " Camera " + m_strVec[i] + " StopGrabbing fail");
}
else
{
ShowInfo(DateTime.Now + " Camera " + m_strVec[i] + " StopGrabbing success");
}
}
isGrabbing = false;
}
private void btnSoftwareTrigger_Click(object sender, EventArgs e)
{
}
private void cbBoxSelect_SelectedIndexChanged(object sender, EventArgs e)
{
//m_index = cbBoxSelect.SelectedIndex;
//checkBoxMode.Checked = m_cbVec[m_index];
}
private void checkBoxMode_CheckedChanged(object sender, EventArgs e)
{
//bool b = checkBoxMode.Checked;
//m_cbVec[m_index] = b;
//Trace.WriteLine("the value is " + b);
if (checkBoxMode.Checked)
{
for (int i = 0; i < DahuaCamera.m_vecs.Count; i++)
{
if (false == m_cameraVec[i].SetTriggerMode(false))
{
ShowInfo(DateTime.Now + " Camera " + m_strVec[i] + " Set TriggerMode fail");
}
else
{
ShowInfo(DateTime.Now + " Camera " + m_strVec[i] + " Set TriggerMode success");
}
}
}
else
{
for (int i = 0; i < DahuaCamera.m_vecs.Count; i++)
{
if(false == m_cameraVec[i].SetTriggerClose())
{
ShowInfo(DateTime.Now + " Camera " + m_strVec[i] + " Close Trigger fail");
}
else
{
ShowInfo(DateTime.Now + " Camera " + m_strVec[i] + " Close Trigger success");
}
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}