DALSA industrial camera SDK secondary development (image acquisition and storage) C# version

First, first configure the generated project, according to the official document steps:
insert image description here

There is nothing to say about this, just follow it step by step. I didn’t pay much attention to the last step at the beginning. Finally, when the code was written and tested, I really encountered a problem. I kept making mistakes like this:
insert image description here

I checked the official document to see the last one~, and then unchecked this in the project properties, the code runs perfectly...

insert image description here
Two, functional steps

In fact, the whole step is very simple:

1. Initialize and connect the camera first: click the Init button and a MessageBox will print the camera name
insert image description here

2. Then read the configuration file (the configuration file is generated by the official CamExpert) and read the parameters, which can also be configured in the program. This program has a setting button, which can be configured and pulled by pressing it. The parameters are written in the corresponding code block (of course, the editor is lazy and has no display function, so you may feel lonely when you press the button, but it has been configured). There is also a button to read the parameters (of course, the editor did not do the display function, so I pressed it lonely), but it is helpful to view the data during debugging, and you can also print it out for yourself.

3. Snap is a snapshot, and the number of snapshots can be set. Because when writing this program, there is only a camera without a lens, so it is completely black... But when it is illuminated by a light source, it will appear white, so there is still a little reaction to know that it is not stuck haha.
  insert image description here
4. Grab is to capture images continuously, and Freeze is to stop.

5. The final saved result (without a lens, I can only test T_T with photosensitivity)
   insert image description here
PS: The most important thing in the program is a callback function: m_Xfer_XferNotify, which will be called every time a frame of picture is read, of course the callback function I added it myself, through this command:

m_Xfer.XferNotify += new SapXferNotifyHandler(m_Xfer_XferNotify);

This command and the m_Xfer_XferNotify function are the essence! Essence! Essence!

Nothing to say, the code. The runnable code is put up verbatim, and the comments are as detailed as possible:

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

Guess you like

Origin blog.csdn.net/weixin_45499836/article/details/126312422