数据集制作-从视频提取关键帧(原理)
# 数据集制作-从视频提取关键帧
# 一、主流关键帧提取方法
# 1. 基于场景变化检测(Scene Change Detection)
import cv2
def detect_scene_changes(video_path, threshold=0.3):
"""检测场景变化并提取关键帧"""
cap = cv2.VideoCapture(video_path)
ret, prev_frame = cap.read()
frames = []
while True:
ret, curr_frame = cap.read()
if not ret: break
# 计算直方图差异
hist_diff = cv2.compareHist(
cv2.calcHist([prev_frame], [0], None, [256], [0,256]),
cv2.calcHist([curr_frame], [0], None, [256], [0,256]),
cv2.HISTCMP_BHATTACHARYYA
)
# 检测场景变化
if hist_diff > threshold:
frames.append(curr_frame)
prev_frame = curr_frame
cap.release()
return frames
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
原理: 通过比较连续帧之间的颜色直方图差异,当差异超过阈值时提取为关键帧 优点: 对亮度变化鲁棒,计算速度快 适用: 新闻剪辑、电视节目等有明显场景切换的视频
# 2. 基于运动分析(Motion Analysis)
import cv2
def detect_motion_based_frames(video_path, motion_threshold=50):
"""基于运动分析提取关键帧"""
cap = cv2.VideoCapture(video_path)
ret, prev_frame = cap.read()
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
frames = []
while True:
ret, curr_frame = cap.read()
if not ret: break
curr_gray = cv2.cvtColor(curr_frame, cv2.COLOR_BGR2GRAY)
# 计算光流
flow = cv2.calcOpticalFlowFarneback(
prev_gray, curr_gray, None, 0.5, 3, 15, 3, 5, 1.2, 0
)
# 计算平均运动量
magnitude = np.sqrt(flow[...,0]**2 + flow[...,1]**2)
avg_motion = np.mean(magnitude)
# 检测显著运动
if avg_motion > motion_threshold:
frames.append(curr_frame)
prev_gray = curr_gray
cap.release()
return frames
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
原理: 使用光流算法分析像素点运动量,检测显著运动区域 优点: 能有效识别物体移动和相机运动 适用: 体育比赛、监控视频等运动量大的场景
# 3. 基于内容显著性(Saliency Detection)
import cv2
import numpy as np
def extract_salient_frames(video_path, saliency_threshold=0.5):
"""基于内容显著性提取关键帧"""
cap = cv2.VideoCapture(video_path)
frames = []
# 创建显著性检测器
saliency = cv2.saliency.StaticSaliencyFineGrained_create()
while True:
ret, frame = cap.read()
if not ret: break
# 计算显著性图
success, saliency_map = saliency.computeSaliency(frame)
if success:
# 计算平均显著性
mean_saliency = np.mean(saliency_map)
# 检测显著内容
if mean_saliency > saliency_threshold:
frames.append(frame)
cap.release()
return frames
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
原理: 识别图像中最吸引人的区域 优点: 符合人类视觉注意机制 适用: 广告视频、产品展示等需要突出主体的内容
# 4. 基于深度学习(Deep Learning)
import tensorflow as tf
from tensorflow.keras.applications import MobileNetV2
from tensorflow.keras.models import Model
import cv2
def extract_deep_features(video_path, threshold=0.75):
"""基于深度学习特征提取关键帧"""
# 加载预训练模型
base_model = MobileNetV2(weights='imagenet', include_top=False, pooling='avg')
model = Model(inputs=base_model.input, outputs=base_model.output)
cap = cv2.VideoCapture(video_path)
ret, prev_frame = cap.read()
frames = []
# 提取第一帧特征
prev_img = cv2.resize(prev_frame, (224, 224))
prev_features = model.predict(np.expand_dims(prev_img, axis=0))
while True:
ret, curr_frame = cap.read()
if not ret: break
curr_img = cv2.resize(curr_frame, (224, 224))
curr_features = model.predict(np.expand_dims(curr_img, axis=0))
# 计算余弦相似度
sim = np.dot(prev_features, curr_features.T)[0][0]
# 检测内容显著变化
if sim < threshold:
frames.append(curr_frame)
prev_features = curr_features
cap.release()
return frames
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
原理: 使用CNN提取高级语义特征进行帧间比较 优点: 识别内容而非像素变化,准确率高 适用: 复杂场景下需要理解语义内容的情况
# 二、高级提取技术
# 1. 压缩域提取(Compressed Domain Extraction)
原理: 直接从视频压缩数据中提取关键帧(I帧) 优势: 无需完整解码视频,速度极快 实现:
# 使用FFmpeg提取I帧
ffmpeg -skip_frame nokey -i input.mp4 -vsync 0 frame_%03d.jpg
1
2
2
# 2. 时间采样法(Temporal Sampling)
def temporal_sampling(video_path, interval=100):
"""按固定间隔提取帧"""
cap = cv2.VideoCapture(video_path)
frames = []
for frame_idx in range(0, int(cap.get(cv2.CAP_PROP_FRAME_COUNT)), interval):
cap.set(cv2.CAP_PROP_POS_FRAMES, frame_idx)
ret, frame = cap.read()
if ret:
frames.append(frame)
cap.release()
return frames
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
原理: 按固定时间间隔采样 优点: 简单高效,分布均匀 缺点: 可能错过重要时刻 适用: 监控视频、时间序列分析
# 3. 混合方法(Hybrid Approaches)
def hybrid_extraction(video_path):
"""混合方法提取关键帧"""
# 第一阶段:快速提取候选帧
candidates = temporal_sampling(video_path, interval=300)
# 第二阶段:内容分析筛选
saliency = cv2.saliency.StaticSaliencyFineGrained_create()
key_frames = []
for frame in candidates:
success, saliency_map = saliency.computeSaliency(frame)
if success and np.mean(saliency_map) > 0.4:
key_frames.append(frame)
return key_frames
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
原理: 结合多种方法的优势 典型流程:
- 时间采样获取候选帧
- 使用场景检测过滤无效帧
- 基于显著性评分排序
- 聚类算法去除相似帧
# 三、方法选择指南
方法类型 | 准确度 | 计算复杂度 | 适用场景 | 推荐实施 |
---|---|---|---|---|
场景变化 | ★★☆ | ★☆☆ | 新闻/影视剧 | 直方图差异法 |
运动分析 | ★★☆ | ★★☆ | 体育/监控 | 光流法 |
内容显著性 | ★★★ | ★★☆ | 广告/产品展示 | OpenCV saliency API |
深度学习 | ★★★ | ★★★ | 复杂语义内容 | MobileNet特征提取 |
压缩域提取 | ★☆☆ | ★☆☆ | 高速批处理 | FFmpeg工具 |
混合方法 | ★★★ | ★★☆ | 通用高要求场景 | 时间采样+内容筛选 |
编辑 (opens new window)
上次更新: 2025/06/07, 21:53:36