关于在C#中实现多相机的使用方法

  • 前言
  • 了解一些概念
  • C#多相机的调用与实现


前言

当我们在布置自己的视觉软件时,难免会遇到需要多工位检测的时候。针对于多相机的控制与显示如何实现,相信对于新手来说是一个十分复杂的问题。但相信经过我的分析,大家能够轻松搞定。

了解一些概念

首先,我们要知道,基于SDK的相机开发其实是用户通过相机厂家提供的函数包,以实现客户想要的功能。也就是说,并没有想象的那么复杂,函数别人已经给你写好了,你只要会使用就好了。在这之前,我们需要安装相机的驱动器,以获取开放的SDK,这里我们以大华相机为例。你可以在官网下载驱动器,或者在资源:中下载安装大华相机的驱动器。

然后,我们可以在驱动器的安装目录下得到SDK开发包。

basler多个相机多线程python代码 多个相机软件怎么调用_1024程序员节

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)
        {

        }

    }
}