DALSA工業相機SDK二次開發(圖像采集及保存)C#版


最近做了好多雜活,忙的找不到北,博客也沒來得及總結。而且現在記性太差了~~~老是做完就忘,趁着今天完成這個的熱乎勁兒趕緊總結一下。

(歡迎加QQ討論:77248031, 或QQ群:585068192)

圖像采集參考了幾位大神的博客:

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM