草庐IT

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

Pass_Time_ 2023-05-20 原文

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

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

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


二,功能步骤

其实整个步骤很简单:

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

有关DALSA工业相机SDK二次开发(图像采集及保存)C#版的更多相关文章

  1. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  2. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  3. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  4. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

    我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

  5. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  6. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  7. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  8. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  9. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  10. ruby-on-rails - 添加回形针新样式不影响旧上传的图像 - 2

    我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司

随机推荐