从rtsp H.264视频流捕获单张图像

时间:2019-02-06 21:13:02

标签: python opencv raspberry-pi3 h.264 rtsp

我正在尝试从RTSP H.264视频帧中按需捕获单个图像。我正在将OpenCV与在Raspberry Pi上运行的Python配合使用。

我的理解是,您不能简单地捕获图像,而是必须不断地从视频中读取图像流,并丢弃偶尔需要的所有图像。这在计算上非常昂贵,并且仅消耗Pi上25%的CPU,而只能读取并丢弃1280x720 15 fps H.264 rtsp视频帧。

还有另一种方法吗?我很灵活,也可以使用GStreamer,FFMPEG或其他任何计算效率更高的东西。

3 个答案:

答案 0 :(得分:2)

您必须读取流的原因是因为H.264具有多种帧(请参阅https://en.wikipedia.org/wiki/Video_compression_picture_types),并且P和B帧需要上下文进行解码。只能对I帧(也称为关键帧)进行独立解码。

如果您想读取真正的任意帧,则可以解析(而不是解码)流,并保留自上一个I帧以来的所有内容。当触发信号到来时,您将从最后一个I帧直到当前点解码流。

如果不需要非常精确,则只需存储最后一个I帧,然后按需对其进行解码。这将非常快,但这意味着您可能会在错误的时间获取图片。

最后,这些关键帧多久出现一次?这取决于来源。例如,C920网络摄像头默认情况下大约每5秒生成一次,但是此间隔可以从1秒更改为30秒(我想这是前一段时间)

答案 1 :(得分:2)

我正在做类似的事情。 这是我的代码:

def CaptureFrontCamera():
    _bytes = bytes()
    stream = urllib.request.urlopen('http://192.168.0.51/video.cgi?resolution=1920x1080')
    while True:
        _bytes += stream.read(1024)
        a = _bytes.find(b'\xff\xd8')
        b = _bytes.find(b'\xff\xd9')
        if a != -1 and b != -1:
            jpg = _bytes[a:b+2]
            _bytes = _bytes[b+2:]
            filename = '/home/pi/capture.jpeg'
            i = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
            cv2.imwrite(filename, i)
            return filename

答案 2 :(得分:0)

回答我自己的问题。而不是使用read():

cap = cv2.VideoCapture('rtsp_url')

def captureimages():
    while True:
        image = cap.read()

s = threading.Thread(target=captureimages)
s.start()

if takepic == True:
    picture = image.copy()

将其分解为grab()和retrieve()效率更高。不是一个完美的解决方案,但是更好:

cap = cv2.VideoCapture('rtsp_url')

def captureimages():
    while True:
        cap.grab()

s = threading.Thread(target=captureimages)
s.start()

if takepic == True:
    picture = cap.retrieve()