Wjs Reframing Video

Polar Sponsor
爱发电 赞助
.NET 9.0

用于在保持宽高比倒置的情况下,将视频从横向转换为纵向或反之(例如 16:9 ↔ 9:16,4:3 ↔ 3:4 等)

wjs-reframing-video. 通过从源头裁剪狭带来转换视频的导向,而不是通过物理旋转. 作物窗口跟随活动扬声器(其嘴是脸)

功能概述

wjs-reframing-video. 通过从源头裁剪狭带来转换视频的导向,而不是通过物理旋转. 作物窗口跟随活动扬声器(其嘴是脸)是一项面向实际任务的技能。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。

核心要点

  • 使用时应结合输入条件选择合适的执行方式,核对必要参数、依赖环境与输出内容,并按原始要求处理异常情况。
  • 该技能适合需要稳定复用相关能力的场景,可作为自动化工作流的一部分,也便于后续检查、调整和扩展。
  • 从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。

使用与执行

实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。

结果检查与注意事项

执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。

wjs-reframing-video

通过从源视频中裁剪一个窄条区域来改变视频朝向,而非物理旋转画面。裁剪窗口始终跟随正在说话的人(active speaker)——即嘴部正在运动的面部,而非仅依据面积最大或置信度最高的面部。配套生成的 .crop.json 辅助文件记录了完整的裁剪方案、各片段的发言人判定结果,以及所用参数。原始输入文件**永远不会被修改**。

适用场景

  • 将 16:9 的播客 / 访谈 / 演讲视频重新适配为竖屏短视频平台(微信视频号、抖音、小红书、YouTube Shorts、TikTok、Reels)。
  • 将 9:16 的手机竖屏录制内容重新适配为横屏播放器(YouTube 长视频、博客嵌入等)。
  • 将 4:3 的存档素材适配为 3:4 移动端比例,或反之。

输出画幅为源画幅的宽高互换 —— 即 16:9 → 9:16,而非“在 9:16 画框内添加黑边的 16:9”。

不适用场景

  • 多人问答类内容(Multi-person Q&A):当每个发言人都需独立裁剪时,本技能仅支持为整段视频选择一条裁剪轨迹。如需按发言人分别渲染,请改用 wjs-editing-multicam。
  • 无面部的动画内容 / B-roll:将退化为居中裁剪,通常不符合创作意图。
  • 源视频存在剧烈镜头运动(手持平移/变焦):人脸追踪器会放大抖动。请先进行画面稳定处理。
  • 源视频已符合目标画幅:无需处理。

该技能的定位 —— “是”与“不是”

是 不是
基于 MAR(嘴部宽高比)方差的视觉主动发言人检测 音视频融合(音频能量 + 嘴唇运动交叉相关)
通过中心距离匹配实现跨帧稳定人脸追踪 长间隔 / 遮挡场景下的人脸重识别
带迟滞(hysteresis)机制的发言人对齐分段,防止画面闪烁 逐帧切换(每出现一次微小波动即切换)
--face-pick speaker(默认)—— 选择嘴部正在运动者 --face-pick largest(可选旧模式)—— 选择面积最大者
分段间硬切,每段内裁剪位置固定(--motion cut,默认) 平滑平移,且在单人发言过程中持续漂移(可选 --motion smooth)
音频流拷贝(比特精确) 音频重处理 / 重编码
使用 MediaPipe Tasks FaceLandmarker(478 点网格),通过 ffmpeg 以 5 fps 采样 逐帧神经网络图像修复 / 外绘(inpainting / out-painting)
单次 ffmpeg crop + scale 处理 逐帧 Python 合成器

当无人讲话(静音、纯音乐段落)时,自动回退至“面积最大面部”策略。

依赖项

pip install mediapipe opencv-python numpy

(MediaPipe 不包含在标准 Python 发行版中;ffmpeg 和 ffprobe 必须位于系统 PATH 中。)

首次运行模型下载:MediaPipe 0.10+ 使用 Tasks API,需加载 face_landmarker.task 模型文件(约 4 MB)。首次调用时,crop.py 将自动下载至 ~/.claude/skills/wjs-reframing-video/models/ 并缓存,供后续运行复用。首次离线运行将失败。

检测距离限制:内置 landmark 检测器针对距摄像头约 2 米范围(自拍 / 播客 / 访谈距离)优化。广角活动场景中若人脸过小可能无法检出 —— 建议先抽帧验证检测效果。

裁剪数学原理

源画幅 = W / H,目标画幅 = H / W(倒置)。裁剪窗口计算如下:

源朝向 裁剪窗口
横屏(W > H)→ 竖屏 W_crop = H × H / W,H_crop = H(垂直窄条)
竖屏(W < H)→ 横屏 W_crop = W,H_crop = W × W / H(水平窄条)

例如 1920×1080 → 竖屏: W_crop = 608,H_crop = 1080;最终缩放至 1080×1920(约 1.78× 上采样)。 1080×1920 → 横屏: W_crop = 1080,H_crop = 608;最终缩放至 1920×1080。

若希望输出为原生裁剪尺寸而非上采样,可通过 --output-size 1080x1920 手动指定最终尺寸。

处理流程

  1. 探测:通过 ffprobe 获取输入分辨率、帧率、时长。
  2. 判断朝向:根据画幅自动推断(可通过 --target portrait|landscape 手动覆盖)。
  3. 帧采样:以 --sample-fps(默认 5 fps)采样帧 —— 足够捕捉嘴部运动(语音奈奎斯特频率约 10 Hz,至少需 4–5 fps)。
  4. 人脸关键点检测:对每帧采样使用 MediaPipe Tasks FaceLandmarker(478 点)检测人脸关键点。对每个检测到的人脸记录:中心坐标、尺寸代理值、MAR(嘴部宽高比 = 内唇垂直距离 / 嘴角水平距离)。
  5. 人脸追踪:基于中心距离匹配实现跨帧追踪 → 每个人脸获得稳定的 face_id。
  6. 逐采样点主动发言人判定:对每个人脸轨迹,在滑动时间窗(--mar-var-window-sec,默认 1 秒)内计算 MAR 方差。方差最高者视为“正在说话”。若低于 --mar-var-threshold,则判定为无声 → 回退至面积最大者。
  7. 迟滞机制:候选发言人切换仅在新发言人持续稳定达 --min-segment-sec(默认 1.5 秒)后才生效;更短的抖动将被抑制 —— 避免因单帧误检导致裁剪窗口来回跳变。
  8. 发言人对齐分段:对每一段,取该发言人在此段内所有帧的面部中心坐标的均值作为裁剪中心,并在整段内保持固定。
  9. 构建 ffmpeg 分段函数表达式(--motion cut,默认):使每段裁剪位置恒定,并在段边界处瞬时跳变 —— 视觉效果等效于真实摄像机角度切换。(--motion smooth 切换为分段线性平移,但对访谈类内容通常不适用,因镜头会在句中漂移。)
  10. 渲染:单次 ffmpeg 渲染 —— crop=W:H:x='expr':y='expr', scale=OUT_W:OUT_H。crop 滤镜原生支持逐帧计算 x 与 y;音频流拷贝。

scripts/crop.py 为具体实现。输出副作用包括:

  • .crop.json —— 记录裁剪方案的辅助文件
  • _cropped.mp4 —— 最终裁剪并缩放后的视频

辅助文件结构(.crop.json)

{
  "_about": "wjs-reframing-video crop plan for cam_a.MOV. Active-speaker detected via MAR variance.",
  "_help": {
    "source_size":     "[width, height] in pixels.",
    "target_size":     "[width, height] of the final rendered output.",
    "crop_window":     "[width, height] of the moving crop in source coords.",
    "chunks":          "Speaker-aligned segments: {t0, t1, cx, cy, speaker_id}.",
    "face_pick_mode":  "speaker = MAR-variance active-speaker; largest = old behavior.",
    "speaker_id":      "Stable face track id. null means no face / silence fallback."
  },
  "schema_version": 2,
  "source": "cam_a.MOV",
  "source_size": [1920, 1080],
  "target": "portrait",
  "target_size": [1080, 1920],
  "crop_window": [608, 1080],
  "face_pick_mode": "speaker",
  "sample_fps": 5.0,
  "mar_var_window_sec": 1.0,
  "mar_var_threshold": 1.5e-4,
  "min_segment_sec": 1.5,
  "chunks": [
    {"t0":  0.0, "t1":  4.2, "cx": 808, "cy": 540, "speaker_id": 0},
    {"t0":  4.2, "t1": 11.6, "cx": 1182, "cy": 540, "speaker_id": 1},
    {"t0": 11.6, "t1": 14.0, "cx": 808, "cy": 540, "speaker_id": 0}
  ],
  "face_sample_count": 1234,
  "track_count": 2
}

性能表现

  • 检测阶段 是瓶颈。Apple Silicon 设备以 2 fps 采样时,预计耗时为实时长度的 ~10–20 倍(30 分钟源视频约需 1–2 分钟完成检测)。提高 --sample-fps 会使检测变慢,但追踪响应更灵敏。
  • 渲染阶段 很快 —— 单次 ffmpeg 硬件编码(macOS 上为 hevc_videotoolbox)。1080p 源视频常低于 1× 实时速度。
  • 对于超长源视频(>200 个分段),ffmpeg 表达式可能过于复杂;脚本会自动对分段中点降采样,将控制点数量控制在约 200 以内。

常见问题

  • 嘴部动作 ≠ 说话:打哈欠、大笑、进食、吸气等动作同样会提升 MAR 方差。检测器可能短暂误判为说话。对于高要求内容,建议检查 sidecar 中的发言人时间线(脚本会打印 face#N: Xs on screen (Y%) 汇总),必要时调整 --mar-var-threshold 后重试。
  • 侧脸或低头姿态:当面部相对摄像头旋转超过 60° 时,MediaPipe 可能无法稳定检测嘴部关键点,导致 MAR 方差趋平。此时将自动回退至“面积最大面部”。若长期存在大量侧脸镜头,可考虑启用 --face-pick largest。
  • 两人重叠发言(打断 / 抢话):双方 MAR 方差均升高,但仅一人胜出。落败者被标记为听众。如需在串扰场景下实现准确的逐发言人追踪,请使用 wjs-editing-multicam 并配备独立摄像头。
  • 长时间静音段(B-roll、纯音乐):将回退至面积最大面部。若该面部非目标发言人(例如听众静止而发言人麦克风拾取背景音乐),将出现裁剪漂移。建议预先对纯音乐段落进行分段处理。
  • 源视频含烧录字幕 / 下栏(lower-thirds):横转竖时,底部区域会被裁掉;竖转横时,下栏虽保留但会被拉伸。运行前请先剥离烧录内容。
  • 广角 / 鱼眼镜头:关键点检测易在画面边缘失效。请先用 ffmpeg lenscorrection 校正畸变。
  • 上采样伪影:如 608×1080 → 1080×1920 需 1.78× 上采样,锐利文字可能出现可见失真。若需保持叠加图层清晰度,可输出原生裁剪尺寸(--output-size 608x1080),交由平台自行上采样。
  • 输出码率超出平台限制:默认为 --bitrate 12M。微信视频号上限为 10 Mbps;针对该平台请指定 --bitrate 8M。

相关专题

更多
js实现base64编码
js实现base64编码

在JavaScript中实现Base64编码,最直接的方式是使用内置的btoa()函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2025.10.24

379

9

html中如何调用外部js
html中如何调用外部js

在 html 中调用外部 js 可通过以下步骤:创建 js 文件并编写代码。在 html 代码中添加 <script> 标签,设置 src 属性为 js 文件路径。保存并刷新页面加载外部 js。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.11

1712

6

php和js的区别
php和js的区别

php和js的区别:PHP主要用于服务器端编程,而JavaScript主要用于客户端编程;PHP代码在服务器端执行,而JavaScript代码在客户端浏览器中执行。想了解更多php和js的相关内容,可以阅读本专题下面的文章。

2024.03.22

4828

11

JS的Document介绍
JS的Document介绍

在JavaScript中,document对象是一个非常重要的全局对象,它代表整个HTML文档。想了解更多Document的相关内容,可以阅读本专题下面的文章。

2024.03.14

6047

11

js中each函数的用法
js中each函数的用法

在JavaScript中,并没有一个内建的each函数,但jQuery库提供了一个非常有用的$.each() 函数,用于遍历数组或对象。想了解更多each函数的相关内容,可以阅读本专题下面的文章。

2024.03.13

1629

5

js和vue的关系
js和vue的关系

js和vue的关系:1、js作为web开发基石;2、vue.js作为前端框架的崛起;3、js与vue的互补关系;4、js与vue的实践应用。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.03.11

353

5

js弹幕功能实现方法
js弹幕功能实现方法

PHP中文网为大家带来,js实现弹幕功能的方法:1、创建html文件;2、添加html代码架构;3、在body标签中使用div、input、button标签分给页面设计效果显示框、输入框、弹幕提交按钮;4、添加script标签并写入js代码来实现弹幕效果;5、通过浏览器方式查看设计效果即可。希望对大家有所帮助。

2024.03.04

2992

11

js事件冒泡可以解决哪些问题
js事件冒泡可以解决哪些问题

js事件冒泡可以解决的问题:1、简化事件处理逻辑;2、提高事件处理性能;3、实现自定义组件和交互效果;4、控制事件传播方向;5、解决事件覆盖问题;6、实现全局事件监听;7、方便调试和排查问题。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.02.23

2824

4

js的split用法
js的split用法

js的split方法是字符串的一个方法,用于将字符串按照指定的分隔符分割成子字符串,并返回一个新的数组,其语法为“string.split(separator, limit)”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.11.24

1127

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 21万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 4.8万人学习