python语言调用海康机器人(hikrobotics)工业相机


系列文章目录

第一章 python调用海康工业相机并用opencv显示(整体实现)

第二章 python 调用海康工业相机图像获取方式之回调取流并用 opencv 显示

第三章 python 调用海康工业相机图像获取方式之主动取流(getoneframetimeout )并用 opencv 显示

第四章 python 调用海康工业相机图像获取方式之主动取流( getimagebuffer )并用 opencv 显示

第五章 python 调用海康工业相机调试后出现被占用问题

第六章 (简略调用版本)python语言下使用opencv接口cv2.VideoCapture()接口调用海康机器人工业相机

第七章 python语言下使用pyqt中的QImage对海康工业相机获取到的图像进行显示

文章目录

目录

python语言调用海康机器人(hikrobotics)工业相机

文章目录

前言

一、底层接口的准备

二、使用步骤

1.引入库

2.枚举设备

3.判断设备类型

4.输入连接设备

5.创建相机实例并创建句柄

6.打开设备

7.获取相关参数

8.获取图像

9.开启取流并获取每张图像数据大小

10.停止取流以及关闭设备

11.调用封装实现相机取流

12.完整代码

三、总结


前言

随着机器视觉的广泛应用,机器视觉在工业领域的使用也越来越成熟;

基于以上情况,海康机器人的接口也比较丰富了,笔者就基于自己项目需求,使用python语言调用海康工业相机,总结python调用的使用方法


一、底层接口的准备

使用工业相机之前,首先需要一个相对应的SDK底层来驱动相机,而这个SDK底层也是开放给我们进行二次开发的,实际上就是一个库,包含各种功能调用的接口函数,现阶段海康使用的底层SDK的库,主要包括两种语言,C语言和C#语言,而python所调用的是C语言的底层SDK,通过将C语言的SDK接口重新封装,达到python调用的目的;海康在海康相机驱动软件的安装目录下,也提供了相应的简单调用例程,具体路径如下:...\MVS\Development\Samples\python

并且提供了相应接口的功能说明以及SDK开发指南,具体路径如下:...\MVS\Development\Documentations  用以方便二次开发中对接口的调用;python语言的接口可以参考C版本;

python中支持的接口以及参数可以从相应文件中查取,具体路径如下:...\MVS\Development\Samples\python\MvImport

其中最主要调用的是 MvCameraControl_class.py ,该文件中包含从C语言底层接口封装过来的所有 python 可调用接口,在调用时是需要导入该文件作为调用包;

二、使用步骤

1.引入库

在调用相机时,需要使用python相关的一些包和海康底层的一些包,这在 python 中是比较常见的,本文中涉及到的包如下导入:
由于海康相机 python 接口是封装于 C 语言,因而在导入包时,需要导入 ctypes 的包,用于一些类型;

import os
import sys
import numpy as np
import cv2
from ctypes import *sys.path.append("../MvImport")
from MvCameraControl_class import *

需要注意的是 sys.path.append("../MvImport") 使用的路径是相对路径,主要是用于 from MvCameraControl_class import * 这句包导入时使用,在此处可能会遇到一个问题,问题报错如下:

Traceback (most recent call last):File "D:/2021_new/Python/MvImport/Mv_CameraControl_function.py", line 17, in <module>from MvCameraControl_class import *File "D:\2021_new\Python\MvImport\MvCameraControl_class.py", line 14, in <module>MvCamCtrldll = WinDLL("MvCameraControl.dll")File "C:\ProgramData\Anaconda3\envs\tf2\lib\ctypes\__init__.py", line 348, in __init__self._handle = _dlopen(self._name, mode)
OSError: [WinError 126] 找不到指定的模块。

主要原因是在 MvCameraControl_class.py 文件中,使用 MvCameraControl.dll 文件时,相对路径失效导致,可以对  MvCameraControl_class.py 文件中导包部分进行如下修改即可;

MvCamCtrldll = WinDLL("C:\\Program Files (x86)\\Common Files\\MVS\\Runtime\\Win64_x64\\MvCameraControl.dll")

2.枚举设备

枚举设备的接口在手册中介绍如下:

其中说明了可以连接的设备种类有 GigE 设备、1394-a/b 设备 、USB3.0设备、cameralink 设备这几种,即在电脑上调用该接口可以枚举到这些类型接口的设备;

对应的 python 中封装的接口在 MvCameraControl_class.py 文件中,代码部分如下所示:

    def MV_CC_EnumDevices(nTLayerType, stDevList):MvCamCtrldll.MV_CC_EnumDevices.argtype = (c_uint, c_void_p)MvCamCtrldll.MV_CC_EnumDevices.restype = c_uint# C原型:int MV_CC_EnumDevices(unsigned int nTLayerType, MV_CC_DEVICE_INFO_LIST* pstDevList)return MvCamCtrldll.MV_CC_EnumDevices(c_uint(nTLayerType), byref(stDevList))

在本次开发中,将枚举设备进行了 python 语言函数的封装,具体代码如下:

def enum_devices(device = 0 , device_way = False):"""device = 0  枚举网口、USB口、未知设备、cameralink 设备device = 1 枚举GenTL设备"""if device_way == False:if device == 0:tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICE | MV_UNKNOW_DEVICE | MV_1394_DEVICE | MV_CAMERALINK_DEVICEdeviceList = MV_CC_DEVICE_INFO_LIST()# 枚举设备ret = MvCamera.MV_CC_EnumDevices(tlayerType, deviceList)if ret != 0:print("enum devices fail! ret[0x%x]" % ret)sys.exit()if deviceList.nDeviceNum == 0:print("find no device!")sys.exit()print("Find %d devices!" % deviceList.nDeviceNum)return deviceListelse:passelif device_way == True:pass

如上所示内容,在枚举设备中,有不同种类的几种设备可以被枚举到,枚举到之后会返回一个 设备列表 deviceList , 由于设备列表是由 MV_CC_DEVICE_INFO_LIST()结构体定义的,由文档可知其中包含两部分内容:

1、在线设备数量

2、设备信息结构体

基于第一部分内容,我们可以获取到枚举到了多少台设备,第二部分内容可以用于后续的一些设备信息的判别和获取;

因为后续要枚举 GenTL设备,所以此处预留了位置,该部分后续加入;

3.判断设备类型

基于以上枚举设备接口调用获取的设备列表,可以获取设备是哪种类型设备并对其中的信息加以利用和输出;

本次开发过程因为只涉及到 GigE 接口设备和 USB设备,所以对这两种类型的设备常用信息进行解析和打印;代码如下:

# 判断不同类型设备
def identify_different_devices(deviceList):# 判断不同类型设备,并输出相关信息for i in range(0, deviceList.nDeviceNum):mvcc_dev_info = cast(deviceList.pDeviceInfo[i], POINTER(MV_CC_DEVICE_INFO)).contents# 判断是否为网口相机if mvcc_dev_info.nTLayerType == MV_GIGE_DEVICE:print ("\n网口设备序号: [%d]" % i)# 获取设备名strModeName = ""for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chModelName:strModeName = strModeName + chr(per)print ("当前设备型号名: %s" % strModeName)# 获取当前设备 IP 地址nip1_1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24)nip1_2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16)nip1_3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8)nip1_4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff)print ("当前 ip 地址: %d.%d.%d.%d" % (nip1_1, nip1_2, nip1_3, nip1_4))# 获取当前子网掩码nip2_1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentSubNetMask & 0xff000000) >> 24)nip2_2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentSubNetMask & 0x00ff0000) >> 16)nip2_3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentSubNetMask & 0x0000ff00) >> 8)nip2_4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentSubNetMask & 0x000000ff)print ("当前子网掩码 : %d.%d.%d.%d" % (nip2_1, nip2_2, nip2_3, nip2_4))# 获取当前网关nip3_1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nDefultGateWay & 0xff000000) >> 24)nip3_2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nDefultGateWay & 0x00ff0000) >> 16)nip3_3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nDefultGateWay & 0x0000ff00) >> 8)nip3_4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nDefultGateWay & 0x000000ff)print("当前网关 : %d.%d.%d.%d" % (nip3_1, nip3_2, nip3_3, nip3_4))# 获取网口 IP 地址nip4_1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nNetExport & 0xff000000) >> 24)nip4_2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nNetExport & 0x00ff0000) >> 16)nip4_3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nNetExport & 0x0000ff00) >> 8)nip4_4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nNetExport & 0x000000ff)print("当前连接的网口 IP 地址 : %d.%d.%d.%d" % (nip4_1, nip4_2, nip4_3, nip4_4))# 获取制造商名称strmanufacturerName = ""for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chManufacturerName:strmanufacturerName = strmanufacturerName + chr(per)print("制造商名称 : %s" % strmanufacturerName)# 获取设备版本stdeviceversion = ""for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chDeviceVersion:stdeviceversion = stdeviceversion + chr(per)print("设备当前使用固件版本 : %s" % stdeviceversion)# 获取制造商的具体信息stManufacturerSpecificInfo = ""for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chManufacturerSpecificInfo:stManufacturerSpecificInfo = stManufacturerSpecificInfo + chr(per)print("设备制造商的具体信息 : %s" % stManufacturerSpecificInfo)# 获取设备序列号stSerialNumber = ""for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chSerialNumber:stSerialNumber = stSerialNumber + chr(per)print("设备序列号 : %s" % stSerialNumber)# 获取用户自定义名称stUserDefinedName = ""for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chUserDefinedName:stUserDefinedName = stUserDefinedName + chr(per)print("用户自定义名称 : %s" % stUserDefinedName)# 判断是否为 USB 接口相机elif mvcc_dev_info.nTLayerType == MV_USB_DEVICE:print ("\nU3V 设备序号e: [%d]" % i)strModeName = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chModelName:if per == 0:breakstrModeName = strModeName + chr(per)print ("当前设备型号名 : %s" % strModeName)strSerialNumber = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chSerialNumber:if per == 0:breakstrSerialNumber = strSerialNumber + chr(per)print ("当前设备序列号 : %s" % strSerialNumber)# 获取制造商名称strmanufacturerName = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chVendorName:strmanufacturerName = strmanufacturerName + chr(per)print("制造商名称 : %s" % strmanufacturerName)# 获取设备版本stdeviceversion = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chDeviceVersion:stdeviceversion = stdeviceversion + chr(per)print("设备当前使用固件版本 : %s" % stdeviceversion)# 获取设备序列号stSerialNumber = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chSerialNumber:stSerialNumber = stSerialNumber + chr(per)print("设备序列号 : %s" % stSerialNumber)# 获取用户自定义名称stUserDefinedName = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chUserDefinedName:stUserDefinedName = stUserDefinedName + chr(per)print("用户自定义名称 : %s" % stUserDefinedName)# 获取设备 GUIDstDeviceGUID = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chDeviceGUID:stDeviceGUID = stDeviceGUID + chr(per)print("设备GUID号 : %s" % stDeviceGUID)# 获取设备的家族名称stFamilyName = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chFamilyName:stFamilyName = stFamilyName + chr(per)print("设备的家族名称 : %s" % stFamilyName)# 判断是否为 1394-a/b 设备elif mvcc_dev_info.nTLayerType == MV_1394_DEVICE:print("\n1394-a/b device: [%d]" % i)# 判断是否为 cameralink 设备elif mvcc_dev_info.nTLayerType == MV_CAMERALINK_DEVICE:print("\ncameralink device: [%d]" % i)# 获取当前设备名strModeName = ""for per in mvcc_dev_info.SpecialInfo.stCamLInfo.chModelName:if per == 0:breakstrModeName = strModeName + chr(per)print("当前设备型号名 : %s" % strModeName)# 获取当前设备序列号strSerialNumber = ""for per in mvcc_dev_info.SpecialInfo.stCamLInfo.chSerialNumber:if per == 0:breakstrSerialNumber = strSerialNumber + chr(per)print("当前设备序列号 : %s" % strSerialNumber)# 获取制造商名称strmanufacturerName = ""for per in mvcc_dev_info.SpecialInfo.stCamLInfo.chVendorName:strmanufacturerName = strmanufacturerName + chr(per)print("制造商名称 : %s" % strmanufacturerName)# 获取设备版本stdeviceversion = ""for per in mvcc_dev_info.SpecialInfo.stCamLInfo.chDeviceVersion:stdeviceversion = stdeviceversion + chr(per)print("设备当前使用固件版本 : %s" % stdeviceversion)

其中相对比较重要的一些参数,比如设备型号、设备序列号、IP地址等,在使用中均可以依据这些去绑定打开设备,本次开发中是以设备序号进行绑定打开使用的,同样可以参考本文方式使用以上的几种方式去绑定打开设备;

4.输入连接设备

如上介绍,可以通过以上的打印信息获取到可以连接的设备,下面通过 python 的方式进行连接,输入相关设备序号,用以连接相机,代码如下:

# 输入需要连接的相机的序号
def input_num_camera(deviceList):nConnectionNum = input("please input the number of the device to connect:")if int(nConnectionNum) >= deviceList.nDeviceNum:print("intput error!")sys.exit()return nConnectionNum

5.创建相机实例并创建句柄

在海康底层接口中,有两个创建句柄的接口,其中一个接口是可以生成日志的,另一个是不生成日志的,这两种接口都可以调用,本次将两个接口都进行了封装函数,用于可选调用;

# 创建相机实例并创建句柄,(设置日志路径)
def creat_camera(deviceList , nConnectionNum ,log = True , log_path = getcwd()):""":param deviceList:        设备列表:param nConnectionNum:    需要连接的设备序号:param log:               是否创建日志:param log_path:          日志保存路径:return:                  相机实例和设备列表"""# 创建相机实例cam = MvCamera()# 选择设备并创建句柄stDeviceList = cast(deviceList.pDeviceInfo[int(nConnectionNum)], POINTER(MV_CC_DEVICE_INFO)).contentsif log == True:ret = cam.MV_CC_SetSDKLogPath(log_path)print(log_path)if ret != 0:print("set Log path  fail! ret[0x%x]" % ret)sys.exit()# 创建句柄,生成日志ret = cam.MV_CC_CreateHandle(stDeviceList)if ret != 0:print("create handle fail! ret[0x%x]" % ret)sys.exit()elif log == False:# 创建句柄,不生成日志ret = cam.MV_CC_CreateHandleWithoutLog(stDeviceList)print(1111)if ret != 0:print("create handle fail! ret[0x%x]" % ret)sys.exit()return cam , stDeviceList

这一部分中,加入了修改相机运行日志的接口在创建句柄(生成日志)前,这个接口可以将相机运行的日志保存到想保存到的目录下;

6.打开设备

在获取到以上内容之后,就需要打开设备了,打开设备使用  MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0) 接口,封装的函数代码如下:

# 打开设备
def open_device(cam):# ch:打开设备 | en:Open deviceret = cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)if ret != 0:print("open device fail! ret[0x%x]" % ret)sys.exit()

7.获取相关参数

在打开设备之后,相机的参数等一些功能均可以使用,比如获取参数,(如获取数据大小),这些在底层中有通用接口支撑,这些通用接口如下图在开发手册中的介绍;

使用这些通用接口,就可以对海康相机的所有功能参数进行获取和设置了,这点还是很方便,为了更方便一些,在下面进行了再次封装,将获取参数的函数和设置参数的函数进行了重新封装;

以下是获取相关参数的代码,其中通过 param_type 获取节点的类型 和 node_name 节点名定位到要获取的节点,再调用底层接口进行参数的获取,( 其中节点值类型和节点名均可以在海康客户端中获取到 )具体代码如下:

# 获取各种类型节点参数
def get_Value(cam , param_type = "int_value" , node_name = "PayloadSize"):""":param cam:            相机实例:param_type:           获取节点值得类型:param node_name:      节点名 可选 int 、float 、enum 、bool 、string 型节点:return:               节点值"""if param_type == "int_value":stParam = MVCC_INTVALUE_EX()memset(byref(stParam), 0, sizeof(MVCC_INTVALUE_EX))ret = cam.MV_CC_GetIntValueEx(node_name, stParam)if ret != 0:print("获取 int 型数据 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()int_value = stParam.nCurValuereturn int_valueelif param_type == "float_value":stFloatValue = MVCC_FLOATVALUE()memset(byref(stFloatValue), 0, sizeof(MVCC_FLOATVALUE))ret = cam.MV_CC_GetFloatValue( node_name , stFloatValue)if ret != 0:print("获取 float 型数据 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()float_value = stFloatValue.fCurValuereturn float_valueelif param_type == "enum_value":stEnumValue = MVCC_ENUMVALUE()memset(byref(stEnumValue), 0, sizeof(MVCC_ENUMVALUE))ret = cam.MV_CC_GetEnumValue(node_name, stEnumValue)if ret != 0:print("获取 enum 型数据 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()enum_value = stEnumValue.nCurValuereturn enum_valueelif param_type == "bool_value":stBool = c_bool(False)ret = cam.MV_CC_GetBoolValue(node_name, stBool)if ret != 0:print("获取 bool 型数据 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()return stBool.valueelif param_type == "string_value":stStringValue =  MVCC_STRINGVALUE()memset(byref(stStringValue), 0, sizeof( MVCC_STRINGVALUE))ret = cam.MV_CC_GetStringValue(node_name, stStringValue)if ret != 0:print("获取 string 型数据 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()string_value = stStringValue.chCurValuereturn string_value

下面部分是设置参数的接口统一封装,对于不同类型的节点,需要用底层不同的接口进行设置,以下代码是通过 param_type ,node_name 定位到要用哪一个底层接口和节点,并将需要设置的 node_value 传入,实现代码部分如下:

# 设置各种类型节点参数
def set_Value(cam , param_type = "int_value" , node_name = "PayloadSize" , node_value = None):""":param cam:               相机实例:param param_type:        需要设置的节点值得类型int:float:enum:     参考于客户端中该选项的 Enum Entry Value 值即可bool:     对应 0 为关,1 为开string:   输入值为数字或者英文字符,不能为汉字:param node_name:         需要设置的节点名:param node_value:        设置给节点的值:return:"""if param_type == "int_value":stParam = int(node_value)ret = cam.MV_CC_SetIntValueEx(node_name, stParam)if ret != 0:print("设置 int 型数据节点 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()print("设置 int 型数据节点 %s 成功 !设置值为 %s !"%(node_name , node_value))elif param_type == "float_value":stFloatValue = float(node_value)ret = cam.MV_CC_SetFloatValue( node_name , stFloatValue)if ret != 0:print("设置 float 型数据节点 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()print("设置 float 型数据节点 %s 成功 !设置值为 %s !" % (node_name, node_value))elif param_type == "enum_value":stEnumValue = node_valueret = cam.MV_CC_SetEnumValue(node_name, stEnumValue)if ret != 0:print("设置 enum 型数据节点 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()print("设置 enum 型数据节点 %s 成功 !设置值为 %s !" % (node_name, node_value))elif param_type == "bool_value":ret = cam.MV_CC_SetBoolValue(node_name, node_value)if ret != 0:print("设置 bool 型数据节点 %s 失败 ! 报错码 ret[0x%x]" %(node_name,ret))sys.exit()print("设置 bool 型数据节点 %s 成功 !设置值为 %s !" % (node_name, node_value))elif param_type == "string_value":stStringValue = str(node_value)ret = cam.MV_CC_SetStringValue(node_name, stStringValue)if ret != 0:print("设置 string 型数据节点 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()print("设置 string 型数据节点 %s 成功 !设置值为 %s !" % (node_name, node_value))

8.获取图像

在海康的接口调用中,取图方式分为两种方式,第一种是主动取图,第二种是回调取图;

主动取图的底层接口包括:MV_CC_GetImageForRGB()、MV_CC_GetImageForBGR()、MV_CC_GetImageBuffer()、MV_CC_GetOneFrameTimeout() 四种方式

MV_CC_GetImageBuffer()这个接口中对于图像解析和显示部分可以参考本系列如下链接文章:python 调用海康工业相机图像获取方式之主动取流( getimagebuffer )并用 opencv 显示

MV_CC_GetOneFrameTimeout() 这个接口中对于图像解析和显示部分可以参考本系列文章中如下链接文章:python 调用海康工业相机图像获取方式之主动取流(getoneframetimeout )并用 opencv 显示

回调取图的底层接口包括:MV_CC_RegisterImageCallBackEx() 、MV_CC_RegisterImageCallBackForRGB()、MV_CC_RegisterImageCallBackForBGR() 三种方式

MV_CC_RegisterImageCallBackEx() 这个接口中对于图像解析和显示部分可以参考本系列文章中如下链接文章:python 调用海康工业相机图像获取方式之回调取流并用 opencv 显示

基于本次项目的使用情况,我选择了 MV_CC_GetOneFrameTimeout() 接口进行了显示,其他接口并未做相关的显示以及数据解析,其他接口在后续文章种实现,本文只主要介绍MV_CC_GetOneFrameTimeout()接口和MV_CC_GetImageBuffer()接口获取的数据进行转换和显示,具体的实现代码和预留接口代码如下:

def access_get_image(cam , active_way = "getImagebuffer"):""":param cam:     相机实例:active_way:主动取流方式的不同方法 分别是(getImagebuffer)(getoneframetimeout):return:"""if active_way == "getImagebuffer":stOutFrame = MV_FRAME_OUT()memset(byref(stOutFrame), 0, sizeof(stOutFrame))while True:ret = cam.MV_CC_GetImageBuffer(stOutFrame, 1000)if None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 17301505:print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)()cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight),dtype=np.uint8)image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)elif None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 17301514:print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)()cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight),dtype=np.uint8)image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)elif None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 35127316:print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight*3)()cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight*3)data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight*3),dtype=np.uint8)image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)elif None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 34603039:print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 2)()cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 2)data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 2),dtype=np.uint8)image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)else:print("no data[0x%x]" % ret)nRet = cam.MV_CC_FreeImageBuffer(stOutFrame)elif active_way == "getoneframetimeout":stParam = MVCC_INTVALUE_EX()memset(byref(stParam), 0, sizeof(MVCC_INTVALUE_EX))ret = cam.MV_CC_GetIntValueEx("PayloadSize", stParam)if ret != 0:print("get payload size fail! ret[0x%x]" % ret)sys.exit()nDataSize = stParam.nCurValuepData = (c_ubyte * nDataSize)()stFrameInfo = MV_FRAME_OUT_INFO_EX()memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))while True:ret = cam.MV_CC_GetOneFrameTimeout(pData, nDataSize, stFrameInfo, 1000)if ret == 0:print("get one frame: Width[%d], Height[%d], nFrameNum[%d] " % (stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nFrameNum))image = np.asarray(pData)image_control(data=image, stFrameInfo=stFrameInfo)else:print("no data[0x%x]" % ret)

这一部分中只使用 getImagebuffer 获取图像,未对数据进行解析,后续解析给出;

其中  stFrameInfo.enPixelType == 17301505 这部分是对图像数据的像素格式的判断,用于后面的转换,其中17301505 这些数字是从 C:\Program Files (x86)\MVS\Development\Samples\Python\MvImport 路径下的 PixelType_header.py 文件种获取到的,分别对应相机的不同像素格式;

使用了 python 下opencv的接口,将数据转换为 opencv 可处理的数据类型,并通过 resize() 接口对图像的整体大小进行了缩放,方便各种分辨率相机的使用;

9.开启取流并获取每张图像数据大小

相机在使用中,主动获取图像前,是要先开启取流的,废话不多少,以下是对开启取流的底层接口进行的封装代码;

# 开启取流并获取数据包大小
def start_grab_and_get_data_size(cam):ret = cam.MV_CC_StartGrabbing()if ret != 0:print("开始取流失败! ret[0x%x]" % ret)sys.exit()# 获取数据包大小stParam = MVCC_INTVALUE_EX()memset(byref(stParam), 0, sizeof(MVCC_INTVALUE_EX))ret = cam.MV_CC_GetIntValueEx("PayloadSize", stParam)if ret != 0:print("get payload size fail! ret[0x%x]" % ret)sys.exit()nPayloadSize = stParam.nCurValuereturn nPayloadSize

cam.MV_CC_GetIntValue(“PayloadSize”, stParam)这一句中的PayloadSize是流通道上的每个图像传输的最大字节数,相机的PayloadSize的典型值是(宽x高x像素大小)

10.停止取流以及关闭设备

相机在需要关掉前,按照正常情况操作,是需要先停止取流,再进行关闭的,最后将句柄销毁所以对这些底层接口进行了简单封装,代码如下:

# 关闭设备与销毁句柄
def close_and_destroy_device(cam , data_buf=None):# 停止取流ret = cam.MV_CC_StopGrabbing()if ret != 0:print("stop grabbing fail! ret[0x%x]" % ret)sys.exit()# 关闭设备ret = cam.MV_CC_CloseDevice()if ret != 0:print("close deivce fail! ret[0x%x]" % ret)del data_bufsys.exit()# 销毁句柄ret = cam.MV_CC_DestroyHandle()if ret != 0:print("destroy handle fail! ret[0x%x]" % ret)del data_bufsys.exit()del data_buf

11.调用封装实现相机取流

经过以上的函数封装,已经完成了对海康工业相机的简单调用的整个流程,以上内容都是对底层接口的封装,以下是对这些封装函数的调用,即调用主函数,代码如下:

def main():# 枚举设备deviceList = enum_devices(device=0, device_way=False)# 判断不同类型设备identify_different_devices(deviceList)# 输入需要被连接的设备nConnectionNum = input_num_camera(deviceList)# 创建相机实例并创建句柄,(设置日志路径)cam, stDeviceList = creat_camera(deviceList, nConnectionNum, log=False)# decide_divice_on_line(cam)  ==============# 打开设备open_device(cam)# # 设置缓存节点个数# set_image_Node_num(cam, Num=10)# # 设置取流策略# set_grab_strategy(cam, grabstrategy=2, outputqueuesize=10)# 设置设备的一些参数# set_Value(cam, param_type="bool_value", node_name="TriggerCacheEnable", node_value=1)# 获取设备的一些参数# get_value = get_Value(cam , param_type = "int_value" , node_name = "PayloadSize")stdcall = input("回调方式取流显示请输入 0    主动取流方式显示请输入 1:")if int(stdcall) == 0:# 回调方式抓取图像call_back_get_image(cam)# 开启设备取流start_grab_and_get_data_size(cam)# 当使用 回调取流时,需要在此处添加print ("press a key to stop grabbing.")msvcrt.getch()# 关闭设备与销毁句柄close_and_destroy_device(cam)elif int(stdcall) == 1:# 开启设备取流start_grab_and_get_data_size(cam)# 主动取流方式抓取图像access_get_image(cam, active_way="getImagebuffer")# 关闭设备与销毁句柄close_and_destroy_device(cam)

以上是对相机的的连接、取图、显示、关闭的整体简单调用,调用效果如下图所示:

如上所示就完成了整个海康工业相机的调用,并对一些基础的接口进行了简单封装;

12.完整代码

import os
import sys
import numpy as np
from os import getcwd
import cv2
import msvcrt
from ctypes import *sys.path.append("../MvImport")
from MvCameraControl_class import *# 枚举设备
def enum_devices(device = 0 , device_way = False):"""device = 0  枚举网口、USB口、未知设备、cameralink 设备device = 1 枚举GenTL设备"""if device_way == False:if device == 0:tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICE | MV_UNKNOW_DEVICE | MV_1394_DEVICE | MV_CAMERALINK_DEVICEdeviceList = MV_CC_DEVICE_INFO_LIST()# 枚举设备ret = MvCamera.MV_CC_EnumDevices(tlayerType, deviceList)if ret != 0:print("enum devices fail! ret[0x%x]" % ret)sys.exit()if deviceList.nDeviceNum == 0:print("find no device!")sys.exit()print("Find %d devices!" % deviceList.nDeviceNum)return deviceListelse:passelif device_way == True:pass# 判断不同类型设备
def identify_different_devices(deviceList):# 判断不同类型设备,并输出相关信息for i in range(0, deviceList.nDeviceNum):mvcc_dev_info = cast(deviceList.pDeviceInfo[i], POINTER(MV_CC_DEVICE_INFO)).contents# 判断是否为网口相机if mvcc_dev_info.nTLayerType == MV_GIGE_DEVICE:print ("\n网口设备序号: [%d]" % i)# 获取设备名strModeName = ""for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chModelName:strModeName = strModeName + chr(per)print ("当前设备型号名: %s" % strModeName)# 获取当前设备 IP 地址nip1_1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24)nip1_2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16)nip1_3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8)nip1_4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff)print ("当前 ip 地址: %d.%d.%d.%d" % (nip1_1, nip1_2, nip1_3, nip1_4))# 获取当前子网掩码nip2_1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentSubNetMask & 0xff000000) >> 24)nip2_2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentSubNetMask & 0x00ff0000) >> 16)nip2_3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentSubNetMask & 0x0000ff00) >> 8)nip2_4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentSubNetMask & 0x000000ff)print ("当前子网掩码 : %d.%d.%d.%d" % (nip2_1, nip2_2, nip2_3, nip2_4))# 获取当前网关nip3_1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nDefultGateWay & 0xff000000) >> 24)nip3_2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nDefultGateWay & 0x00ff0000) >> 16)nip3_3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nDefultGateWay & 0x0000ff00) >> 8)nip3_4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nDefultGateWay & 0x000000ff)print("当前网关 : %d.%d.%d.%d" % (nip3_1, nip3_2, nip3_3, nip3_4))# 获取网口 IP 地址nip4_1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nNetExport & 0xff000000) >> 24)nip4_2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nNetExport & 0x00ff0000) >> 16)nip4_3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nNetExport & 0x0000ff00) >> 8)nip4_4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nNetExport & 0x000000ff)print("当前连接的网口 IP 地址 : %d.%d.%d.%d" % (nip4_1, nip4_2, nip4_3, nip4_4))# 获取制造商名称strmanufacturerName = ""for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chManufacturerName:strmanufacturerName = strmanufacturerName + chr(per)print("制造商名称 : %s" % strmanufacturerName)# 获取设备版本stdeviceversion = ""for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chDeviceVersion:stdeviceversion = stdeviceversion + chr(per)print("设备当前使用固件版本 : %s" % stdeviceversion)# 获取制造商的具体信息stManufacturerSpecificInfo = ""for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chManufacturerSpecificInfo:stManufacturerSpecificInfo = stManufacturerSpecificInfo + chr(per)print("设备制造商的具体信息 : %s" % stManufacturerSpecificInfo)# 获取设备序列号stSerialNumber = ""for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chSerialNumber:stSerialNumber = stSerialNumber + chr(per)print("设备序列号 : %s" % stSerialNumber)# 获取用户自定义名称stUserDefinedName = ""for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chUserDefinedName:stUserDefinedName = stUserDefinedName + chr(per)print("用户自定义名称 : %s" % stUserDefinedName)# 判断是否为 USB 接口相机elif mvcc_dev_info.nTLayerType == MV_USB_DEVICE:print ("\nU3V 设备序号e: [%d]" % i)strModeName = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chModelName:if per == 0:breakstrModeName = strModeName + chr(per)print ("当前设备型号名 : %s" % strModeName)strSerialNumber = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chSerialNumber:if per == 0:breakstrSerialNumber = strSerialNumber + chr(per)print ("当前设备序列号 : %s" % strSerialNumber)# 获取制造商名称strmanufacturerName = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chVendorName:strmanufacturerName = strmanufacturerName + chr(per)print("制造商名称 : %s" % strmanufacturerName)# 获取设备版本stdeviceversion = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chDeviceVersion:stdeviceversion = stdeviceversion + chr(per)print("设备当前使用固件版本 : %s" % stdeviceversion)# 获取设备序列号stSerialNumber = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chSerialNumber:stSerialNumber = stSerialNumber + chr(per)print("设备序列号 : %s" % stSerialNumber)# 获取用户自定义名称stUserDefinedName = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chUserDefinedName:stUserDefinedName = stUserDefinedName + chr(per)print("用户自定义名称 : %s" % stUserDefinedName)# 获取设备 GUIDstDeviceGUID = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chDeviceGUID:stDeviceGUID = stDeviceGUID + chr(per)print("设备GUID号 : %s" % stDeviceGUID)# 获取设备的家族名称stFamilyName = ""for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chFamilyName:stFamilyName = stFamilyName + chr(per)print("设备的家族名称 : %s" % stFamilyName)# 判断是否为 1394-a/b 设备elif mvcc_dev_info.nTLayerType == MV_1394_DEVICE:print("\n1394-a/b device: [%d]" % i)# 判断是否为 cameralink 设备elif mvcc_dev_info.nTLayerType == MV_CAMERALINK_DEVICE:print("\ncameralink device: [%d]" % i)# 获取当前设备名strModeName = ""for per in mvcc_dev_info.SpecialInfo.stCamLInfo.chModelName:if per == 0:breakstrModeName = strModeName + chr(per)print("当前设备型号名 : %s" % strModeName)# 获取当前设备序列号strSerialNumber = ""for per in mvcc_dev_info.SpecialInfo.stCamLInfo.chSerialNumber:if per == 0:breakstrSerialNumber = strSerialNumber + chr(per)print("当前设备序列号 : %s" % strSerialNumber)# 获取制造商名称strmanufacturerName = ""for per in mvcc_dev_info.SpecialInfo.stCamLInfo.chVendorName:strmanufacturerName = strmanufacturerName + chr(per)print("制造商名称 : %s" % strmanufacturerName)# 获取设备版本stdeviceversion = ""for per in mvcc_dev_info.SpecialInfo.stCamLInfo.chDeviceVersion:stdeviceversion = stdeviceversion + chr(per)print("设备当前使用固件版本 : %s" % stdeviceversion)# 输入需要连接的相机的序号
def input_num_camera(deviceList):nConnectionNum = input("please input the number of the device to connect:")if int(nConnectionNum) >= deviceList.nDeviceNum:print("intput error!")sys.exit()return nConnectionNum# 创建相机实例并创建句柄,(设置日志路径)
def creat_camera(deviceList , nConnectionNum ,log = True , log_path = getcwd()):""":param deviceList:        设备列表:param nConnectionNum:    需要连接的设备序号:param log:               是否创建日志:param log_path:          日志保存路径:return:                  相机实例和设备列表"""# 创建相机实例cam = MvCamera()# 选择设备并创建句柄stDeviceList = cast(deviceList.pDeviceInfo[int(nConnectionNum)], POINTER(MV_CC_DEVICE_INFO)).contentsif log == True:ret = cam.MV_CC_SetSDKLogPath(log_path)print(log_path)if ret != 0:print("set Log path  fail! ret[0x%x]" % ret)sys.exit()# 创建句柄,生成日志ret = cam.MV_CC_CreateHandle(stDeviceList)if ret != 0:print("create handle fail! ret[0x%x]" % ret)sys.exit()elif log == False:# 创建句柄,不生成日志ret = cam.MV_CC_CreateHandleWithoutLog(stDeviceList)print(1111)if ret != 0:print("create handle fail! ret[0x%x]" % ret)sys.exit()return cam , stDeviceList# 打开设备
def open_device(cam):# ch:打开设备 | en:Open deviceret = cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)if ret != 0:print("open device fail! ret[0x%x]" % ret)sys.exit()# 获取各种类型节点参数
def get_Value(cam , param_type = "int_value" , node_name = "PayloadSize"):""":param cam:            相机实例:param_type:           获取节点值得类型:param node_name:      节点名 可选 int 、float 、enum 、bool 、string 型节点:return:               节点值"""if param_type == "int_value":stParam = MVCC_INTVALUE_EX()memset(byref(stParam), 0, sizeof(MVCC_INTVALUE_EX))ret = cam.MV_CC_GetIntValueEx(node_name, stParam)if ret != 0:print("获取 int 型数据 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()int_value = stParam.nCurValuereturn int_valueelif param_type == "float_value":stFloatValue = MVCC_FLOATVALUE()memset(byref(stFloatValue), 0, sizeof(MVCC_FLOATVALUE))ret = cam.MV_CC_GetFloatValue( node_name , stFloatValue)if ret != 0:print("获取 float 型数据 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()float_value = stFloatValue.fCurValuereturn float_valueelif param_type == "enum_value":stEnumValue = MVCC_ENUMVALUE()memset(byref(stEnumValue), 0, sizeof(MVCC_ENUMVALUE))ret = cam.MV_CC_GetEnumValue(node_name, stEnumValue)if ret != 0:print("获取 enum 型数据 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()enum_value = stEnumValue.nCurValuereturn enum_valueelif param_type == "bool_value":stBool = c_bool(False)ret = cam.MV_CC_GetBoolValue(node_name, stBool)if ret != 0:print("获取 bool 型数据 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()return stBool.valueelif param_type == "string_value":stStringValue =  MVCC_STRINGVALUE()memset(byref(stStringValue), 0, sizeof( MVCC_STRINGVALUE))ret = cam.MV_CC_GetStringValue(node_name, stStringValue)if ret != 0:print("获取 string 型数据 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()string_value = stStringValue.chCurValuereturn string_value# 设置各种类型节点参数
def set_Value(cam , param_type = "int_value" , node_name = "PayloadSize" , node_value = None):""":param cam:               相机实例:param param_type:        需要设置的节点值得类型int:float:enum:     参考于客户端中该选项的 Enum Entry Value 值即可bool:     对应 0 为关,1 为开string:   输入值为数字或者英文字符,不能为汉字:param node_name:         需要设置的节点名:param node_value:        设置给节点的值:return:"""if param_type == "int_value":stParam = int(node_value)ret = cam.MV_CC_SetIntValueEx(node_name, stParam)if ret != 0:print("设置 int 型数据节点 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()print("设置 int 型数据节点 %s 成功 !设置值为 %s !"%(node_name , node_value))elif param_type == "float_value":stFloatValue = float(node_value)ret = cam.MV_CC_SetFloatValue( node_name , stFloatValue)if ret != 0:print("设置 float 型数据节点 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()print("设置 float 型数据节点 %s 成功 !设置值为 %s !" % (node_name, node_value))elif param_type == "enum_value":stEnumValue = node_valueret = cam.MV_CC_SetEnumValue(node_name, stEnumValue)if ret != 0:print("设置 enum 型数据节点 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()print("设置 enum 型数据节点 %s 成功 !设置值为 %s !" % (node_name, node_value))elif param_type == "bool_value":ret = cam.MV_CC_SetBoolValue(node_name, node_value)if ret != 0:print("设置 bool 型数据节点 %s 失败 ! 报错码 ret[0x%x]" %(node_name,ret))sys.exit()print("设置 bool 型数据节点 %s 成功 !设置值为 %s !" % (node_name, node_value))elif param_type == "string_value":stStringValue = str(node_value)ret = cam.MV_CC_SetStringValue(node_name, stStringValue)if ret != 0:print("设置 string 型数据节点 %s 失败 ! 报错码 ret[0x%x]" % (node_name , ret))sys.exit()print("设置 string 型数据节点 %s 成功 !设置值为 %s !" % (node_name, node_value))# 寄存器读写
def read_or_write_memory(cam , way = "read"):if way == "read":passcam.MV_CC_ReadMemory()elif way == "write":passcam.MV_CC_WriteMemory()# 判断相机是否处于连接状态(返回值如何获取)=================================
def decide_divice_on_line(cam):value = cam.MV_CC_IsDeviceConnected()if value == True:print("该设备在线 !")else:print("该设备已掉线 !", value)# 设置 SDK 内部图像缓存节点个数
def set_image_Node_num(cam , Num = 1):ret = cam.MV_CC_SetImageNodeNum(nNum = Num)if ret != 0:print("设置 SDK 内部图像缓存节点个数失败 ,报错码 ret[0x%x]" % ret)else:print("设置 SDK 内部图像缓存节点个数为 %d  ,设置成功!" % Num)# 设置取流策略
def set_grab_strategy(cam , grabstrategy = 0 , outputqueuesize = 1):"""• OneByOne: 从旧到新一帧一帧的从输出缓存列表中获取图像,打开设备后默认为该策略• LatestImagesOnly: 仅从输出缓存列表中获取最新的一帧图像,同时清空输出缓存列表• LatestImages: 从输出缓存列表中获取最新的OutputQueueSize帧图像,其中OutputQueueSize范围为1 - ImageNodeNum,可用MV_CC_SetOutputQueueSize()接口设置,ImageNodeNum默认为1,可用MV_CC_SetImageNodeNum()接口设置OutputQueueSize设置成1等同于LatestImagesOnly策略,OutputQueueSize设置成ImageNodeNum等同于OneByOne策略• UpcomingImage: 在调用取流接口时忽略输出缓存列表中所有图像,并等待设备即将生成的一帧图像。该策略只支持GigE设备,不支持U3V设备"""if grabstrategy != 2:ret = cam.MV_CC_SetGrabStrategy(enGrabStrategy = grabstrategy)if ret != 0:print("设置取流策略失败 ,报错码 ret[0x%x]" % ret)else:print("设置 取流策略为 %d  ,设置成功!" % grabstrategy)else:ret = cam.MV_CC_SetGrabStrategy(enGrabStrategy=grabstrategy)if ret != 0:print("设置取流策略失败 ,报错码 ret[0x%x]" % ret)else:print("设置 取流策略为 %d  ,设置成功!" % grabstrategy)ret = cam.MV_CC_SetOutputQueueSize(nOutputQueueSize = outputqueuesize)if ret != 0:print("设置使出缓存个数失败 ,报错码 ret[0x%x]" % ret)else:print("设置 输出缓存个数为 %d  ,设置成功!" % outputqueuesize)# 显示图像
def image_show(image , name):image = cv2.resize(image, (600, 400), interpolation=cv2.INTER_AREA)name = str(name)cv2.imshow(name, image)cv2.imwrite("name.bmp", image)k = cv2.waitKey(1) & 0xff# 需要显示的图像数据转换
def image_control(data , stFrameInfo):if stFrameInfo.enPixelType == 17301505:image = data.reshape((stFrameInfo.nHeight, stFrameInfo.nWidth))image_show(image=image , name = stFrameInfo.nHeight)elif stFrameInfo.enPixelType == 17301514:data = data.reshape(stFrameInfo.nHeight, stFrameInfo.nWidth, -1)image = cv2.cvtColor(data, cv2.COLOR_BAYER_GB2RGB)image_show(image=image, name = stFrameInfo.nHeight)elif stFrameInfo.enPixelType == 35127316:data = data.reshape(stFrameInfo.nHeight, stFrameInfo.nWidth, -1)image = cv2.cvtColor(data, cv2.COLOR_RGB2BGR)image_show(image=image, name = stFrameInfo.nHeight)elif stFrameInfo.enPixelType == 34603039:data = data.reshape(stFrameInfo.nHeight, stFrameInfo.nWidth, -1)image = cv2.cvtColor(data, cv2.COLOR_YUV2BGR_Y422)image_show(image = image, name = stFrameInfo.nHeight)# 主动图像采集
def access_get_image(cam , active_way = "getImagebuffer"):""":param cam:     相机实例:active_way:主动取流方式的不同方法 分别是(getImagebuffer)(getoneframetimeout):return:"""if active_way == "getImagebuffer":stOutFrame = MV_FRAME_OUT()memset(byref(stOutFrame), 0, sizeof(stOutFrame))while True:ret = cam.MV_CC_GetImageBuffer(stOutFrame, 1000)if None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 17301505:print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)()cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight),dtype=np.uint8)image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)elif None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 17301514:print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)()cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight)data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight),dtype=np.uint8)image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)elif None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 35127316:print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight*3)()cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight*3)data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight*3),dtype=np.uint8)image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)elif None != stOutFrame.pBufAddr and 0 == ret and stOutFrame.stFrameInfo.enPixelType == 34603039:print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stOutFrame.stFrameInfo.nWidth, stOutFrame.stFrameInfo.nHeight, stOutFrame.stFrameInfo.nFrameNum))pData = (c_ubyte * stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 2)()cdll.msvcrt.memcpy(byref(pData), stOutFrame.pBufAddr,stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 2)data = np.frombuffer(pData, count=int(stOutFrame.stFrameInfo.nWidth * stOutFrame.stFrameInfo.nHeight * 2),dtype=np.uint8)image_control(data=data, stFrameInfo=stOutFrame.stFrameInfo)else:print("no data[0x%x]" % ret)nRet = cam.MV_CC_FreeImageBuffer(stOutFrame)elif active_way == "getoneframetimeout":stParam = MVCC_INTVALUE_EX()memset(byref(stParam), 0, sizeof(MVCC_INTVALUE_EX))ret = cam.MV_CC_GetIntValueEx("PayloadSize", stParam)if ret != 0:print("get payload size fail! ret[0x%x]" % ret)sys.exit()nDataSize = stParam.nCurValuepData = (c_ubyte * nDataSize)()stFrameInfo = MV_FRAME_OUT_INFO_EX()memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))while True:ret = cam.MV_CC_GetOneFrameTimeout(pData, nDataSize, stFrameInfo, 1000)if ret == 0:print("get one frame: Width[%d], Height[%d], nFrameNum[%d] " % (stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nFrameNum))image = np.asarray(pData)image_control(data=image, stFrameInfo=stFrameInfo)else:print("no data[0x%x]" % ret)# 回调取图采集
winfun_ctype = WINFUNCTYPE
stFrameInfo = POINTER(MV_FRAME_OUT_INFO_EX)
pData = POINTER(c_ubyte)
FrameInfoCallBack = winfun_ctype(None, pData, stFrameInfo, c_void_p)
def image_callback(pData, pFrameInfo, pUser):global img_buffimg_buff = NonestFrameInfo = cast(pFrameInfo, POINTER(MV_FRAME_OUT_INFO_EX)).contentsif stFrameInfo:print ("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nFrameNum))if img_buff is None and stFrameInfo.enPixelType == 17301505:img_buff = (c_ubyte * stFrameInfo.nWidth*stFrameInfo.nHeight)()cdll.msvcrt.memcpy(byref(img_buff) , pData , stFrameInfo.nWidth*stFrameInfo.nHeight)data = np.frombuffer(img_buff , count = int(stFrameInfo.nWidth*stFrameInfo.nHeight) , dtype = np.uint8)image_control(data=data, stFrameInfo=stFrameInfo)del img_buffelif img_buff is None and stFrameInfo.enPixelType == 17301514:img_buff = (c_ubyte * stFrameInfo.nWidth*stFrameInfo.nHeight)()cdll.msvcrt.memcpy(byref(img_buff) , pData , stFrameInfo.nWidth*stFrameInfo.nHeight)data = np.frombuffer(img_buff , count = int(stFrameInfo.nWidth*stFrameInfo.nHeight) , dtype = np.uint8)image_control(data=data, stFrameInfo=stFrameInfo)del img_buffelif img_buff is None and stFrameInfo.enPixelType == 35127316:img_buff = (c_ubyte * stFrameInfo.nWidth * stFrameInfo.nHeight*3)()cdll.msvcrt.memcpy(byref(img_buff), pData, stFrameInfo.nWidth * stFrameInfo.nHeight*3)data = np.frombuffer(img_buff, count=int(stFrameInfo.nWidth * stFrameInfo.nHeight*3), dtype=np.uint8)image_control(data=data, stFrameInfo=stFrameInfo)del img_buffelif img_buff is None and stFrameInfo.enPixelType == 34603039:img_buff = (c_ubyte * stFrameInfo.nWidth * stFrameInfo.nHeight * 2)()cdll.msvcrt.memcpy(byref(img_buff), pData, stFrameInfo.nWidth * stFrameInfo.nHeight * 2)data = np.frombuffer(img_buff, count=int(stFrameInfo.nWidth * stFrameInfo.nHeight * 2), dtype=np.uint8)image_control(data=data, stFrameInfo=stFrameInfo)del img_buff
CALL_BACK_FUN = FrameInfoCallBack(image_callback)# 事件回调
stEventInfo = POINTER(MV_EVENT_OUT_INFO)
pData = POINTER(c_ubyte)
EventInfoCallBack = winfun_ctype(None, stEventInfo, c_void_p)
def event_callback(pEventInfo, pUser):stPEventInfo = cast(pEventInfo, POINTER(MV_EVENT_OUT_INFO)).contentsnBlockId = stPEventInfo.nBlockIdHighnBlockId = (nBlockId << 32) + stPEventInfo.nBlockIdLownTimestamp = stPEventInfo.nTimestampHighnTimestamp = (nTimestamp << 32) + stPEventInfo.nTimestampLowif stPEventInfo:print ("EventName[%s], EventId[%u], BlockId[%d], Timestamp[%d]" % (stPEventInfo.EventName, stPEventInfo.nEventID, nBlockId, nTimestamp))
CALL_BACK_FUN_2 = EventInfoCallBack(event_callback)# 注册回调取图
def call_back_get_image(cam):# ch:注册抓图回调 | en:Register image callbackret = cam.MV_CC_RegisterImageCallBackEx(CALL_BACK_FUN, None)if ret != 0:print("register image callback fail! ret[0x%x]" % ret)sys.exit()# 关闭设备与销毁句柄
def close_and_destroy_device(cam , data_buf=None):# 停止取流ret = cam.MV_CC_StopGrabbing()if ret != 0:print("stop grabbing fail! ret[0x%x]" % ret)sys.exit()# 关闭设备ret = cam.MV_CC_CloseDevice()if ret != 0:print("close deivce fail! ret[0x%x]" % ret)del data_bufsys.exit()# 销毁句柄ret = cam.MV_CC_DestroyHandle()if ret != 0:print("destroy handle fail! ret[0x%x]" % ret)del data_bufsys.exit()del data_buf# 开启取流并获取数据包大小
def start_grab_and_get_data_size(cam):ret = cam.MV_CC_StartGrabbing()if ret != 0:print("开始取流失败! ret[0x%x]" % ret)sys.exit()def main():# 枚举设备deviceList = enum_devices(device=0, device_way=False)# 判断不同类型设备identify_different_devices(deviceList)# 输入需要被连接的设备nConnectionNum = input_num_camera(deviceList)# 创建相机实例并创建句柄,(设置日志路径)cam, stDeviceList = creat_camera(deviceList, nConnectionNum, log=False)# decide_divice_on_line(cam)  ==============# 打开设备open_device(cam)# # 设置缓存节点个数# set_image_Node_num(cam, Num=10)# # 设置取流策略# set_grab_strategy(cam, grabstrategy=2, outputqueuesize=10)# 设置设备的一些参数# set_Value(cam, param_type="bool_value", node_name="TriggerCacheEnable", node_value=1)# 获取设备的一些参数# get_value = get_Value(cam , param_type = "int_value" , node_name = "PayloadSize")stdcall = input("回调方式取流显示请输入 0    主动取流方式显示请输入 1:")if int(stdcall) == 0:# 回调方式抓取图像call_back_get_image(cam)# 开启设备取流start_grab_and_get_data_size(cam)# 当使用 回调取流时,需要在此处添加print ("press a key to stop grabbing.")msvcrt.getch()# 关闭设备与销毁句柄close_and_destroy_device(cam)elif int(stdcall) == 1:# 开启设备取流start_grab_and_get_data_size(cam)# 主动取流方式抓取图像access_get_image(cam, active_way="getImagebuffer")# 关闭设备与销毁句柄close_and_destroy_device(cam)if __name__=="__main__":main()

三、总结

本文就使用 python 调用海康的工业相机并使用主动取流的方式获取相关数据,最后通过数据的转换,实现opencv格式的支持,实现了python+opencv 对相机的调用和显示。

在后续的文章中,会不断更新不同接口的使用,以及不同取流方式的实现等,并基于以上这些调用,实现实时调用海康工业相机,最后完成一些应用。

python调用海康工业相机并用opencv显示(整体实现)相关推荐

  1. Python调用海康工业相机:包含相机参数修改、彩色原图显示(不失真)

    [引言] 海康相机作为目前工业检测.视觉定位等领域应用较为广泛的国产品牌相机,其搭配有一套专用视觉软件VM,而在完成具有复杂场景.复杂任务的科研项目时依靠其VM算法平台提供的视觉算法往往无法满足项目要 ...

  2. python 调用海康工业相机调试后出现被占用问题

    问题描述: 在使用海康工业网口相机开发过程中,调试阶段异常结束程序调试时,经常出现相机被占用的异常情况,无论是使用海康的客户端界面连接相机还是使用调试代码连接相机,都没有权限再次打开相机,需要相机断电 ...

  3. 调用海康工业相机图像获取方式之主动取流(getimagebuffer )

    本文仅作记录!原文链接!:https://blog.csdn.net/qq_39570716/article/details/114304110 目录 一.使用前提 二.主动取流(官方例程说明) 1. ...

  4. (一)Qt+OpenCV调用海康工业相机SDK示例开发

    系列文章目录 提示:这里是该系列文章的所有文章的目录 第一章: (一)Qt+OpenCV调用海康工业相机SDK示例开发 第二章: (二)Qt多线程实现海康工业相机图像实时采集 文章目录 系列文章目录 ...

  5. QT+opencv调用海康工业相机

    这里写自定义目录标题 QT+opencv调用海康工业相机 开发环境 引用海康开发文件 直接上代码 QT+opencv调用海康工业相机 最近在使用Opencv调用海康工业相机的程序,从网上查了好多资料, ...

  6. 海康工业相机SDK+OpenCV实例(2):RawDataFormatConvert详解

    海康工业相机SDK+OpenCV实例(2): RawDataFormatConvert详解 文章目录 海康工业相机SDK+OpenCV实例(2): RawDataFormatConvert详解 前言 ...

  7. python调用海康相机进行Apriltag检测

    python调用海康相机进行Apriltag检测 第一章:win10下安装Apriltag库 1.安装Apriltag库 打开cmd输入 pip install pupil-apriltags 这个是 ...

  8. 海康工业相机SDK + OpenCV实例(4):相机参数设置详解

    海康工业相机SDK + OpenCV实例(4): 相机参数设置详解 文章目录 海康工业相机SDK + OpenCV实例(4): 相机参数设置详解 前言 一.相机参数基本接口 二.自动曝光时间调整亮度 ...

  9. 海康工业相机SDK + OpenCV实例(5):相机双线程读写缓存策略

    海康工业相机SDK + OpenCV实例(5): 相机双线程读写缓存策略 文章目录 海康工业相机SDK + OpenCV实例(5): 相机双线程读写缓存策略 前言 一.双线程 二.缓存区容量为2的生产 ...

最新文章

  1. SAP IDoc 报错- Function module not allowed SPEIDOC_INPUT_DESADV1 –
  2. 他研究了5000家AI公司,说人工智能应用该这么做!
  3. ADO.NET连接SQL Server数据库
  4. Drupal中的分类(Taxonomy)用法 (转)
  5. asp.net 添加成功弹出个div提示_Word双栏目录怎么做,这3个步骤早知道,让人眼前一亮...
  6. python文件读取 ,json文件的存储
  7. 如何保存QQ聊天记录
  8. Java是类型安全的语言,而C++是非类型安全的?【解释】
  9. SVN本地代码未提交而被覆盖
  10. 解决:Module not found: node_modules\sass-loader\package.json (directory description file)
  11. 关于js中的判断数组为空的问题
  12. r语言结构方程模型可视化_R语言时间序列分析(二):ts对象及其可视化
  13. mysql中整理设置__MySQL的常用操作命令整理
  14. 苹果画画软件_iPhone自带的软件你真的会用使用吗?
  15. 谷歌浏览器网页截屏插件工具下载与安装——FireShot
  16. datagrid的deleteRow使用
  17. ftp上传文件时出现 550 Permission denied,不是用户权限问题
  18. linux6.6卸载防火墙,Linux-centos6.8下关闭防火墙
  19. 录制PPT课件哪个录屏软件好?这3款值得收藏
  20. apache2 不解析php,apache2不解析php怎么办

热门文章

  1. CentOS7安装FATE1.5
  2. zk-SNARKs详细原理介绍(简单通俗易懂)
  3. 解读完这32个观点,我终于发现周鸿祎凭啥这么牛了
  4. 浏览器与搜索引擎他俩到底啥关系:浏览器与搜索引擎二者缺一不可!
  5. 设计模式学习笔记之(桥接模式brid…
  6. 合约安全(2):Bancor Network权限配置错误漏洞
  7. 脑电分析系列[MNE-Python-21]| Python协方差矩阵处理脑电数据
  8. 百度链接提交自动推送JS代码版
  9. 第一家关店的盒马鲜生,大数据眼光看新零售的转型之路
  10. 【Ubuntu20.04】好用的快捷键\截屏录屏