• DALSA工业相机SDK二次开发(图像采集及保存)C#版


    最近做了好多杂活,忙的找不到北,博客也没来得及总结。而且现在记性太差了~~~老是做完就忘,趁着今天完成这个的热乎劲儿赶紧总结一下。

    图像采集参考了几位大神的博客:

    DALSA网口线扫相机SDK开发详解例程(C#版

    DALSA相机SDK不完全教程

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

    上述几位大神大部分是用Halcon来转存和显示的,或者bitmap介绍的不完全。小编总结吸纳了几位大神的精髓,结合着官方的帮助文档,终于在不用halcon的前题下完成拉~

    PS:小编用c# 来写的,因为网上c#的资源最多。话说最近c++, python, c#混着用,脑子里乱成一锅粥了,总是出现类似忘记打分号,忘记定义类型,忘记小括号~要么就是and写成&&,总之各种错乱。

    一,首先先配置生成项目,根据官方文档步骤来:

      这个没啥好说的,一步步照做就是了,就最后一步,开始我没重视,最后代码写完测试的时候还真的遇到问题了,一直出这样的错:

       查了官方文档才看到最后一条~,然后在项目属性中把这个勾掉了,代码完美运行拉……

    二,功能步骤

      其实整个步骤很简单:

      1,首先初始化连接相机:点击Init按钮会有MessageBox打印相机名

      2,然后读取配置文件(配置文件是通过官方自带的CamExpert来生成的)读取参数,也可以在程序中配置,本程序有个setting按钮,按一下就可以配置拉,把想配置的参数写在对应的代码块里(当然小编很懒,没做显示的功能,所以按按钮的时候你可能觉得按了个寂寞,但已经配置好了)。还有个读取参数的按钮(当然小编也没做显示的功能,所以也按了个寂寞),但有助于debug的时候查看数据,也可以自己打印出来看看。

      3,Snap是快照,可以设置快照的张数,因为写本程序时只有相机没有镜头,所以是黑乎乎一片…但用光源照的时候会呈现白色,所以还是有点反应知道不是卡住的哈哈。

       4,Grab就是连续抓取图像了,Freeze是停止。

       5,最后的保存结果(没有镜头只能可怜巴巴的用感光性来测试了T_T)

      PS:程序最重要的是一个回调函数:m_Xfer_XferNotify,每读取一帧图片的时候会调用这个函数,当然回调函数是自己加的,通过这个命令:

        m_Xfer.XferNotify += new SapXferNotifyHandler(m_Xfer_XferNotify);

        这条命令和m_Xfer_XferNotify函数是精髓!精髓!精髓!

      没啥说的,上代码。可运行代码一字不差的放上来咯,注释也尽可能详细了:

    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.Drawing.Imaging;
    using DALSA.SaperaLT.SapClassBasic;
    
    namespace dalsaSave
    {
        public partial class Form1 : Form
        {
            // 全局变量
            private static int picCountNum = 0; // 统计采集了多少张图,有利于理解m_Xfer.Sanp(15)中15的意思
            private string configFilePath = @"D:\T_Linea_M4096-7um_Default_Default.ccf"; // 配置文件的路径
            private string imgPath = @"D:\imgs\"; // 采集图片保存地址
            private SapLocation m_ServerLocation; // 设备的连接地址
            private SapAcqDevice m_AcqDevice; //采集设备
            private SapBuffer m_Buffers; // 缓存对象
            private SapAcqDeviceToBuf m_Xfer; // 传输对象
    
    
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
    
            }
    
            private void Form1_FormClosed(object sender, FormClosedEventArgs e)
            {
                DestroyObjects();
                DisposeObjects();
            }
    
            // 初始化并连接相机
            private void btn_init_Click(object sender, EventArgs e)
            {
                CreateNewObjects();
            }
    
            private void btn_setting_Click(object sender, EventArgs e)
            {
                // 设置曝光值,为了设置的值不超限,需要获取曝光值的允许范围(主要是最大值)
                double valuetemp = GetMaxValue("ExposureTime");
                if (valuetemp > 0)
                {
                    m_AcqDevice.SetFeatureValue("ExposureTime", valuetemp);
                }
                m_AcqDevice.SetFeatureValue("Gain", "9.9");
            }
    
            private void btn_getValue_Click(object sender, EventArgs e)
            {
                string deviceModelName;
                string deviceUserId;
                string pixelFormat;
                string triggerMode;
    
                double acquisitionLineRate; // 行频和曝光时间不能设置为int类型
                double exposureTime;
                double gain;
                int width;
                int height;
                int sensorWidth;
                int sensorHeight;
    
                m_AcqDevice.GetFeatureValue("DeviceModelName", out deviceModelName);  //Linea M4096-7um
                m_AcqDevice.GetFeatureValue("DeviceUserID", out deviceUserId);  //
                m_AcqDevice.GetFeatureValue("PixelFormat", out pixelFormat);  //Mono8
                m_AcqDevice.GetFeatureValue("TriggerMode", out triggerMode);  //Off
    
                m_AcqDevice.GetFeatureValue("AcquisitionLineRate", out acquisitionLineRate);  //10000.0
                m_AcqDevice.GetFeatureValue("ExposureTime", out exposureTime);  //70.0
                m_AcqDevice.GetFeatureValue("Gain", out gain);  //9.0          
                m_AcqDevice.GetFeatureValue("Width", out width);  //4096
                m_AcqDevice.GetFeatureValue("Height", out height);  //2800
                m_AcqDevice.GetFeatureValue("SensorWidth", out sensorWidth);  //4096
                m_AcqDevice.GetFeatureValue("SensorHeight", out sensorHeight);  //1
            }
    
            #region
            private void btn_snap_Click(object sender, EventArgs e)
            {
                // Snap() 只采集一张, 如果是Snap(15)则连续采集15张
                m_Xfer.Snap(15); //m_Xfer.Snap(m_Buffers.Count)
            }
    
            private void btn_grab_Click(object sender, EventArgs e)
            {
                m_Xfer.Grab();
            }
    
    
            //关闭的时候,执行Freez()停止采集,线程等待5秒,
            //目的是停止采集后,将还存在内存地址通道中的裸数据都取出来,
            //如果freeze之后直接释放,就拿不到还在地址上的数据了,缓存对象释放之后,将本次采集所有对象摧毁。
    
            private void btn_freeze_Click(object sender, EventArgs e)
            {
                m_Xfer.Freeze();
            }
            #endregion
    
            //得到所有连接的相机信息,并将他们加入到ArrayList里面去
            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;
    
            }
    
    
            // 初始化并连接相机
            public bool CreateNewObjects()
            {
                Console.WriteLine("相机初始化");
                string Name;
                int Index;
    
                // 获取相机详细信息
                bool RTemp = GetCameraInfo(out Name, out Index);
                if (RTemp)
                {
                    MessageBox.Show(Name);
                }
                else
                {
                    MessageBox.Show("Get camera info false!");
                    return false;
                }
    
                m_ServerLocation = new SapLocation(Name, 0);
    
                //创建采集设备,new SapAcqDevice()的括号中第二个参数既可以写配置文件路径,也可以写false,false是用相机当前的设置
                // 获取相机信息,加载相机配置文件(用相机专家调整好参数后导出ccf文件),加载参数
                if (configFilePath.Length > 0)
                    m_AcqDevice = new SapAcqDevice(m_ServerLocation, configFilePath);
                else
                    m_AcqDevice = new SapAcqDevice(m_ServerLocation, false);
    
                Console.WriteLine(m_AcqDevice.Create());
    
                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;
            }
    
    
            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;
                }
            }
        
    
            void m_Xfer_XferNotify(object sender, SapXferNotifyEventArgs argsNotify)
            {
                // 首先判断此帧是否为废弃帧,若是则立即返回,等待下一帧(但这句话有时候m_Xfer.Snap(n)时会导致丢帧,可以注释掉试试)
                if (argsNotify.Trash) return;
    
                // 获取m_Buffers的地址(指针),只要知道了图片内存的地址,其实就能有各种办法搞出图片了(例如转成Bitmap)
                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; //2800
                int weight = m_Buffers.Width; //4096
                int pixd = m_Buffers.PixelDepth; //8
    
                //显示实时帧率
                UpdateFrameRate();
                lbl_FrameRate.BeginInvoke(new Action(() => { lbl_FrameRate.Text = m_Buffers.FrameRate.ToString(); }));
    
    
                picCountNum++;
    
                // 保存到本地。这个save方法就是从SDK中提取出来的,给上参数,就可以实现图片的保存,不用借助其他任何的技术方法
                m_Buffers.Save(imgPath + picCountNum + ".bmp", "-format bmp" );
    
    
                // 从内存读取图片,并转换成bitmap格式,创建调色板,打印到PictureBox
                PixelFormat pf = PixelFormat.Format8bppIndexed;
                Bitmap bmp = new Bitmap(weight, height, m_Buffers.Pitch, pf, addr);
                ColorPalette m_grayPalette;
                using (Bitmap tempbmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
                {
                    m_grayPalette = tempbmp.Palette;
                }
                for (int i = 0; i <= 255; i++)
                {
                    m_grayPalette.Entries[i] = Color.FromArgb(i, i, i);
                }
    
                bmp.Palette = m_grayPalette;
    
                Image img = Image.FromHbitmap(bmp.GetHbitmap());
                picBox.Image = img;
            }
    
         
    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; } } // 获得相机参数的最大值(行频和曝光时间是近似倒数的关系,获得参数最大值可以防止设置参数超限) private double GetMaxValue(string featureName) { SapFeature feature = new SapFeature(m_ServerLocation); if (!feature.Create()) return -1; if (!m_AcqDevice.GetFeatureInfo(featureName, feature)) return -1; double maxValue = 0; if (!feature.GetValueMax(out maxValue)) return -1; return maxValue; } // 这个一般用的少,最小值一般是很小的数(比如Gain最小0.125, width最小128),我们一般不会设置这样的数 private double GetMinValue(string featureName) { SapFeature feature = new SapFeature(m_ServerLocation); if (!feature.Create()) return -1; if (!m_AcqDevice.GetFeatureInfo(featureName, feature)) return -1; int minValue = 0; if (!feature.GetValueMin(out minValue)) return -1; return minValue; } } }
  • 相关阅读:
    ES6-->ECMAScript 6.0 新增方法,一些基本语法
    初识 Nodejs (了解Nodejs)
    Vue框架初识
    python语法入门之流程控制
    python中基本运算符
    格式化输出
    基本数据类型
    变量,解释器,垃圾回收机制,小整数池总结
    编程语言发展史
    计算机基础
  • 原文地址:https://www.cnblogs.com/boligongzhu/p/15740230.html
Copyright © 2020-2023  润新知