Python实时获取大华网络摄像头视频图像(SDK版本)

一、序:

dahua_url = "rtsp://用户名:密码@192.168.1.108/cam/realmonitor?channel=1&subtype=0?tcp"
cap = cv2.VideoCapture(dahua_url)

想用大华网络摄像头做目标检测,但是使用上述CV方法获取大华网络摄像头无法达到实时检测效果(延迟2秒左右),故想找其他办法解决这个问题。

困扰多日,想要实时检测,必须使用大华SDK进行二次开发,使用搜索大法,发现使用pyhon获取大华摄像头SDK的方法寥寥无几,今灵光乍现,解决该问题,故写此文,告诉给位道友。


二、下载大华SDK:

大华SDK下载 点击此处
1.选择 SDK 开发,选择设备SDK

2. 选择第2页, 找到python win64版本,点击下载

3. 解压文件,点进入,找到dist 点击去

4. 在 NetSDK 封装库.whl 文件存放目录下打开命令终端,运行以下命令安装插件。(放入项目虚拟环境)
pip install NetSDK-2.0.0.1-py3-none-win_amd64.whl

至此,安装完毕!

三、大华SDK二次开发:

1.在刚刚解压的SDK文件中,点击Demo文件,选择RealPlayDemo项目,使用Pycharm打开该项目
2.SDK手册在Doc文件中,大家可以看看RealPlayDemo项目的一些官方讲解,我这里只讲重点,具体可以看看官方手册(关键是它也不具体)。
(1). 项目环境:主要是PyQt5 和 SDK环境,然后就是目标检测的环境(我用的YOLOv8),都下好测试一下。
(2). 配置好项目环境后,先检测项目能不能直接运行,点击run,能成功显示UI,证明环境配置好了

(3). 修改IP , 端口,用户名,密码(这部分可以在代码中改,后续就不需要填了)。端口我是用的是代码默认的37777,可以运行。然后点击登录、再点击预览,出现此画面后,说明摄像头配置成功了,至此马上开始开发SDK。

3. 二次开发SDK
先说一下运行流程:SDK进行实时监控是使用的回调函数(拉流回调),然后绑定UI窗口句柄id,摄像头每收到1帧图画,回调函数就会运行一次,画面就会显示到UI窗口上,我们现在想要做的就是,如何截取摄像头接受的1帧图画,将其转换为RGB格式,然后进行目标检测,最后矩形框显示到播放窗口中。

但是现在出现一个问题,传入到窗口句柄id的数据是码流数据,没有解码,我们不太好直接使用该数据,其中的数据还是以地址的方式传送,python 不太好操作地址(用ctypes标准库是可以的),我们得找一下SDK现成解码方法。

刚好在拉流回调函数得下面就找到了解码回调函数,该函数也是1帧图像被自动调用1次。我们就从此处切入,从文档和注释可以知道该解码函数得到的是一个YUV420格式数据,那么我们就是将YUV420转化为RGB格式即可。

上面图片中的data就是YUV420数据,我们先打印看一下

data = cast(pBuf, POINTER(c_ubyte * nSize)).contents
print("data: ",data)
结果:data:  <__main__.c_ubyte_Array_3110400 object at 0x0000018187A855C0>

data是c_ubyte格式数组的地址,道友无须担心,然我们一起揭开该妖孽的真面目。

先将data 数据转化为我们熟悉的array数组,打印看一下

# 使用 numpy.frombuffer 将 c_ubyte_Array 对象转换为 numpy 数组
numpy_array = np.frombuffer(data, dtype=np.uint8)
print(numpy_array)
print(len(numpy_array))
结果:
[195 195 195 ... 123 123 123]
3110400

YUV格式图像的高是RGB的1.5倍(这里需要补YUV图像格式的基础,此处不展开讲,你需要知道要这么做),我们先把numpy_array转化为2维数组(2维数组是YUV标准格式,后续方便调用cv2函数),info是回调函数中给的一个变量,直接用就行,可以获取图像高宽,代码如下:

yuv = numpy_array.reshape(int(info.nHeight * 1.5), info.nWidth)

后面调用cv2转换函数,大功告成!

rgb = cv2.cvtColor(yuv,cv2.COLOR_YUV2BGR_I420)
print(rgb.shape)
cv2.imshow('RGB Image', rgb)
cv2.waitKey(1)
结果:
(1080, 1920, 3)

最后我们运行函数看一下效果:

两个画面都成功显示,我们拿到了RGB图片,后续就可以方便的进行目标检测操作,后续内容我就不细讲了,SDK使用告一段落。

四、尾声:

完整代码(只需要修改Demo中的解码回调函数即可):

# PLAYSDK解码回调函数功能
def DecodingCallBack(self, nPort, pBuf, nSize, pFrameInfo, pUserData, nReserved2):
    # here get YUV data, pBuf is YUV data IYUV/YUV420 ,size is nSize, pFrameInfo is frame info with height, width.
    # 对于planar 的YUV格式,先连续存储所有相速度的Y,紧接着存储所有像素点的U,随后是V
    # 对于packed 的YUV格式,每个像素点的Y,U,V是连续交叉存储的
    # uv 的排列格式分为p、sp ,错误会导致颜色不对
    data = cast(pBuf, POINTER(c_ubyte * nSize)).contents
    # print(data)
    info = pFrameInfo.contents
    # info.nType == 3 is YUV data,others ard audio data.
    # you can parse YUV420 data to RGB
    if info.nType == 3:
        # # 使用 numpy.frombuffer 将 c_ubyte_Array 对象转换为 numpy 数组
        numpy_array = np.frombuffer(data, dtype=np.uint8)
      
        yuv = numpy_array.reshape(int(info.nHeight * 1.5), info.nWidth)

        rgb = cv2.cvtColor(yuv,cv2.COLOR_YUV2BGR_I420)

        # # 如果需要显示图像,可以使用以下代码
        cv2.imshow('RGB Image', rgb)
        cv2.waitKey(1)

转载请标明出处,文章有问题请留言,我看到会修改,中途出现问题也可以留言,我有时间就会解答。如果比较着急,可以+我微信,咨询费1杯奶茶的价格,备注:大华SDK。

物联沃分享整理
物联沃-IOTWORD物联网 » Python实时获取大华网络摄像头视频图像(SDK版本)

发表评论