从 rtsp H.264 视频流中捕获单个图像
Capturing a SINGLE image from an rtsp H.264 video stream
我正在尝试从 RTSP H.264 视频帧中按需捕获单个图像。我在 Raspberry Pi 上将 OpenCV 与 Python 运行 一起使用。
我的理解是,您不能简单地捕获图像,而是必须不断地从视频中读取图像流,并丢弃除偶尔需要的图像之外的所有图像。这在计算上非常昂贵,并且在 Pi 上消耗了大约 25% 的 CPU 除了读取和丢弃 1280x720 15 fps H.264 rtsp 视频帧之外什么都不做。
还有别的办法吗?我很灵活,也可以使用 GStreamer、FFMPEG 或任何其他计算效率更高的东西。
你必须读取流的原因是因为 H.264 有多种帧(参见 https://en.wikipedia.org/wiki/Video_compression_picture_types)并且 P 和 B 帧需要解码上下文。只有 I 帧(也称为关键帧)可以独立解码。
如果您想读取真正的任意帧,您可以解析(而不是解码)流,并保留自最后一个 I 帧以来的所有内容。当您的触发器到来时,您将解码从最后一个 I 帧到当前点的流。
如果不需要很精确,可以只存最后一个I帧,按需解码。这将非常快,但这意味着您可能会在错误的时间获得照片。
最后,这些关键帧多久出现一次?这取决于来源。例如,C920 网络摄像头默认情况下大约每 5 秒生成一次,但这个间隔可以从 1 秒更改为 30 秒(我想,这是前一段时间)
我也在做类似的事情。
这是我的代码:
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
回答我自己的问题。而不是使用 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()
我正在尝试从 RTSP H.264 视频帧中按需捕获单个图像。我在 Raspberry Pi 上将 OpenCV 与 Python 运行 一起使用。
我的理解是,您不能简单地捕获图像,而是必须不断地从视频中读取图像流,并丢弃除偶尔需要的图像之外的所有图像。这在计算上非常昂贵,并且在 Pi 上消耗了大约 25% 的 CPU 除了读取和丢弃 1280x720 15 fps H.264 rtsp 视频帧之外什么都不做。
还有别的办法吗?我很灵活,也可以使用 GStreamer、FFMPEG 或任何其他计算效率更高的东西。
你必须读取流的原因是因为 H.264 有多种帧(参见 https://en.wikipedia.org/wiki/Video_compression_picture_types)并且 P 和 B 帧需要解码上下文。只有 I 帧(也称为关键帧)可以独立解码。
如果您想读取真正的任意帧,您可以解析(而不是解码)流,并保留自最后一个 I 帧以来的所有内容。当您的触发器到来时,您将解码从最后一个 I 帧到当前点的流。
如果不需要很精确,可以只存最后一个I帧,按需解码。这将非常快,但这意味着您可能会在错误的时间获得照片。
最后,这些关键帧多久出现一次?这取决于来源。例如,C920 网络摄像头默认情况下大约每 5 秒生成一次,但这个间隔可以从 1 秒更改为 30 秒(我想,这是前一段时间)
我也在做类似的事情。 这是我的代码:
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
回答我自己的问题。而不是使用 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()