Python调用海康SDK打开工业相机全流程详解

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

下载最新版的 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博客

作者:PAQQ

物联沃分享整理
物联沃-IOTWORD物联网 » Python调用海康SDK打开工业相机全流程详解

发表回复