step0:概述

  • 动机:手头有数个20秒左右的短视频(守望先锋最佳镜头),期望能组合成一个长视频
  • 技术路线:opencv+python(opencv在Python中的封装库是cv2,依赖于numpy)

    step1:打开并显示视频

    要组合视频,首先需要打开视频并获取每一帧的图像,在opencv中可以使用VideoCapture这个类来打开视频,打开的视频也存在于这个类中,使用.read()方法也可以获得每一帧的图像,该方法的用法类似于生成器,每调用一次都会返回下一帧的图像。其中.waitKey()方法是延迟并获取键盘输入,传入参数是延迟时间数,单位是1/60s且必须是整数,因为原视频是60帧,所以间隔为1时是常速播放
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import cv2

    capture = cv2.VideoCapture(
    "../leviathan's highlight_17-08-16_00-52-33.mp4")
    if capture.isOpened():
    while True:
    ret, prev = capture.read()
    if ret is True:
    cv2.imshow("", prev)
    else:
    break
    cv2.waitKey(1)
    玩过守望先锋的小伙伴应该知道,那个最佳镜头的最后会一段浮现守望先锋logo的部分,我们需要切掉这一部分,方法是只截取前17.5秒的视频,因为不知道是否有24帧的视频,所以要先获得帧率再截取前17.5*fps的视频,现在的代码是
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import cv2

    capture = cv2.VideoCapture(
    "../leviathan's highlight_17-08-16_00-52-33.mp4")
    print(capture.get(cv2.CAP_PROP_FRAME_WIDTH))
    print(capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
    fps = capture.get(cv2.CAP_PROP_FPS)
    if capture.isOpened():
    i = 0
    while i < fps * 17.5:
    i += 1
    ret, prev = capture.read()
    if ret is True:
    cv2.imshow("", prev)
    else:
    break
    cv2.waitKey(1)
    顺便还看了下幕布的尺寸为1920*1080
    参考python tools:计算视频的 FPS,以及总帧数

    step2打开并显示一堆视频

    因为视频一共有20个左右,所以可以使用os模块中的listdir()获取所有文件,并筛选带.mp4后缀的视频文件。这样获取的list是完全按顺序排列的,我们还可以使用random.shuffle()方法打乱整个视频列表
    1
    2
    mp4list = [x for x in os.listdir("../") if x[-4:] == ".mp4"]
    random.shuffle(mp4list)
    于是遍历整个列表看所有视频了
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    import cv2
    import os
    import random

    mp4list = [x for x in os.listdir("../") if x[-4:] == ".mp4"]
    random.shuffle(mp4list)
    print(mp4list)
    for mp4file in mp4list:
    capture = cv2.VideoCapture("../%s" % mp4file)
    fps = capture.get(cv2.CAP_PROP_FPS)
    print(fps)
    if fps != 60:
    jump = 20
    else:
    jump = 1
    if capture.isOpened():
    i = 0
    while i < fps * 1:
    i += 1
    ret, prev = capture.read()
    if ret is True:
    cv2.imshow("", prev)
    else:
    break
    cv2.waitKey(jump)
    cv2.destroyAllWindows()

    step3:保存为一个大视频

    保存视频首先需要创建一个视频容器,可以使用cv2.VideoWriter,输入参数为路径,压缩方式,帧率,幕布大小,随后使用该对象的write()方法即可写入一帧,写入完成后,使用release()方法释放容器并保存,若在次之前程序中断,那视频文件会是损坏状态,于是程序是这样的
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    import cv2
    import os
    import random

    VideoWriter = cv2.VideoWriter(
    "./overwatch.avi",
    cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'), 60,
    (1920, 1080))

    mp4list = [x for x in os.listdir("../") if x[-4:] == ".mp4"]
    random.shuffle(mp4list)
    print(mp4list)
    for mp4file in mp4list:
    print(mp4file)
    capture = cv2.VideoCapture("../%s" % mp4file)
    fps = capture.get(cv2.CAP_PROP_FPS)
    if capture.isOpened():
    i = 0
    while i < fps * 17.5:
    i += 1
    ret, prev = capture.read()
    if ret is True:
    if fps == 60:
    VideoWriter.write(prev)
    else:
    VideoWriter.write(prev)
    VideoWriter.write(prev)
    else:
    break
    VideoWriter.release()
    cv2.destroyAllWindows()
    其中为了补偿30帧左右的视频,非60帧图片一帧写入两次