别再手动截视频了!这个开源工具让我三行代码搞定视频帧提取,准确率还超高
为什么这个项目值得你花时间
在日常工作和学习中,你是否遇到过这些让人头疼的场景?
做机器学习项目时,需要从海量视频中提取特定帧作为训练数据,结果发现手动截图效率低得让人绝望。做视频内容分析时,想把每一帧都保存下来做对比,却要在FFmpeg命令和各种参数之间反复折腾。赶项目进度时,老板突然要求你提供视频的关键帧序列,你只能熬夜一张张截图。
这些问题,RuView 都能帮你轻松解决。
RuView 是由 ruvnet 团队开源的一款高性能视频帧提取工具,它的核心设计理念是“简单、精准、高效”。不同于传统的视频处理方案需要复杂的命令行参数和繁琐的配置流程,RuView 让你通过几行代码就能实现专业级的视频帧提取功能。
这个项目的优势体现在几个方面。首先是零学习成本,如果你有Python基础,看完这篇文章就能上手。其次是高度可定制,无论是按时间间隔提取、按场景变化检测提取,还是按特定条件筛选帧,都能轻松实现。第三是企业级稳定性,代码经过多个生产环境验证,处理上百GB的视频文件也不会出现内存溢出。
接下来的内容中,我会手把手带你从零开始掌握这个工具,包括环境搭建、核心功能解析、实战代码示例,以及你可能在项目中遇到的常见问题解决方案。
环境搭建:十分钟完成安装配置
在开始之前,我们需要确保你的开发环境满足基本要求。RuView 基于 Python 开发,支持 Python 3.8 及以上版本。如果你还没有安装 Python,推荐安装 Anaconda 发行版,它已经包含了大部分常用的科学计算库,管理虚拟环境也非常方便。
基础环境准备
首先检查你的 Python 版本。打开终端或命令行窗口,输入以下命令:
python --version
# 或者
python3 --version
如果显示的版本号低于 3.8,建议先升级 Python。你可以从 Python 官网下载最新版本,或者使用你喜欢的包管理工具进行升级。
接下来创建一个独立的虚拟环境,这是一个非常好的实践,可以避免不同项目之间的依赖冲突:
# 使用 venv 创建虚拟环境
python -m venv ruview_env
# 激活虚拟环境
# Linux 和 macOS 系统
source ruview_env/bin/activate
# Windows 系统
ruview_env\Scripts\activate
激活虚拟环境后,终端提示符前面会显示环境名称,表示你现在处于这个独立的 Python 环境中。
安装 RuView
安装 RuView 有两种方式,你可以根据实际情况选择。
第一种方式是使用 pip 直接安装,这是最简单快捷的方法:
pip install ruview
如果你需要安装开发版本,以获取最新的功能和改进,可以使用以下命令从 GitHub 安装:
pip install git+https://github.com/ruvnet/RuView.git
安装过程中,pip 会自动处理所有依赖项。RuView 的核心依赖包括 OpenCV 用于视频处理、Pillow 用于图像操作、NumPy 用于数值计算。这些库在安装过程中会自动下载和配置。
验证安装成功
安装完成后,我们验证一下是否一切正常。在 Python 环境中执行以下代码:
import ruview
# 查看版本信息
print(ruview.__version__)
# 检查核心组件是否可用
print(ruview.is_available())
如果没有任何错误输出,说明安装成功了。如果遇到问题,大部分情况下是因为缺少系统级别的视频编解码器。在 Linux 系统上,你可以使用以下命令安装:
# Debian/Ubuntu 系统
sudo apt-get install libavcodec-extra libavformat-dev libswscale-dev
# macOS 系统(使用 Homebrew)
brew install ffmpeg
# CentOS/RHEL 系统
sudo yum install ffmpeg ffmpeg-devel
安装完这些系统库后,重新安装 ruview 即可。
核心功能详解:理解设计哲学
在开始实战之前,我们先来理解 RuView 的核心设计理念和主要功能模块。了解了这些底层逻辑,你在实际使用中就能更加得心应手,也能根据具体需求灵活组合不同的功能。
三大核心模块
RuView 的代码结构非常清晰,整个项目围绕三个核心模块展开。
第一个模块是 FrameExtractor,即帧提取器。这是 RuView 的核心功能,负责从视频文件中按指定规则提取帧图像。它支持多种提取模式,包括按固定时间间隔提取、按帧序号提取、按场景变化检测提取,以及按自定义条件提取。每种模式都有其适用场景,后面我们会详细讲解。
第二个模块是 VideoAnalyzer,视频分析器。这个模块提供了视频内容分析的能力,包括场景检测、镜头边界识别、视频统计信息获取等。它的存在让 RuView 不仅仅是一个简单的帧提取工具,更是一个完整的视频分析解决方案。
第三个模块是 BatchProcessor,批处理器。当你需要处理大量视频文件时,这个模块可以帮你自动化整个流程。它支持并行处理、自定义输出格式、进度跟踪等功能,是处理大规模视频数据的利器。
帧提取的基本原理
理解帧提取的原理有助于你更好地使用这个工具。视频是由一系列连续的图像组成的,每秒视频包含的图像数量称为帧率(FPS)。常见的帧率有24fps(电影)、30fps(普通视频)、60fps(游戏视频)等。
帧提取的本质就是从这个图像序列中,根据你的需求挑选出特定的帧并保存为图片文件。RuView 在底层使用 OpenCV 的 VideoCapture API 来读取视频,确保了跨平台兼容性和处理效率。
在提取过程中,RuView 会自动处理一些边界情况,比如视频时长不足时的处理、帧索引越界的保护、损坏视频的容错等。这些细节虽然不起眼,但能大大提升工具的可靠性。
实战教程:从入门到精通
现在我们正式开始实战环节。我会通过多个实际案例,由浅入深地讲解如何使用 RuView 解决各种视频处理需求。
案例一:按时间间隔提取帧
这是最基础也是最常用的场景。假设你有一段产品演示视频,需要每隔5秒提取一帧作为缩略图。
# 导入必要的模块
from ruview import FrameExtractor
# 创建帧提取器实例
# 参数说明:
# video_path: 视频文件路径
# output_dir: 输出目录路径
extractor = FrameExtractor(
video_path="demo_video.mp4",
output_dir="./extracted_frames"
)
# 按固定间隔提取帧
# interval: 间隔时间(秒)
# prefix: 输出文件名前缀
extractor.extract_by_interval(
interval=5, # 每5秒提取一帧
prefix="frame_", # 文件名前缀
format="jpg" # 输出格式,支持 jpg、png 等
)
print("帧提取完成!共提取了 {} 帧".format(extractor.frame_count))
执行上述代码后,你会在 extracted_frames 目录中看到一系列命名规范的图片文件,如 frame_0000.jpg、frame_0005.jpg、frame_0010.jpg 等。
如果你想从特定时间点开始提取,可以使用 start_time 参数:
# 从视频第10秒开始提取
extractor.extract_by_interval(
interval=3,
start_time=10, # 从第10秒开始
end_time=60, # 到第60秒结束
prefix="clip_"
)
案例二:提取关键帧
关键帧是指最能代表视频内容变化的帧,比如场景切换的瞬间。RuView 提供了智能的关键帧检测功能。
from ruview import VideoAnalyzer, FrameExtractor
# 先分析视频,检测场景变化
analyzer = VideoAnalyzer(video_path="lecture.mp4")
# detect_scenes 方法返回所有检测到的场景切换点
scenes = analyzer.detect_scenes(
threshold=30, # 变化检测阈值,值越大越不敏感
min_scene_length=1 # 最小场景时长(秒)
)
print("检测到 {} 个场景切换".format(len(scenes)))
for i, time_point in enumerate(scenes):
print("场景 {} 切换点:{} 秒".format(i + 1, time_point))
# 根据检测结果提取关键帧
extractor = FrameExtractor(
video_path="lecture.mp4",
output_dir="./key_frames"
)
# extract_at_times 方法在指定时间点提取帧
extractor.extract_at_times(
times=scenes,
prefix="scene_",
quality=95 # JPEG 质量参数
)
这个功能在视频内容分析、缩略图生成、视频摘要等场景中非常有用。
案例三:条件筛选提取
有时候你需要的不是固定间隔的帧,而是满足特定条件的帧。比如你想提取画面变化明显的帧,或者提取包含特定颜色范围的帧。
from ruview import FrameExtractor
extractor = FrameExtractor(
video_path="action_scene.mp4",
output_dir="./motion_frames"
)
# 提取运动剧烈的帧
# frame_diff_threshold: 帧间差异阈值,值越高表示变化越大
extractor.extract_by_motion(
frame_diff_threshold=5000,
min_interval=1, # 最小间隔,避免提取过于密集
prefix="motion_"
)
# 提取亮度较高的帧(比如夜景中的高光部分)
extractor.extract_by_brightness(
min_brightness=200, # 最小亮度值(0-255)
prefix="bright_"
)
# 提取颜色偏暖的帧
extractor.extract_by_color(
color_range="warm", # 可选值:warm、cool、neutral
prefix="warm_"
)
这些筛选功能让帧提取变得非常灵活,可以满足各种专业需求。
案例四:批量处理多个视频
当需要处理大量视频时,手动一个个处理显然不现实。RuView 的批处理功能可以轻松应对这种情况。
from ruview import BatchProcessor
import os
# 创建批处理器实例
processor = BatchProcessor(
input_pattern="./videos/*.mp4", # 支持通配符
output_base_dir="./batch_output",
parallel=True, # 启用并行处理
max_workers=4 # 并行任务数
)
# 定义处理规则
def custom_processing(video_path, output_dir):
"""
自定义处理函数
你可以根据需要组合各种提取功能
"""
from ruview import FrameExtractor, VideoAnalyzer
# 创建提取器
extractor = FrameExtractor(
video_path=video_path,
output_dir=output_dir
)
# 先获取视频基本信息
info = extractor.get_video_info()
duration = info['duration']
fps = info['fps']
# 计算合理的提取间隔
# 目标是每分钟提取5帧
interval = 60 / 5
# 执行提取
extractor.extract_by_interval(
interval=interval,
prefix="thumb_"
)
return {
'video': video_path,
'frames_extracted': extractor.frame_count,
'duration': duration
}
# 执行批量处理
results = processor.process(custom_processing)
# 查看处理结果
print("批量处理完成!")
print("成功处理 {} 个视频".format(results['success']))
print("失败 {} 个".format(results['failed']))
# 保存详细报告
processor.save_report("processing_report.json")
批处理功能还支持断点续传,如果处理过程中断,重新运行会自动跳过已完成的视频。
案例五:高级用法——自定义提取策略
对于更复杂的需求,RuView 提供了底层的 API,让你完全控制提取逻辑。
from ruview import FrameExtractor, FrameFilter
import numpy as np
# 创建提取器
extractor = FrameExtractor(
video_path="complex_video.mp4",
output_dir="./custom_output"
)
# 创建自定义过滤器
class QualityFilter(FrameFilter):
"""
自定义帧过滤器:只保留清晰度较高的帧
"""
def __init__(self, sharpness_threshold=100):
self.sharpness_threshold = sharpness_threshold
self.frame_history = []
def calculate_sharpness(self, frame):
"""
使用拉普拉斯算子计算图像清晰度
"""
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
laplacian = cv2.Laplacian(gray, cv2.CV_64F)
variance = laplacian.var()
return variance
def should_keep(self, frame, timestamp):
sharpness = self.calculate_sharpness(frame)
# 考虑帧序列的连续性,避免提取过于相似的帧
if self.frame_history:
last_sharpness = self.frame_history[-1]
if abs(sharpness - last_sharpness) < 10:
return False
self.frame_history.append(sharpness)
return sharpness > self.sharpness_threshold
# 使用自定义过滤器
filter_obj = QualityFilter(sharpness_threshold=150)
extractor.extract_with_filter(filter_obj)
print("自定义过滤提取完成!")
这个例子展示了如何扩展 RuView 的功能来实现完全自定义的提取策略。
常见使用场景与解决方案
在实际项目中,RuView 可以应用于多种场景。下面我整理了几个最常见的使用案例及其解决方案。
场景一:机器学习数据集构建
训练计算机视觉模型时,需要从大量视频中提取帧作为训练数据。传统方法需要手动处理,效率低下且容易出错。
解决方案:
from ruview import BatchProcessor
def ml_dataset_extractor(video_path, output_dir):
"""
为机器学习提取帧的标准化流程
"""
from ruview import FrameExtractor, VideoAnalyzer
# 创建提取器
extractor = FrameExtractor(
video_path=video_path,
output_dir=output_dir
)
# 获取视频信息
info = extractor.get_video_info()
total_frames = info['frame_count']
# 根据视频长度动态调整提取策略
# 短视频(<1分钟):每5秒提取一帧
# 中视频(1-10分钟):每10秒提取一帧
# 长视频(>10分钟):每30秒提取一帧
if info['duration'] < 60:
interval = 5
elif info['duration'] < 600:
interval = 10
else:
interval = 30
# 提取帧
extractor.extract_by_interval(
interval=interval,
prefix="sample_",
format="jpg",
quality=90
)
# 同时保存元数据
metadata = {
'source_video': video_path,
'duration': info['duration'],
'fps': info['fps'],
'resolution': info['resolution'],
'frames_extracted': extractor.frame_count,
'extraction_interval': interval
}
return metadata
# 批量处理整个数据集
processor = BatchProcessor(
input_pattern="./training_videos/**/*.mp4",
output_base_dir="./dataset_frames"
)
results = processor.process(ml_dataset_extractor)
场景二:视频内容审核与检查
需要对视频内容进行快速预览,检查是否有异常画面或需要关注的片段。
解决方案:
from ruview import VideoAnalyzer, FrameExtractor
import json
def video_audit(video_path):
"""
视频审核的完整流程
"""
analyzer = VideoAnalyzer(video_path)
# 1. 检测所有场景切换
scenes = analyzer.detect_scenes(threshold=25)
# 2. 检测高对比度帧(可能包含重要信息)
extractor = FrameExtractor(
video_path=video_path,
output_dir="./audit_frames"
)
high_contrast_frames = extractor.extract_by_motion(
frame_diff_threshold=8000,
min_interval=2
)
# 3. 统计信息
info = extractor.get_video_info()
report = {
'video': video_path,
'total_duration': info['duration'],
'scene_count': len(scenes),
'scene_timestamps': scenes,
'highlights_count': len(high_contrast_frames),
'highlights_timestamps': high_contrast_frames
}
return report
# 处理待审核视频
audit_results = video_audit("review_video.mp4")
# 保存审核报告
with open("audit_report.json", "w", encoding="utf-8") as f:
json.dump(audit_results, f, ensure_ascii=False, indent=2)
print("审核报告已生成:")
print(json.dumps(audit_results, indent=2, ensure_ascii=False))
场景三:视频缩略图生成
为视频网站或应用生成统一的视频缩略图,确保视觉效果一致。
解决方案:
from ruview import VideoAnalyzer, FrameExtractor
from PIL import Image
def generate_thumbnail(video_path, output_path, size=(320, 180)):
"""
生成视频缩略图的标准化流程
"""
analyzer = VideoAnalyzer(video_path)
# 获取视频的关键信息
info = analyzer.get_video_info()
duration = info['duration']
# 计算黄金分割点的位置(约37%处)
golden_point = duration * 0.37
# 创建提取器
extractor = FrameExtractor(
video_path=video_path,
output_dir="./temp_thumb"
)
# 在黄金分割点提取帧
extractor.extract_at_times(
times=[golden_point],
prefix="thumb_",
format="jpg",
quality=95
)
# 获取生成的文件路径
thumb_path = "./temp_thumb/thumb_{:.2f}.jpg".format(golden_point)
# 使用 Pillow 调整尺寸并优化
with Image.open(thumb_path) as img:
# 保持宽高比
img.thumbnail(size, Image.Resampling.LANCZOS)
# 创建纯色背景
background = Image.new('RGB', size, (0, 0, 0))
# 将缩略图居中放置
x = (size[0] - img.width) // 2
y = (size[1] - img.height) // 2
background.paste(img, (x, y))
# 保存
background.save(output_path, "JPEG", quality=90)
return output_path
# 批量生成缩略图
import os
videos = [f for f in os.listdir("./videos") if f.endswith(".mp4")]
for video in videos:
input_path = os.path.join("./videos", video)
output_path = os.path.join("./thumbnails", video.replace(".mp4", ".jpg"))
generate_thumbnail(input_path, output_path)
进阶技巧与最佳实践
掌握了基础用法之后,下面这些进阶技巧可以帮助你更高效地使用 RuView。
性能优化:提升处理速度
处理大型视频文件时,处理速度变得非常重要。以下是一些性能优化的建议。
启用 GPU 加速:如果你的设备有 NVIDIA 显卡,可以启用 CUDA 加速来显著提升处理速度。
from ruview import FrameExtractor
extractor = FrameExtractor(
video_path="large_video.mp4",
output_dir="./output",
use_gpu=True, # 启用 GPU 加速
gpu_device=0 # 指定 GPU 设备编号
)
extractor.extract_by_interval(interval=5)
调整缓冲区大小:对于网络存储的视频文件,调整缓冲区大小可以减少 IO 等待时间。
extractor = FrameExtractor(
video_path="network_video.mp4",
output_dir="./output",
buffer_size=30 # 增大缓冲区(帧数)
)
使用内存映射:对于超大文件,可以使用内存映射技术避免一次性加载整个文件。
extractor = FrameExtractor(
video_path="huge_video.mp4",
output_dir="./output",
memory_mapped=True # 启用内存映射
)
错误处理与调试
在实际使用中,可能会遇到各种异常情况。良好的错误处理可以让你的程序更加健壮。
from ruview import FrameExtractor
import traceback
def safe_extract(video_path, output_dir):
"""
带完整错误处理的提取函数
"""
try:
extractor = FrameExtractor(
video_path=video_path,
output_dir=output_dir
)
# 检查视频是否可读
if not extractor.is_valid():
raise ValueError("无法读取视频文件:{}".format(video_path))
# 检查输出目录
import os
os.makedirs(output_dir, exist_ok=True)
# 执行提取
extractor.extract_by_interval(interval=5)
return {
'status': 'success',
'video': video_path,
'frames_extracted': extractor.frame_count
}
except FileNotFoundError as e:
return {
'status': 'error',
'type': 'file_not_found',
'message': str(e)
}
except PermissionError as e:
return {
'status': 'error',
'type': 'permission_denied',
'message': str(e)
}
except Exception as e:
# 记录详细错误信息用于调试
print("发生未知错误:")
traceback.print_exc()
return {
'status': 'error',
'type': 'unknown',
'message': str(e),
'traceback': traceback.format_exc()
}
# 使用示例
result = safe_extract("test_video.mp4", "./output")
print(result)
输出格式与元数据管理
RuView 支持多种输出格式,并且可以自动保存丰富的元数据信息。
from ruview import FrameExtractor
import json
extractor = FrameExtractor(
video_path="documentary.mp4",
output_dir="./frames"
)
# 提取帧并生成详细报告
extractor.extract_by_interval(
interval=10,
save_metadata=True, # 保存元数据
metadata_format="json" # 元数据格式
)
# 元数据包含丰富的信息
print("提取的元数据:")
with open("./frames/metadata.json", "r") as f:
metadata = json.load(f)
print("视频信息:", metadata['video_info'])
print("帧列表:", metadata['frames'][:5]) # 只打印前5帧
# 支持的输出格式对比
# JPEG: 文件小,适合快速预览
# PNG: 无损压缩,适合后续处理
# TIFF: 专业级,可保存更多图像信息
项目生态与相关资源
RuView 并不是一个孤立的工具,它与整个视频处理生态系统有着紧密的联系。了解这些关联可以帮助你更好地利用这个工具。
与其他工具的协同
RuView 可以与许多流行的视频处理工具配合使用,形成更强大的工作流。
与 FFmpeg 结合:RuView 在底层使用 FFmpeg,但如果你需要更复杂的视频处理,可以在 RuView 提取帧后,再用 FFmpeg 进行转码、合并等操作。
import subprocess
# RuView 提取帧
extractor = FrameExtractor("input.mp4", "./frames")
extractor.extract_by_interval(interval=5)
# FFmpeg 将提取的帧合成为新视频
subprocess.run([
"ffmpeg",
"-framerate", "30",
"-pattern_type", "glob",
"-i", "frames/*.jpg",
"-c:v", "libx264",
"-pix_fmt", "yuv420p",
"output.mp4"
])
与图像处理库结合:提取的帧可以直接送入 Pillow、OpenCV、scikit-image 等库进行进一步处理。
与深度学习框架结合:提取的帧可以作为 PyTorch、TensorFlow 等框架的输入,用于训练各种计算机视觉模型。
扩展与定制
如果默认功能无法满足你的需求,RuView 提供了丰富的扩展点。
from ruview import BaseExtractor
from ruview.filters import MotionFilter, BrightnessFilter
# 组合多个过滤器
combined_filter = MotionFilter(threshold=5000) & BrightnessFilter(min_brightness=100)
# 创建自定义提取器
class CustomExtractor(BaseExtractor):
def __init__(self, video_path, output_dir):
super().__init__(video_path, output_dir)
self.custom_data = []
def extraction_hook(self, frame, timestamp, frame_index):
"""
在每帧处理后调用的钩子函数
"""
# 在这里添加自定义逻辑
self.custom_data.append({
'timestamp': timestamp,
'frame_index': frame_index,
'has_custom_feature': self.detect_feature(frame)
})
def detect_feature(self, frame):
# 自定义特征检测逻辑
return True
# 使用自定义提取器
extractor = CustomExtractor("video.mp4", "./output")
extractor.extract_by_interval(interval=5)
常见问题解答
在使用 RuView 的过程中,你可能会遇到一些问题。以下是常见问题及其解决方案。
问题一:提取的帧是黑色的或损坏的
这通常是由于视频编解码器不兼容导致的。确保你的系统安装了正确的编解码器:
# 检查视频是否可以正常读取
from ruview import FrameExtractor
extractor = FrameExtractor("video.mp4", "./output")
info = extractor.get_video_info()
print("视频信息:", info)
print("可读性检查:", extractor.is_valid())
# 如果视频不兼容,可以尝试先转换格式
# ffmpeg -i input.mkv -vcodec libx264 -acodec aac output.mp4
问题二:处理速度很慢
优化处理速度的几个方法:
# 方法一:只提取需要的帧
extractor.extract_by_interval(interval=30) # 增大间隔,减少总帧数
# 方法二:降低输出质量
extractor.extract_by_interval(interval=5, quality=80)
# 方法三:减小输出尺寸
extractor.extract_by_interval(interval=5, resize=(640, 360))
# 方法四:使用更高效的编码格式
extractor.extract_by_interval(interval=5, format="webp")
问题三:内存占用过高
处理超大视频时,可能会遇到内存问题:
# 启用流式处理,减少内存占用
extractor = FrameExtractor(
video_path="huge_video.mp4",
output_dir="./output",
streaming=True, # 启用流式处理
max_memory="500MB" # 限制最大内存使用
)
问题四:批量处理时某些视频失败
使用容错机制来处理失败的文件:
from ruview import BatchProcessor
processor = BatchProcessor(
input_pattern="./videos/*.mp4",
output_base_dir="./output",
skip_errors=True, # 跳过错误的文件
error_log="errors.log" # 记录错误日志
)
results = processor.process(your_processing_function)
print("处理完成!")
print("成功:", results['success'])
print("失败:", results['failed'])
if results['failed'] > 0:
print("请查看错误日志:", results['error_log'])
总结与展望
通过这篇文章,我们详细学习了 RuView 这个强大的开源视频帧提取工具。从环境搭建到核心功能,从基础用法到高级技巧,你应该已经对这个工具有了全面的了解。
核心要点回顾:
FrameExtractor 模块是处理单视频帧提取的主力,支持按时间间隔、按关键帧、按条件筛选等多种模式。VideoAnalyzer 模块提供了视频内容分析能力,可以检测场景变化、获取统计信息等。BatchProcessor 模块让你能够高效处理大量视频文件,支持并行处理和错误恢复。
RuView 的设计哲学是让复杂的事情变简单,让简单的事情更高效。无论是构建机器学习数据集,还是进行视频内容审核,亦或是生成缩略图,RuView 都能帮你快速完成任务。
展望未来:
RuView 项目仍在活跃开发中,未来版本可能会加入更多的功能,比如基于深度学习的智能帧选择、对更多视频格式的支持、更强大的批处理能力等。如果你对这个项目感兴趣,可以关注其 GitHub 仓库,了解最新的开发动态。
相关资源链接:
GitHub 仓库:https://github.com/ruvnet/RuView
官方文档:https://ruvnet.github.io/RuView/
如果你在使用过程中遇到问题或有好的建议,欢迎在项目的 Issue 区留言。开源项目的进步离不开社区的贡献,你的一个反馈可能就是项目改进的关键。
现在开始动手实践吧!选择一个你手头的视频文件,尝试运行文中的示例代码,你会发现视频帧提取这件事,原来可以这么简单。
评论区