首先吐槽一句,官方的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的全部内容如下:

 using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DALSA.SaperaLT.SapClassBasic;
using HalconDotNet;

namespace WinDalsa
{
public partial class Form1 : Form
{
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 > )
{
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); //
m_AcqDevice.GetFeatureValue("Height", out height); //
m_AcqDevice.GetFeatureValue("SensorWidth", out sensorWidth); //
m_AcqDevice.GetFeatureValue("SensorHeight", out sensorHeight); // } #region 单步采集、连续采集、冻结采集
private void btn_snap_Click(object sender, EventArgs e)
{ //Snap()只采集一张,如果是Snap(15)则连续采集15张
m_Xfer.Snap();//m_Xfer.Snap(m_Buffers.Count)
} private void btn_grab_Click(object sender, EventArgs e)
{
m_Xfer.Grab();
} private void btn_freeze_Click(object sender, EventArgs e)
{
m_Xfer.Freeze(); //还有m_Xfer.Abort()的用法; } #endregion //得到所有连接的相机信息,并将它们加入到ArrayList里面去
public bool GetCameraInfo(out string sCameraName, out int nIndex)
{
sCameraName = "";
nIndex = ; int serverCount = SapManager.GetServerCount();
int GenieIndex = ;
System.Collections.ArrayList listServerNames = new System.Collections.ArrayList(); bool bFind = false;
string serverName = "";
for (int serverIndex = ; serverIndex < serverCount; serverIndex++)
{
if (SapManager.GetResourceCount(serverIndex, SapManager.ResourceType.AcqDevice) != )
{
serverName = SapManager.GetServerName(serverIndex);
listServerNames.Add(serverName);
GenieIndex++;
bFind = true;
}
} int count = ;
string deviceName = "";
foreach (string sName in listServerNames)
{
deviceName = SapManager.GetResourceName(sName, SapManager.ResourceType.AcqDevice, );
count++;
} sCameraName = serverName;
nIndex = GenieIndex; return bFind;
} private bool CreateNewObjects()
{ 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, ); // 创建采集设备,new SapAcqDevice()的括号中第二个参数既可以写配置文件路径,也可以写false,猜测false是用相机当前的设置
//m_AcqDevice = new SapAcqDevice(m_ServerLocation, false);
m_AcqDevice = new SapAcqDevice(m_ServerLocation, @"C:\Users\xh6300\Desktop\dalsa_win7_develop\gray\T_Linea_M4096-7um_Default_Default_2800.ccf"); if (m_AcqDevice.Create() == false)
{
DestroyObjects();
DisposeObjects();
return false;
}
// 创建缓存对象
if (SapBuffer.IsBufferTypeSupported(m_ServerLocation, SapBuffer.MemoryType.ScatterGather))
{
m_Buffers = new SapBufferWithTrash(, m_AcqDevice, SapBuffer.MemoryType.ScatterGather);
}
else
{
m_Buffers = new SapBufferWithTrash(, 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[].EventType = SapXferPair.XferEventType.EndOfFrame;
m_Xfer.Pairs[].Cycle = SapXferPair.CycleMode.NextWithTrash;
if (m_Xfer.Pairs[].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; }
} private static int picCountNum = ; //统计采集了多少张图,有利于理解m_Xfer.Snap(15)中15的意思 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; //
SapFormat format = m_Buffers.Format; //Uint8
double rate = m_Buffers.FrameRate; //30.0,连续采集时,这个值会动态变化
int height = m_Buffers.Height; //
int weight = m_Buffers.Width; //
int pixd = m_Buffers.PixelDepth; //8 //显示实时帧率
UpdateFrameRate();
lbl_FrameRate.BeginInvoke(new Action(() => { lbl_FrameRate.Text = m_Buffers.FrameRate.ToString();})); //利用halcon从内存中采集图片并保存
HObject ImageTemp = null;
HOperatorSet.GenImage1(out ImageTemp, "byte", , , addr);//取内存数据,生成图像,halcon实现 hWindowControl1.HalconWindow.SetPart(, , , );
HOperatorSet.DispObj(ImageTemp, hWindowControl1.HalconWindow);
picCountNum++;
HOperatorSet.WriteImage(ImageTemp, "bmp", , "C:\\Users\\xh6300\\Desktop\\tt\\" + picCountNum); } 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 -;
if (!m_AcqDevice.GetFeatureInfo(featureName, feature))
return -;
double maxValue = ;
if (!feature.GetValueMax(out maxValue))
return -;
return maxValue;
} //这个一般用得少,最小值一般是很小的数(比如Gain最小0.125,width最小128),我们一般不会设置这样的数
private double GetMinValue(string featureName)
{
SapFeature feature = new SapFeature(m_ServerLocation);
if (!feature.Create())
return -;
if (!m_AcqDevice.GetFeatureInfo(featureName, feature))
return -;
int minValue = ;
if (!feature.GetValueMin(out minValue))
return -;
return minValue;
}
}
}

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

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

DALSA网口线扫相机SDK开发详解例程(C#版)的更多相关文章

  1. Dalsa线扫相机SDK开发-小试牛刀(1)

    拿到了dalsa相机,可以用Sapera软件配置相机,进行图像采集.但是自己开发的话就得撸起袖子写代码了,查了两篇不错的博文,作为指导. Sapera帮助文档 - <好好先生>专栏 - 博 ...

  2. 【转发】NPAPI开发详解,Windows版

    NPAPI开发详解,Windows版 9 jiaofeng601, +479 9人支持,来自Meteor.猪爪.hanyuxinting更多 .是非黑白 .Yuan Xulei.hyolin.Andy ...

  3. Dalsa线扫相机SDK下载和安装

    1.首先去官方网站下载SDK Support Downloads - Teledyne DALSA http://www.teledynedalsa.com/imaging/support/downl ...

  4. 《Linux设备驱动开发详解(第3版)》(即《Linux设备驱动开发详解:基于最新的Linux 4.0内核》)--宋宝华

    http://blog.csdn.net/21cnbao/article/details/45322629

  5. VisionPro连接Dalsa线扫相机

    1 环境配置 硬件:编码器(提供编码信号的PLC) 线扫相机 镜头 相机线缆 图像采集卡(Dalsa_Xcelera-CL_PX4 Dual) 软件:VisionPro 8.2 VisionPro软件 ...

  6. 基于H5的微信支付开发详解

    这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可 ...

  7. ****基于H5的微信支付开发详解[转]

    这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可 ...

  8. iOS原生地图开发详解

    在上一篇博客中:http://my.oschina.net/u/2340880/blog/414760.对iOS中的定位服务进行了详细的介绍与参数说明,在开发中,地位服务往往与地图框架结合使用,这篇博 ...

  9. iOS应用开发详解

    <iOS应用开发详解> 基本信息 作者: 郭宏志    出版社:电子工业出版社 ISBN:9787121207075 上架时间:2013-6-28 出版日期:2013 年7月 开本:16开 ...

随机推荐

  1. 浅谈一致性Hash原理及应用

    在讲一致性Hash之前我们先来讨论一个问题. 问题:现在有亿级用户,每日产生千万级订单,如何将订单进行分片分表? 小A:我们可以按照手机号的尾数进行分片,同一个尾数的手机号写入同一片/同一表中. 大佬 ...

  2. 《DSP using MATLAB》示例 Example 9.8

    代码: %% ------------------------------------------------------------------------ %% Output Info about ...

  3. timescaledb replication 使用

    replication 可以确保系统的ha 以及lb 数据的查询,timesacledb 使用pg 内置的stream replication 进行复制的支持 docker 运行参考 https:// ...

  4. C#在64位操作系统上连接Oracle的问题和解决方案

    C#使用System.Data.OracleClient连接Oracle数据库.之前在WinXP上正常运行的程序移植到Windows 2008 x64上之后就连不上数据库了.错误信息如下: 尝试加载O ...

  5. CentOS6.6 VSFTP服务器安装设置

    1:安装vsftpd    yum install vsftpd 2:关闭防火墙 service iptables stop 3:允许21端口通行 vi /etc/sysconfig/iptables ...

  6. java项目打包部署

    网上打包的教程很多, 但是自己动手总归出现各种各样的问题,自己总结下: 由于刚刚接触JAVA,做了一个简单的java project 项目, 但是包含第三方的jar包, 结果打包的时候就出现问题了. ...

  7. java web 程序---javabean实例--登陆界面并显示用户名和密码

    重点:注意大小写,不注意细节,这点小事,还需要请教 发现一个问题,也是老师当时写的时候,发现代码没错,但是就是运行问题. 大家看,那个java类,我们要求是所有属性均为私有变量,但是方法为公有的,如果 ...

  8. mysql如何处理外码约束

    http://hi.baidu.com/wangzhiqing999/item/e74b2be28be445a3c00d7528 MySQL 外键约束 -- 创建测试主表. ID 是主键.CREATE ...

  9. 2018 Multi-University Training Contest 4-Problem B. Harvest of Apples

    由公式$S(n, m)=S(n - 1, m) + S(n - 1, m - 1) = 2 * S(n - 1, m) - C_{n-1}^{m}$ 莫队思想

  10. jsp中 RequestDispatcher接口的两种跳转:forward()和include()

    在web程序中,经常是由多个Servlet来完成请求.RequestDispatcher接口就是为了多个Servlet之间的调整而实现的.该接口可以用httpSerbletRequest的getReq ...