最近用到海康的工业相机,需要读取它的视频流,听说RTSP协议延迟较高,并且没有尝试成功,用了CSDN中一篇文章分享的方法
(59条消息) 利用python加opencv与海康工业相机交互。(得到供opencv处理的数据)_叔均的博客-CSDN博客_getoneframetimeout
,实现了视频流的读取,做一个简单的学习记录。
main.py
import sys
import threading
import msvcrt
import numpy as np
import cv2
from ctypes import *
sys.path.append(r"C:\Program Files (x86)\MVS\Development\Samples\Python\MvImport") # 换成自己的MVS中的路径
from MvCameraControl_class import *
g_bExit = False
# 这是官方给的线程,只能捕获帧的信息,类似于get one frame: Width[3072], Height[2048], nFrameNum[711]
# 不能得到帧的数据
def work_thread(cam=0, pData=0, nDataSize=0):
stFrameInfo = MV_FRAME_OUT_INFO_EX()
memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))
while True:
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))
else:
print("no data[0x%x]" % ret)
if g_bExit == True:
break
# 自己在这个线程中修改,可以将相机获得的数据转换成opencv支持的格式,然后再用opencv操作
def work_thread2(cam=0, pData=0, nDataSize=0):
# 输出帧的信息
stFrameInfo = MV_FRAME_OUT_INFO_EX()
# void *memset(void *s, int ch, size_t n);
# 函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s
# memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法
# byref(n)返回的相当于C的指针右值&n,本身没有被分配空间
# 此处相当于将帧信息全部清空了
memset(byref(stFrameInfo), 0, sizeof(stFrameInfo))
while True:
temp = np.asarray(pData) # 将c_ubyte_Array转化成ndarray得到(3686400,)
# print(temp)
# print(temp.shape)
temp = temp.reshape((1024, 1280, 3)) # 根据自己分辨率进行转化 这里出现报错的时候注意看SDK中的配置,我选用的 RGB8
temp = cv2.cvtColor(temp, cv2.COLOR_BGR2RGB) # 这一步获取到的颜色不对,因为默认是BRG,要转化成RGB,颜色才正常
# gray = cv2.cvtColor(temp, cv2.COLOR_BGR2GRAY)
# ret, binary = cv2.threshold(gray, 130, 255, cv2.THRESH_BINARY)
# cv2.namedWindow("binary", cv2.WINDOW_NORMAL)
cv2.namedWindow("ori", cv2.WINDOW_NORMAL)
# cv2.imshow('binary', binary) # 黑白二值图
cv2.imshow("ori", temp)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 采用超时机制获取一帧图片,SDK内部等待直到有数据时返回,成功返回0
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))
else:
print("no data[0x%x]" % ret)
if g_bExit == True:
break
cv2.waitKey()
if __name__ == "__main__":
# 获得设备信息
deviceList = MV_CC_DEVICE_INFO_LIST()
tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICE
# ch:枚举设备 | en:Enum device
# nTLayerType [IN] 枚举传输层 ,pstDevList [OUT] 设备列表
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)
# 输出设备ID
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))
# 输出USB接口的信息
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 = input("please input the number of the device to connect:")
if int(nConnectionNum) >= deviceList.nDeviceNum:
print("intput error!")
sys.exit()
# ch:创建相机实例 | en:Creat Camera Object
cam = MvCamera()
# ch:选择设备并创建句柄 | en:Select device and create handle
# cast(typ, val),这个函数是为了检查val变量是typ类型的,但是这个cast函数不做检查,直接返回val
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()
# csharp中没有memset函数,用什么代替?
memset(byref(stParam), 0, sizeof(MVCC_INTVALUE))
# MV_CC_GetIntValue,获取Integer属性值,handle [IN] 设备句柄
# strKey [IN] 属性键值,如获取宽度信息则为"Width"
# pIntValue [IN][OUT] 返回给调用者有关相机属性结构体指针
# 得到图片尺寸,这一句很关键
# payloadsize,为流通道上的每个图像传输的最大字节数,相机的PayloadSize的典型值是(宽x高x像素大小),此时图像没有附加任何额外信息
ret = cam.MV_CC_GetIntValue("PayloadSize", stParam)
if ret != 0:
print("get payload size fail! ret[0x%x]" % ret)
sys.exit()
# 关键句,官方没有这个句子,抓取的图片数据是空的,nCurValue是int64
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()
# 关键句,官方没有这个句子,抓取的图片数据是空的,CSharp中怎么实现这句话。
data_buf = (c_ubyte * nPayloadSize)()
# date_buf前面的转化不用,不然报错,因为转了是浮点型
hThreadHandle = threading.Thread(target=work_thread2, args=(cam, data_buf, nPayloadSize))
hThreadHandle.start()
except:
print("error: unable to start thread")
print("press a key to stop grabbing.")
msvcrt.getch()
g_bExit = True
hThreadHandle.join()
# 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
除了main.py,还需要五个py文件,在海康的SDK中可以找到,把他们拿出来和main.py放一起就可以开run。
五个文件的路径
自己的一些探索发现:直接连摄像头的时候会报错,主要是分辨率不匹配的问题,原因是相机在刚上电以后会保存初始配置,他的分别率设置和代码中不一样,需要打开SDK连接相机,基本属性->像素格式->下拉设置为RGB8,在SDK中断开相机连接,再run代码就可以辣。最近用到海康的工业相机,需要读取它的视频流,听说RTSP协议延迟较高,并且没有尝试成功,用了CSDN中一篇文章分享的方法。除了main.py,还需要五个py文件,在海康的SDK中可以找到,把他们拿出来和main.py放一起就可以开run。
图片信息的表示不止只有我们熟知的RGB,还有HLS、HSV、YUV、bayer,由于
opencv
等视觉处理库的广泛运用,RGB空间色彩模型运用最为广泛(实际上是BGR)。
摄像头传感器的感光原理是通过一个个的感光点对光进行采样和量化。但是每一个感光点只能感光RGB中的一种颜色。所以通常所说的50万像素或5000万像素等,指的是有50万或5000万个感光点。每一个感光点只能感光一种颜色,但一个真正图像需要每一个像素点都有RGB三种颜色分量。
在传感器模组的内部有ISP模块,主要用来对前
程序说明:
程序将
海康
摄像头开发需要进行的操作封面到类HK_camera中,使用只需要在mian()函数中实例化HK_camera,将摄像头的IP,用户名,密码给对象即可使用。
程序调用接口的流程都是参考SDK开发文档,并做了简单的修改,有不明白或者觉得不对的地方希望可以给我留言,谢谢。环境:
摄像机型号:CS-C1-11WPFR
电脑环境:32位
opencv
版本:
opencv
2.4.
搜罗了网上一些关于如何在
python
中实现
海康
威视
相机
的连接与画面播放的资料,最直接的方式是通过rtsp流来实现。
海康
的rtsp协议格式如下(参考:
海康
相机
使用RTSP):
rtsp://[username]:[passwd]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream
rtsp://admin:12345@192.168....
海康
工业相机
的底层SDK中提供了两种不同方式的图像数据获
取
方式,一种是回调方式,一种是主动
取
流方式。但是官方示例中,只提供了相关数据获
取
到之后的打印信息,对于图像数据的解析并没有给出,基于以上情况,本文对于这两种
取
流方式获
取
到的图像数据进行解析。
一、使用前提..
# 绘制矩形框
x, y, w, h = 100, 100, 200, 200
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 提
取
ROI
roi = img[y:y+h, x:x+w]
# 显示结果
cv2.imshow('image', img)
cv2.imshow('roi', roi)
cv2.waitKey(0)
cv2.destroyAllWindows()
hhaaiius:
海康工业相机 python opencv取视频流 学习记录
杨杨杨s:
海康工业相机 python opencv取视频流 学习记录
绝迹632: