Skip to content

视频:解析关键帧+抽取语义帧 #2

Description

@nana-123456

【视频】解析关键帧/抽取语义帧

背景

视频分析的第二步是基于结构化文本段落,从视频画面中找到与文本内容语义相关的关键帧。

该步骤依赖上一阶段生成的结构化文本:

videos/{video_id}/transcript/transcript_tree.json

本功能只负责解析关键帧和抽取语义帧,不负责生成线框图,也不负责生成最终 Markdown。

目标

实现视频关键帧解析和语义帧抽取功能,包括:

  1. 使用 FFmpeg 对视频进行 2 秒密集抽帧。
  2. 对抽帧结果进行图像质量过滤。
  3. 使用 HSV 色彩直方图 + pHash + 10 秒窗口进行短时间重复帧去重。
  4. 使用 qwen3-vl-embedding 生成文本段落 embedding 和图片 embedding。
  5. 计算每个文本段落和每张候选帧之间的 cosine similarity。
  6. 输出每个文本段落下的原始 2 秒关键帧、语义帧和相似度分数。

前置条件

执行该步骤前,必须已经完成“转写文本(包括结构化文本)”。

需要读取:

videos/{video_id}/transcript/transcript_tree.json

如果结构化文本不存在,则不继续执行语义帧抽取。

实现步骤

1. FFmpeg 2 秒密集抽帧

使用技术:

FFmpeg

抽帧规则:

每 2 秒抽 1 张图片

抽帧图片保存路径:

videos/{video_id}/frames/{timestamp_ms}.jpg

文件名示例:

000000000.jpg
000002000.jpg
000004000.jpg
000006000.jpg

这些图片是原始 2 秒关键帧,不是最终语义帧。

2. 图像质量过滤

对 2 秒抽帧后的图片进行基础图像质量过滤。

使用技术:

OpenCV
Pillow 兜底

过滤指标:

清晰度
亮度
黑屏比例
过曝比例

使用方法:

Laplacian 方差:判断清晰度
灰度均值:判断亮度
暗像素比例:判断黑屏/过暗
亮像素比例:判断过曝

质量过滤报告保存为:

frame_quality_report.json

存储路径:

videos/{video_id}/frames/frame_quality_report.json

3. HSV + pHash + 10 秒窗口去重

对通过质量过滤的图片进行短时间重复帧去重。

使用技术:

HSV 色彩直方图
pHash 感知哈希
10 秒时间窗口

重复判断规则:

两张图片时间差 <= 10 秒
HSV 色彩直方图相似度 >= 0.92
pHash 汉明距离 <= 6

处理方式:

1. 满足重复条件的帧归入同一个 dedup group。
2. 每个 dedup group 保留质量分最高的一张。
3. 其他重复帧只标记为 duplicate_rejected,不物理删除原始图片。

去重报告保存为:

frame_dedup_report.json

存储路径:

videos/{video_id}/frames/frame_dedup_report.json

去重后保留下来的代表帧称为:

candidate frames

4. 生成文本段落 embedding

读取结构化文本:

videos/{video_id}/transcript/transcript_tree.json

第一版本只做段落级 embedding,不做句子级 embedding。

文本输入格式:

段落标题 + 段落正文

使用模型:

qwen3-vl-embedding

输出内容:

每个文本段落对应一个 text embedding

5. 生成候选帧图片 embedding

图片侧只处理去重后保留下来的 candidate frames。

图片输入:

candidate frame 图片

使用模型:

qwen3-vl-embedding

输出内容:

每张 candidate frame 对应一个 image embedding

说明:

图片直接使用 FFmpeg 抽帧得到的图片。
默认不裁剪、不增强、不额外做尺寸标准化。

如果没有配置 qwen3-vl-embedding 所需的 API Key,则直接报错,不输出无效的相似度结果。

6. 计算段落和图片的语义相似度

对每个文本段落 embedding 和每张 candidate frame image embedding 计算:

cosine similarity

计算范围:

每个文本段落 vs 所有 candidate frames

相似度越高,表示该图片越可能与该文本段落相关。

第一版本不限制每个段落最终选几张图,只输出全部语义匹配结果和相似度分数。

7. 保存语义帧匹配结果

语义帧匹配结果保存为:

semantic_frame_matches.json

存储路径:

videos/{video_id}/frames/semantic_frame_matches.json

该 JSON 中需要包含:

视频 ID
embedding 模型名称
原始 2 秒关键帧数量
candidate frames 数量
文本段落数量
每个文本段落下的原始 2 秒关键帧
每个文本段落下的语义帧
每张语义帧的 similarity 分数

每个文本段落下至少包含:

段落序号
段落标题
段落正文
段落开始时间
段落结束时间
raw_frames
semantic_frames

每张 semantic frame 至少包含:

frame_id
timestamp_seconds
图片路径
similarity
rank

产物汇总

该步骤最终需要生成以下产物:

videos/{video_id}/frames/{timestamp_ms}.jpg
videos/{video_id}/frames/frame_quality_report.json
videos/{video_id}/frames/frame_dedup_report.json
videos/{video_id}/frames/semantic_frame_matches.json

验收标准

  1. 可以基于视频文件按 2 秒间隔抽取关键帧。
  2. 可以生成并保存原始 2 秒关键帧图片。
  3. 可以完成图像质量过滤,并生成:
videos/{video_id}/frames/frame_quality_report.json
  1. 可以完成 HSV + pHash + 10 秒窗口去重,并生成:
videos/{video_id}/frames/frame_dedup_report.json
  1. 可以调用 qwen3-vl-embedding 为文本段落和 candidate frames 生成 embedding。
  2. 可以计算每个文本段落和每张 candidate frame 的 cosine similarity。
  3. 可以生成并保存:
videos/{video_id}/frames/semantic_frame_matches.json
  1. semantic_frame_matches.json 中能按文本段落看到:
原始 2 秒关键帧
语义帧
similarity 分数
  1. 第一版本不做线框图生成。
  2. 第一版本不做最终 Markdown 生成。
  3. 第一版本不限制每个段落最终选几张语义帧,只输出相似度匹配结果。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions