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


    首先吐槽一句,官方的demos写的真的不好,坑爹啊。对于小白来说,开发官方demos为我所用太难了。为什么呢?因为它Dalsa的DALSA.SaperaLT.SapClassBasic.dll中,不仅有采图的代码库,还有用于显示的UI库(它不是用Winform的PictureBox显示图片,而是用它自家的UI显示图片),demos把采图程序和UI库杂糅在一起,而且隐藏了少部分细节。

    后来我在网上狂搜资料,搜到了两个大佬的两篇好文章:

    dalsa 8k线阵网口相机c#开发

    https://blog.csdn.net/baidu_30028771/article/details/64628784

    DALSA相机SDK不完全教程

    http://www.cnblogs.com/lgyup/p/4313332.html

    文章一的代码是一个完整的例子,是可以直接采到图的。文章二的代码缺少关键的GetCameraInfo()方法,是不能直接运行的,但是这篇文章的讲解更全面、深入,可以说两篇都是必备的啦。

    我为什么要写这两篇文章呢?因为我想集合这两家之长,再加入一点自己的经验、代码,并且提供完整的源代码方便大家开发。很忏愧 ,只做了一点微小的贡献。

    我的开发硬件、软件信息:

    操作系统:windows 10、windows 7   64bit都有

    线扫相机:Dalsa  Linea Mono 4k  26 kHz GigE (LA-GM-04K08A)

    IDE :Visual studio 2013

    第一篇文章我直接运行代码报错了,是到了跟Dalsa相关的dll的语句时报错的。Win 10系统很扯淡,报错的提示一点都看不懂,我换Win 7的系统后,也报错,但是明确把错误原因找出来了。其实是Dalsa的dll中有低版本.Net Framework的代码,导致不兼容。解决的办法,网上一大推,核心就一句:在app.config的合适位置,加这句话useLegacyV2RuntimeActivationPolicy=”true”。

    如果没有app.config文件,你就需要创建这个文件。

    我的app.config文件内容如下:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <startup useLegacyV2RuntimeActivationPolicy="true">
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
      </startup>
    </configuration>

    现在你需要把我上文提到的两篇博客仔细看一下了。

    ……

    看完了吗?看完了的话,接着往下看我的文章。

    首先学习一下相机配置文件(.ccf)如何生成:

    ① 打开相机软件Sapera CamExpert,确保相机已经正常工作,然后自己改变到合适的参数;

    ② 点击软件左上角的File——Save As...,选择文件夹路径,修改文件名。

    我的解决方案资源结构如下:

    因为我是用Halcon显示图片,因此我添加了两个dll引用。除了app.config之外,我所有自己编写的代码全部在Form1.cs中。其实相当于我把全部源代码一字不漏全告诉你了。

    我的Form1界面如下:

    (点击Init初始化,会弹出该线阵相机的型号)

    然后点击“snap”的话,它会连续采集15张图,并保存,如下:

    Form1.cs的全部内容如下:

    复制代码
      1 using System;
      2 using System.Collections.Generic;
      3 using System.ComponentModel;
      4 using System.Data;
      5 using System.Drawing;
      6 using System.Linq;
      7 using System.Text;
      8 using System.Windows.Forms;
      9 using DALSA.SaperaLT.SapClassBasic;
     10 using HalconDotNet;
     11 
     12 namespace WinDalsa
     13 {
     14     public partial class Form1 : Form
     15     {
     16         private SapLocation m_ServerLocation;   // 设备的连接地址
     17         private SapAcqDevice m_AcqDevice;       // 采集设备
     18         private SapBuffer m_Buffers;            // 缓存对象
     19         private SapAcqDeviceToBuf m_Xfer;       // 传输对象
     20 
     21         public Form1()
     22         {
     23             InitializeComponent();
     24         }
     25 
     26 
     27         private void Form1_Load(object sender, EventArgs e)
     28         {
     29             
     30         }
     31 
     32         private void Form1_FormClosed(object sender, FormClosedEventArgs e)
     33         {
     34             DestroyObjects();
     35             DisposeObjects();
     36         }
     37 
     38 
     39         private void btn_init_Click(object sender, EventArgs e)
     40         {
     41             CreateNewObjects();
     42         }
     43 
     44         private void btn_setting_Click(object sender, EventArgs e)
     45         {
     46             //设置曝光值,为了设置的值不超限,需要获取曝光值的允许范围(主要是最大值)
     47             double valuetemp = GetMaxValue("ExposureTime");
     48             if (valuetemp > 0)
     49             {
     50                 m_AcqDevice.SetFeatureValue("ExposureTime", valuetemp);
     51             }
     52 
     53             m_AcqDevice.SetFeatureValue("Gain", "9.9");
     54         }
     55 
     56 
     57         // 获得相机部分属性的值  
     58         private void btn_getValue_Click(object sender, EventArgs e)
     59         {
     60             string deviceModelName;
     61             string deviceUserId;
     62             string pixelFormat;
     63             string triggerMode;
     64 
     65             double acquisitionLineRate;  //行频和曝光时间不能设置为int类型
     66             double exposureTime;
     67             double gain;
     68             int width;
     69             int height;
     70             int sensorWidth;
     71             int sensorHeight;
     72 
     73 
     74             m_AcqDevice.GetFeatureValue("DeviceModelName", out deviceModelName);  //Linea M4096-7um
     75             m_AcqDevice.GetFeatureValue("DeviceUserID", out deviceUserId);  //空
     76             m_AcqDevice.GetFeatureValue("PixelFormat", out pixelFormat);  //Mono8
     77             m_AcqDevice.GetFeatureValue("TriggerMode", out triggerMode);  //Off
     78 
     79             m_AcqDevice.GetFeatureValue("AcquisitionLineRate", out acquisitionLineRate);  //10000.0
     80             m_AcqDevice.GetFeatureValue("ExposureTime", out exposureTime);  //70.0
     81             m_AcqDevice.GetFeatureValue("Gain", out gain);  //9.0          
     82             m_AcqDevice.GetFeatureValue("Width", out width);  //4096
     83             m_AcqDevice.GetFeatureValue("Height", out height);  //2800
     84             m_AcqDevice.GetFeatureValue("SensorWidth", out sensorWidth);  //4096
     85             m_AcqDevice.GetFeatureValue("SensorHeight", out sensorHeight);  //1
     86 
     87         }
     88 
     89 
     90         #region 单步采集、连续采集、冻结采集
     91         private void btn_snap_Click(object sender, EventArgs e)
     92         {
     93 
     94             //Snap()只采集一张,如果是Snap(15)则连续采集15张
     95             m_Xfer.Snap(15);//m_Xfer.Snap(m_Buffers.Count)
     96         }
     97 
     98         private void btn_grab_Click(object sender, EventArgs e)
     99         {
    100             m_Xfer.Grab();
    101         }
    102 
    103         private void btn_freeze_Click(object sender, EventArgs e)
    104         {
    105             m_Xfer.Freeze(); //还有m_Xfer.Abort()的用法;
    106 
    107         }
    108 
    109         #endregion
    110 
    111 
    112 
    113         //得到所有连接的相机信息,并将它们加入到ArrayList里面去
    114         public bool GetCameraInfo(out string sCameraName, out int nIndex)
    115         {
    116             sCameraName = "";
    117             nIndex = 0;
    118 
    119             int serverCount = SapManager.GetServerCount();
    120             int GenieIndex = 0;
    121             System.Collections.ArrayList listServerNames = new System.Collections.ArrayList();
    122 
    123             bool bFind = false;
    124             string serverName = "";
    125             for (int serverIndex = 0; serverIndex < serverCount; serverIndex++)
    126             {
    127                 if (SapManager.GetResourceCount(serverIndex, SapManager.ResourceType.AcqDevice) != 0)
    128                 {
    129                     serverName = SapManager.GetServerName(serverIndex);
    130                     listServerNames.Add(serverName);
    131                     GenieIndex++;
    132                     bFind = true;
    133                 }
    134             }
    135 
    136             int count = 1;
    137             string deviceName = "";
    138             foreach (string sName in listServerNames)
    139             {
    140                 deviceName = SapManager.GetResourceName(sName, SapManager.ResourceType.AcqDevice, 0);
    141                 count++;
    142             }
    143 
    144             sCameraName = serverName;
    145             nIndex = GenieIndex;
    146 
    147             return bFind;
    148         }
    149 
    150 
    151 
    152         private bool CreateNewObjects()
    153         {
    154 
    155             string Name;
    156             int Index;
    157             bool RTemp = GetCameraInfo(out Name, out Index);
    158             if (RTemp)
    159             {
    160                 MessageBox.Show(Name);
    161             }
    162             else
    163             {
    164                 MessageBox.Show("Get camera info false!");
    165                 return false;
    166             }
    167             
    168 
    169             m_ServerLocation = new SapLocation(Name, 0);
    170 
    171 
    172             // 创建采集设备,new SapAcqDevice()的括号中第二个参数既可以写配置文件路径,也可以写false,猜测false是用相机当前的设置
    173             //m_AcqDevice = new SapAcqDevice(m_ServerLocation, false);
    174             m_AcqDevice = new SapAcqDevice(m_ServerLocation, @"C:Usersxh6300Desktopdalsa_win7_developgrayT_Linea_M4096-7um_Default_Default_2800.ccf");
    175             
    176 
    177             if (m_AcqDevice.Create() == false)
    178             {
    179                 DestroyObjects();
    180                 DisposeObjects();
    181                 return false;
    182             }
    183             // 创建缓存对象
    184             if (SapBuffer.IsBufferTypeSupported(m_ServerLocation, SapBuffer.MemoryType.ScatterGather))
    185             {
    186                 m_Buffers = new SapBufferWithTrash(2, m_AcqDevice, SapBuffer.MemoryType.ScatterGather);
    187             }
    188             else
    189             {
    190                 m_Buffers = new SapBufferWithTrash(2, m_AcqDevice, SapBuffer.MemoryType.ScatterGatherPhysical);
    191             }
    192             if (m_Buffers.Create() == false)
    193             {
    194                 DestroyObjects();
    195                 DisposeObjects();
    196                 return false;
    197             }
    198 
    199             m_AcqDevice.SetFeatureValue("AcquisitionLineRate", 20000.0); //注意:行频在相机工作时不能设置(曝光、增益可以),最好在初始化阶段设置
    200 
    201             // 创建传输对象
    202             m_Xfer = new SapAcqDeviceToBuf(m_AcqDevice, m_Buffers);
    203             m_Xfer.XferNotify += new SapXferNotifyHandler(m_Xfer_XferNotify);
    204             m_Xfer.XferNotifyContext = this;
    205             m_Xfer.Pairs[0].EventType = SapXferPair.XferEventType.EndOfFrame;
    206             m_Xfer.Pairs[0].Cycle = SapXferPair.CycleMode.NextWithTrash;
    207             if (m_Xfer.Pairs[0].Cycle != SapXferPair.CycleMode.NextWithTrash)
    208             {
    209                 DestroyObjects();
    210                 DisposeObjects();
    211                 return false;
    212             }
    213             if (m_Xfer.Create() == false)
    214             {
    215                 DestroyObjects();
    216                 DisposeObjects();
    217                 return false;
    218             }
    219             return true;
    220         }
    221 
    222 
    223         private void DestroyObjects()
    224         {
    225             if (m_Xfer != null && m_Xfer.Initialized)
    226                 m_Xfer.Destroy();
    227             if (m_Buffers != null && m_Buffers.Initialized)
    228                 m_Buffers.Destroy();
    229             if (m_AcqDevice != null && m_AcqDevice.Initialized)
    230                 m_AcqDevice.Destroy();
    231         }
    232 
    233         private void DisposeObjects()
    234         {
    235             if (m_Xfer != null)
    236             { m_Xfer.Dispose(); m_Xfer = null; }
    237             if (m_Buffers != null)
    238             { m_Buffers.Dispose(); m_Buffers = null; }
    239             if (m_AcqDevice != null)
    240             { m_AcqDevice.Dispose(); m_AcqDevice = null; }
    241         }
    242 
    243 
    244         private static int picCountNum = 0; //统计采集了多少张图,有利于理解m_Xfer.Snap(15)中15的意思
    245 
    246         void m_Xfer_XferNotify(object sender, SapXferNotifyEventArgs argsNotify)
    247         {
    248             //首先需判断此帧是否是废弃帧,若是则立即返回,等待下一帧(但这句话似乎有时候m_Xfer.Snap(n)时会导致丢帧,可以注释掉试试)
    249             if (argsNotify.Trash) return; 
    250 
    251             //获取m_Buffers的地址(指针),只要知道了图片内存的地址,其实就能有各种办法搞出图片了(例如转成Bitmap)
    252             IntPtr addr;
    253             m_Buffers.GetAddress(out addr);
    254 
    255             //观察buffer中的图片的一些属性值,语句后注释里面的值是可能的值
    256             int count = m_Buffers.Count;  //2
    257             SapFormat format = m_Buffers.Format;  //Uint8
    258             double rate = m_Buffers.FrameRate;  //30.0,连续采集时,这个值会动态变化
    259             int height = m_Buffers.Height;  //2800
    260             int weight = m_Buffers.Width;  //4096
    261             int pixd = m_Buffers.PixelDepth;  //8
    262 
    263             //显示实时帧率
    264             UpdateFrameRate();
    265             lbl_FrameRate.BeginInvoke(new Action(() => { lbl_FrameRate.Text = m_Buffers.FrameRate.ToString();})); 
    266             
    267             //利用halcon从内存中采集图片并保存  
    268             HObject ImageTemp = null;
    269             HOperatorSet.GenImage1(out ImageTemp, "byte", 4096, 2000, addr);//取内存数据,生成图像,halcon实现
    270 
    271             hWindowControl1.HalconWindow.SetPart(0, 0, 2000, 4096);
    272             HOperatorSet.DispObj(ImageTemp, hWindowControl1.HalconWindow);
    273             picCountNum++;
    274             HOperatorSet.WriteImage(ImageTemp, "bmp", 0, "C:\Users\xh6300\Desktop\tt\" + picCountNum);
    275             
    276         }
    277 
    278 
    279         private void UpdateFrameRate()
    280         {
    281             if (m_Xfer.UpdateFrameRateStatistics())
    282             {
    283                 float framerate = 0.0f;
    284                 SapXferFrameRateInfo stats = m_Xfer.FrameRateStatistics;
    285 
    286                 if (stats.IsBufferFrameRateAvailable)
    287                     framerate = stats.BufferFrameRate;
    288                 else if (stats.IsLiveFrameRateAvailable && !stats.IsLiveFrameRateStalled)
    289                     framerate = stats.LiveFrameRate;
    290 
    291                 m_Buffers.FrameRate = framerate;
    292             }
    293         }
    294 
    295 
    296 
    297         //获得相机参数的最大值(行频和曝光时间是近似倒数的关系,获得参数最大值可以防止设置参数超限)
    298         private double GetMaxValue(string featureName)
    299         {
    300             SapFeature feature = new SapFeature(m_ServerLocation);
    301             if (!feature.Create())
    302                 return -1;
    303             if (!m_AcqDevice.GetFeatureInfo(featureName, feature))
    304                 return -1;
    305             double maxValue = 0;
    306             if (!feature.GetValueMax(out maxValue))
    307                 return -1;
    308             return maxValue;     
    309         }
    310 
    311 
    312         //这个一般用得少,最小值一般是很小的数(比如Gain最小0.125,width最小128),我们一般不会设置这样的数
    313         private double GetMinValue(string featureName)
    314         {
    315             SapFeature feature = new SapFeature(m_ServerLocation);
    316             if (!feature.Create())
    317                 return -1;
    318             if (!m_AcqDevice.GetFeatureInfo(featureName, feature))
    319                 return -1;
    320             int minValue = 0;
    321             if (!feature.GetValueMin(out minValue))
    322                 return -1;
    323             return minValue;
    324         }
    325     }
    326 }
    复制代码

    当你完全理解了这篇文章(以及我提到的两篇),Dalsa网口线阵相机的开发基本就没啥问题了,当然这时候你返回去看官方demos会有新的收获,比如我上面的UpdateFrameRate()就是从官方demos中剥离出来的,该函数可以得到采图时的实际帧率。

    有什么问题可以留言询问。

    作者:xh6300

    --------------------------------------------

  • 相关阅读:
    响应头中的 ETag 值是如何生成的
    http请求状态码
    RPC 和 REST 有什么优劣
    comet 长轮询与 node 实现
    HTTPS 加密
    iterm2 快捷键
    static in C/C++
    03-树3 Tree Traversals Again
    2016.03.19随笔
    03-树2 List Leaves
  • 原文地址:https://www.cnblogs.com/wwwbdabc/p/11288001.html
Copyright © 2020-2023  润新知