将视频转换为帧时如何在使用“cv2”时更改每秒帧数(FPS)?

How to change frame per second (FPS) while using `cv2` when converting video to frames?

目前我正在使用 2017_08_31_0121.mp4 作为我的视频,这是一个 21 秒长的视频,一旦我将它分成帧,我得到 504 帧。意思是frame per second设置为24,我想改frame number但是不知道下面的代码哪一部分负责设置frame per second

问题:

  1. 想了很久默认FPS是25,现在是24了,请问默认FPS在哪里设置,是多少?

  2. 如果我想使用自定义 FPS(比方说 10),我该如何修改以下代码来实现?

import cv2
vidcap = cv2.VideoCapture('/content/2017_08_31_0121.mp4')
success, image = vidcap.read()
count = 0
while success:
  if count<10:
    id = f'00{count}'
  elif count < 100:
    id = f'0{count}'
  else:
    id = count
  cv2.imwrite(f"./new_frames/frame{id}.jpg", image)    # save frame as JPEG file      
  success, image = vidcap.read()
  count += 1

您需要了解“视频”的工作原理。

视频由关键帧和 P/B-frames 组成。关键帧本身就是完整的图像。要解码 P/B-frame,需要先解码前面的帧。一些视频文件仅包含关键帧(“帧内”)。一些视频文件每隔 ~0.1-10 秒包含一个关键帧,中间只有 P/B-frames。

您可以在视频中跳转,但只能直接跳到关键帧。如果你想跳到一个非关键帧,你必须先跳到前面的关键帧,然后解码每个后续帧,直到你到达目的地。

我建议您关注的想法:

  • ffmpeg -i INPUT -r 3 OUTPUT 会读取整个视频,并根据需要读取 duplicate/drop 帧以达到每秒 3 帧,同时保持您在视频中看到的“速度” .它 必须重新编码结果。如果您需要以该帧速率重复阅读同一视频,那只是一个明智的选择。

  • 涉及 GNU Parallel 与 ffmpeg 将毫无意义,因为 ffmpeg 本身并行运行其解码和编码(对于大多数编解码器),使用所有可用的 CPU.

这是您可以做的事情:

使用VideoCapture的方法grabretrieve。重复调用 grab。这对解码帧和在视频中前进进行了最少的工作。为您真正想要的框架调用 retrieve。这会完成剩下的工作,它会给你那个框架作为一个数组。

您必须使用 vidcap.get(cv.CAP_PROP_FPS) 检查视频的 fps 值,然后计算并决定您是只需要抓取,还是同时抓取和检索。

import numpy as np
import cv2 as cv

vidcap = cv2.VideoCapture('/content/2017_08_31_0121.mp4')
assert vidcap.isOpened()

fps_in = vidcap.get(cv.CAP_PROP_FPS)
fps_out = 3

index_in = -1
index_out = -1

while True:
    success = vidcap.grab()
    if not success: break
    index_in += 1

    out_due = int(index_in / fps_in * fps_out)
    if out_due > index_out:
        success, frame = vidcap.retrieve()
        if not success: break
        index_out += 1

        # do something with `frame`