通过python调用海康威视工业摄像头并进行图像存储(数据流获取问题未能解决)
先说情况,本人是做视觉检测的需要高倍率摄像头进行实时检测,也就是需要深度学习进行图片数据处理,但是这个又是python来进行分析,而海康威视主要程序代码是以C为主的,传过来的数据我也尝试的去解析都是不能转化成python的BGR图像。
一开始参照了:通过cv2调用海康威视摄像头,但这个不能调用工业摄像头,通过官方给一个400什么软件要激活摄像头,可是却并不能检测到工业摄像头,通过mvs软件调用到摄像头地址进行测试也无法获取到摄像头数据,这和我之前说的,工业摄像头是基于C编写的,python的调用都是使用C的包,经过大量询问工作人员(最后还是课题组有老主顾,才找到一个稍微靠谱的),给了一个不太一样的代码自己分析后才成功,中间还是删掉了一些感觉没什么用的东西。
先给整体代码,然后再逐步分析代码功能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | # -- coding: utf-8 -- import cv2 import sys import copy import msvcrt import numpy as np from ctypes import * sys.path.append("../MvImport") from MvCameraControl_class import * if __name__ == "__main__": deviceList = MV_CC_DEVICE_INFO_LIST() tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICE # ch:枚举设备 | en:Enum device ret = MvCamera.MV_CC_EnumDevices(tlayerType, deviceList) if ret != 0: print ("enum devices fail! ret[0x%x]" % ret) sys.exit() if deviceList.nDeviceNum == 0: print ("find no device!") sys.exit() print ("find %d devices!" % deviceList.nDeviceNum) for i in range(0, deviceList.nDeviceNum): mvcc_dev_info = cast(deviceList.pDeviceInfo[i], POINTER(MV_CC_DEVICE_INFO)).contents if mvcc_dev_info.nTLayerType == MV_GIGE_DEVICE: print ("\ngige device: [%d]" % i) strModeName = "" for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chModelName: strModeName = strModeName + chr(per) print ("device model name: %s" % strModeName) nip1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24) nip2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16) nip3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8) nip4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff) print ("current ip: %d.%d.%d.%d\n" % (nip1, nip2, nip3, nip4)) elif mvcc_dev_info.nTLayerType == MV_USB_DEVICE: print ("\nu3v device: [%d]" % i) strModeName = "" for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chModelName: if per == 0: break strModeName = strModeName + chr(per) print ("device model name: %s" % strModeName) strSerialNumber = "" for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chSerialNumber: if per == 0: break strSerialNumber = strSerialNumber + chr(per) print ("user serial number: %s" % strSerialNumber) nConnectionNum = 0 if int(nConnectionNum) >= deviceList.nDeviceNum: print ("intput error!") sys.exit() # ch:创建相机实例 | en:Creat Camera Object cam = MvCamera() # ch:选择设备并创建句柄 | en:Select device and create handle stDeviceList = cast(deviceList.pDeviceInfo[int(nConnectionNum)], POINTER(MV_CC_DEVICE_INFO)).contents 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:探测网络最佳包大小(只对GigE相机有效) | en:Detection network optimal package size(It only works for the GigE camera) if stDeviceList.nTLayerType == MV_GIGE_DEVICE: nPacketSize = cam.MV_CC_GetOptimalPacketSize() if int(nPacketSize) > 0: ret = cam.MV_CC_SetIntValue("GevSCPSPacketSize", nPacketSize) if ret != 0: print ("Warning: Set Packet Size fail! ret[0x%x]" % ret) else: print ("Warning: Get Packet Size fail! ret[0x%x]" % nPacketSize) # 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:Get payload size stParam = MVCC_INTVALUE() memset(byref(stParam), 0, sizeof(MVCC_INTVALUE)) ret = cam.MV_CC_GetIntValue("PayloadSize", stParam) if ret != 0: print ("get payload size fail! ret[0x%x]" % ret) sys.exit() nPayloadSize = stParam.nCurValue # ch:开始取流 | en:Start grab image ret = cam.MV_CC_StartGrabbing() if ret != 0: print ("start grabbing fail! ret[0x%x]" % ret) sys.exit() stDeviceList = MV_FRAME_OUT_INFO_EX() memset(byref(stDeviceList), 0, sizeof(stDeviceList)) data_buf = (c_ubyte * nPayloadSize)() ret = cam.MV_CC_GetOneFrameTimeout(byref(data_buf), 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 = 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 = cam.MV_CC_SaveImageEx2(stConvertParam) if ret != 0: print ("convert pixel fail ! ret[0x%x]" % ret) del data_buf sys.exit() file_path = "AfterConvert_RGB2.jpg" file_open = open(file_path.encode('ascii'), 'wb+') img_buff = (c_ubyte * stConvertParam.nImageLen)() cdll.msvcrt.memcpy(byref(img_buff), stConvertParam.pImageBuffer, stConvertParam.nImageLen) file_open.write(img_buff) print ("Save Image succeed!") # ch:停止取流 | en:Stop grab image ret = cam.MV_CC_StopGrabbing() if ret != 0: print ("stop grabbing fail! ret[0x%x]" % ret) del data_buf sys.exit() # ch:关闭设备 | Close device ret = cam.MV_CC_CloseDevice() if ret != 0: print ("close deivce fail! ret[0x%x]" % ret) del data_buf sys.exit() # ch:销毁句柄 | Destroy handle ret = cam.MV_CC_DestroyHandle() if ret != 0: print ("destroy handle fail! ret[0x%x]" % ret) del data_buf sys.exit() del data_buf |
首先看import里面有一个
1 2 | sys.path.append("../MvImport") from MvCameraControl_class import * |
这是整个代码的核心,文件里面内容如下,具体可以下载MVS里面例程里面有:
之后的代码都有注释,具体要刨根问底的分析我建议直接入职海康威视可能会更快一点,我们只是使用它,所以这一系列步骤缺一不可。到后面就是比较让人苦恼的图片数据流获取,具体代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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 = 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 = cam.MV_CC_SaveImageEx2(stConvertParam) if ret != 0: print ("convert pixel fail ! ret[0x%x]" % ret) del data_buf sys.exit() file_path = "AfterConvert_RGB2.jpg" file_open = open(file_path.encode('ascii'), 'wb+') img_buff = (c_ubyte * stConvertParam.nImageLen)() cdll.msvcrt.memcpy(byref(img_buff), stConvertParam.pImageBuffer, stConvertParam.nImageLen) file_open.write(img_buff) print ("Save Image succeed!") |
这一部分主要是将C程序给过来的数据流进行了一个转换,仔细看保存的路径不难看出,img_buff就是我们想要的图像数据流。但是我把它print出来的时候它仍然是一个C*ubyte的数据类型,所以没法直接用python-opencv进行直接读取,只能先将其存储下来然后再通过cv2进行读取来进行一系列图片操作。
file_path是我们图片存储的路径,可以自己更改。原本下面有一个输入a退出的按钮但没有反应,所以我删掉了它。
再到之后就是关闭数据流,关闭摄像头操作。因为博主没法直接读取数据流不能直接视频显示,没法得知这个数据是实时更新图像还是一次整体运行获取一次图像信息,所以我的方法是整体运行关闭一次采集一次数据,非常麻烦。
有兴趣的可以实时while()获取数据包大小和开始取流看看能不能获取到不断的获取新图像。