将视频转换为帧时如何在使用“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
问题:
想了很久默认FPS是25,现在是24了,请问默认FPS在哪里设置,是多少?
如果我想使用自定义 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的方法grab
和retrieve
。重复调用 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`
目前我正在使用 2017_08_31_0121.mp4
作为我的视频,这是一个 21 秒长的视频,一旦我将它分成帧,我得到 504 帧。意思是frame per second设置为24,我想改frame number但是不知道下面的代码哪一部分负责设置frame per second
问题:
想了很久默认FPS是25,现在是24了,请问默认FPS在哪里设置,是多少?
如果我想使用自定义 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的方法grab
和retrieve
。重复调用 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`