海康工业相机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

  • 24
    点赞
  • 181
    收藏
    觉得还不错? 一键收藏
  • 23
    评论
以下是使用PythonOpenCV调用海康工业相机并显示的步骤: 1.安装海康SDK并配置环境变量。 2.安装PythonOpenCV。 3.导入必要的库和模块。 ```python import sys from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout import cv2 from HCNetSDK import * ``` 4.创建一个Qt窗口并在其中添加一个标签。 ```python class Video(QWidget): def __init__(self): super().__init__() self.label = QLabel(self) self.layout = QVBoxLayout() self.layout.addWidget(self.label) self.setLayout(self.layout) ``` 5.初始化海康SDK并登录相机。 ```python def init_camera(): # 初始化SDK if not NET_DVR_Init(): print("SDK初始化失败") sys.exit() # 登录相机 device_info = NET_DVR_DEVICEINFO_V30() device_ip = "192.168.1.64" device_port = 8000 device_username = "admin" device_password = "12345" device_id = NET_DVR_Login_V30(device_ip, device_port, device_username, device_password, device_info) if device_id < 0: print("登录相机失败") sys.exit() return device_id ``` 6.获取相机数据并将其转换为OpenCV支持的格式。 ```python def get_frame(device_id): # 获取相机数据 frame = NET_DVR_GetRealPlayImage(device_id) # 将相机数据转换为OpenCV支持的格式 frame_data = frame.contents.pBuffer frame_size = frame.contents.dwSize frame_image = np.frombuffer(frame_data, dtype=np.uint8) frame_image = frame_image.reshape((frame_size[1], frame_size[0], 4)) frame_image = cv2.cvtColor(frame_image, cv2.COLOR_BGRA2BGR) return frame_image ``` 7.在Qt窗口中显示相机数据。 ```python def show_camera(): app = QApplication(sys.argv) video = Video() video.show() device_id = init_camera() while True: frame_image = get_frame(device_id) frame_image = cv2.resize(frame_image, (640, 480)) frame_image = cv2.cvtColor(frame_image, cv2.COLOR_BGR2RGB) video.label.setPixmap(QPixmap.fromImage(QImage(frame_image.data, frame_image.shape[1], frame_image.shape[0], QImage.Format_RGB888))) if cv2.waitKey(1) & 0xFF == ord('q'): break NET_DVR_Logout(device_id) NET_DVR_Cleanup() sys.exit(app.exec_()) ``` 8.运行程序并显示相机数据。 ```python if __name__ == '__main__': show_camera() ```
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值