当前位置:   article > 正文

海康威视工业相机SDK的开发使用笔记_海康0x80000006

海康0x80000006

环境说明:Ubuntu16.04
海康威视SDK包:MVS-2.1.0_x86_64_20201228.tar.gz

如若在Windows环境下配合Visual Studio使用请移至
海康威视工业相机SDK二次开发(VS+Opencv+QT+海康SDK+C++)(一)
海康威视工业相机SDK二次开发(VS+Opencv+QT+海康SDK+C++)(二)

记录自己的学习过程,方便以后查阅,若有错误或遗漏,欢迎大佬指正补充。

这里写目录标题
  • 1.准备
  • 1.1 相关资料
  • 1.2 Debug常备
  • 1.3 针对错误码的解析
  • MV_E_HANDLE 0x80000000 错误或无效的句柄
  • MV_E_SUPPORT 0x80000001 不支持的功能
  • MV_E_BUFOVER 0x80000002 缓存已满
  • MV_E_CALLORDER 0x80000003 函数调用顺序有误
  • MV_E_PARAMETER 0x80000004 错误的参数
  • MV_E_RESOURCE 0x80000006 资源申请失败
  • MV_E_NODATA 0x80000007 无数据
  • MV_E_NOENOUGH_BUF 0x8000000A 传入的内存空间不足
  • MV_E_UNKNOW 0x800000FF 未知的错误
  • MV_E_GC_GENERIC 0x80000100 通用错误
  • MV_E_GC_RANGE 0x80000102 值超出范围
  • MV_E_GC_ACCESS 0x80000106 节点访问条件有误
  • MV_E_GC_TIMEOUT 0x80000107 超时
  • MV_E_ACCESS_DENIED 0x80000203 设备无访问权限
  • MV_E_NETER 0x80000206 网络相关错误
  • MV_E_IP_CONFLICT 0x80000221 设备IP冲突
  • MV_E_USB_READ 0x80000300 读USB出错
  • MV_E_USB_WRITE 0x80000301 写USB出错
  • MV_E_USB_DRIVER 0x80000305 驱动不匹配或者未装驱动
  • 2.通过海康相机SDK熟悉C接口取图流程和取图方式
  • 2.1 设备连接接口流程
  • 2.2 相机取图——主动取流
  • 2.3 设置相机的一些参数
  • 3.将相机抓取到的图像转为Mat格式,方便后续使用
  • 4.将Mat格式图像转为QImage格式,用于UI界面上控件的显示

1.准备

  首先是安装海康威视的MVS软件,VMware虚拟机中Ubuntu16.04系统下通过MVS运行海康威视工业相机

1.1 相关资料

  • 工业相机SDK(C)开发指南
    这是最重要的资料,里面有(环境配置:SDK编程环境配置,包括网络配置、驱动安装等)、(编程导引:相机连接流程和取图方式介绍)、相机的常用节点等等。
    在这里插入图片描述
    在这里插入图片描述
  • 相机的常用节点查询
    这部分主要是用于SDK提供API接口中的参数设置,如设置曝光模式、曝光值、增益模式、增益值、外触发等等。
    在这里插入图片描述
    根据我实际开发过程中常用的相机节点值如下:
    在这里插入图片描述
  • CameraParams.h:包含编程需要的所有结构体、宏定义和枚举量
  • MvCameraControl.h包含所有控制相机的API接口
  • 相关示例程序
    在这里插入图片描述

1.2 Debug常备

  如果遇到问题,比如相机未正常打开、相机无法取图等等,及时打印每次调用SDK接口返回的输出值,对照错误码定义去排查问题(记得将输出值转化为十六进制)事半功倍。

  如果函数正常完成而没有检测到任何错误,则返回值为MV_OK,否则返回错误码 。
在这里插入图片描述

1.3 针对错误码的解析

  调试时如果遇到常见的错误码,如0x80000000——错误或无效的句柄,很自然的我们就会去排查是不是对于句柄的操作有误,好歹给了我们一些方向,但有些错误码如0x80000006——资源申请失败或者通用错误这些,仅凭类型信息描述根本无法提供方向去排查,这里列出我网上找到的和我实际遇到的及其解决方法供大家参考。
参考:https://zhuanlan.zhihu.com/p/437976222

MV_E_HANDLE 0x80000000 错误或无效的句柄

解析:-2147483648/0x80000000 无效句柄。
常见问题如下
用户没有申请句柄,直接调用接口,新手常犯的错误,要引导去学习我们接口使用流程。
用户创建了句柄,但是其他地方销毁了句柄,用户没有注意到,需要仔细排查代码。

MV_E_SUPPORT 0x80000001 不支持的功能

解析:-2147483647/0x80000001
SDK接口的bayer空域降噪、无损压缩、色彩矫正等ISP功能,需要配合CS-Pro系列相机支持。
格式转化时,不同格式的相互转化,超出了算法能力集,详情请仔细查阅SDK接口说明。

MV_E_BUFOVER 0x80000002 缓存已满

解析:-2147483646/0x80000002
常见于gige驱动启动时报错,低版本SDK在某些网卡上面易发,驱动启动失败后,走socket协议发送接收相机数据,效率低,CPU负载大 推荐使用SDK3.5版本解决此问题。

MV_E_CALLORDER 0x80000003 函数调用顺序有误

解析:-2147483645/0x80000003
sdk接口调用,有一定流程顺序,例如getimagebuffer在startgrabing之前调用,就违反了接口流程,就会报错顺序调用错误 还比如,没有调用startgrabing接口,就去调用频繁调用stopgrabing接口,也会报此错误。

MV_E_PARAMETER 0x80000004 错误的参数

解析:-2147483644/0x80000004
常见问题: 常见于格式转化、图像保存等需要补充数据结构的接口调用,部分参数传入错误,或者没有传入,这个时候,要去仔细检查参数的传入是否正确。

MV_E_RESOURCE 0x80000006 资源申请失败

解析:-2147483654/0x80000004
这个问题我在另一台设备上部署相机服务端时,枚举相机第一步就报了这个错误,最后是安装了MVS后才得以解决,推测是缺了什么依赖库,但ldd的时候并未显示缺失的库。

2022-9-14记录:今天又遇到了这个问题,原来是缺了libMVGigEVisionSDK.so.3.1.3.0libMVGigEVisionSDK.so这两个库。猜测海康这里是dlopen的这两个库,巨坑!!!通过ldd根本看不出什么错误。
在这里插入图片描述

MV_E_NODATA 0x80000007 无数据

解析:-2147483641/0x80000007无数据
相机帧率低,用户调用主动取流接口getimagebuffer/getoneframetimout频率高于相机出图频率,且超时时间短,没有拿到图片,此时应该打印相机帧号,如帧号连续则为正常现象。
相机处于触发模式,没有触发信号给到相机,此时,应该排查用户是否给了软触发或者硬触发信号。
相机停流,此时,建议打开MVS,观察相机状态。
耐心寻找规律,看看是否跟packsize、scpd、取流超时时间不合理所致。

MV_E_NOENOUGH_BUF 0x8000000A 传入的内存空间不足

解析:-2147483638/0x8000000A
1.用户自行开辟的内存大小,小于当前相机图像所需要的图像大小,例如用mono8的图像大小,接收RGB的图像。
2.用户定义的内存大小,中途更换了分辨率更高的相机,导致所需内存较多
3.相机开启了chunk功能,用户开辟缓存大小,仅考虑了图像宽像素格式,没有考虑到chunk。
解决方法:
排查内存开辟大小,建议使用相机payloadsize大小
检查相机图像格式
关闭相机chunk等功能

MV_E_UNKNOW 0x800000FF 未知的错误

解析:-2147483137/0x800000FF GenICam未知错误
未知错误,形成原因较难分析,建议如下:
更新最新版本的sdk
开启sdk日志等级,通过日志分析形成原因

MV_E_GC_GENERIC 0x80000100 通用错误

解析:-2147483392/0x80000100
通用接口调用,关键词写错,例如曝光:ExposureTime,拼写错误就会报错。
第三方相机链接,例如迈德威视相机链接MVS,也会报通用错误,这是因为迈德威视不是标准的genicam协议的相机导致的。
接口类型用错,例如曝光时float型节点,我们使用了一个int型的节点接口进行读写,访问,那么也会报通用错误。

MV_E_GC_RANGE 0x80000102 值超出范围

解析:-2147483390/0x80000102
接口传入的参数值,超出相机接受范围,例如,曝光存在上下限,图像宽高存在步进,没有按照步进进行设置等等。

MV_E_GC_ACCESS 0x80000106 节点访问条件有误

解析:-2147483386/0x80000106
常见的问题类型有: 相机节点不存在或者无法访问,例如,自动曝光,在手动曝光情况下,自动曝光节点会被隐藏,或者其他相机存在这个参数,而使用的相机无此参数,例如线扫相机的行频参数等等,还比如说部分相机无此功能,例如event参数,部分相机固件暂不支持用户调用。

MV_E_GC_TIMEOUT 0x80000107 超时

解析:-2147483385/0x80000107
GVCP命名包回复超时,一般出现在网络环境不好的情况下,此时应该调用接口加大gvcp命令包等待时间(MV_GIGE_GetGvcpTimeout()),持续出现该报错,应该排查网络环境问题。

MV_E_ACCESS_DENIED 0x80000203 设备无访问权限

解析:-2147483133/0x80000203常见问题有:
相机被其他软件打开占用,关闭其他软件,检查设备管理器中,可能存在的残留进程。
代码debug下,心跳时间问题,等待60s后,可以重新打开(此问题参考心跳问题解决方法,可缩短打开时间)。
其余问题,例如一上电就打不开相机,需要重新插拔网线、USB线,就是其他问题,需要具体问题,具体分析。

MV_E_NETER 0x80000206 网络相关错误

解析:-2147483130/0x80000206
此类报错非常常见,主要分以下集中:
相机掉线,能够在日志中发现大量的206报错,此时需要去区分掉线原因,结合相机上电时间、心跳时间、相机权限,日志等信息,综合判断。
网线异常,导致相机掉线,也需要具体问题分析。

MV_E_IP_CONFLICT 0x80000221 设备IP冲突

解析:-2147483103/0x80000221
常见于IP设置时,当前ip已经被其他设备使用,需要更换ip重新设置。

MV_E_USB_READ 0x80000300 读USB出错

解析:-2147482880/0x80000300
USB读取相机信息失败,此类问题较为复制,与USB接口稳定性、线缆长度、电磁环境相关,往往不好分析,可以尝试插拔一下,或者更换USB接口尝试。

MV_E_USB_WRITE 0x80000301 写USB出错

解析:-2147482879/0x80000301
同0x80000300一样,不好分析,可以尝试插拔一下,或者更换USB接口尝试。

MV_E_USB_DRIVER 0x80000305 驱动不匹配或者未装驱动

解析: -2147482875/0x80000305
同0x80000300一样,问题复杂,除了更换USB接口外,还可以尝试更换sdk版本。

2.通过海康相机SDK熟悉C接口取图流程和取图方式

个人总结:句柄(void *handle)是相机开发中重要的一环,SDK中的接口中,大部分都是针对句柄的操作,如果有多个相机,要将每个相机和其对应的句柄关联好,防止后期使用的过程中未及时释放句柄、造成混乱等。

2.1 设备连接接口流程

  对设备进行操作,实现图像采集、参数配置等功能,需要先连接设备(打开设备),具体流程如下图所示:
在这里插入图片描述
  1.调用 MV_CC_EnumDevices() 枚举子网内指定传输协议对应的所有设备。可以通过 pstDevList 在结构 MV_CC_DEVICE_INFO_LIST 中找到设备的信息。
在这里插入图片描述

  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">#include "MvCameraControl.h"
  2. void main()
  3. {
  4. unsigned int nTLayerType = MV_GIGE_DEVICE | MV_USB_DEVICE;
  5. MV_CC_DEVICE_INFO_LIST m_stDevList = {0};
  6. int nRet = MV_CC_EnumDevices(nTLayerType, &m_stDevList);
  7. if (MV_OK != nRet)
  8. {
  9. printf("error: EnumDevices fail [%x]\n", nRet);
  10. }
  11. }
  12. </code></span></span>

  关于搜索到的所有相机设备信息在 MV_CC_DEVICE_INFO_LIST结构体中,

  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">/// \~chinese 设备信息列表 \~english Device Information List
  2. typedef struct _MV_CC_DEVICE_INFO_LIST_
  3. {
  4. unsigned int nDeviceNum; ///< [OUT] \~chinese 在线设备数量 \~english Online Device Number
  5. MV_CC_DEVICE_INFO* pDeviceInfo[MV_MAX_DEVICE_NUM]; ///< [OUT] \~chinese 支持最多256个设备 \~english Support up to 256 devices
  6. }MV_CC_DEVICE_INFO_LIST;
  7. </code></span></span>

  通过MV_CC_DEVICE_INFO结构体可以访问每个设备的详细信息,

  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">/// \~chinese 设备信息 \~english Device info
  2. typedef struct _MV_CC_DEVICE_INFO_
  3. {
  4. unsigned short nMajorVer; ///< [OUT] \~chinese 主要版本 \~english Major Version
  5. unsigned short nMinorVer; ///< [OUT] \~chinese 次要版本 \~english Minor Version
  6. unsigned int nMacAddrHigh; ///< [OUT] \~chinese 高MAC地址 \~english High MAC Address
  7. unsigned int nMacAddrLow; ///< [OUT] \~chinese 低MAC地址 \~english Low MAC Address
  8. unsigned int nTLayerType; ///< [OUT] \~chinese 设备传输层协议类型,e.g. MV_GIGE_DEVICE \~english Device Transport Layer Protocol Type, e.g. MV_GIGE_DEVICE
  9. unsigned int nReserved[4]; ///< \~chinese 预留 \~english Reserved
  10. union
  11. {
  12. MV_GIGE_DEVICE_INFO stGigEInfo; ///< [OUT] \~chinese GigE设备信息 \~english GigE Device Info
  13. MV_USB3_DEVICE_INFO stUsb3VInfo; ///< [OUT] \~chinese USB设备信息 \~english USB Device Info
  14. MV_CamL_DEV_INFO stCamLInfo; ///< [OUT] \~chinese CameraLink设备信息 \~english CameraLink Device Info
  15. // more ...
  16. }SpecialInfo;
  17. }MV_CC_DEVICE_INFO;
  18. </code></span></span>

  这里以我使用的网口相机GigE设备为例,要获取到设备的详细内容:

  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">// 我通过std::map<std::string, std::tuple<void*,MV_CC_DEVICE_INFO*>>m_dev_info_list_;来存储枚举到的所示设备。
  2. // 第一个参数的设备的名称,这个可以自己定义,方便后面对哪一个相机进行操作;
  3. // 第二个参数是句柄
  4. // 第三个参数就是MV_CC_DEVICE_INFO设备信息的结构体
  5. MV_CC_DEVICE_INFO* pstMVDevInfo = std::get<1>(m_dev_info_list_[dev_name]);
  6. if (pstMVDevInfo->nTLayerType == MV_GIGE_DEVICE) {
  7. std::string model =
  8. (char*)pstMVDevInfo->SpecialInfo.stGigEInfo.chModelName;
  9. std::string cam_ip = "Current IP Address: " ;
  10. int nIp1 =
  11. ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >>
  12. 24);
  13. int nIp2 =
  14. ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >>
  15. 16);
  16. int nIp3 =
  17. ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >>
  18. 8);
  19. int nIp4 =
  20. (pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);
  21. }
  22. </code></span></span>

  有些参数我也没搞懂是什么信息。。。
在这里插入图片描述
  2.在打开指定设备之前,调用 MV_CC_IsDeviceAccessible() 检查指定设备是否可访问。 (这一步在实际使用中并未用到)
在这里插入图片描述
  3.调用 MV_CC_CreateHandle() 以创建设备句柄。
在这里插入图片描述

  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">#include "MvCameraControl.h"
  2. void main()
  3. {
  4. int nRet = -1;
  5. void* m_handle = NULL;
  6. //枚举子网内指定的传输协议对应的所有设备
  7. unsigned int nTLayerType = MV_GIGE_DEVICE | MV_USB_DEVICE;
  8. MV_CC_DEVICE_INFO_LIST m_stDevList = {0};
  9. int nRet = MV_CC_EnumDevices(nTLayerType, &m_stDevList);
  10. if (MV_OK != nRet)
  11. {
  12. printf("error: EnumDevices fail [%x]\n", nRet);
  13. return;
  14. }
  15. int i = 0;
  16. if (m_stDevList.nDeviceNum == 0)
  17. {
  18. printf("no camera found!\n");
  19. return;
  20. }
  21. //选择查找到的第一台在线设备,创建设备句柄
  22. int nDeviceIndex = 0;
  23. MV_CC_DEVICE_INFO m_stDevInfo = {0};
  24. memcpy(&m_stDevInfo, m_stDevList.pDeviceInfo[nDeviceIndex], sizeof(MV_CC_DEVICE_INFO));
  25. nRet = MV_CC_CreateHandle(&m_handle, &m_stDevInfo);
  26. if (MV_OK != nRet)
  27. {
  28. printf("error: CreateHandle fail [%x]\n", nRet);
  29. return;
  30. }
  31. //...其他处理
  32. //销毁句柄,释放资源
  33. nRet = MV_CC_DestroyHandle(m_handle);
  34. if (MV_OK != nRet)
  35. {
  36. printf("error: DestroyHandle fail [%x]\n", nRet);
  37. return;
  38. }
  39. }
  40. </code></span></span>

  4.调用 MV_CC_OpenDevice() 打开设备。
在这里插入图片描述
  去该API定义后发现,后面两个参数有默认值,所以实际使用中只需要输入第一个参数设备的句柄即可。

  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">/********************************************************************//**
  2. * @~chinese
  3. * @brief 打开设备
  4. * @param handle [IN] 设备句柄
  5. * @param nAccessMode [IN] 访问权限
  6. * @param nSwitchoverKey [IN] 切换访问权限时的密钥
  7. * @return 成功,返回MV_OK;错误,返回错误码
  8. * @remarks 根据设置的设备参数,找到对应的设备,连接设备。\n
  9. 调用接口时可不传入nAccessMode和nSwitchoverKey,此时默认设备访问模式为独占权限。目前设备暂不支持MV_ACCESS_ExclusiveWithSwitch、MV_ACCESS_ControlWithSwitch、MV_ACCESS_ControlSwitchEnable、MV_ACCESS_ControlSwitchEnableWithKey这四种抢占模式。\n
  10. 对于U3V设备,nAccessMode、nSwitchoverKey这两个参数无效。 */
  11. #ifndef __cplusplus
  12. MV_CAMCTRL_API int __stdcall MV_CC_OpenDevice(IN void* handle, IN unsigned int nAccessMode, IN unsigned short nSwitchoverKey);
  13. #else
  14. MV_CAMCTRL_API int __stdcall MV_CC_OpenDevice(IN void* handle, IN unsigned int nAccessMode = MV_ACCESS_Exclusive, IN unsigned short nSwitchoverKey = 0);
  15. #endif
  16. </code></span></span>
  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">int nRet = MV_CC_OpenDevice(m_handle);
  2. </code></span></span>

  5.调用 MV_CC_CloseDevice() 关闭设备。
在这里插入图片描述
  6.调用 MV_CC_DestroyHandle() 来销毁句柄并释放资源。
在这里插入图片描述

2.2 相机取图——主动取流

  SDK提供主动获取图像的接口,用户可以在开启取流后直接调用此接口获取图像,也可以使用异步方式(线程、定时器等)获取图像。示例代码详见 GrabImage.cpp 和 GrabImage_HighPerformance.cpp 。
在这里插入图片描述

  • 主动获取图像有两种方式(两种方式不能同时使用)
    方式一:调用 MV_CC_StartGrabbing() 开始采集,需要自己开启一个buffer,然后在应用层循环调用 MV_CC_GetOneFrameTimeout() 获取指定像素格式的帧数据,获取帧数据时上层应用程序需要根据帧率控制好调用该接口的频率。
    方式二:调用 MV_CC_StartGrabbing() 开始采集,然后在应用层调用 MV_CC_GetImageBuffer() 获取指定像素格式的帧数据,然后调用 MV_CC_FreeImageBuffer() 释放buffer,获取帧数据时上层应用程序需要根据帧率控制好调用该接口的频率。
  • 主动取图方式使用的场景
    主动取图方式需要先调用 MV_CC_StartGrabbing() 启动图像采集。上层应用程序需要根据帧率,控制好调用主动取图接口的频率。两种主动取图方式都支持设置超时时间,SDK内部等待直到有数据时返回,可以增加取流平稳性,适合用于对平稳性要求较高的场合。
  • 两种主动取图方式的区别
    a、 MV_CC_GetImageBuffer() 需要与 MV_CC_FreeImageBuffer() 配套使用,当处理完取到的数据后,需要用 MV_CC_FreeImageBuffer() 接口将pstFrame内的数据指针权限进行释放。
    b、 MV_CC_GetImageBuffer() 与 MV_CC_GetOneFrameTimeout() 相比,有着更高的效率。且其取流缓存的分配是由sdk内部自动分配的,而 MV_CC_GetOneFrameTimeout() 接口是需要客户自行分配。

这里我使用方式一的取图流程。

  1.开始取流。
在这里插入图片描述
  2.停止取流。
在这里插入图片描述
  3.方式一的取图方式,采用超时机制获取一帧图片,SDK内部等待直到有数据时返回。
在这里插入图片描述

所获取的帧属于裸数据,数据保存在pData,并无图像格式(具体数据格式可以提前设定)。pFrameInfo表示输出帧的信息。

  可以通过函数MV_CC_Display(IN void* handle, IN void* hWnd)来实时显示采集到的图像。该函数需要在MV_CC_StartGrabbing之后调用,显示采集到的图像。如果相机当前采集图像是JPEG压缩的格式,则不支持调用该函数接口进行显示。

  可以通过函数MV_CC_SaveImage(IN&OUT MV_SAVE_IMAGE_PARAM* pSaveParam)将原始图像数据转换成图片格式并保存在指定内存里,再通过函数fwrite写入文件中。
  也可以通过函数MV_CC_SaveImageEx将原始图像数据转换成图片格式并保存在指定内存中,可支持设置JPEG编码质量。

  可通过函数memcpy(OUT void* dst, IN void const* src, IN size_t size) 把资源内存(src所指向的内存区域)拷贝到目标内存(dest所指向的内存区域),从而将unsigned char格式的图像数据转换为QImage格式的图像数据,这里要注意输入数据的格式,代码中输入的unsigned char pFrameBuf数据格式分别为Mono8的灰度图像和RGB8_Packed的彩色图像。

  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">#include "MvCameraControl.h"
  2. void main()
  3. {
  4. int nRet = -1;
  5. void* m_handle = NULL;
  6. //枚举子网内指定的传输协议对应的所有设备
  7. unsigned int nTLayerType = MV_GIGE_DEVICE | MV_USB_DEVICE;
  8. MV_CC_DEVICE_INFO_LIST m_stDevList = {0};
  9. int nRet = MV_CC_EnumDevices(nTLayerType, &m_stDevList);
  10. if (MV_OK != nRet)
  11. {
  12. printf("error: EnumDevices fail [%x]\n", nRet);
  13. return;
  14. }
  15. int i = 0;
  16. if (m_stDevList.nDeviceNum == 0)
  17. {
  18. printf("no camera found!\n");
  19. return;
  20. }
  21. //选择查找到的第一台在线设备,创建设备句柄
  22. int nDeviceIndex = 0;
  23. MV_CC_DEVICE_INFO m_stDevInfo = {0};
  24. memcpy(&m_stDevInfo, m_stDevList.pDeviceInfo[nDeviceIndex], sizeof(MV_CC_DEVICE_INFO));
  25. nRet = MV_CC_CreateHandle(&m_handle, &m_stDevInfo);
  26. if (MV_OK != nRet)
  27. {
  28. printf("error: CreateHandle fail [%x]\n", nRet);
  29. return;
  30. }
  31. //连接设备
  32. nRet = MV_CC_OpenDevice(m_handle, nAccessMode, nSwitchoverKey);
  33. if (MV_OK != nRet)
  34. {
  35. printf("error: OpenDevice fail [%x]\n", nRet);
  36. return;
  37. }
  38. //...其他处理
  39. //开始采集图像
  40. nRet = MV_CC_StartGrabbing(m_handle);
  41. if (MV_OK != nRet)
  42. {
  43. printf("error: StartGrabbing fail [%x]\n", nRet);
  44. return;
  45. }
  46. //获取一帧数据的大小
  47. MVCC_INTVALUE stIntvalue = {0};
  48. nRet = MV_CC_GetIntValue(m_handle, "PayloadSize", &stIntvalue);
  49. if (nRet != MV_OK)
  50. {
  51. printf("Get PayloadSize failed! nRet [%x]\n", nRet);
  52. return;
  53. }
  54. int nBufSize = stIntvalue.nCurValue; //一帧数据大小
  55. unsigned int nTestFrameSize = 0;
  56. unsigned char* pFrameBuf = NULL;
  57. pFrameBuf = (unsigned char*)malloc(nBufSize);
  58. MV_FRAME_OUT_INFO_EX stInfo;
  59. memset(&stInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));
  60. //上层应用程序需要根据帧率,控制好调用该接口的频率
  61. //此次代码仅供参考,实际应用建议另建线程进行图像帧采集和处理
  62. while(1)
  63. {
  64. if (nTestFrameSize > 99)
  65. {
  66. break;
  67. }
  68. nRet = MV_CC_GetOneFrameTimeout(m_handle, pFrameBuf, nBufSize, &stInfo, 1000);
  69. if (MV_OK != nRet)
  70. {
  71. Sleep(10);
  72. }
  73. else
  74. {
  75. //...图像数据处理
  76. nTestFrameSize++;
  77. }
  78. }
  79. //...其他处理
  80. //停止采集图像
  81. nRet = MV_CC_StopGrabbing(m_handle);
  82. if (MV_OK != nRet)
  83. {
  84. printf("error: StopGrabbing fail [%x]\n", nRet);
  85. return;
  86. }
  87. //关闭设备,释放资源
  88. nRet = MV_CC_CloseDevice(m_handle);
  89. if (MV_OK != nRet)
  90. {
  91. printf("error: CloseDevice fail [%x]\n", nRet);
  92. return;
  93. }
  94. //销毁句柄,释放资源
  95. nRet = MV_CC_DestroyHandle(m_handle);
  96. if (MV_OK != nRet)
  97. {
  98. printf("error: DestroyHandle fail [%x]\n", nRet);
  99. return;
  100. }
  101. }
  102. </code></span></span>

SDK还提供了回调出流的方法,这里我没研究,如果大佬采用的这种方式,也可以一起交流,方便我学习。

2.3 设置相机的一些参数

  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">/********************************************************************//**
  2. * @~chinese
  3. * @brief 设置Enum型属性值
  4. * @param handle [IN] 设备句柄
  5. * @param strKey [IN] 属性键值,如获取像素格式信息则为"PixelFormat"
  6. * @param nValue [IN] 想要设置的设备的属性值
  7. * @return 成功,返回MV_OK,失败,返回错误码
  8. * @remarks 连接设备之后调用该接口可以设置Enum类型的指定节点的值。strKey取值可以参考XML节点参数类型列表,表格里面数据类型为“IEnumeration”的节点值都可以通过该接口设置,strKey参数取值对应列表里面的“名称”一列。
  9. ************************************************************************/
  10. MV_CAMCTRL_API int __stdcall MV_CC_SetEnumValue(IN void* handle,IN const char* strKey,IN unsigned int nValue);
  11. /********************************************************************//**
  12. * @~chinese
  13. * @brief 设置float型属性值
  14. * @param handle [IN] 设备句柄
  15. * @param strKey [IN] 属性键值
  16. * @param fValue [IN] 想要设置的设备的属性值
  17. * @return 成功,返回MV_OK,失败,返回错误码
  18. * @remarks 连接设备之后调用该接口可以设置float类型的指定节点的值。strKey取值可以参考XML节点参数类型列表,表格里面数据类型为“IFloat”的节点值都可以通过该接口设置,strKey参数取值对应列表里面的“名称”一列。 ************************************************************************/
  19. MV_CAMCTRL_API int __stdcall MV_CC_SetFloatValue(IN void* handle,IN const char* strKey,IN float fValue);
  20. </code></span></span>

  关于输入参数参考相机中的节点。

  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">int setCameraParametMode(const char* str_key, unsigned int val)
  2. {
  3. // TriggerMode 0: Off 1: On
  4. // TriggerSource 0:Line0 1:Line1 7:Software
  5. // GainAuto 0: Off 1: Once 2: Continuous
  6. int temp_val = MV_CC_SetEnumValue(m_handle, str_key, val);
  7. if (temp_val != 0) {
  8. return -1;
  9. }
  10. else {
  11. return 0;
  12. }
  13. }
  14. int setCameraParametValue(const char* str_type, float num_val)
  15. {
  16. // ExposureTime
  17. // Gain
  18. int temp_value = MV_CC_SetFloatValue(m_handle, str_type, num_val);
  19. if (temp_value != 0) {
  20. return -1;
  21. }
  22. else {
  23. return 0;
  24. }
  25. }
  26. </code></span></span>

  使用:

  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">camera_obj->setCameraParametMode("ExposureAuto", 0);
  2. camera_obj->setCameraParametValue("ExposureTime", exposure_time);
  3. camera_obj->setCameraParametMode("GainAuto", 0);
  4. camera_obj->setCameraParametValue("Gain", gain);
  5. </code></span></span>

3.将相机抓取到的图像转为Mat格式,方便后续使用

  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">/************************************************************************
  2. * @fn MV_CAMCTRL_API int __stdcall MV_CC_GetIntValue(IN void* handle,
  3. IN const char* strKey,
  4. OUT MVCC_INTVALUE *pIntValue);
  5. * @brief 获取Integer属性值(建议改用MV_CC_GetIntValueEx接口)
  6. * @param void* handle [IN] 相机句柄
  7. * @param char* strKey [IN] 属性键值,如获取宽度信息则为"Width"
  8. * @param MVCC_INTVALUE* pstValue [IN][OUT] 返回给调用者有关相机属性结构体指针
  9. * @return 成功,返回MV_OK,失败,返回错误码
  10. ************************************************************************/
  11. MV_CAMCTRL_API int __stdcall MV_CC_GetIntValue(IN void* handle,IN const char* strKey,OUT MVCC_INTVALUE *pIntValue);
  12. </code></span></span>
  • 相机采集到的图像格式是buffer,需要将其转化为Mat类型。
  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">int HikCamera::CameraOneFrameImageToMat(void* dev_handle,const std::string& dev_name, cv::Mat& image)
  2. {
  3. cv::Mat* getImage = new cv::Mat();
  4. unsigned int nRecvBufSize = 0;
  5. MVCC_INTVALUE stParam;
  6. memset(&stParam, 0, sizeof(MVCC_INTVALUE));
  7. int tempValue = MV_CC_GetIntValue(dev_handle, "PayloadSize", &stParam);
  8. if (tempValue != 0) {
  9. return -1;
  10. }
  11. nRecvBufSize = stParam.nCurValue;
  12. unsigned char* pDate;
  13. pDate = (unsigned char*)malloc(nRecvBufSize);
  14. MV_FRAME_OUT_INFO_EX stImageInfo = { 0 };
  15. tempValue = MV_CC_GetOneFrameTimeout(dev_handle, pDate, nRecvBufSize,
  16. &stImageInfo, 500);
  17. if (tempValue != 0) {
  18. return -1;
  19. }
  20. m_nBufSizeForSaveImage_ =
  21. stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;
  22. unsigned char* m_pBufForSaveImage;
  23. m_pBufForSaveImage = (unsigned char*)malloc(m_nBufSizeForSaveImage_);
  24. bool isMono; //判断是否为黑白图像
  25. switch (stImageInfo.enPixelType) {
  26. case PixelType_Gvsp_Mono8:
  27. case PixelType_Gvsp_Mono10:
  28. case PixelType_Gvsp_Mono10_Packed:
  29. case PixelType_Gvsp_Mono12:
  30. case PixelType_Gvsp_Mono12_Packed:
  31. isMono = true;
  32. break;
  33. default:
  34. isMono = false;
  35. break;
  36. }
  37. if (isMono) {
  38. *getImage =
  39. cv::Mat(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC1, pDate);
  40. }
  41. else {
  42. // 转换图像格式为BGR8
  43. MV_CC_PIXEL_CONVERT_PARAM stConvertParam = { 0 };
  44. memset(&stConvertParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));
  45. stConvertParam.nWidth = stImageInfo.nWidth;
  46. stConvertParam.nHeight = stImageInfo.nHeight;
  47. stConvertParam.pSrcData = pDate;
  48. stConvertParam.nSrcDataLen = stImageInfo.nFrameLen; // 输入数据大小
  49. stConvertParam.enSrcPixelType = stImageInfo.enPixelType; // 输入像素格式
  50. stConvertParam.enDstPixelType = PixelType_Gvsp_BGR8_Packed; // 输出像素格式
  51. stConvertParam.pDstBuffer = m_pBufForSaveImage; // 输出数据缓存
  52. stConvertParam.nDstBufferSize = m_nBufSizeForSaveImage_; // 输出缓存大小
  53. MV_CC_ConvertPixelType(dev_handle, &stConvertParam);
  54. *getImage = cv::Mat(stImageInfo.nHeight, stImageInfo.nWidth, CV_8UC3, m_pBufForSaveImage);
  55. }
  56. (*getImage).copyTo(image);
  57. (*getImage).release();
  58. free(pDate);
  59. free(m_pBufForSaveImage);
  60. return 0;
  61. }
  62. </code></span></span>

4.将Mat格式图像转为QImage格式,用于UI界面上控件的显示

  转化为Mat后,通过display_myImage_L再将Mat转化为QImage类型,进行在控件上显示。软触发的话,就是采集到当前帧图像,通过display_myImage_L显示,连续采集的话,通过多线程,将线程对象myThread_camera_L_show发送信号display给主线程,主线程调用display_myImage_L将相机采集到的图像进行显示。

  1. <span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">void display_myImage_L(const cv::Mat* image_ptr)
  2. {
  3. cv::Mat rgb;
  4. // cv::cvtColor(*imagePrt, rgb, CV_BGR2RGB);
  5. //判断是黑白、彩色图像
  6. QImage QmyImage_L;
  7. if (lbl_camera_L_image->channels() > 1) {
  8. cv::cvtColor(*image_ptr, rgb, CV_BGR2RGB);
  9. QmyImage_L = QImage((const unsigned char*)(rgb.data), rgb.cols,
  10. rgb.rows, QImage::Format_RGB888);
  11. }
  12. else {
  13. cv::cvtColor(*image_ptr, rgb, CV_GRAY2RGB);
  14. QmyImage_L = QImage((const unsigned char*)(rgb.data), rgb.cols,
  15. rgb.rows, QImage::Format_RGB888);
  16. }
  17. QmyImage_L = (QmyImage_L).scaled(ui.lbl_camera_L->size(), Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
  18. ui.lbl_camera_L->setPixmap(QPixmap::fromImage(QmyImage_L));
  19. }
  20. </code></span></span>

参考博文:
hikvision SDK使用(转)-腾讯云开发者社区-腾讯云
rm记录第三阶段(二):海康威视工业相机的使用,cmake的复习_海康工业相机cmakelists-CSDN博客
关于相机SDK开发
海康相机SDK联合c++标定-腾讯云开发者社区-腾讯云

海康威视工业相机SDK的开发使用笔记_海康工业相机sdk-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/885114
推荐阅读
相关标签
  

闽ICP备14008679号