Wjs Reframing Video — Wjs 重构视频
v0.1.0当用户想要在保持反转长宽比(16:9 ↔ 9:16,4:3 ↔ 3:4,21:9 ↔ 9:21)的情况下,将视频在水平和垂直方向之间转换时使用。该技能从源视频中裁剪一窄条,并通过MediaPipe面部标志和口部宽高比方差跟踪活动说话者——即嘴巴移动的人——以便说话者即使其他人可见时也保持在画面中。触发器——“横转竖”、“竖转横”、“做成竖屏发抖音/视频号/小红书”、“16:9 to 9:16”、“make this vertical for Reels / TikTok / YouTube Shorts”、“crop to portrait”、“convert to landscape”。
运行时依赖
安装命令
点击复制技能文档
wjs-reframing-video 通过从源视频中裁剪一条窄带来改变视频的方向,而不是物理旋转。裁剪窗口跟随活动说话者(嘴巴移动的脸),而不仅仅是最大的或最自信的脸。一个 .crop.json 配置文件记录了裁剪计划、每个片段的说话者决定和使用的参数。原始输入永远不会被修改。
何时使用 将 16:9 播客/采访/演讲转换为垂直短视频平台(WeChat Channels 视频号、Douyin 抖音、Xiaohongshu 小红书、YouTube Shorts、TikTok、Reels)。 将 9:16 手机录制转换为水平播放器(YouTube 长视频、博客嵌入)。 将 4:3 存档片段转换为 3:4 移动设备,或反之亦然。 输出宽高比是源宽高比的反转 — 16:9 → 9:16,而不是“带有字母盒的 16:9 在 9:16 框架中”。
何时不使用 多人问答,每个面孔都需要自己的裁剪 — 这个技能为每个视频选择一个裁剪轨道。 对于每个说话者的分割渲染,请使用 wjs-editing-multicam 代替。 没有面孔的动画内容/辅助镜头 — 回退到居中裁剪,通常不正确。 源视频中的相机运动剧烈(手持平移/变焦) — 面部跟踪器放大相机抖动。 请先稳定。 源视频已经是目标宽高比 — 没有工作要做。
这个技能是什么 — 和不是什么 是 视觉上的活动说话者检测通过 MAR(嘴巴宽高比)变化 音视频融合(音频能量 + 嘴唇运动相关联) 通过中心距离匹配实现的稳定面部跟踪 跨长时间间隔/遮挡的重新识别 具有滞后效应以防止闪烁的说话者对齐片段 每帧切换在每个闪烁上 --face-pick speaker(默认)— 选择嘴巴移动的人 --face-pick largest(可选的遗产)— 选择最大的面孔 每个片段内的固定裁剪,片段之间的硬切换(--motion cut,默认) 在说话者转身期间平滑移动的裁剪(--motion smooth,选项) 音频流复制(位精确) 音频重新处理/重新编码 MediaPipe 任务 FaceLandmarker(478-pt 网格)在 5 fps 采样通过 ffmpeg 每帧神经 inpainting / out-painting 一个 ffmpeg 裁剪 + 缩放通道 每帧 Python 组合器 在没有人说话时(沉默、音乐只段)自动回退到“最大的面孔”。
依赖项 pip install mediapipe opencv-python numpy(MediaPipe 位于标准 Python 分发之外;ffmpeg 和 ffprobe 必须在 PATH 上。) 首次运行模型下载:MediaPipe 0.10+ 使用任务 API,该 API 需要 face_landmarker.task 模型文件(~4 MB)。 在第一次调用时,crop.py 将其下载到 ~/.claude/skills/wjs-reframing-video/models/ 并缓存以备后续运行。 脚本在首次运行时离线失败。
范围限制: 捆绑的 landmarker 适用于距离相机 ~2 m 的面孔(自拍/播客/采访距离)。 可能无法检测到带有小面孔的广泛事件镜头 — 请先采样一帧以确认。
裁剪数学 源宽高比 = 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 覆盖最终大小,如果您想要本地裁剪尺寸而不是放大。
管道 通过 ffprobe 探测输入维度、fps、持续时间。 决定方向 — 自动从宽高比(--target portrait|landscape 覆盖)。 在 --sample-fps(默认 5;足以捕捉嘴巴运动 — 语音的奈奎斯特频率为 ~10 Hz,我们需要至少 4-5 fps)下采样帧。 使用 MediaPipe 任务 FaceLandmarker(478 个标志)检测每个采样帧的面部标志。 对于每个检测到的面孔记录:中心、大小代理、MAR(嘴巴宽高比 = 内唇垂直距离/嘴巴角距离)。 通过中心距离匹配跟踪面孔跨帧 — 每个面孔获得一个稳定的 face_id。 每个样本的活动说话者:对于每个面孔跟踪,MAR 在滑动窗口(--mar-var-window-sec,默认 1 s)上的变化。 具有最高变化的面孔是“说话者”。 在 --mar-var-threshold 之下,无人说话 — 回退到最大的面孔。 滞后效应:候选切换仅在新说话者稳定为 --min-segment-sec(默认 1.5 s)时提交。 较短的闪烁被压制 — 防止裁剪在一个帧的误检测上来回跳动。 说话者对齐片段 — 对于每个片段,平均(cx,cy)成为裁剪中心,固定为整个片段持续时间。 构建一个 ffmpeg 步函数表达式(--motion cut,默认)以保持每个片段的裁剪位置常数并在每个片段边界跳转 — 真实相机角度之间的切换的视觉感受。 (--motion smooth 切换到平滑移动)。