55

我最近的工作涉及以编程方式制作视频。在 python 中,典型的工作流程如下所示:

import subprocess, Image, ImageDraw

for i in range(frames_per_second * video_duration_seconds):
    img = createFrame(i)
    img.save("%07d.png" % i)

subprocess.call(["ffmpeg","-y","-r",str(frames_per_second),"-i", "%07d.png","-vcodec","mpeg4", "-qscale","5", "-r", str(frames_per_second), "video.avi"])

此工作流程为视频中的每一帧创建一个图像并将其保存到磁盘。保存所有图像后,调用 ffmpeg 从所有图像构建视频。

将图像保存到磁盘(不是在内存中创建图像)消耗了这里的大部分周期,并且似乎没有必要。有没有办法执行相同的功能,但不将图像保存到磁盘?因此,将调用 ffmpeg 并在构建后立即构建图像并将其馈送到 ffmpeg。

4

3 回答 3

69

好的,我让它工作了。感谢 LordNeckbeard 建议使用 image2pipe。我不得不使用 jpg 编码而不是png,因为带有 png 的 image2pipe 在我的 ffmpeg 版本上不起作用。第一个脚本与您的问题代码基本相同,除了我实现了一个简单的图像创建,它只创建从黑色到红色的图像。我还添加了一些代码来计时执行。

串行执行

import subprocess, Image

fps, duration = 24, 100
for i in range(fps * duration):
    im = Image.new("RGB", (300, 300), (i, 1, 1))
    im.save("%07d.jpg" % i)
subprocess.call(["ffmpeg","-y","-r",str(fps),"-i", "%07d.jpg","-vcodec","mpeg4", "-qscale","5", "-r", str(fps), "video.avi"])

并行执行(没有图像保存到磁盘)

import Image
from subprocess import Popen, PIPE

fps, duration = 24, 100
p = Popen(['ffmpeg', '-y', '-f', 'image2pipe', '-vcodec', 'mjpeg', '-r', '24', '-i', '-', '-vcodec', 'mpeg4', '-qscale', '5', '-r', '24', 'video.avi'], stdin=PIPE)
for i in range(fps * duration):
    im = Image.new("RGB", (300, 300), (i, 1, 1))
    im.save(p.stdin, 'JPEG')
p.stdin.close()
p.wait()

结果很有趣,我运行每个脚本 3 次来比较性能: 串行:

12.9062321186
12.8965060711
12.9360799789

平行线:

8.67797684669
8.57139396667
8.38926696777

所以看起来并行版本快了大约 1.5 倍。

于 2012-11-08T21:58:29.567 回答
6

imageio直接支持这一点。它使用 FFMPEG 和Video Acceleration API,速度非常快:

import imageio

writer = imageio.get_writer('video.avi', fps=fps)
for i in range(frames_per_second * video_duration_seconds):
    img = createFrame(i)
    writer.append_data(img)
writer.close()
于 2019-03-29T14:06:08.860 回答
1

我有点晚了,但是VidGearPython 库的WriteGear API可以通过 硬件编码器支持在任何平台上实时将 OpenCV 帧流水线化到 FFmpeg 的过程自动化,同时提供相同的 opencv-python 语法。这是一个基本的python示例:

# import libraries
from vidgear.gears import WriteGear
import cv2

output_params = {"-vcodec":"libx264", "-crf": 0, "-preset": "fast"} #define (Codec,CRF,preset) FFmpeg tweak parameters for writer

stream = cv2.VideoCapture(0) #Open live webcam video stream on first index(i.e. 0) device

writer = WriteGear(output_filename = 'Output.mp4', compression_mode = True, logging = True, **output_params) #Define writer with output filename 'Output.mp4' 

# infinite loop
while True:
    
    (grabbed, frame) = stream.read()
    # read frames

    # check if frame empty
    if not is grabbed:
        #if True break the infinite loop
        break
    

    # {do something with frame here}
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # write a modified frame to writer
    writer.write(gray) 
       
    # Show output window
    cv2.imshow("Output Frame", frame)

    key = cv2.waitKey(1) & 0xFF
    # check for 'q' key-press
    if key == ord("q"):
        #if 'q' key-pressed break out
        break

cv2.destroyAllWindows()
# close output window

stream.release()
# safely close video stream
writer.close()
# safely close writer

来源:https ://abhitronix.github.io/vidgear/latest/gears/writegear/compression/usage/#using-compression-mode-with-opencv

您可以查看VidGear Docs以获得更高级的应用程序和功能。

于 2021-12-30T03:04:30.150 回答