乐于分享
好东西不私藏

【动手学YOLO】序列(三):计算机视觉AI工具库(Supervision库)视频处理的相关函数

【动手学YOLO】序列(三):计算机视觉AI工具库(Supervision库)视频处理的相关函数

本文摘自《动手学YOLO技术原理与项目实践》第五章,目前已在当当、京东等网站上架
书中全部数据及源代码均可从gitee网站
https://gitee.com/jiabiao1602/yolo11_object_detection)下载
我们常用训练好的YOLO模型对视频进行实时目标检测,因此本小节介绍常用的处理视频相关的函数,方便后续对视频进行实时目标检测。

5.3.1 在线下载视频

我们经常需要用到一些图片或者视频进行目标检测项目的训练、验证或推理。幸运的是,Supervision库自带了一些视频资源,可以利用supervision.assetsdownload_assets方法非常轻松地将视频下载到本地,方便后续使用。

我们通过下面的代码查看supervision.assets提供的可下载视频。

from supervision.assets import download_assets, VideoAssets
import re

# 查看VideoAssets的属性
my_list = dir(VideoAssets)
# 定义正则表达式模式
pattern = re.compile(r'^__.*__$')
# 使用列表推导式过滤列表
filtered_list = [item for item in my_list ifnot pattern.match(item)]
# 打印结果
print(filtered_list)

输出结果为:

['BASKETBALL', 'BEACH', 'GROCERY_STORE', 'MARKET_SQUARE', 'MILK_BOTTLING_PLANT', 'PEOPLE_WALKING', 'SKIING', 'SUBWAY', 'VEHICLES', 'VEHICLES_2']

在了解可下载的视频清单后,假如我们想下载行人走路的视频,可以通过下面的代码实现。

# 下载一段行人走路的视频
download_assets(VideoAssets.PEOPLE_WALKING)

下载完成后,当前目录中将有一个名为people-walking.mp4的视频文件。可以通过下面的代码读取刚下载的视频信息。

# 读取视频文件的宽度、高度、fps和总帧数。
video_info = sv.VideoInfo.from_video_path(video_path="videos/people-walking.mp4")
video_info

输出结果为:

VideoInfo(width=1920, height=1080, fps=25, total_frames=341)

people-walking.mp4视频的宽度为1920,高度为1080,fps(帧率)为25,总帧数为341。

5.3.2 生成并保存视频

sv.get_video_frames_generator函数可以创建一个生成器,该生成器逐帧生成视频帧。其参数如下:

  • source_path (str): 视频文件路径。
  • stride (int): 表示返回帧的间隔,每间隔 stride – 1 帧返回一个帧。
  • start (int): 表示视频开始生成帧的起始位置。
  • end (Optional[int]): 表示视频停止生成帧的结束位置。如果为 None,视频会一直读取到末尾。
  • iterative_seek (bool): 如果为 True,生成器将通过逐帧抓取的方式定位到 start 帧,这种方式会慢得多。这是对于设置 start 值时无法打开的视频的一种解决方法。

sv.VideoSink类是一个上下文管理器,用于使用OpenCV将视频帧保存到文件中。其参数如下:

  • target_path (str): 输出文件的路径,视频将保存到此位置。
  • video_info (VideoInfo): 视频的分辨率、帧率以及总帧数信息。
  • codec (str): 视频格式的FOURCC代码(默认为’mp4v’)。

下面的代码实现从一个视频文件中每隔10帧提取一帧,最多提取到第100帧(根据 stride 和 end 参数),然后将这些提取出的帧保存到一个新的视频文件中(格式为mp4)。并通过tqdm显示进度条,让用户了解处理进度。

import supervision as sv
from tqdm import tqdm

video_path = "videos/people-walking.mp4"
# 从源视频路径获取视频信息
video_info = sv.VideoInfo.from_video_path(video_path)
# 获取视频帧生成器
frames_generator = sv.get_video_frames_generator(source_path=video_path,
                                                 stride=10, start=0, end=100)
TARGET_VIDEO_PATH = "out.mp4"
# 使用VideoSink上下文管理器保存视频帧到目标路径
with sv.VideoSink(target_path=TARGET_VIDEO_PATH, video_info=video_info) as sink:
for frame in tqdm(frames_generator):
        sink.write_frame(frame=frame)  # 将每一帧写入到目标视频文件中

代码运行后,会在当前目录生成一个名为out.mp4的文件。

我们也可以利用sv.ImageSink类创建一个用于保存图像的上下文管理器,将视频保存为本地图片。其参数如下:

  • target_dir_path (str):图像被保存的目标目录。
  • overwrite (bool):是否覆盖现有目录,默认为 False。
  • image_name_pattern (str):图像文件名的格式。默认为 “image_{:05d}.png”。

通过下面的代码,将视频中的每一帧保存为本地的一张图片。

# 获取视频帧生成器
frames_generator = sv.get_video_frames_generator(source_path=video_path,
                                                 stride=10, start=0, end=100)
# 将生成视频保存为图片
with sv.ImageSink(target_dir_path='output', overwrite=Trueas sink:
for image in frames_generator:
        sink.save_image(image=image)

代码运行后,将在本地生成一个output文件夹,用于存放10张图片。

我们也可以直接将本地的视频文件保存为本地的图片,以下代码实现的结果与上面相同。

# 将本地的视频保存为本地图片
with sv.ImageSink(target_dir_path='output', overwrite=Trueas sink:
for image in sv.get_video_frames_generator(source_path='out.mp4'):
        sink.save_image(image=image)