机器视觉之Basler工业相机使用和配置方法(C++)

news2024/11/27 13:43:11

basler工业相机做双目视觉用,出现很多问题记录一下:

首先是多看手册:https://zh.docs.baslerweb.com/software

手册内有所有的源码和参考示例,实际上在使用过程中,大部分都是这些源码,具体项目选择对应的示例代码。

一、相机和镜头选型

可以通过balser的镜头选型工具,按照自己需要测量目标的距离,目标大小等信息进行配置选择,地址在这;界面如下:
在这里插入图片描述
相机的焦距大小一般和测量的目标距离有关系,一般对应的选择方式总结如下:
(1)焦距越小,测量的范围越大,相应的,目标一般都看起来很小,类似于手机拍照的最小倍数拍摄目标;
(2)焦距越大,测量范围就越窄,对远距离小目标的检查就比较好,但是太大的焦距会导致大目标容易拍不全,类似与手机拍照放大倍数拍摄目标;
(3)具体有计算公式,可以参考,建议直接通过basler的配置工具进行选择

二、相机安装和使用

(1)balser相机使用需要网线和电源线(12V供电),可以在官网找对应的线材;
(2)相机接上电源,网线连接计算机后,去官网下载相机软件和驱动,一般windows下安装后,会在目录下生成对应的文件夹,包括C++对应的库和参考代码示例等,linux下直接下载tar.gz包,解压防止到对应的文件目录下,执行:source pylon目录/bin/pylon-setup-env.sh ./pylon目录 即可,例如我安装的是pylon7.3.0,解压后的目录为:/opt/pylon7,里面直接就是inlcude这些文件夹,在linux下目录执行:

source /opt/pylon7/bin/pylon-setup-env.sh /opt/pylon7

完成linux下相机驱动和环境的安装。
(3)配置相机IP,windows下配置相机IP可以使用basler的工具:
ipconfigurator,Linux下如果安装的系统有GUI界面,一样可以使用,配置相机IP地址,保证IP地址和接计算机的接口IP地址在同一网段即可,子网掩码推荐255。255.255.0,厂家说其他的可能会出现异常断开错误;
(4)IP配置完成后,在windows下启动pylon Viewer工具,查看相机,能找到相机说明IP配置正确,确保计算机和相机处于同一个网段内
(5)要保持basler相机的帧率,需要保证千兆网,如果是两个相机,连交换机之后就要求是2000M的网,依次类推,才可以达到最大帧率,否则会出现相机丢帧等问题,直连相机到计算机不影响,开启巨帧数就行了。

三、C++调用相机环境部署

1.相机驱动和软件安装完成后,有以下文件夹:

开发环境在development文件夹下,linux下解压之后是:
在这里插入图片描述
2.可以使用visua studio等C++ IDE开发工具进行编程,将依赖库和头文件等信息通过链接include和lib文件,即可开始相机调用;

四、C++相机调用

1.相机初始化:

相机初始化包括寻找相机,匹配对应相机,还可以设置相机的曝光,帧率,增益等,两个相机的初始化,依据API文档整理如下:
参加API:Grab_MultipleCameras

void initCamera()
{
    try
    {
        PylonInitialize();	//初始化
        CTlFactory& tlFactory = CTlFactory::GetInstance();
        pTL = dynamic_cast<IGigETransportLayer*>(tlFactory.CreateTl( BaslerGigEDeviceClass ));
        if (pTL == NULL)
        {
            throw RUNTIME_EXCEPTION( "No GigE cameras available." );
        }

        DeviceInfoList_t allDeviceInfos;
        if (pTL->EnumerateDevices( allDeviceInfos ) == 0)
        {
            throw RUNTIME_EXCEPTION( "No GigE cameras available." );
        }

        DeviceInfoList_t usableDeviceInfos;
        string left_camera_ip="172.16.105.21"
		//left_camera_ip 用于区分两个相机,可以通过配置的IP,序列号等进行区分
        if (string(allDeviceInfos[0].GetIpAddress()) == left_camera_ip) {
            usableDeviceInfos.push_back(allDeviceInfos[0]);
            subnet = allDeviceInfos[0].GetSubnetAddress();//主相机
            usableDeviceInfos.push_back(allDeviceInfos[1]);
            LOG(INFO)<<"主相机:"<<allDeviceInfos[0].GetIpAddress()<<endl;
            LOG(INFO)<<"副相机:"<<allDeviceInfos[1].GetIpAddress()<<endl;
        }
        else if(string(allDeviceInfos[1].GetIpAddress()) == left_camera_ip) {
            usableDeviceInfos.push_back(allDeviceInfos[1]);
            subnet = allDeviceInfos[1].GetSubnetAddress();//主相机
            usableDeviceInfos.push_back(allDeviceInfos[0]);
            LOG(INFO)<<"主相机IP:"<<allDeviceInfos[1].GetIpAddress()<<endl;
            LOG(INFO)<<"SubnetAddress:"<<allDeviceInfos[1].GetSubnetAddress()<<endl;
            LOG(INFO)<<"DefaultGateway:"<<allDeviceInfos[1].GetDefaultGateway()<<endl;
            LOG(INFO)<<"SubnetMask:"<<allDeviceInfos[1].GetSubnetMask()<<endl;

            LOG(INFO)<<"副相机IP:"<<allDeviceInfos[0].GetIpAddress()<<endl;
            LOG(INFO)<<"SubnetAddress:"<<allDeviceInfos[0].GetSubnetAddress()<<endl;
            LOG(INFO)<<"DefaultGateway:" <<allDeviceInfos[0].GetDefaultGateway()<<endl;
            LOG(INFO)<<"SubnetMask:"<<allDeviceInfos[0].GetSubnetMask()<<endl;


        }
        else{
            LOG(INFO) << "Camera IP is error ,please set IP" << endl;
        }
       // CInstantCameraArray cameras = { 2 };
       //初始化两个相机
        for (size_t i = 0; i < 2; ++i)
        {
            cameras[i].Attach(tlFactory.CreateDevice(usableDeviceInfos[i]));
            const CBaslerGigEDeviceInfo& di = cameras[i].GetDeviceInfo();
            LOG(INFO) << "Camera serial: " << di.GetSerialNumber() << endl;
        }

//        srand( (unsigned) time( NULL ) );
//        DeviceKey = rand();
//        GroupKey = 0x112233;

        for (size_t i = 0; i < cameras.GetSize(); ++i)
        {
            cameras[i].Attach( tlFactory.CreateDevice( usableDeviceInfos[i] ) );
            //cameras[i].RegisterConfiguration( new CActionTriggerConfiguration( DeviceKey, GroupKey, AllGroupMask ), RegistrationMode_Append, Cleanup_Delete );
            //cameras[i].SetCameraContext( i );
            const CBaslerGigEDeviceInfo& di = cameras[i].GetDeviceInfo();
            cout << "Using camera " << i << ": " << di.GetSerialNumber() << " (" << di.GetIpAddress() << ")" << endl;
        }

        cameras.Open();

        //相机基本设置
        SetCamera(cameras[0], Type_Basler_ExposureTimeAbs, expore_time_l);			//曝光时间
        SetCamera(cameras[0], Type_Basler_GainRaw, gain_l);						//增益
        SetCamera(cameras[0], Type_Basler_AcquisitionFrameRateAbs, fps_l);			//频率
        SetCamera(cameras[0], Type_Basler_Width, 2448);
        SetCamera(cameras[0], Type_Basler_Height, 2048);

        SetCamera(cameras[1], Type_Basler_ExposureTimeAbs, expore_time_r);			//曝光时间
        SetCamera(cameras[1], Type_Basler_GainRaw, gain_r);						//增益
        SetCamera(cameras[1], Type_Basler_AcquisitionFrameRateAbs, fps_r);			//频率
        SetCamera(cameras[1], Type_Basler_Width, 2448);
        SetCamera(cameras[1], Type_Basler_Height, 2048);

        //设置相机触发模式 	TriggerSelector
        //TriggerSoftware
        //主相机设置为软件触发,输出设置为exposure active
        //SetCamera(cameras[0], Type_Basler_Freerun, 0);

        //从相机设置:触发模式为外触发,IO设置为1
        //SetCamera(cameras[1], Type_Basler_Line1, 0);

    }
    catch (const GenericException& e)
    {
        if(cameras.IsGrabbing())
            cameras.StopGrabbing();
        // Error handling
        LOG(INFO) << "init,An exception occurred." << endl
                  << e.GetDescription() << endl;
    }
}

2.调用相机

调用相机时,最容易出现的问题是,grab image丢帧,在抓取图像丢帧的原因中,主要是由相机帧率设置过大,带宽不足等问题导致。
其中:
if(cameras.IsGrabbing()) 这句可以改成while循环,这样就可以持续输出,if表示就近输出了,根据实际使用情况而定,基本上抓取一帧在50ms左右。其中 cameras.StartGrabbing()可以放在初始化中,这样就不停的抓取,能够保证1秒20帧,不用频繁开始抓取和停止抓取,实际上很耗时。

void GetCameraImage() {
	try {
        //pTL->IssueActionCommand(DeviceKey, GroupKey, AllGroupMask, subnet );
		//1秒内抓取了多少张图,全部存下来
        int skiptime = 1000;
        //LOG(INFO)<<"采集图像的最长时间:"<<skiptime<<" ms"<<endl;
        cameras.StartGrabbing(GrabStrategy_OneByOne,GrabLoop_ProvidedByUser);

        if(cameras.IsGrabbing()) {
            std::chrono::high_resolution_clock::time_point tStartTime(std::chrono::high_resolution_clock::now());
            int lTimeAloInterval = 0;
            count_grab_once++;
            cameras[0].RetrieveResult(skiptime, ptrGrabResultl, TimeoutHandling_ThrowException);
            cameras[1].RetrieveResult(skiptime, ptrGrabResultr, TimeoutHandling_ThrowException);

            if (ptrGrabResultl->GrabSucceeded() && ptrGrabResultr->GrabSucceeded() ) {
                intptr_t cameraContextValuel = ptrGrabResultl->GetCameraContext();
                intptr_t cameraContextValuer = ptrGrabResultr->GetCameraContext();
                const uint8_t *pImageBufferl = (uint8_t *) ptrGrabResultl->GetBuffer();
                const uint8_t *pImageBufferr = (uint8_t *) ptrGrabResultr->GetBuffer();
                // 将 pylon image转成OpenCV image.
                Mat SaveImagel = cv::Mat(ptrGrabResultl->GetHeight(), ptrGrabResultl->GetWidth(), CV_8UC1,
                                        (uint8_t *) pImageBufferl);
                Mat SaveImager = cv::Mat(ptrGrabResultr->GetHeight(), ptrGrabResultr->GetWidth(), CV_8UC1,
                                         (uint8_t *) pImageBufferr);

               
            }
         
            lTimeAloInterval =std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1, 1000> >>(std::chrono::high_resolution_clock::now() - tStartTime).count();
            LOG(INFO) << "------------ single Grab image cost time:----------------" << lTimeAloInterval << " ms" << endl;
        }
        cameras.StopGrabbing();
	}
	catch (const GenericException& e)
	{
        if(cameras.IsGrabbing())
            cameras.StopGrabbing();
		// Error handling
		LOG(INFO) << "An exception occurred." << endl
			<< e.GetDescription() << endl;
	}
	
}

3.关闭相机

相机及时关闭:

void CloseCamera()
{
	//最后终止Pylon相机,即调用PylonTerminate。//关闭摄像头
	try
	{
		if (cameras.IsOpen()) {
			cameras.DetachDevice();
			cameras.Close();
			cameras.DestroyDevice();
			//关闭库
			LOG(INFO) << "SBaslerCameraControl deleteAll: PylonTerminate";
			PylonTerminate();
		}
	}
	catch (const Pylon::GenericException& e)
	{
		LOG(INFO) << "close camera failed..." << e.what();
	}
}

五、常见问题

1.相机连不上

IP配置不正确,确保在同一网段,子网掩码相同。

2.连接后丢帧

 Error: e1004 The bufer was incopletely gratbed. This can be caused by perfomnane problens of the metwork hardware used,fer underuns can also case ina loss.To fix this, us the pylonbioEtonfigurator tol to optinize your setip and use more uffers for aratbin in your aplication to prerent buferunderruns

常见于连接多个相机的时候出现,确保开启巨帧,相机帧率和网络传输的帧率是否满足要求,参加API手册
在这里插入图片描述

3.相机连接后,使用过程中出现找得到相机,但卡住不动了

这种问题不知道是什么原因导致的,可能是长时间没调用导致相机休眠,关机重启下可解决。

4.grab time out 抓取超时

一般是设置waittime时间太短导致,可以改大一些:

 cameras[1].RetrieveResult(waittime, ptrGrabResultr, TimeoutHandling_ThrowException);

还有一种可能是相机连上之后一直么有抓取成功,导致等待时间过长,需要检查代码,常见有时候做触发的操作导致。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1008775.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java实现克里金插值导出geojson矢量数据(kriging)

生成效果 在现代科学研究中&#xff0c;数据的处理和分析是至关重要的一环。然而&#xff0c;我们往往会遇到数据缺失的情况&#xff0c;这时就需要使用插值方法来填补这些缺失值。其中&#xff0c;克里金插值法是一种常用的方法&#xff0c;在很多领域都有广泛的应用。 首先&…

RK3568开发笔记(九):开发板buildroot固件调通RS485口,运行项目中RS485协议调试工具Demo

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/132869448 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

【剑指Offer】52.两个链表的第一个公共节点

题目 输入两个链表&#xff0c;找出它们的第一个公共节点。 如下面的两个链表&#xff1a; 在节点 c1 开始相交。 示例 1&#xff1a; 输入&#xff1a;intersectVal 8, listA [4,1,8,4,5], listB [5,0,1,8,4,5], skipA 2, skipB 3 输出&#xff1a;Reference of the n…

【Linux】网络编程套接字(C++)

目录 一、预备知识 【1.1】理解源IP地址和目的IP地址 【1.2】认识端口号 【1.3】理解 "端口号" 和 "进程ID" 【1.4】理解源端口号和目的端口号 【1.5】认识TCP协议 【1.6】认识UDP协议 二、网络字节序 【2.1】socket编程接口 【2.1.1】socket AP…

5款实用的Redis可视化工具

Redis可视化工具是一种用于管理和监视Redis数据库的工具&#xff0c;它提供了一个可视化界面来操作和查看Redis的数据和配置信息&#xff0c; 可以让我们更加直观地管理和操作Redis数据库。下面介绍四款比较不错的Redis可视化工具。 1.Redis可视化工具推荐—RedisInsight Red…

美创科技入选第二届安徽省网络和数据安全应急技术支撑单位

9月11日&#xff0c;2023年安徽省网络安全宣传周活动在阜阳市正式启动。安徽省委常委、宣传部部长陈舜出席并宣布网安周正式启动。阜阳市委书记刘玉杰、省委宣传部副部长、省委网信办主任张杰华出席并致辞。 开幕式上&#xff0c;省委网信办副主任齐海洋发布第二届安徽省网络和…

Template serialization - shared_ptr<class T>

下面包含的所有代码片段都在 boost::serialization 命名空间内定义。 shared_ptr < T > 在 shared_ptr.hpp 中定义。 shared_ptr 的一般类轮廓如下&#xff1a; shared_ptr 包括以下成员&#xff1a; T *px;shared_count pn;&#xff0c;其中包含指向&#xff1a; sp_c…

(二十七)大数据实战——hbase高可用集群安装与部署

前言 本节内容我们主要介绍HBase高可用集群的安装部署。HBase是一个开源的分布式非关系型数据库管理系统&#xff08;NoSQL&#xff09;&#xff0c;它运行在Apache Hadoop之上。它基于Google的Bigtable论文设计&#xff0c;并且具有高扩展性、高可靠性和高性能的特点。HBase通…

Python 04 之变量【列表,元组,集合,字典,字符串】

&#x1f600;前言 在Python编程语言中&#xff0c;我们经常会遇到各种数据类型和相应的操作方法。理解和掌握这些基本构造是进行有效编程的前提。在本文中&#xff0c;我们将介绍两种非常重要的数据结构 - 集合和字典&#xff0c;然后我们将深入探讨字符串及其相关的操作和处理…

父域 Cookie实现sso单点登录

单点登录&#xff08;Single Sign On, SSO&#xff09;是指在同一帐号平台下的多个应用系统中&#xff0c;用户只需登录一次&#xff0c;即可访问所有相互信任的应用系统。Cookie 的作用域由 domain 属性和 path 属性共同决定。在 Tomcat 中&#xff0c;domain 属性默认为当前域…

CUDA小白 - NPP(8) 图像处理 Morphological Operations

cuda小白 原始API链接 NPP GPU架构近些年也有不少的变化&#xff0c;具体的可以参考别的博主的介绍&#xff0c;都比较详细。还有一些cuda中的专有名词的含义&#xff0c;可以参考《详解CUDA的Context、Stream、Warp、SM、SP、Kernel、Block、Grid》 常见的NppStatus&#xf…

消除笔哪个P图软件有?这几种软件都有消除笔功能

哪些软件中有消除笔工具呢&#xff1f;我们在日常的生活中&#xff0c;会经常有编辑图片的需求&#xff0c;如果图片上有一些内容我们想要将它去除掉&#xff0c;如文字、涂鸦、笔记、标记等&#xff0c;需要用到一些消除笔工具&#xff0c;那么哪些软件具有这个功能并且还非常…

Excel变天了!国内已经可以用Python了!看看如何操作

对于大部分学python的同学来说&#xff0c;绝大部分场景都是用Pandas处理excel。 但有时简单的处理还要打开Jupyter或者VS Code&#xff0c;就有点麻烦。 现在&#xff01;微软已经把Python塞到Excel里啦&#xff01; 其实之前就已经塞了&#xff0c;但这几天国内都可以用了。…

传猪场员工因抑郁症去世,ACM金牌

前言 一位素未蒙面的学弟&#xff0c;R.I.P 既然是 “传”&#xff0c;我们就不能假定人家有抑郁症&#xff0c;其实前天就收到了这个消息&#xff0c;因为是一个学校的&#xff0c;又是ACM金牌&#xff0c;所以第一时间就在群里刷屏了&#xff0c;这件事情对于一个家庭来说&am…

10个TikTok影响力营销策略,让你的品牌崭露头角

TikTok已经成为一种崭露头角和塑造品牌声誉的强大平台。随着数以亿计的用户在这个短视频应用上分享创意和内容&#xff0c;品牌和营销专业人士也越来越多地将其作为推广产品和服务的渠道。 在本文中&#xff0c;我们将探讨10个TikTok影响力营销策略&#xff0c;帮助你的品牌在…

【Spring Boot】有这一文就够了

作者简介 前言 作者之前写过一个Spring Boot的系列&#xff0c;包含自动装配原理、MVC、安全、监控、集成数据库、集成Redis、日志、定时任务、异步任务等内容&#xff0c;本文将会一文拉通来总结这所有内容&#xff0c;不骗人&#xff0c;一文快速入门Spring Boot。 专栏地址…

了解CRM软件系统三种类型的特点与区别

市面上的CRM系统大致可以分为三种主要类型&#xff1a;分析型CRM、运营型CRM和协作型CRM。很多人对这三种类型的CRM系统不太了解&#xff0c;不知道该如何区分&#xff0c;下面我们就来说说CRM系统的3种类型&#xff1a;分析型、运营型和协作型的区别。 分析型CRM的特点&#…

系统灰度随笔记

系统灰度随笔记 这段时间系统重构&#xff0c;负责重构的其中一个模块需要与四个上游系统对接进行切换&#xff0c;虽然自己在这个过程中也设计了一套灰度方案来承接&#xff0c;将灰度的主动权控制在下游&#xff0c;但是很难同时应对四个上游系统&#xff0c;因为每个上游系…

Python语言学习实战-内置函数reduce()的使用(附源码和实现效果)

实现功能 reduce()是一个内置函数&#xff0c;它用于对一个可迭代对象中的元素进行累积操作。它接受一个函数和一个可迭代对象作为参数&#xff0c;并返回一个单个的累积结果。reduce()函数的语法如下&#xff1a; reduce(function, iterable[, initializer])其中&#xff0c;…

SpringMVC之JSON返回及异常处理

目录 JSON处理 导入依赖 配置Spring-mvc.xml ResponseBody注解使用 测试 目录 JSON处理 导入依赖 配置Spring-mvc.xml ResponseBody注解使用 测试 Jackson 定义 用法 常用注解 统一异常处理 为什么要全局异常处理&#xff1f; 异常处理思路 SpringMVC异常分类 综…