系列文章目录

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

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

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

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

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


 


前言

海康工业相机的底层SDK中提供了两种不同方式的图像数据获取方式,一种是回调方式,一种是主动取流方式。但是官方示例中,只提供了相关数据获取到之后的打印信息,对于图像数据的解析并没有给出,基于以上情况,本文对回调取流方式获取到的图像数据进行解析。


一、使用前提

需要先安装海康工业相机的底层SDK,在安装之后,会有相关例程在安装目录下,本文的代码调用需要在该目录下调用(未作移植使用);

基于上一章节(python调用海康工业相机并用opencv显示)对于海康工业相机连接的内容,本文对于海康工业相机的回调取图方式取到的图像解析进行说明。

二、回调取流(官方例程说明)

1.接口说明

在海康提供的底层SDK中,有相关回调取流的接口,并且在安装目录下的工业相机SDK开发指南中,有对该接口的具体介绍,具体如下:

接口:MV_CC_RegisterImageCallBackEx()

对应于 C 语言接口如下:

MV_CAMCTRL_API int __stdcall MV_CC_RegisterImageCallBackEx  ( void *  handle,  
                                                              void(__stdcall *cbOutput)(unsigned char *pData, MV_FRAME_OUT_INFO_EX *pstFrameInfo, void *pUser)  ,  
                                                              void *  pUser ) 

参数:

。handle :设备句柄

。cbOutput:回调函数指针

。pUser:用户自定义变量

返回值:

。调用成功,返回 MV_OK

。调用失败,返回错误码

注:

     1、通过该接口可以设置图像数据回调函数,需要在 MV_CC_CreateHandle() 接口之后调用,并且需要在 MV_CC_StarGrabbing() 接口之前设置,这样采集的图像数据在设置的回调函数中才能返回;

     2、该接口不支持 Cameralink 设备,仅支持 GigE 、USB 设备;

2.python 下接口实现

(1)根据以上说明可知,MV_CC_RegisterImageCallBackEx() 接口需要在打开设备和开启采集接口之间声明调用,即官方例程中的注册抓图回调,如下:

 # ch:注册抓图回调 | en:Register image callback
    ret = cam.MV_CC_RegisterImageCallBackEx(CALL_BACK_FUN,None)
    if ret != 0:
        print ("register image callback fail! ret[0x%x]" % ret)
        sys.exit()

(2)并且在开启取流和停止取流接口调用中间,需要写入如下代码,否则回调取图只能获取到一张图像后会停止获取图像,如下:

 print ("press a key to stop grabbing.")
    msvcrt.getch()

其中 msvcrt 模块时 python 语言标准库中的一个 控制输入输出的库;

(3)实现回调函数功能

winfun_ctype = WINFUNCTYPE             # 声明回调函数指针类型,首先要声明返回值类型
stFrameInfo = POINTER(MV_FRAME_OUT_INFO_EX)   # 使用 POINTER 指向 stFrameInfo 数据的类型为 MV_FRAME_OUT_INFO_EX
pData = POINTER(c_ubyte)       # 使用 POINTER 指向 pData 数据的类型为 c_ubyte
FrameInfoCallBack = winfun_ctype(None, pData, stFrameInfo, c_void_p)   # 定义回调函数类型
# 实现回调函数功能
def image_callback(pData, pFrameInfo, pUser):
        stFrameInfo = cast(pFrameInfo, POINTER(MV_FRAME_OUT_INFO_EX)).contents
        if stFrameInfo:
            print ("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nFrameNum))
CALL_BACK_FUN = FrameInfoCallBack(image_callback)

以上三步均为官方例程中的调用介绍,如上代码中可以看到当取到图像数据后,仅打印图像数据的信息,并没有对图像数据进行解析,接下来将对图像数据进行解析,并作显示;

三、回调取流并对黑白图像数据解析并用 opencv 显示

1.回调数据获取并解析 mono 格式的图像数据

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_buff
    img_buff = None
    stFrameInfo = cast(pFrameInfo, POINTER(MV_FRAME_OUT_INFO_EX)).contents
    if stFrameInfo:
        print ("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nFrameNum))
    if img_buff is None:
        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)
CALL_BACK_FUN = FrameInfoCallBack(image_callback)

通过对官方例程中回调获取图像数据的代码修改,获取到相关图像的数据,如上代码中 data 即为回调获取到的图像数据,并通过自定义函数 image_control() 对图像数据进行 reshape 操作,获取到可以显示的数据;

2.图像数据显示

def image_show(image):
    image = cv2.resize(image, (600, 400), interpolation=cv2.INTER_AREA)
    cv2.imshow('fgmask', image)
    k = cv2.waitKey(1) & 0xff

def image_control(data , stFrameInfo):
    image = data.reshape((stFrameInfo.nHeight, stFrameInfo.nWidth))
    image_show(image = image)

以上代码是对回调获取到的图像数据进行显示的代码,但是以上代码仅在使用海康工业相机黑白模式下使用,因为没有考虑像素格式以及通道等信息,下面对多种像素格式图像数据进行解析并显示;

四、回调取流并对多种像素格式的图像数据解析并用 opencv 显示

1.回调数据获取并解析多种像素格式的数据

基于第一章(python调用海康工业相机并用opencv显示)中,对于常用接口的封装,回调部分也进行相关内容的封装,将回调中的数据解析部分封装为一体,具体代码如下所示:

# 回调取图采集
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_buff
    img_buff = None
    stFrameInfo = cast(pFrameInfo, POINTER(MV_FRAME_OUT_INFO_EX)).contents
    if 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_buff
    elif 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_buff
    elif 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_buff
    elif 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)

因为工业相机总有不同的像素格式,也就对应有不同的通道数,所以在图像解析过程中就会出现不同分支的解析方式,以上内容是根据海康提供的官方定义中获取到的像素格式对应的数字,进行判定,具体的定义在海康 SDK 目录下:../MVS/Development/Samples/Python/MvImport/PixelType_header.py 文件中,如有需要,请自行查询;

2.图像数据显示

由以上内容可以知道,通过回调获取到的图像数据是多种像素格式类型的,不同像素格式类型图像通道不同,自然也会导致显示时,不同通道配置的代码,以下内容是对不同像素格式类型的图像数据的显示,代码如下:

# 显示图像
def image_show(image):
    image = cv2.resize(image, (600, 400), interpolation=cv2.INTER_AREA)
    cv2.imshow('fgmask', 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)
    elif stFrameInfo.enPixelType == 17301514:
        data = data.reshape(stFrameInfo.nHeight, stFrameInfo.nWidth, -1)
        image = cv2.cvtColor(data, cv2.COLOR_BAYER_GB2RGB)
        image_show(image=image)
    elif stFrameInfo.enPixelType == 35127316:
        data = data.reshape(stFrameInfo.nHeight, stFrameInfo.nWidth, -1)
        image = cv2.cvtColor(data, cv2.COLOR_RGB2BGR)
        image_show(image=image)
    elif stFrameInfo.enPixelType == 34603039:
        data = data.reshape(stFrameInfo.nHeight, stFrameInfo.nWidth, -1)
        image = cv2.cvtColor(data, cv2.COLOR_YUV2BGR_Y422)
        image_show(image = image)

可以看到不同的通道数,对应不同的数据转换,最终将图像显示在桌面上;


总结

在工业相机的使用中,很多场景使用的都是回调方式获取图像,而回调方式获取到的图像数据如何解析,就相对比较重要,以上是对海康工业相机回调获取图像数据的解析;由于现阶段大部分工业相机的SDK底层是以 C 语言和 C# 为主要语言,所以 python 的调用,就选择了使用 C 语言为基础的接口转换后的 python 接口来调用相机,而这种方式在工业界相对比较常见。

GitHub 加速计划 / opencv31 / opencv
145
15
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:3 个月前 )
d9a139f9 Animated WebP Support #25608 related issues #24855 #22569 ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [x] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake 2 天前
09030615 V4l default image size #25500 Added ability to set default image width and height for V4L capture. This is required for cameras that does not support 640x480 resolution because otherwise V4L capture cannot be opened and failed with "Pixel format of incoming image is unsupported by OpenCV" and then with "can't open camera by index" message. Because of the videoio architecture it is not possible to insert actions between CvCaptureCAM_V4L::CvCaptureCAM_V4L and CvCaptureCAM_V4L::open so the only way I found is to use environment variables to preselect the resolution. Related bug report is [#25499](https://github.com/opencv/opencv/issues/25499) Maybe (but not confirmed) this is also related to [#24551](https://github.com/opencv/opencv/issues/24551) This fix was made and verified in my local environment: capture board AVMATRIX VC42, Ubuntu 20, NVidia Jetson Orin. ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [X] I agree to contribute to the project under Apache 2 License. - [X] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [X] The PR is proposed to the proper branch - [X] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake 3 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐