海康工业相机Python+OpenCV调用实现取流

前言

随着python这们语言不断深入发展,那么python调用工业相机也成为了一项流行的需求;
本文了就简单梳理下海康工业相机python的使用

参考链接

搬砖了一些写的好的文章做参考
海康机器人工业相机sdk简介
python语言调用海康机器人(hikrobotics)工业相机
利用python加opencv与海康工业相机交互
海康工业相机参数设置与获取

环境设置

  1. 先安装MVS,下载地址 海康机器人官网,SDK简介也可以看看上面的引用博客
  2. 条件:Python+海康官方的mvs文件下的development/samples下的python文件夹
  3. 注意:相机连接后不要用官方app打开相机,不然python代码检测不到设备,代码在pycharm会提示报错,亲测能跑并能截取到图片(这个就是说,相机不要被其他软件链接占用啦,同一时刻,一个相机只能被一个软件链接)
  4. 需要添加模块MvImport的路径: 这是整个代码的核心,文件里面内容如下,具体可以下载MVS里面例程里面有:
import sys
sys.path.append("C:\Program Files (x86)\MVS\Development\Samples\Python\MvImport")

在这里插入图片描述

相机控制与数据获取

我们可以把工业相机sdk调用,分成两个部分,相机控制与图像数据获取
1. 相机控制
参考其SDK提供的流程图我们可以看出,相机控制分成枚举、打开、参数设置、关闭,销毁句柄五个步骤
在这里插入图片描述
那么就分别调用对应的python接口就能实现

  • 枚举相机
# ch:枚举设备 | en:Enum device
    ret = MvCamera.MV_CC_EnumDevices(tlayerType, deviceList)
    if ret != 0:
        print ("enum devices 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()
    # ch:打开设备 | en:Open device
    ret = cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)
    if ret != 0:
        print ("open device fail! ret[0x%x]" % ret)
        sys.exit()
  # ch:设置触发模式为off | en:Set trigger mode as off
    ret = cam.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_OFF)
    if ret != 0:
        print ("set trigger mode fail! ret[0x%x]" % ret)
        sys.exit()
  • 关闭相机
   # ch:停止取流 | en:Stop grab image
    ret = cam.MV_CC_StopGrabbing()
    if ret != 0:
        print ("stop grabbing fail! ret[0x%x]" % ret)
        sys.exit()

    # ch:关闭设备 | Close device
    ret = cam.MV_CC_CloseDevice()
    if ret != 0:
        print ("close deivce fail! ret[0x%x]" % ret)
        sys.exit()
  • 销毁句柄
    # ch:销毁句柄 | Destroy handle
    ret = cam.MV_CC_DestroyHandle()
    if ret != 0:
        print ("destroy handle fail! ret[0x%x]" % ret)
        sys.exit()

2. 图像数据获取
图像数据获取,有两种方法,一种是参考Grab_Callback.py,使用回调函数获取,另外一种,参考GrabImage使用主动取流接口获取,两种方法有其不同的使用场景;
以其官方提供的示例程序Grab_Callback.py为例子,它的主要目的是在回调函数中,函数接口数据地址pData,pData是一个C*ubyte的数据类型,是没有办法直接用python-opencv进行直接读取,即不能直接转成numpy array的形式

  • 回调函数
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)
  • 主动取流函数
	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))

数据格式转换

如何将pdata转opencv的数据格式呢
第一步,获取图像数据。我们通过上面介绍的两种不同的取流函数可以获取到pdata指针,但是pdata是POINTER(c_ubyte))类型的指针,我们要转化成asarray
第二步,图像格式判断与转化。我们要了解到相机输出pdata的是什么图像格式,以及opencv能够处理什么格式海康彩色工业相机图像格式转换方法(Bayer转RGB)
黑白单通道还好,彩色就需要转成BGR三通道数据啦
第三步,opencv显示

 #实现GetImagebuffer函数取流,HIK格式转换函数
def work_thread_1(cam=0, pData=0, nDataSize=0):
    stFrameInfo = MV_FRAME_OUT_INFO_EX()
    memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))
    print("work_thread_1!\n")
    img_buff = None
    while True:
        ret = cam.MV_CC_GetOneFrameTimeout(pData, nDataSize, stFrameInfo, 1000)
        if ret == 0:
            print ("MV_CC_GetOneFrameTimeout: Width[%d], Height[%d], nFrameNum[%d]"  % (stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.nFrameNum))
            time_start = time.time()
            stConvertParam = MV_CC_PIXEL_CONVERT_PARAM()
            memset(byref(stConvertParam), 0, sizeof(stConvertParam))
            if IsImageColor(stFrameInfo.enPixelType) == 'mono':
                print("mono!")
                stConvertParam.enDstPixelType = PixelType_Gvsp_Mono8
                nConvertSize = stFrameInfo.nWidth * stFrameInfo.nHeight
            elif IsImageColor(stFrameInfo.enPixelType) == 'color':
                print("color!")
                stConvertParam.enDstPixelType = PixelType_Gvsp_BGR8_Packed  # opecv要用BGR,不能使用RGB
                nConvertSize = stFrameInfo.nWidth * stFrameInfo.nHeight* 3
            else:
                print("not support!!!")
            if img_buff is None:
                img_buff = (c_ubyte * stFrameInfo.nFrameLen)()
            # ---
            stConvertParam.nWidth = stFrameInfo.nWidth
            stConvertParam.nHeight = stFrameInfo.nHeight
            stConvertParam.pSrcData = cast(pData, POINTER(c_ubyte))
            stConvertParam.nSrcDataLen = stFrameInfo.nFrameLen
            stConvertParam.enSrcPixelType = stFrameInfo.enPixelType
            stConvertParam.pDstBuffer = (c_ubyte * nConvertSize)()
            stConvertParam.nDstBufferSize = nConvertSize
            ret = cam.MV_CC_ConvertPixelType(stConvertParam)
            if ret != 0:
                print("convert pixel fail! ret[0x%x]" % ret)
                del stConvertParam.pSrcData
                sys.exit()
            else:
                print("convert ok!!")
                # 转OpenCV
                # 黑白处理
                if IsImageColor(stFrameInfo.enPixelType) == 'mono':
                    img_buff = (c_ubyte * stConvertParam.nDstLen)()
                    cdll.msvcrt.memcpy(byref(img_buff), stConvertParam.pDstBuffer, stConvertParam.nDstLen)
                    img_buff = np.frombuffer(img_buff,count=int(stConvertParam.nDstLen), dtype=np.uint8)
                    img_buff = img_buff.reshape((stFrameInfo.nHeight, stFrameInfo.nWidth))
                    print("mono ok!!")
                    image_show(image=img_buff)  # 显示图像函数
                # 彩色处理
                if IsImageColor(stFrameInfo.enPixelType) == 'color':
                    img_buff = (c_ubyte * stConvertParam.nDstLen)()
                    cdll.msvcrt.memcpy(byref(img_buff), stConvertParam.pDstBuffer, stConvertParam.nDstLen)
                    img_buff = np.frombuffer(img_buff, count=int(stConvertParam.nDstBufferSize), dtype=np.uint8)
                    img_buff = img_buff.reshape(stFrameInfo.nHeight,stFrameInfo.nWidth,3)
                    print("color ok!!")
                    image_show(image=img_buff)  # 显示图像函数
                time_end = time.time()
                print('time cos:', time_end - time_start, 's') 
        else:
            print ("no data[0x%x]" % ret)
        if g_bExit == True:
                break
# 显示图像
def image_show(image):
    image = cv2.resize(image, (600, 400), interpolation=cv2.INTER_AREA)
    cv2.imshow('test', image)
    k = cv2.waitKey(1) & 0xff
# 判读图像格式是彩色还是黑白
def IsImageColor(enType):
    dates = {
    
    
        PixelType_Gvsp_RGB8_Packed: 'color',
        PixelType_Gvsp_BGR8_Packed: 'color',
        PixelType_Gvsp_YUV422_Packed: 'color',
        PixelType_Gvsp_YUV422_YUYV_Packed: 'color',
        PixelType_Gvsp_BayerGR8: 'color',
        PixelType_Gvsp_BayerRG8: 'color',
        PixelType_Gvsp_BayerGB8: 'color',
        PixelType_Gvsp_BayerBG8: 'color',
        PixelType_Gvsp_BayerGB10: 'color',
        PixelType_Gvsp_BayerGB10_Packed: 'color',
        PixelType_Gvsp_BayerBG10: 'color',
        PixelType_Gvsp_BayerBG10_Packed: 'color',
        PixelType_Gvsp_BayerRG10: 'color',
        PixelType_Gvsp_BayerRG10_Packed: 'color',
        PixelType_Gvsp_BayerGR10: 'color',
        PixelType_Gvsp_BayerGR10_Packed: 'color',
        PixelType_Gvsp_BayerGB12: 'color',
        PixelType_Gvsp_BayerGB12_Packed: 'color',
        PixelType_Gvsp_BayerBG12: 'color',
        PixelType_Gvsp_BayerBG12_Packed: 'color',
        PixelType_Gvsp_BayerRG12: 'color',
        PixelType_Gvsp_BayerRG12_Packed: 'color',
        PixelType_Gvsp_BayerGR12: 'color',
        PixelType_Gvsp_BayerGR12_Packed: 'color',
        PixelType_Gvsp_Mono8: 'mono',
        PixelType_Gvsp_Mono10: 'mono',
        PixelType_Gvsp_Mono10_Packed: 'mono',
        PixelType_Gvsp_Mono12: 'mono',
        PixelType_Gvsp_Mono12_Packed: 'mono'}
    return dates.get(enType, '未知')

效果展示:
彩色:
在这里插入图片描述
黑白:
在这里插入图片描述
示例程序下载:GrabImage.py

猜你喜欢

转载自blog.csdn.net/qq_23107577/article/details/113984935