使用python将opencv图像通过管道传输到ffmpeg

Posted

技术标签:

【中文标题】使用python将opencv图像通过管道传输到ffmpeg【英文标题】:Pipe opencv images to ffmpeg using python 【发布时间】:2016-03-14 01:40:32 【问题描述】:

如何将 openCV 图像通过管道传输到 ffmpeg(将 ffmpeg 作为子进程运行)? (我正在使用 spyder/anaconda)

我正在从视频文件中读取帧并对每一帧进行一些处理。

import cv2   
cap = cv2.VideoCapture(self.avi_path)
img = cap.read()
gray = cv2.cvtColor(img[1], cv2.COLOR_BGR2GRAY)
bgDiv=gray/vidMed #background division

然后,为了将处理后的帧传输到 ffmpeg,我在一个相关问题中找到了这个命令:

sys.stdout.write( bgDiv.tostring() )

接下来,我尝试将 ffmpeg 作为子进程运行:

cmd='ffmpeg.exe -f rawvideo -pix_fmt gray -s 2048x2048 -r 30 -i - -an -f avi -r 30 foo.avi'
sp.call(cmd,shell=True)

(这也来自提到的帖子) 但是,这会使我的 IPython 控制台充满神秘的象形文字,然后使其崩溃。有什么建议吗?

最后,我想输出 4 个流并让 ffmpeg 并行编码这 4 个流。

【问题讨论】:

您是否有理由不想使用 OpenCV VideoWriter 界面来写出您的视频?我不认为你可以一次输出 4 个流。 我希望这样可以更快地保存视频。我注意到我上面使用 VideoWriter 的 openCV 读写示例所花费的时间大约是相同输入视频的纯 ffmpeg 编码的两倍(当然,ffmpeg 编码不包括背景分割 - 这就是我尝试使用 openCV 的原因第一名)。我希望使用命名管道... 【参考方案1】:

我曾经遇到过类似的问题。 I opened an issue on Github,原来它可能是平台问题。

与您的问题相关,您也可以将 OpenCV 图像通过管道传输到 FFMPEG。这是一个示例代码:

# This script copies the video frame by frame
import cv2
import subprocess as sp

input_file = 'input_file_name.mp4'
output_file = 'output_file_name.mp4'

cap = cv2.VideoCapture(input_file)
ret, frame = cap.read()
height, width, ch = frame.shape

ffmpeg = 'FFMPEG'
dimension = 'x'.format(width, height)
f_format = 'bgr24' # remember OpenCV uses bgr format
fps = str(cap.get(cv2.CAP_PROP_FPS))

command = [ffmpeg,
        '-y',
        '-f', 'rawvideo',
        '-vcodec','rawvideo',
        '-s', dimension,
        '-pix_fmt', 'bgr24',
        '-r', fps,
        '-i', '-',
        '-an',
        '-vcodec', 'mpeg4',
        '-b:v', '5000k',
        output_file ]

proc = sp.Popen(command, stdin=sp.PIPE, stderr=sp.PIPE)

while True:
    ret, frame = cap.read()
    if not ret:
        break
    proc.stdin.write(frame.tostring())

cap.release()
proc.stdin.close()
proc.stderr.close()
proc.wait()

【讨论】:

我收到一个错误:pipe.proc.stdin.write(frame.tostring()) AttributeError: 'Popen' object has no attribute 'proc 当我将您的代码更改为 pipe.stdin.write(frame.tostring()) 时,我收到另一个错误:pipe.stdin.write(frame.tostring()) IOError: [Errno 22] Invalid argumen 这是 python 2.7 代码。你的python是什么版本的? 我已经尝试过这些更改。使用此代码,我得到:IOError: [Errno 22] Invalid argument. @jlarsch 是的,你是对的。 ffmpeg 命令出错,现在修复。我刚刚在我的机器上测试了这段代码,它工作得很好!【参考方案2】:

我有点晚了,但是我强大的VidGear Python 库使用其WriteGear API's Compression Mode 可以在任何平台上自动将 OpenCV 帧流水线化到 FFmpeg 的过程。 OP,您可以按如下方式实现您的答案:

# import libraries
from vidgear.gears import WriteGear
import cv2

output_params = "-s":"2048x2048", "-r":30 #define 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 了解更多高级应用程序和功能。

希望有帮助!

【讨论】:

再晚一点... op 正朝着相反的方向发展。您的 api 可以将 cv 输入发送到 Youtube 直播吗? WriteGear 用法示例? @dbmitch 谢谢,答案已更新。您可以直接使用 FFmpeg 将 cv 输入发送到 Youtube 直播吗?如果是,那么 WriteGear 可以做到,如果不是,那么答案是否定的。 好的 - 我会试一试 - 但如果我能做到,我会从 WriteGear 获得什么 轻松灵活。 一个很好的例子会更好——WriteGear 需要一个输出文件名——你将如何将它发送到流?您的 github 上没有示例。您可以将 ffmpeg 命令与 cv2 流一起使用吗?

以上是关于使用python将opencv图像通过管道传输到ffmpeg的主要内容,如果未能解决你的问题,请参考以下文章

将图像从 python 传输到 C++ 并返回

Python OpenCV 图像到字节字符串以进行 json 传输

OpenCV Python,从命名管道中读取视频

从 python 中的 opencv 写入 Gstreamer 管道

node.js - 将图像缓存到文件系统并将图像通过管道传输到响应

在将输出从 tail -f 通过管道传输到 grep 后写入文件