如何将实时视频帧从 ffmpeg 传输到 PIL?
How to pipe live video frames from ffmpeg to PIL?
我需要使用 ffmpeg/avconv 将 jpg 帧通过管道传输到 python PIL (Pillow) Image 对象,使用 gst 作为中介*。我一直在到处寻找这个答案,但运气不佳。我想我很接近 - 但我被困住了。 使用 Python 2.7
我理想的管道,从 python 开始,看起来像这样:
- ffmpeg/avconv(作为 h264 视频)
- 管道 ->
- gst-streamer(帧拆分为 jpg)
- 管道 ->
- Pil 图像对象
我将前几个步骤控制为一个命令,该命令以硬件允许的最快速度将 .jpg 写入磁盘。
该命令看起来像这样:
command = [
"ffmpeg",
"-f video4linux2",
"-r 30",
"-video_size 1280x720",
"-pixel_format 'uyvy422'",
"-i /dev/video0",
"-vf fps=30",
"-f H264",
"-vcodec libx264",
"-preset ultrafast",
"pipe:1 -",
"|", # Pipe to GST
"gst-launch-1.0 fdsrc !",
"video/x-h264,framerate=30/1,stream-format=byte-stream !",
"decodebin ! videorate ! video/x-raw,framerate=30/1 !",
"videoconvert !",
"jpegenc quality=55 !",
"multifilesink location=" + Utils.live_sync_path + "live_%04d.jpg"
]
如果 运行 使用 popen 或 os.system,这将成功地将帧写入磁盘。
但是我不想将帧写入磁盘,而是想在我的子进程管道中捕获输出,并在写入时读取帧,然后将其写入类似文件的缓冲区中,然后 PIL 可以读取该缓冲区。
像这样:
import subprocess as sp
import shlex
import StringIO
clean_cmd = shlex.split(" ".join(command))
pipe = sp.Popen(clean_cmd, stdout = sp.PIPE, bufsize=10**8)
while pipe:
raw = pipe.stdout.read()
buff = StringIO.StringIO()
buff.write(raw)
buff.seek(0)
# Open or do something clever...
im = Image.open(buff)
im.show()
pipe.flush()
此代码不起作用 - 我什至不确定我能否以这种方式使用 "while pipe"。我对以这种方式使用缓冲区和管道还很陌生。
我不确定如何知道图像已写入管道或何时读取 'next' 图像。
对于理解如何从管道而不是磁盘读取图像的任何帮助,我们将不胜感激。
- 这最终是一个 Raspberry Pi 3 管道,为了提高我的帧速率,我不能 (A) read/write to/from 磁盘或 (B ) 使用逐帧捕获方法 - 而不是 运行 H246 视频直接来自相机芯片。
我假设最终目标是在 Linux 上以高帧率处理 USB 摄像头,以下内容解决了这个问题。
首先,虽然一些 USB 摄像头支持 H.264,但 USB 摄像头的 Linux 驱动程序(UVC 驱动程序)目前不支持 stream-based 有效载荷,其中包括 H.264,请参阅 "UVC Feature" table 上driver home page。用户 space 像 ffmpeg 这样的工具使用该驱动程序,因此对于用于 USB 传输的视频格式有相同的限制。
好消息是,如果相机支持 H.264,它几乎肯定会支持 MJPEG,它由 UVC 驱动程序支持并且压缩得很好,可以通过 USB 2.0 以 30 fps 支持 1280x720。您可以使用 v4l2-ctl -d 0 --list-formats-ext
列出您的相机支持的视频格式。对于 Microsoft Lifecam Cinema,例如,1280x720 仅支持 10 fps 的 YUV 4:2:2,但支持 30 fps 的 MJPEG。
对于从相机读取,我对 OpenCV 有很好的经验。在我的一个项目中,我有 24(!)个 Lifecams 连接到一台 Ubuntu 6 核 i7 机器,它使用 real-time 跟踪果蝇320x240,每个摄像头 7.5 fps(并且还为每个摄像头保存一个 MJPEG AVI 以记录实验)。由于 OpenCV 直接使用 V4L2 API,因此它应该比使用 ffmpeg、gst-streamer 和两个管道的解决方案更快。
使用 OpenCV 从相机读取并创建 PIL 图像的基本代码(无错误检查)如下所示:
import cv2
from PIL import Image
cap = cv2.VideoCapture(0) # /dev/video0
while True:
ret, frame = cap.read()
if not ret:
break
pil_img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
... # do something with PIL image
最后说明:您可能需要构建 v4l 版本的 OpenCV 以获得压缩 (MJPEG),请参阅 this answer。
我需要使用 ffmpeg/avconv 将 jpg 帧通过管道传输到 python PIL (Pillow) Image 对象,使用 gst 作为中介*。我一直在到处寻找这个答案,但运气不佳。我想我很接近 - 但我被困住了。 使用 Python 2.7
我理想的管道,从 python 开始,看起来像这样:
- ffmpeg/avconv(作为 h264 视频)
- 管道 ->
- gst-streamer(帧拆分为 jpg)
- 管道 ->
- Pil 图像对象
我将前几个步骤控制为一个命令,该命令以硬件允许的最快速度将 .jpg 写入磁盘。
该命令看起来像这样:
command = [
"ffmpeg",
"-f video4linux2",
"-r 30",
"-video_size 1280x720",
"-pixel_format 'uyvy422'",
"-i /dev/video0",
"-vf fps=30",
"-f H264",
"-vcodec libx264",
"-preset ultrafast",
"pipe:1 -",
"|", # Pipe to GST
"gst-launch-1.0 fdsrc !",
"video/x-h264,framerate=30/1,stream-format=byte-stream !",
"decodebin ! videorate ! video/x-raw,framerate=30/1 !",
"videoconvert !",
"jpegenc quality=55 !",
"multifilesink location=" + Utils.live_sync_path + "live_%04d.jpg"
]
如果 运行 使用 popen 或 os.system,这将成功地将帧写入磁盘。
但是我不想将帧写入磁盘,而是想在我的子进程管道中捕获输出,并在写入时读取帧,然后将其写入类似文件的缓冲区中,然后 PIL 可以读取该缓冲区。
像这样:
import subprocess as sp
import shlex
import StringIO
clean_cmd = shlex.split(" ".join(command))
pipe = sp.Popen(clean_cmd, stdout = sp.PIPE, bufsize=10**8)
while pipe:
raw = pipe.stdout.read()
buff = StringIO.StringIO()
buff.write(raw)
buff.seek(0)
# Open or do something clever...
im = Image.open(buff)
im.show()
pipe.flush()
此代码不起作用 - 我什至不确定我能否以这种方式使用 "while pipe"。我对以这种方式使用缓冲区和管道还很陌生。
我不确定如何知道图像已写入管道或何时读取 'next' 图像。
对于理解如何从管道而不是磁盘读取图像的任何帮助,我们将不胜感激。
- 这最终是一个 Raspberry Pi 3 管道,为了提高我的帧速率,我不能 (A) read/write to/from 磁盘或 (B ) 使用逐帧捕获方法 - 而不是 运行 H246 视频直接来自相机芯片。
我假设最终目标是在 Linux 上以高帧率处理 USB 摄像头,以下内容解决了这个问题。
首先,虽然一些 USB 摄像头支持 H.264,但 USB 摄像头的 Linux 驱动程序(UVC 驱动程序)目前不支持 stream-based 有效载荷,其中包括 H.264,请参阅 "UVC Feature" table 上driver home page。用户 space 像 ffmpeg 这样的工具使用该驱动程序,因此对于用于 USB 传输的视频格式有相同的限制。
好消息是,如果相机支持 H.264,它几乎肯定会支持 MJPEG,它由 UVC 驱动程序支持并且压缩得很好,可以通过 USB 2.0 以 30 fps 支持 1280x720。您可以使用 v4l2-ctl -d 0 --list-formats-ext
列出您的相机支持的视频格式。对于 Microsoft Lifecam Cinema,例如,1280x720 仅支持 10 fps 的 YUV 4:2:2,但支持 30 fps 的 MJPEG。
对于从相机读取,我对 OpenCV 有很好的经验。在我的一个项目中,我有 24(!)个 Lifecams 连接到一台 Ubuntu 6 核 i7 机器,它使用 real-time 跟踪果蝇320x240,每个摄像头 7.5 fps(并且还为每个摄像头保存一个 MJPEG AVI 以记录实验)。由于 OpenCV 直接使用 V4L2 API,因此它应该比使用 ffmpeg、gst-streamer 和两个管道的解决方案更快。
使用 OpenCV 从相机读取并创建 PIL 图像的基本代码(无错误检查)如下所示:
import cv2
from PIL import Image
cap = cv2.VideoCapture(0) # /dev/video0
while True:
ret, frame = cap.read()
if not ret:
break
pil_img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
... # do something with PIL image
最后说明:您可能需要构建 v4l 版本的 OpenCV 以获得压缩 (MJPEG),请参阅 this answer。