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

4

我正在尝试从RTSP H.264视频帧中按需捕获单个图像。我在树莓派上使用Python的OpenCV。

我的理解是您不能简单地捕获图像,而必须不断读取视频流的图像,并舍弃除了偶尔需要的一些以外的所有图像。这非常消耗计算资源,仅读取和舍弃1280x720 15 fps H.264 rtsp视频帧就会占用Pi约25%的CPU。

是否有其他方法?我很灵活,也可以使用GStreamer、FFMPEG或任何其他更具计算效率的工具。

3个回答

2
你需要读取流的原因是因为H.264有多种类型的帧(参见https://en.wikipedia.org/wiki/Video_compression_picture_types),而P和B帧需要上下文才能解码。只有I帧(也称为关键帧)可以独立解码。
如果你想读取真正任意的帧,可以解析(而不是解码)流,并保留自上一个I帧以来的所有内容。当触发器到来时,你就可以解码从上一个I帧到当前点之间的流。
如果你不需要非常精确,可以只存储最后一个I帧,并在需要时解码它。这样会很快,但这意味着你可能会在错误的时间得到图像。
最后,这些关键帧出现的频率有多高?这取决于来源。例如,C920网络摄像头默认每5秒生成一次关键帧,但这个间隔可以从1到30秒改变(我想,这是一段时间以前的情况)。

我知道H.264如何压缩数据,但是我忘记了I帧的间隔可能很重要,需要注意。感谢您提出这一点。 - FarNorth

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

这看起来很有前途,但我无法弄清如何使用rtsp(而不是http)视频流。有什么想法吗? - FarNorth
您的链接提到使用cv2.VideoCapture()来读取rtsp流,这也是我现在正在使用的方法。问题在于read()会消耗大量的处理能力,并生成我99%不需要的图像。理想情况下,我希望它可以摄取字节流,并仅在需要时构建图像。 - FarNorth
抱歉,我无法提供更多帮助。在图像处理方面,我还是个新手。希望你能找到解决方案。 - Koxo

1

回答我自己的问题。不要使用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()

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