解决cv2读取rtsp延迟,Python使用FFmpeg通过tcp拉取rtsp流,并转化成numpy array

问题产生的原因

最近在捣鼓图像方面的项目,项目过程中,发现使用cv2.VideoCapture这个方法获取rtsp流会有一定的延迟,于是就有了这篇文章。方法步骤如下

1. 安装ffmepg-python包

打开终端进入你的anacondad虚拟环境或者python环境,用pip包进行安装

pip install ffmpeg-python

2. 安装ffmpeg

目前我还没找到解耦ffmpeg软件的方法,下面程序跑通必选安装此软件并将其添加到环境变量当中。
去官网(https://ffmpeg.org/)下载ffmpeg并进行安装。
然后将安装目录,包含目录下的bin文件夹(bin文件夹里有三个.exe文件),将其添加到环境变量中
在终端中输入

ffmpeg

如果显示ffmpeg命令找不到的话,说明环境变量没配置好

3. 使用ffmpeg软件测试rtsp流

  • rtsp需要改成自己的
ffplay -i "rtsp://admin:admin123@192.168.1.163/cam/realmonitor?channel=1&subtype=1"
  • 使用tcp
ffplay -rtsp_transport tcp -i "rtsp://admin:admin123@192.168.1.163/cam/realmonitor?channel=1&subtype=1"

点击画面并按键盘上的q键即可退出播放

4. 使用ffmpeg读取rtsp流并转换成numpy array,并使用cv2.imshow显示

代码参考

import ffmpeg
import numpy as np
import cv2


def main(source):
    args = {"rtsp_transport": "tcp"}    # 添加参数
    probe = ffmpeg.probe(source)
    cap_info = next(x for x in probe['streams'] if x['codec_type'] == 'video')
    print("fps: {}".format(cap_info['r_frame_rate']))
    width = cap_info['width']           # 获取视频流的宽度
    height = cap_info['height']         # 获取视频流的高度
    up, down = str(cap_info['r_frame_rate']).split('/')
    fps = eval(up) / eval(down)
    print("fps: {}".format(fps))    # 读取可能会出错错误
    process1 = (
        ffmpeg
        .input(source, **args)
        .output('pipe:', format='rawvideo', pix_fmt='rgb24')
        .overwrite_output()
        .run_async(pipe_stdout=True)
    )
    while True:
        in_bytes = process1.stdout.read(width * height * 3)     # 读取图片
        if not in_bytes:
            break
        # 转成ndarray
        in_frame = (
            np
            .frombuffer(in_bytes, np.uint8)
            .reshape([height, width, 3])
        )
        frame = cv2.resize(in_frame, (1280, 720))   # 改变图片尺寸
        frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)  # 转成BGR
        cv2.imshow("ffmpeg", frame)
        if cv2.waitKey(1) == ord('q'):
            break
    process1.kill()             # 关闭


if __name__ == "__main__":
    # rtsp流需要换成自己的
    source = "rtsp://admin:admin123@192.168.1.163/cam/realmonitor?channel=1&subtype=0"
    main(source)

代码更新,参考issue,相比之前所占用的内存更少了。

import ffmpeg
import numpy as np
import cv2


def main(source):
    args = {
        "rtsp_transport": "tcp",
        "fflags": "nobuffer",
        "flags": "low_delay"
    }    # 添加参数
    probe = ffmpeg.probe(source)
    cap_info = next(x for x in probe['streams'] if x['codec_type'] == 'video')
    print("fps: {}".format(cap_info['r_frame_rate']))
    width = cap_info['width']           # 获取视频流的宽度
    height = cap_info['height']         # 获取视频流的高度
    up, down = str(cap_info['r_frame_rate']).split('/')
    fps = eval(up) / eval(down)
    print("fps: {}".format(fps))    # 读取可能会出错错误
    process1 = (
        ffmpeg
        .input(source, **args)
        .output('pipe:', format='rawvideo', pix_fmt='rgb24')
        .overwrite_output()
        .run_async(pipe_stdout=True)
    )
    while True:
        in_bytes = process1.stdout.read(width * height * 3)     # 读取图片
        if not in_bytes:
            break
        # 转成ndarray
        in_frame = (
            np
            .frombuffer(in_bytes, np.uint8)
            .reshape([height, width, 3])
        )
        # in_frame = cv2.resize(in_frame, (1280, 720))   # 改变图片尺寸
        frame = cv2.cvtColor(in_frame, cv2.COLOR_RGB2BGR)  # 转成BGR
        cv2.imshow("ffmpeg", frame)
        if cv2.waitKey(1) == ord('q'):
            break
    process1.kill()             # 关闭


if __name__ == "__main__":
    # rtsp流需要换成自己的
    camera_ip = "192.168.20.221"    # 摄像头ip
    camera_login_user = "admin"
    camera_login_pwd = "admin123"
    camera_channel = 0      # 选择主码流,还是辅码流

    alhua_rtsp = f"rtsp://{camera_login_user}:{camera_login_pwd}@{camera_ip}/cam/realmonitor?channel=1&subtype={camera_channel}"

    main(alhua_rtsp)

结论

使用的摄像头:大华摄像头,
测试使用的网络环境:网线直连。
相比其摄像头自带的网页上的画面会快上个0.01秒左右

评论 32
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值