Decord
Decord比Opencv块6倍!!
1. 使用教程
读取视频
# 1、读取使用
from decord import VideoReader
from decord import cpu, gpu
vr = VideoReader('tiny-Kinetics-400\\abseiling\\_4YTwq0-73Y_000044_000054.mp4', ctx=cpu(0))
print('video frames:', len(vr))
>>> video frames: 300
加载指定帧
# 加载指定帧
frames = vr.get_batch([1, 3, 5, 7, 200])
print(frames.shape)
>>> (5, 256, 454, 3)
保存帧为图片
# 2、保存帧为图片
frame1 = vr[5].asnumpy()
from matplotlib import pyplot as plt
plt.imshow(frame1)
plt.axis('off')
>>> (-0.5, 453.5, 255.5, -0.5)
2. 视频抽帧脚本
import cv2
import os
from decord import VideoReader
from decord import cpu
from tqdm import tqdm
video_bytes = "tiny-Kinetics-400\\abseiling\\_4YTwq0-73Y_000044_000054.mp4" # 视频路径
pic_folder = "frames" # 抽帧保存文件夹
file_basename = "abseiling" # 文件名前缀
archive_fps = 30 # 间隔帧数
# 压缩大图片的大小
def resize_image(image):
height, width = image.shape[:2]
n_width = int(256 * width / max(width, height))
n_height = int(256 * height / max(width, height))
img_new = cv2.resize(image, (n_width, n_height))
return img_new
# 读取视频
vr = VideoReader(video_bytes, ctx=cpu(0))
fra_num = len(vr) # 所有帧长度
# 获取指定帧并进行resize保存(使用tqdm显示进度)
frames = vr.get_batch(list(range(0, fra_num, archive_fps))).asnumpy()
for count, frame in tqdm(enumerate(frames), total=len(frames)):
frame = resize_image(frame)
image_name = f"{file_basename}_{count}.jpg"
cv2.imwrite(os.path.join(pic_folder, image_name), cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
3、抽指定帧,然后存为MP4视频
用cv2的话太慢了,得把decord.ndarray.NDArray
对象转为np.ndarray
一帧一帧存。不如用imageio直接将整个NDArray
转为np.ndarray
后直接存储。
from decord import VideoReader, cpu
import imageio
# 例如只存原视频前16帧
video_path = '/mnt/petrelfs/yuezhengrong/Data/action.mp4'
output_path = 'test.mp4'
vr = VideoReader(video_path, ctx=cpu(0))
frame_indices = list(range(0, 16)) # 读取前16帧
frames = vr.get_batch(frame_indices) # <class 'decord.ndarray.NDArray'> (16, 2160, 5070, 3)
imageio.mimsave(output_path, frames.asnumpy(), fps=30)
按照indeces或timestamps抽帧
decord库只提供了使用帧索引frame_idxs进行get_batch抽帧,如果你只有时间戳,可以选择:
- 使用decord库,获取fps,然后将时间戳转换为帧索引。
- 直接使用pytorchvideo库的get_clip获取帧,但速度不如decord。
import decord
def get_frames_by_indices(video_path, start_idx, end_idx):
"""
根据帧索引获取视频帧。
参数:
video_path : str
视频文件的路径。
start_idx : int
起始帧索引。
end_idx : int
结束帧索引。
返回:
frames : list
根据索引获取的帧列表。
"""
# 加载视频
vr = decord.VideoReader(video_path)
# 获取帧索引范围内的帧
frames = vr.get_batch(frame_idxs=range(start_idx, end_idx + 1))
return frames
def get_frames_by_timestamps(video_path, start_sec, end_sec):
"""
根据时间戳获取视频帧。
参数:
video_path : str
视频文件的路径。
start_sec : float
起始时间戳(秒)。
end_sec : float
结束时间戳(秒)。
返回:
frames : list
根据时间戳获取的帧列表。
"""
# 加载视频
vr = decord.VideoReader(video_path)
# 获取帧率
fps = vr.get_avg_fps()
# 将时间戳转换为帧索引
start_idx = int(start_sec * fps)
end_idx = int(end_sec * fps)
# 获取时间戳范围内的帧
frames = vr.get_batch(frame_idxs=range(start_idx, end_idx + 1))
return frames
# 假设我们有一个视频文件路径
video_path = 'path_to_your_video.mp4'
# 根据帧索引获取帧
start_frame_idx = 150
end_frame_idx = 250
frames_by_indices = get_frames_by_indices(video_path, start_frame_idx, end_frame_idx)
# 根据时间戳获取帧
start_timestamp = 5.0 # 5秒
end_timestamp = 10.0 # 10秒
frames_by_timestamps = get_frames_by_timestamps(video_path, start_timestamp, end_timestamp)