python通过调用海康SDK打开工业相机(全流程)

news2025/4/7 14:37:10

首先打开海康机器人-机器视觉-下载中心

下载最新版的 MVS

安装后打开目录找到

...\MVS\Development\Samples\Python

将MvImport内所有文件拷贝至工作目录

然后到

C:\Program Files (x86)\Common Files\MVS\Runtime

找到适合自己系统的版本,将整个文件夹拷贝至工作目录,并重命名为lib,方便后期移植

完成上述操作后,工作目录是这样的:

打开MvCameraControl_class.py 找到

由于python3.8往后的版本导入动态链接库的机制发生了改变,因此这里时常会导入失败(2025-4-5)

因此需要更改为

*动态链接库的位置在刚刚更改名字的lib文件夹内,需根据实际情况做更改*

创建一个新的py文件(我的叫HKCamera.py)用于创建相机类,方便进行相机任务

在这个新的py文件中,创建一个类,用于创建句柄、开启流等操作

class Camera:
    #初始化
    def __init__(self):
        ...
    #打开相机
    def _open(self):
        ...
    #关闭相机
    def _close(self):
        ...
    #获取图像数据
    def get_img(self):
        ...

初始化中,可以选择是否查看设备信息,并打开相机,方便取流

    def __init__(self,camera_index):
        """
        初始化参数
        :param camera_index:相机索引,未装驱动电脑索引从0开始,装了驱动的从1开始
        """
        #设备信息表初始化
        self._deviceList = MV_CC_DEVICE_INFO_LIST()

        #设备类型
        self._tlayerType = MV_USB_DEVICE

        #相机实例
        self._cam = MvCamera()

        #相机参数
        self._stParam = None

        #数据包大小
        self._nPayloadSize = None

        #数据流
        self._data_buf = None

        #相机索引
        self._camera_index = camera_index

        #相机型号等打印
        self._Show_info = True

        #获取设备信息
        MvCamera.MV_CC_EnumDevices(self._tlayerType, self._deviceList)
        
        #打印设备信息
        if self._Show_info:
            self._print_debug_info()
        
        #打开相机流
        self._open()

设备型号打印函数:

    def _print_debug_info(self):
        mvcc_dev_info = cast(self._deviceList.pDeviceInfo[self._camera_index], POINTER(MV_CC_DEVICE_INFO)).contents
        if mvcc_dev_info.nTLayerType == MV_USB_DEVICE:
            print("\n设备列表: [%d]" % self._camera_index)
            strModeName = ""
            for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chModelName:
                if per == 0:
                    break
                strModeName = strModeName + chr(per)
            print("设备名称: %s" % strModeName)

            strSerialNumber = ""
            for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chSerialNumber:
                if per == 0:
                    break
                strSerialNumber = strSerialNumber + chr(per)
            print("串行代号: %s" % strSerialNumber)

成功打开后会看到(先注释掉_open函数,再运行):

然后完善open函数,打开相机流

    def _open(self):
        """
        打开设备
        :return: 
        """
        if int(self._camera_index) >= self._deviceList.nDeviceNum:
            print("索引相机失败!")
            sys.exit()

        #创建相机实例

        stDeviceList = cast(self._deviceList.pDeviceInfo[int(self._camera_index)], POINTER(MV_CC_DEVICE_INFO)).contents
        ret = self._cam.MV_CC_CreateHandle(stDeviceList)
        if ret != 0:
            print("相机打开错误: 相机索引创建句柄失败! 错误码:[0x%x]" % ret)
            sys.exit()

        #打开设备
        ret = self._cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0)
        if ret != 0:
            print("相机打开错误: 设备打开失败! 错误码:[0x%x]" % ret)
            sys.exit()

        ret = self._cam.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_OFF)
        if ret != 0:
            print("相机打开错误: 触发模式设置失败! 错误码:[0x%x] ret[0x%x]" % ret)
            sys.exit()

        #获取数据包大小
        self._stParam = MVCC_INTVALUE()
        memset(byref(self._stParam), 0, sizeof(MVCC_INTVALUE))

        ret = self._cam.MV_CC_GetIntValue("PayloadSize", self._stParam)
        if ret != 0:
            print("相机打开错误: 数据包大小获取失败! 错误码:[0x%x]" % ret)
            sys.exit()
        self._nPayloadSize = self._stParam.nCurValue

        # ch:开始取流 | en:Start grab image
        ret = self._cam.MV_CC_StartGrabbing()
        if ret != 0:
            print("取流失败: 开始取流失败! 错误码:[0x%x]" % ret)
            sys.exit()

打开相机可以看作是一个流程,一个流程过完才能过下一个流程

分别是   

创建相机实例   ->  打开设备  ->  获取数据包大小  ->  开始取流

然后就是get_img函数了,这个函数是获取相机图像的

将相机的图像buffer转化成opencv能够识别的图像数据

    def get_img(self):
        """
        获取一帧图像
        :return: 
        """
        #创建图像信息表
        stDeviceList = MV_FRAME_OUT_INFO_EX()
        
        #初始化图像信息表
        memset(byref(stDeviceList), 0, sizeof(stDeviceList))
        
        #创建原始图像信息表
        self._data_buf = (c_ubyte * self._nPayloadSize)()
        
        #采用超时机制获取一帧图片,SDK内部等待直到有数据时返回
        ret = self._cam.MV_CC_GetOneFrameTimeout(byref(self._data_buf), self._nPayloadSize, stDeviceList, 1000)
        if ret == 0:
            # print("get one frame: Width[%d], Height[%d], nFrameNum[%d]" % (stDeviceList.nWidth, stDeviceList.nHeight, stDeviceList.nFrameNum))
            
            #配置图像参数
            nRGBSize = stDeviceList.nWidth * stDeviceList.nHeight * 3
            stConvertParam = MV_SAVE_IMAGE_PARAM_EX()
            stConvertParam.nWidth = stDeviceList.nWidth
            stConvertParam.nHeight = stDeviceList.nHeight
            stConvertParam.pData = self._data_buf
            stConvertParam.nDataLen = stDeviceList.nFrameLen
            stConvertParam.enPixelType = stDeviceList.enPixelType
            stConvertParam.nImageLen = stConvertParam.nDataLen
            stConvertParam.nJpgQuality = 70
            stConvertParam.enImageType = MV_Image_Jpeg
            stConvertParam.pImageBuffer = (c_ubyte * nRGBSize)()
            stConvertParam.nBufferSize = nRGBSize
            # ret = cam.MV_CC_ConvertPixelType(stConvertParam)
            # print(stConvertParam.nImageLen)
            
            #覆盖上一帧图像
            ret = self._cam.MV_CC_SaveImageEx2(stConvertParam)
            if ret != 0:
                print("convert pixel fail ! ret[0x%x]" % ret)
                del self._data_buf
                sys.exit()
            
            #获取图像信息
            img_buff = (c_ubyte * stConvertParam.nImageLen)()
            cdll.msvcrt.memcpy(byref(img_buff), stConvertParam.pImageBuffer, stConvertParam.nImageLen)

            # 将 ctypes 数组转换为 NumPy 数组
            _img_array = np.frombuffer(img_buff, dtype=np.uint8)

            # 使用 cv2.imdecode 解码图像
            _image = cv2.imdecode(_img_array, cv2.IMREAD_COLOR)

            return _image

(可选)

最后是关闭相机函数

    def _close(self):

        ret = self._cam.MV_CC_StopGrabbing()
        if ret != 0:
            print("相机关闭失败: 停止取流失败! 错误码:[0x%x]" % ret)
            del self._data_buf
            sys.exit()


        ret = self._cam.MV_CC_CloseDevice()
        if ret != 0:
            print("相机关闭失败: 设别关闭失败! 错误码:[0x%x]" % ret)
            del self._data_buf
            sys.exit()


        ret = self._cam.MV_CC_DestroyHandle()
        if ret != 0:
            print("相机关闭失败: 句柄销毁失败! 错误码:[0x%x]" % ret)
            del self._data_buf
            sys.exit()

        del self._data_buf

至此相机已经可以调用并使用啦

#实例
def main():
    camera = Camera(0)
    while True:
        img = camera.get_img()

        cv2.imshow('img', img)
        if cv2.waitKey(1) & 0xff == 27:
            break


if __name__ == '__main__':
    main()

感谢:

Python海康相机api---超简单入坑学习必看_python海康相机连接教程-CSDN博客

Python 实现海康机器人工业相机 MV-CU060-10GM 的实时显示视频流及拍照功能 - 龙凌云端 - 博客园

win11 python调用dll问题:FileNotFoundError: Could not find module ‘xxx.dll‘ (or one of its dependencies)_filenotfounderror: could not find module 'nvcuda.d-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2329231.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

manim,制作专业的数学公式动画

manim是一个Python第三方库,全称是mathematical animation engine(数学动画引擎)。manim用于解说线性代数、微积分、神经网络、黎曼猜想、傅里叶变换以及四元数等数学概念。 manim使你能够以编程的方式创建精确的数学图形、动画和场景。与传统的几何画板等绘图软件不同,man…

小刚说C语言刷题——第15讲 多分支结构

1.多分支结构 所谓多分支结构是指在选择的时候有多种选择。根据条件满足哪个分支,就走对应分支的语句。 2.语法格式 if(条件1) 语句1; else if(条件2) 语句2; else if(条件3) 语句3; ....... else 语句n; 3.示例代码 从键盘输入三条边的长度,…

[ctfshow web入门] web6

前置知识 入口点(目录)爆破 还记得之前说过网站的入口的吗,我们输入url/xxx,其中如果url/xxx存在,那么访问成功,证明存在这样一个入口点;如果访问失败则证明不存在此入口点。所以我们可以通过遍历url/xxx,…

简单程序语言理论与编译技术·22 实现一个从AST到RISCV的编译器

本文是记录专业课“程序语言理论与编译技术”的部分笔记。 LECTURE 22(实现一个从AST到RISCV的编译器) 一、问题分析 1、完整的编译器(如LLVM)需先完成AST到IR的转换,并进行代码优化,再到汇编&#xff0…

lua和C的交互

1.C调用lua例子 #include <iostream> #include <lua.hpp>int main() {//用于创建一个新的lua虚拟机lua_State* L luaL_newstate();luaL_openlibs(L);//打开标准库/*if (luaL_dofile(L, "test.lua") ! LUA_OK) {std::cerr << "Lua error: &…

Css:如何解决绝对定位子元素内容被父级元素overflow:hidden属性剪裁

一、问题描述 今天小伙伴提了一个bug&#xff0c;在点击列表项的“…”按钮应该出现的悬浮菜单显示不完整&#xff1a; 二、问题排查 一般这种问题&#xff0c;是由于悬浮菜单采用的是绝对定位&#xff0c;而父级采用了overflow:hidden属性。但需要注意的是&#xff0c;这里的…

RoMo: Robust Motion Segmentation Improves Structure from Motion

前言 看起来像是一篇投稿CVPR的文章&#xff0c;不知道被哪个瞎眼审稿人拒了。同期还有一篇CVPR被接收的工作Segment Any Motion in Videos&#xff0c;看起来不如这篇直白&#xff08;也可能是因为我先看过spotlesssplats的缘故&#xff09;&#xff0c;后面也应该一并介绍了…

MCP 极简入门 - 三分钟 Cline + Smithery 运行 time 服务

文章目录 一、&#x1f680; 初识Smithery&#xff1a;AI服务的新大陆找到心仪的服务 二、Cline 编辑配置文件&#x1f527;1、打开配置文件2. 添加Time Server配置3. 验证配置效果 三、&#x1f4ac; 实战对话&#xff1a;让AI告诉你时间四、服务管理小技巧&#x1f504;&…

基本机动飞行性能

机动飞行时描述飞机在给定构型和发动机工作状态下改变飞行速度、飞行高度和飞行方向的能力 1. 水平加&#xff08;减&#xff09;速 水平加&#xff08;减&#xff09;速性能反映飞机在水平面内改变直线飞行速度的能力。描述水平加&#xff08;减&#xff09;速性能的参数包括…

【Linux】进程间通信、匿名管道、进程池

一.什么是通信 进程间通信(Inter-Process Communication&#xff0c;IPC),是指在操作系统中&#xff0c;不同进程之间进行数据交换和同步的机制。由于每个进程通常拥有独立的内存空间&#xff0c;进程间无法直接访问对方的内存&#xff0c;因此需要通过特定的机制来实现通信和…

【MATLAB定位例程】TDOA(到达时间差)的chan-tylor,三维环境,附完整代码

该代码实现了基于三维空间的动态目标TDOA定位,结合了Chan算法(解析解)与Taylor级数展开法(迭代优化)的双重优势。 文章目录 运行结果MATLAB代码代码讲解代码功能概述核心算法原理代码结构解析可视化与结果分析运行结果 定位示意图: 三轴状态曲线: 三轴误差曲线: MA…

数字化转型中的开源AI智能客服与S2B2C商城小程序的融合创新

摘要 数字经济时代&#xff0c;企业需通过技术重构用户交互与供应链体系。本文以“开源AI智能客服”“AI智能名片”及“S2B2C商城小程序”为核心&#xff0c;研究三者如何通过技术协同与场景化应用实现企业营销、客户服务与供应链管理的智能化升级。通过案例分析、技术架构设…

重生之我是去噪高手——diffusion model

diffusion model是如何运作的&#xff1f; 想象一下&#xff0c;你有一张清晰的图片。扩散模型的核心思想分为两个过程&#xff1a; 前向过程&#xff08;Forward Process / Diffusion Process&#xff09;&#xff1a;逐步加噪反向过程&#xff08;Reverse Process / Denois…

【C#】.net core 6.0 依赖注入常见问题之一,在构造函数使用的类,都需要注入到容器里,否则会提示如下报错,让DeepSeek找找原因,看看效果

&#x1f339;欢迎来到《小5讲堂》&#x1f339; &#x1f339;这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。&#x1f339; &#x1f339;温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01;&#…

论文阅读笔记——RDT-1B: A DIFFUSION FOUNDATION MODEL FOR BIMANUAL MANIPULATION

RDT-1B 论文 模型表达与泛化能力&#xff1a;由于双臂操作中动作空间维度是单臂空间的两倍&#xff0c;传统方法难以建模其多模态分布。 数据&#xff1a;双臂数据少且不同机器人的物理结构和动作空间差异&#xff08;如关节数、运动范围&#xff09;导致数据分布不一致&#x…

Vue中将pdf文件转为图片

平时开发中,我们经常遇到的场景应该是调用后端接口返回给前端pdf格式的文件流,然后我们可以通过URL.createObjectURL的方式转为object url临时路径然后可以通过window.open的方式来打开一个新的浏览器页签来进行预览,效果如下图: 但有时候这样满足不了的需求,它不想这样预…

day39——输入操作:多值输入

数组输入&#xff1a; int main() {//***** 1、多值输入&#xff08;C&#xff09;/*输入&#xff1a;3 --> 3个值5 4 9*/int n;cin >> n; //输入个数const int MAX_SIZE 0xFFFF;//限定最大个数int a[MAX_SIZE];for (int i 0; i < n; i) {//用 n 作控制输入…

微软的 Copilot 现在可以浏览网页并为您执行操作

在庆祝其 50 岁生日之际&#xff0c;微软正在向其人工智能驱动的 Copilot 聊天机器人传授一些新技巧。 从 BASIC 到 AI&#xff0c;改变世界的公司&#xff1a;微软 微软表示&#xff0c;Copilot 现在可以在“大多数网站”上采取行动&#xff0c;使其能够预订门票、预订餐厅等…

深入理解Python元组:从基础到高级应用

1. 元组基础认知 1.1 什么是元组 不可变序列&#xff1a;元组(tuple)是Python内置的不可变序列类型异构容器&#xff1a;可以存储不同类型的数据&#xff08;与列表类似&#xff09;语法特征&#xff1a;使用圆括号()定义&#xff0c;元素间用逗号分隔 # 基本示例 t1 (1, 2…

【零基础入门unity游戏开发——动画篇】unity旧动画系统Animation组件的使用

考虑到每个人基础可能不一样&#xff0c;且并不是所有人都有同时做2D、3D开发的需求&#xff0c;所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】&#xff1a;主要讲解C#的基础语法&#xff0c;包括变量、数据类型、运算符、…