图片采集以及转存—DALSA相机SDK开发(不再涉及halcon或opencv等)

借助DALSA提供的官方SDK,以及部分,完成相机的信息获取、相机连接、内存裸数据采集、转存图片一系列流程,不再像之前一样涉及到halcon或者opencv来处理图像,而是只使用DALSA的官方SDK来进行开发。

本项目做的是C#控制台项目,没有界面,如果要界面的话,网上也有代码可以借鉴,可以添加halcon的空间HalconWindow,来直接用halcon的HOperatorSet来放;

也可以不使用halcon,只用winForm内自带的pictureBox控件,但是那样的话就需要将图片先转成bitMap,并且使用调色板来放置。

我不作Form窗体,界面的事不再赘述,因为我是自动连续采集(Grab),自动停止(Freeze),开始和结束靠的是控制程序发过来的信号,使用Socket通信实现。

1.全局变量

        private SapLocation m_ServerLocation;   // 设备的连接地址
        private SapAcqDevice m_AcqDevice;       // 采集设备
        private SapBuffer m_Buffers;            // 缓存对象
        private SapAcqDeviceToBuf m_Xfer;       // 传输对象
        private String urlFromJava;
        private Boolean socketStatu = true;

前四个是DALSA的DLL内的对象,后两个是用于自动触发和停止用的变量。

2.main方法调用

        static void Main(string[] args)
        {
            Program p = new Program();
            p.socketServer();//开始Socket通信服务端,监听等待java发送的开始采集信号
        }

很简单,因为main方法是static静态的,但是我socketServer()方法不是静态的,所以调用的时候需要实例化项目再调用,要不然就是socketServer()直接调用了。

3.触发

    private void socketServer()
        {
            Console.WriteLine("开启Socket通信--C#服务端");
            Socket soo = new Socket(AddressFamily.InterNetwork, SocketType.Stream,             ProtocolType.Tcp);
            IPAddress ip = IPAddress.Parse("127.0.0.1");
            IPEndPoint ipend = new IPEndPoint(ip, 61666);
            soo.Bind(ipend);
            soo.Listen(10);
            byte[] by = new byte[1024];
            while (true)
            {
                Socket so = soo.Accept();
                int len = so.Receive(by);//Send发送 Receive接收
                Console.WriteLine("len=" + len);
                if (socketStatu)
                {
                    urlFromJava = Encoding.UTF8.GetString(by, 0, len);
                    Console.WriteLine("赋值地址");
                }
                if (len > 5)
                {
                    Console.WriteLine("urlFromJava=" + urlFromJava);
                    CreateNewObjects();//初始化相机
                    Console.WriteLine("java字符串:" + urlFromJava + "-----C#开始采集");
                    m_Xfer.Grab();
                    socketStatu = false;
                }
                else if (len == 3)
                {
                    m_Xfer.Freeze();
                    Thread.Sleep(5000);
                    m_Xfer.Abort();
                    DestroyObjects();
                    DisposeObjects();
                    picCountNum = 0;
                    socketStatu = true;
                    Console.WriteLine("java字符串:" + urlFromJava + "-----C#结束采集");
                }
            }
        }

C#这边程序是Socket服务器端,接收来java程序(Scoket客户端,负责控制)的信号,根据收到信息不同进行开始采集或者结束采集。

urlFromJava这个变量是一个地址,java端来告诉采集程序保存地址。地址传过来之后,第一步初始化相机,连接相机,然后Grab(),开始采集。

关闭的时候,执行Freez()停止采集,线程等待5秒,目的是停止采集后,将还存在内存地址通道中的裸数据都取出来,如果freeze之后直接释放,就拿不到还在地址上的数据了,缓存对象释放之后,将本次采集所有对象摧毁。

4.初始化并连接相机

private bool CreateNewObjects()
        {
            Console.WriteLine("相机初始化");
            string Name;
            int Index;
            //获取相机详细信息
            bool RTemp = GetCameraInfo(out Name, out Index);
            if (RTemp)
            {
                Console.WriteLine("相机" + Name);
            }
            else
            {
                Console.WriteLine("未获取到相机信息!");
                return false;
            }

            m_ServerLocation = new SapLocation(Name, 0);
            // 创建采集设备,new SapAcqDevice()的括号中第二个参数写配置文件路径,配置文件为ccf格式
            m_AcqDevice = new SapAcqDevice(m_ServerLocation, @"C:\Users\Administrator\Desktop\T_Linea_M4096-7um_Default_Default.ccf");
            //当参数为false时表示采用相机当前设备
            //m_AcqDevice = new SapAcqDevice(m_ServerLocation, false);
            if (m_AcqDevice.Create() == false)
            {
                DestroyObjects();
                DisposeObjects();
                return false;
            }
            // 创建缓存对象
            if (SapBuffer.IsBufferTypeSupported(m_ServerLocation, SapBuffer.MemoryType.ScatterGather))
            {
                m_Buffers = new SapBufferWithTrash(2, m_AcqDevice, SapBuffer.MemoryType.ScatterGather);
            }
            else
            {
                m_Buffers = new SapBufferWithTrash(2, m_AcqDevice, SapBuffer.MemoryType.ScatterGatherPhysical);
            }
            if (m_Buffers.Create() == false)
            {
                DestroyObjects();
                DisposeObjects();
                return false;
            }
            //设置行频
            //注意:行频在相机工作时不能设置(曝光、增益可以),最好在初始化阶段设置
            m_AcqDevice.SetFeatureValue("AcquisitionLineRate", 20000.0);
            // 创建传输对象
            m_Xfer = new SapAcqDeviceToBuf(m_AcqDevice, m_Buffers);
            m_Xfer.XferNotify += new SapXferNotifyHandler(m_Xfer_XferNotify);
            m_Xfer.XferNotifyContext = this;
            m_Xfer.Pairs[0].EventType = SapXferPair.XferEventType.EndOfFrame;
            m_Xfer.Pairs[0].Cycle = SapXferPair.CycleMode.NextWithTrash;
            if (m_Xfer.Pairs[0].Cycle != SapXferPair.CycleMode.NextWithTrash)
            {
                DestroyObjects();
                DisposeObjects();
                return false;
            }
            if (m_Xfer.Create() == false)
            {
                DestroyObjects();
                DisposeObjects();
                return false;
            }
            return true;
        }

获取相机信息,加载相机配置文件(用相机专家调整好参数后导出ccf文件),加载参数,m_Xfer.XferNotify += new SapXferNotifyHandler(m_Xfer_XferNotify);这一句是核心,这是回调函数,就靠它采图了。后面会告诉你们m_Xfer_XferNotify的实现。

记下来一次介绍初始化中调用的几个子方法,分别是GetCameraInfo、DestroyObjects、DisposeObjects、m_Xfer_XferNotify、UpdateFrameRate。

5.获取相机信息

public bool GetCameraInfo(out string sCameraName, out int nIndex)
        {
            Console.WriteLine("开始获取相机信息");
            sCameraName = "";
            nIndex = 0;
            //查询相机数量
            int serverCount = SapManager.GetServerCount();
            int GenieIndex = 0;
            //实例化一个list,作为容器
            System.Collections.ArrayList listServerNames = new System.Collections.ArrayList();
            bool bFind = false;
            string serverName = "";
            for (int serverIndex = 0; serverIndex < serverCount; serverIndex++)
            {
                //有几个相机连接就循环几次
                if (SapManager.GetResourceCount(serverIndex, SapManager.ResourceType.AcqDevice) != 0)
                {
                    serverName = SapManager.GetServerName(serverIndex);
                    listServerNames.Add(serverName);
                    GenieIndex++;
                    bFind = true;
                }
            }
            int count = 1;
            string deviceName = "";
            foreach (string sName in listServerNames)
            {
                deviceName = SapManager.GetResourceName(sName, SapManager.ResourceType.AcqDevice, 0);
                count++;
            }
            sCameraName = serverName;
            nIndex = GenieIndex;
            return bFind;
        }

6.回调函数m_Xfer_XferNotify

private static int picCountNum = 0; 
        void m_Xfer_XferNotify(object sender, SapXferNotifyEventArgs argsNotify)
        {
            if (argsNotify.Trash) return;
            //获取m_Buffers的地址(指针)
            IntPtr addr;
            m_Buffers.GetAddress(out addr);
            //观察buffer中的图片的一些属性值,语句后注释里面的值是可能的值
            int count = m_Buffers.Count;  //2
            SapFormat format = m_Buffers.Format;  //Uint8
            double rate = m_Buffers.FrameRate;  //30.0,连续采集时,这个值会动态变化
            int height = m_Buffers.Height;  //1000
            int weight = m_Buffers.Width;  //4096
            int pixd = m_Buffers.PixelDepth;  //8
            //显示实时帧率
            UpdateFrameRate();
            picCountNum++;
            m_Buffers.Save(urlFromJava + picCountNum + ".bmp", "-format bmp");
        }

这个sava方法就是从SDK中提取出来的,给上参数,就可以实现图片的保存,不用借助任何其他的技术方法,SDK本身就可以。

7.更新实时帧率

private void UpdateFrameRate()
        {
            if (m_Xfer.UpdateFrameRateStatistics())
            {
                float framerate = 0.0f;
                SapXferFrameRateInfo stats = m_Xfer.FrameRateStatistics;
                if (stats.IsBufferFrameRateAvailable)
                    framerate = stats.BufferFrameRate;
                else if (stats.IsLiveFrameRateAvailable && !stats.IsLiveFrameRateStalled)
                    framerate = stats.LiveFrameRate;
                m_Buffers.FrameRate = framerate;
            }
        }

8.dispose和destory摧毁以及释放

private void DestroyObjects()
        {
            if (m_Xfer != null && m_Xfer.Initialized)
                m_Xfer.Destroy();
            if (m_Buffers != null && m_Buffers.Initialized)
                m_Buffers.Destroy();
            if (m_AcqDevice != null && m_AcqDevice.Initialized)
                m_AcqDevice.Destroy();
        }

        private void DisposeObjects()
        {
            if (m_Xfer != null)
            { m_Xfer.Dispose(); m_Xfer = null; }
            if (m_Buffers != null)
            { m_Buffers.Dispose(); m_Buffers = null; }
            if (m_AcqDevice != null)
            { m_AcqDevice.Dispose(); m_AcqDevice = null; }
        }

 


版权声明:本文为qq_40903561原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>