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

本文详细介绍了如何使用Python语言与海康机器人工业相机进行交互,包括设备枚举、打开、参数设置、图像获取(回调与主动方式)、数据格式转换和效果展示。适合初学者了解海康相机SDK在Python中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

随着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()

  1. 图像数据获取

图像数据获取,有两种方法:
一种,使用回调函数获取,参考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)

主动取流

	# 注意:MV_CC_GetOneFrameTimeout 老式用法,在新版MVS中使用MV_CC_GetImageBuffer()方法
	
	# MVS老式API用法
	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))

	# MVS新式API用法
	

数据格式转换

如何将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))		# 初始化变量 采用C的方式
    # byref(stFrameInfo) 获得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, '未知')

效果展示:
彩色:
在这里插入图片描述
黑白:
在这里插入图片描述

<think>好的,用户的问题是关于如何通过PythonOpenCV调用海康SDK实现目标检测。我需要先理解用户的具体需求,然后结合提供的参考信息来构建答案。 首先,用户提到了两个引用,引用[1]和引用[2],都涉及使用Python调用海康威视的C++ SDK,特别是通过C接口获取数据,然后用OpenCV处理。引用[2]中还提到使用cv2.VideoCapture调用GIGE相机失败,所以用户可能遇到了类似的问题,或者希望找到替代方案。 用户的目标是实现目标检测,这意味着需要从海康相机获取实时视频流,用OpenCV处理每一帧,并应用目标检测算法(如YOLO、SSD等)。因此,步骤可能包括:调用SDK获取图像数据,将数据转换为OpenCV可处理的格式,然后进行目标检测。 接下来,我需要考虑如何将海康SDK的C++接口与Python结合。通常,这可以通过Python的ctypes模块或Cython来实现,将C++的SDK封装成Python调用的库。引用中提到的GrabImage.py可能是一个例子,用户可能需要参考该代码的结构。 另外,数据获取是关键。海康SDK可能提供了回调函数来获取实时图像数据。在Python中,需要设置回调函数,将获取的图像数据转换为numpy数组,以便OpenCV处理。这一步需要注意内存管理和数据格式转换的正确性,比如颜色空间转换(BGR转RGB)或数据对齐。 然后,目标检测部分可以使用现有的模型,比如加载预训练的YOLO模型,用OpenCV的dnn模块进行推理。这需要用户已经具备模型文件,或者使用其他框架如TensorFlow或PyTorch,结合OpenCV进行处理。 用户可能遇到的挑战包括SDK的兼容性、数据的稳定获取、图像格式转换以及检测算法的集成。需要分步骤指导用户,确保每一步都清晰,并指出可能的常见错误,比如SDK初始化失败、回调函数设置不当、内存泄漏等。 最后,生成的相关问题需要考虑用户可能的后续疑问,比如如何处理多线程、优化性能、处理不同相机型号或解决图像延迟等问题。这些问题可以帮助用户进一步深入应用开发。</think>### 分步实现方案 #### 1. **环境准备** - 安装海康威视官方SDK(Windows/Linux版本),获取开发文档和库文件(如`HCNetSDK.dll`、`libhcnetsdk.so`等) - 安装Python依赖库: ```bash pip install opencv-python numpy ctypes ``` #### 2. **封装SDK接口(关键步骤)** 通过`ctypes`模块调用C接口,参考示例代码结构: ```python from ctypes import * import cv2 # 加载SDK库 hcnetsdk = cdll.LoadLibrary("./libhcnetsdk.so") # Linux示例路径 # 定义SDK初始化函数 NET_DVR_Init = hcnetsdk.NET_DVR_Init NET_DVR_Init.restype = c_bool ``` #### 3. **图像采集与转换** 建立回调函数处理视频流,将原始数据转换为OpenCV格式: ```python def decode_frame_callback(lPlayHandle, pBuffer, dwBufSize, pUserData): # 将二进制转换为numpy数组 img_data = np.frombuffer(pBuffer, dtype=np.uint8) frame = cv2.imdecode(img_data, cv2.IMREAD_COLOR) # 此处插入目标检测代码 detection_result = run_detection(frame) cv2.imshow("Output", frame) cv2.waitKey(1) ``` #### 4. **目标检测集成** 使用OpenCV的dnn模块加载预训练模型: ```python def load_detection_model(): net = cv2.dnn.readNet("yolov4.weights", "yolov4.cfg") with open("coco.names", "r") as f: classes = [line.strip() for line in f.readlines()] return net, classes def run_detection(frame): blob = cv2.dnn.blobFromImage(frame, 1/255, (416,416), swapRB=True, crop=False) net.setInput(blob) output_layers = net.getUnconnectedOutLayersNames() outputs = net.forward(output_layers) # 解析检测结果... return processed_frame ``` #### 5. **完整程控制** ```python def main(): # SDK初始化 if not NET_DVR_Init(): print("SDK初始化失败") return # 创建设备登录信息 device_info = NET_DVR_DEVICEINFO_V30() user_id = NET_DVR_Login_V30("192.168.1.64", 8000, "admin", "password", byref(device_info)) # 启动预览 preview_info = NET_DVR_PREVIEWINFO() preview_info.hPlayWnd = 0 preview_info.lChannel = 1 preview_info.dwStreamType = 0 # 主码 # 设置回调函数 REALDATACALLBACK = CFUNCTYPE(None, c_long, POINTER(c_byte), c_long, c_void_p) callback_func = REALDATACALLBACK(decode_frame_callback) handle = NET_DVR_RealPlay_V40(user_id, byref(preview_info), callback_func, None) # 保持主线程运行 while True: time.sleep(1) ``` ### 关键问题解决 1. **图像格式转换** 海康SDK返回的通常是H.264/H.265编码,需使用`cv2.imdecode`解码。若出现花屏,检查解码前是否包含完整帧数据[^2] 2. **多线程处理** 建议将图像解码和检测逻辑分离到独立线程,避免阻塞回调函数: ```python from threading import Thread import queue frame_queue = queue.Queue(maxsize=10) def detection_thread(): while True: frame = frame_queue.get() run_detection(frame) Thread(target=detection_thread, daemon=True).start() ``` 3. **性能优化** - 设置`dwBufSize`控制图像分辨率(如从1080P调整为720P) - 使用硬件加速解码: ```python cv2.ocl.setUseOpenCL(True) # 启用OpenCL加速 ``` ### 效果验证 成功运行后应观察到: 1. 实时视频窗口显示 2. 画面中出现目标检测框 3. 控制台输出检测结果(类别+置信度)
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值