繁体   English   中英

使用 python opencv 编写 mp4 视频

[英]Writing an mp4 video using python opencv

我想从网络摄像头捕获视频并使用 opencv 将其保存到 mp4 文件。 我在stackoverflow(下)上找到了很好的示例代码。 唯一的问题是我试图将其保存为 mp4,而不是 avi。 我不明白的部分是传递给 FOURCC 编写器的“XVID”参数应该是,我认为,一个 mp4 编解码器(来自这个链接)。 如果我将文件名更改为“output.mp4”,它会告诉我标签无效,所以我必须相信 XVID 编解码器实际上是在制作 avi 文件。 这是一个愚蠢的问题吗? 如何写入 mp4?

我找到了显示如何将 avi 转换为 mp4 的链接,但这似乎效率低下。 似乎我应该能够在初始写入期间做到这一点。

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

# Define the codec and create VideoWriter object
fourcc = cv2.cv.CV_FOURCC(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret==True:
        frame = cv2.flip(frame,0)

        # write the flipped frame
        out.write(frame)

        cv2.imshow('frame',frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()

这对我有用。

self._name = name + '.mp4'
self._cap = VideoCapture(0)
self._fourcc = VideoWriter_fourcc(*'MP4V')
self._out = VideoWriter(self._name, self._fourcc, 20.0, (640,480))

对我有用的是确保输入的“帧”大小等于输出视频的大小(在本例中为 (680, 480) )。

http://answers.opencv.org/question/27902/how-to-record-video-using-opencv-and-python/

这是我的工作代码(Mac OSX Sierra 10.12.6):

cap = cv2.VideoCapture(0)
cap.set(3,640)
cap.set(4,480)

fourcc = cv2.VideoWriter_fourcc(*'MP4V')
out = cv2.VideoWriter('output.mp4', fourcc, 20.0, (640,480))

while(True):
    ret, frame = cap.read()
    out.write(frame)
    cv2.imshow('frame', frame)
    c = cv2.waitKey(1)
    if c & 0xFF == ord('q'):
        break

cap.release()
out.release()
cv2.destroyAllWindows()

注意:我按照@10SecTom 的建议安装了 openh264,但我不确定这是否与问题有关。

以防万一:

brew install openh264

您的代码中有一些需要更改的地方:

  1. 将输出名称更改为“output.mp4”(更改为 .mp4)
  2. 我遇到了人们在评论中遇到的同样问题,所以我将fourcc更改为0x7634706dout = cv2.VideoWriter('output.mp4',0x7634706d , 20.0, (640,480))

这是保存相机拍摄的视频的默认代码

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret==True:
        frame = cv2.flip(frame,0)

        # write the flipped frame
        out.write(frame)

        cv2.imshow('frame',frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()

大约两分钟的剪辑捕捉到了FULL HD

使用

cap = cv2.VideoCapture(0,cv2.CAP_DSHOW)
cap.set(3,1920)
cap.set(4,1080)
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (1920,1080))

保存的文件超过150MB

然后不得不使用ffmpeg来减小保存的文件大小,根据需要更改的视频质量在30MB60MB之间使用crf降低 crf 更好的视频质量并生成更大的文件大小。 您还可以更改格式avimp4mkv

然后我找到了ffmpeg-python

这是使用ffmpeg-python将每帧的numpy array保存为视频的代码

import numpy as np
import cv2
import ffmpeg

def save_video(cap,saving_file_name,fps=33.0):

    while cap.isOpened():
        ret, frame = cap.read()
        if ret:
            i_width,i_height = frame.shape[1],frame.shape[0]
            break

    process = (
    ffmpeg
        .input('pipe:',format='rawvideo', pix_fmt='rgb24',s='{}x{}'.format(i_width,i_height))
        .output(saved_video_file_name,pix_fmt='yuv420p',vcodec='libx264',r=fps,crf=37)
        .overwrite_output()
        .run_async(pipe_stdin=True)
    )

    return process

if __name__=='__main__':

    cap = cv2.VideoCapture(0,cv2.CAP_DSHOW)
    cap.set(3,1920)
    cap.set(4,1080)
    saved_video_file_name = 'output.avi'
    process = save_video(cap,saved_video_file_name)

    while(cap.isOpened()):
        ret, frame = cap.read()
        if ret==True:
            frame = cv2.flip(frame,0)
            process.stdin.write(
                cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                    .astype(np.uint8)
                    .tobytes()
                    )

            cv2.imshow('frame',frame)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                process.stdin.close()
                process.wait()
                cap.release()
                cv2.destroyAllWindows()
                break
        else:
            process.stdin.close()
            process.wait()
            cap.release()
            cv2.destroyAllWindows()
            break

fourcc = cv2.VideoWriter_fourcc(*'mp4v')

'mp4v' 不返回错误,这与在fourcc 中定义的'MP4V' 不同

对于错误:

“OpenCV:FFMPEG:标签 0x5634504d/'MP4V' 不支持编解码器 id 13 和格式'mp4 / MP4(MPEG-4 第 14 部分)' OpenCV:FFMPEG:回退使用标签 0x00000020/'???'”

这对我有用,我添加了 images.sort() 以保持序列顺序:

import cv2
import numpy as np
import os

image_folder = 'data-set-race-01'
video_file = 'race-01.mp4'
image_size = (160, 120)
fps = 24

images = [img for img in os.listdir(image_folder) if img.endswith(".jpg")]
images.sort()

out = cv2.VideoWriter(video_file, cv2.VideoWriter_fourcc(*'MP4V'), fps, image_size)

img_array = []
for filename in images:
    img = cv2.imread(os.path.join(image_folder, filename))
    img_array.append(img)
    out.write(img)

out.release()

对于仍在为问题苦苦挣扎的人。 根据这篇文章,我使用了这个示例,它对我有用:

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'X264')
out = cv2.VideoWriter('output.mp4',fourcc, 20.0, (640,480))

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret==True:
        frame = cv2.flip(frame,0)

        # write the flipped frame
        out.write(frame)

        cv2.imshow('frame',frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()

所以我不得不使用cv2.VideoWriter_fourcc(*'X264')编解码器。 使用从源代码编译的 OpenCV 3.4.3 进行测试。

任何正在寻找使用 OpenCV 或 FFmpeg 编写 MP4 文件的最方便和最强大的方法的人,都可以查看我最先进的VidGear视频处理 Python 库的WriteGear API ,它可与OpenCV 后端FFmpeg 后端一起使用,甚至支持 GPU 编码器. 这是一个在带有 FFmpeg 后端的 WriteGear 中使用 H264 编码器进行编码的示例:

# import required libraries
from vidgear.gears import WriteGear
import cv2

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

# Open suitable video stream, such as webcam on first index(i.e. 0)
stream = cv2.VideoCapture(0) 

# Define writer with defined parameters and suitable output filename for e.g. `Output.mp4`
writer = WriteGear(output_filename = 'Output.mp4', logging = True, **output_params)

# loop over
while True:

    # read frames from stream
    (grabbed, frame) = stream.read()

    # check for frame if not grabbed
    if not grabbed:
      break

    # {do something with the frame here}
    # lets convert frame to gray for this example
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # write gray frame to writer
    writer.write(gray)

    # Show output window
    cv2.imshow("Output Gray Frame", gray)

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

# close output window
cv2.destroyAllWindows()

# safely close video stream
stream.release()

# safely close writer
writer.close() 
  • 来源: https ://github.com/abhiTronix/vidgear
  • 文档: https ://abhitronix.github.io/vidgear/
  • 更多 FFmpeg 后端示例: https ://abhitronix.github.io/vidgear/latest/gears/writegear/compression/usage/
  • OpenCV 后端示例: https ://abhitronix.github.io/vidgear/gears/writegear/non_compression/usage/

诸如OpenCV: FFMPEG: tag 0x5634504d/'MP4V' is not supported with codec id 13 and format 'mp4 / MP4 (MPEG-4 Part 14)' OpenCV: FFMPEG: fallback to use tag 0x00000020/' ???' 也许您的输出视频大小与原始视频不同。 您可以先查看视频的帧大小。

您需要将编解码器设置为'mp4v'小写)。 如果设置为大写,则会抛出一个错误,说不支持,建议改用小写: OpenCV: FFMPEG :fallback to use tag 0x7634706d/'mp4v' 您可能还想查看VideoWriter的文档以及此处给出的示例。 另外,请确保您的输出视频的大小等于您的输入frame大小(下面使用VideoCapture对象的尺寸来处理这个问题)。

cap = cv2.VideoCapture(0)
w = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
h = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
fps = cap.get(cv2.CAP_PROP_FPS) 
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('output.mp4', fourcc, fps, (int(w),int(h)))

您可以通过设置fourcc=-1来获取可用于mp4等的编解码器的完整列表。 例如:

out = cv2.VideoWriter('output.mp4', -1, fps, (int(w),int(h)))

关于 VideoWriter,OpenCV 文档不是很丰富,但是我设法通过以下方式使其工作(通过查看堆栈跟踪):

import cv2

HEIGHT = 480
WIDTH = 640
FPS = 30.0

cap = cv2.VideoCapture(0, cv2.CAP_ANY)

cap.set(cv2.CAP_PROP_FPS, FPS)
cap.set(cv2.CAP_PROP_CONVERT_RGB , 1)
cap.set(cv2.CAP_PROP_BUFFERSIZE, 100)


cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)

fourcc = cv2.VideoWriter_fourcc(*'mp4v')

# output parameters such as fps and size can be changed
output = cv2.VideoWriter("output.mp4", fourcc, FPS, (WIDTH, HEIGHT))

while True:
    if cap.isOpened():
        (ret, frame) = cap.read()
        if ret:
            output.write(frame)
        cv2.imshow("frame", frame)

    if cv2.waitKey(10) == ord('q'):
        break

output.release()
cap.release()
cv2.destroyAllWindows()

堆栈跟踪错误是:

OpenCV: FFMPEG: tag 0x5634504d/'MP4V' is not supported with codec id 12 and 
format 'mp4 / MP4 (MPEG-4 Part 14)'
OpenCV: FFMPEG: fallback to use tag 0x7634706d/'mp4v'

不幸的是,很难找到 OpenCV 使用的官方编解码器列表,或者至少我找不到它们。 无论如何,您似乎必须输入以小写形式编写的编解码器“mp4v”。

https://docs.opencv.org/3.4/dd/d01/group__videoio__c.html#gac005718f121379beffdbdbfb44f2646a

我注意到的一件重要的事情是帧和输出视频的纵横比必须相同,这就是为什么我使用两个变量来表示高度和宽度。 如果这两个不同,则创建文件,但不保存帧(您总是得到一个 1KB 的 mp4 文件)。 为避免任何问题,您可以对 FPS 执行相同操作。

只需将编解码器更改为"DIVX" 此编解码器适用于所有格式。

fourcc = cv2.VideoWriter_fourcc(*'DIVX')

我希望这对你有用!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM