其实OpenCV已经提供了写视频的接口,但是编码和文件后缀的对应真是让人头疼,动不动就不支持。经过尝试,总结出目前两种可以正常写入视频的对应关系:

MJPG --> .avi
mp4v -->.mp4

一、编码MJPG、后缀.avi

MJPG是大写!!!

# coding=utf-8
from __future__ import absolute_import, division, print_function
import cv2
import warnings
import numpy as np
warnings.simplefilter("always")
class VideoWriter:
    def __init__(self, name, width, height, fps=25):
        # type: (str, int, int, int) -> None
        if not name.endswith('.avi'):  # 保证文件名的后缀是.avi
            name += '.avi'
            warnings.warn('video name should ends with ".avi"')
        self.__name = name          # 文件名
        self.__height = height      # 高
        self.__width = width        # 宽
        fourcc = cv2.VideoWriter_fourcc(*'MJPG')  # 如果是avi视频,编码需要为MJPG
        self.__writer = cv2.VideoWriter(name, fourcc, fps, (width, height))
    def write(self, frame):
        if frame.dtype != np.uint8:  # 检查frame的类型
            raise ValueError('frame.dtype should be np.uint8')
        # 检查frame的大小
        row, col, _ = frame.shape
        if row != self.__height or col != self.__width:
            warnings.warn('长和宽不等于创建视频写入时的设置,此frame不会被写入视频')
            return
        self.__writer.write(frame)
    def close(self):
        self.__writer.release()
def main():
    width = 512
    height = 256
    vw = VideoWriter('test.avi', width, height)
    for i in range(25*50):
        # 随机生成一幅图像
        frame = np.random.randint(0, 255, (height, width, 3), dtype=np.uint8)
        # 写入图像
        vw.write(frame)
    vw.close()
if __name__ == '__main__':
    main()

二、编码mp4v、后缀.mp4

mp4v是小写!!!

# coding=utf-8
from __future__ import absolute_import, division, print_function
import cv2
import warnings
import numpy as np
warnings.simplefilter("always")
class VideoWriter:
    def __init__(self, name, width, height, fps=25):
        # type: (str, int, int, int) -> None
        if not name.endswith('.mp4'):  # 保证文件名的后缀是.mp4
            name += '.mp4'
            warnings.warn('video name should ends with ".mp4"')
        self.__name = name          # 文件名
        self.__height = height      # 高
        self.__width = width        # 宽
        fourcc = cv2.VideoWriter_fourcc(*'mp4v')  # 如果是mp4视频,编码需要为mp4v
        self.__writer = cv2.VideoWriter(name, fourcc, fps, (width, height))
    def write(self, frame):
        if frame.dtype != np.uint8:  # 检查frame的类型
            raise ValueError('frame.dtype should be np.uint8')
        # 检查frame的大小
        row, col, _ = frame.shape
        if row != self.__height or col != self.__width:
            warnings.warn('长和宽不等于创建视频写入时的设置,此frame不会被写入视频')
            return
        self.__writer.write(frame)
    def close(self):
        self.__writer.release()
def main():
    width = 512
    height = 256
    vw = VideoWriter('test.mp4', width, height)
    for i in range(25*50):
        # 随机生成一幅图像
        frame = np.random.randint(0, 255, (height, width, 3), dtype=np.uint8)
        # 写入图像
        vw.write(frame)
    vw.close()
if __name__ == '__main__':
    main()

三、视频写入失败的原因

不支持对应的编码和后缀。目前我知道支持的是:

  • mp4v–>.mp4
  • MJPG–>.avi
    frame的值类型不是uint8。
    frame的高或者宽和新建cv2.VideoWriter设置的高或宽不对应。