在Python中从RTSP流中读取视频帧

26

我最近设置了一个树莓派摄像头,并通过RTSP流传输帧。虽然可能并不完全必要,但以下是我正在使用的广播视频命令:

raspivid -o - -t 0 -w 1280 -h 800 |cvlc -vvv stream:///dev/stdin --sout '#rtp{sdp=rtsp://:8554/output.h264}' :demux=h264

这个视频流非常流畅。

现在我想用Python解析这个流并逐帧读取。我想做一些运动检测以用于监控目的。

我完全不知道从哪里开始这个任务。有人能指点我一个好的教程吗?如果无法使用Python实现,我可以使用什么工具/语言来完成这个任务?


看这里:http://superuser.com/questions/225367/i-need-motion-detection-on-a-rtsp-stream ... 看起来连VLC也可以做到.. - hek2mgl
7个回答

33

使用“depu”列出的相同方法对我非常有效。 我只是用实际相机的“RTSP URL”替换了“视频文件”。 下面的示例适用于AXIS IP Camera。 (在先前的OpenCV版本中一段时间内无法正常工作) 适用于OpenCV 3.4.1 Windows 10)

import cv2
cap = cv2.VideoCapture("rtsp://root:pass@192.168.0.91:554/axis-media/media.amp")

while(cap.isOpened()):
    ret, frame = cap.read()
    cv2.imshow('frame', frame)
    if cv2.waitKey(20) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

1
一点点文档 - 555Russich

21

虽然有些hacky,但你可以使用VLC Python绑定(你可以使用pip install python-vlc安装它)来播放流:

import vlc
player=vlc.MediaPlayer('rtsp://:8554/output.h264')
player.play()

然后每秒钟拍摄一次快照:

while 1:
    time.sleep(1)
    player.video_take_snapshot(0, '.snapshot.tmp.png', 0, 0)

那么您可以使用SimpleCV之类的工具进行处理(只需将图像文件'.snapshot.tmp.png'加载到您的处理库中)。


8

2

1
这里有另一种选项。
它比其他答案更加复杂。但是,通过仅连接到相机,您可以将同一流同时分叉到多个多进程、屏幕、重新转换为多播、写入磁盘等。当然,只有在需要这样做的情况下(否则您会选择早期的答案)。
让我们创建两个独立的Python程序:
1. 服务器程序(rtsp连接,解码)server.py 2. 客户端程序(从共享内存读取帧)client.py
必须先启动服务器,然后再启动客户端。
python3 server.py

然后在另一个终端中:
python3 client.py

这里是代码:

(1) server.py

import time
from valkka.core import *

# YUV => RGB interpolation to the small size is done each 1000 milliseconds and passed on to the shmem ringbuffer
image_interval=1000  
# define rgb image dimensions
width  =1920//4
height =1080//4
# posix shared memory: identification tag and size of the ring buffer
shmem_name    ="cam_example" 
shmem_buffers =10 

shmem_filter    =RGBShmemFrameFilter(shmem_name, shmem_buffers, width, height)
sws_filter      =SwScaleFrameFilter("sws_filter", width, height, shmem_filter)
interval_filter =TimeIntervalFrameFilter("interval_filter", image_interval, sws_filter)

avthread        =AVThread("avthread",interval_filter)
av_in_filter    =avthread.getFrameFilter()
livethread      =LiveThread("livethread")

ctx =LiveConnectionContext(LiveConnectionType_rtsp, "rtsp://user:password@192.168.x.x", 1, av_in_filter)

avthread.startCall()
livethread.startCall()

avthread.decodingOnCall()
livethread.registerStreamCall(ctx)
livethread.playStreamCall(ctx)

# all those threads are written in cpp and they are running in the
# background.  Sleep for 20 seconds - or do something else while
# the cpp threads are running and streaming video
time.sleep(20)

# stop threads
livethread.stopCall()
avthread.stopCall()

print("bye") 

(2) client.py
import cv2
from valkka.api2 import ShmemRGBClient

width  =1920//4
height =1080//4

# This identifies posix shared memory - must be same as in the server side
shmem_name    ="cam_example"
# Size of the shmem ringbuffer - must be same as in the server side
shmem_buffers =10              

client=ShmemRGBClient(
name          =shmem_name,
n_ringbuffer  =shmem_buffers,
width         =width,
height        =height,
mstimeout     =1000,        # client timeouts if nothing has been received in 1000 milliseconds
verbose       =False
) 

while True:
index, isize = client.pull()
if (index==None):
    print("timeout")
else:
    data =client.shmem_list[index][0:isize]
    img =data.reshape((height,width,3))
    img =cv2.GaussianBlur(img, (21, 21), 0)
    cv2.imshow("valkka_opencv_demo",img)
    cv2.waitKey(1)

如果您感兴趣,请查看https://elsampsa.github.io/valkka-examples/了解更多信息。


0

在这里使用

cv2.VideoCapture("rtsp://username:password@IPAddress:PortNO(rest  of the link after the IPAdress)").

0

嗨,使用Python和OpenCV可以实现从视频中读取帧。以下是示例代码。在Python和OpenCV2版本下运行良好。

import cv2
import os
#Below code will capture the video frames and will sve it a folder (in current working directory)

dirname = 'myfolder'
#video path
cap = cv2.VideoCapture("your rtsp url")
count = 0
while(cap.isOpened()):
    ret, frame = cap.read()
    if not ret:
        break
    else:
        cv2.imshow('frame', frame)
        #The received "frame" will be saved. Or you can manipulate "frame" as per your needs.
        name = "rec_frame"+str(count)+".jpg"
        cv2.imwrite(os.path.join(dirname,name), frame)
        count += 1
    if cv2.waitKey(20) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

7
可惜这里没有涵盖重点部分(读取RTSP流中的帧),需要翻译。 - Zac

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接