Video Overlay 是 video-agent 下的视频叠加与合成技能,面向“把已知素材确定性地合成到视频里”的需求。按资料说明,它用于叠加与合成,而不负责生成式改写素材(若需重新着色物体、添加烟雾火焰等生成式编辑,资料指明应改用 grok-video-edit)。
主要能力与叠加类型 资料给出的叠加类型与对应方式包括:
- 文字标签:使用 overlay-text,通过 PIL 渲染(资料提到 mise ffmpeg 缺少 drawtext)。
- 多个文字标签:使用 overlay-texts,一次完成,例如倒计时。
- 静态图片/Logo:使用 overlay-image。
- 静态透明图形:使用 RGBA PNG 加 ffmpeg overlay,资料称 alpha 是原生支持的,无需 colorkey。
- 动画透明效果:使用 RGBA PNG 序列加 ffmpeg。
使用方式 资料给出的示例命令: uv run video-agent overlay-text in.mp4 --text "BOOM!" --x center --y center --size 120 --color yellow --start 5.0 --end 7.0 -o out.mp4 uv run video-agent overlay-image in.mp4 --image logo.png --x "W-w-20" --y 20 --scale 200:100 --start 0.0 --end 5.0 -o out.mp4 其中 --x/--y 可接受像素偏移、center 或 ffmpeg 表达式(例如 W-w-10 表示距右边缘 10px)。
透明处理规则
资料总结了透明素材的处理要点:静态透明叠加直接使用 RGBA PNG,overlay 原生处理 8 位 alpha,无需 colorkey;动画透明叠加应使用 RGBA PNG 序列而不是 GIF,因为 PIL 保存的 GIF 会量化为 1 位调色板,overlay-gif 会静默地无法合成其透明度。渲染帧命名为 seq/000.png、001.png 等,并给出如下命令:
ffmpeg -i video.mp4 -framerate 25 -stream_loop -1 -i "seq/%03d.png"
-filter_complex "[1:v]format=rgba[ov];[0:v]format=rgba[bg];[bg][ov]overlay=X:Y,format=yuv420p"
-c:v h264_videotoolbox -b:v 8M -c:a copy -shortest out.mp4
若仍要用 GIF 加 colorkey,顺序应为 colorkey → scale → format=rgba → overlay(资料解释 scale 会把 BGRA 转成 YUV,若先做会破坏 key)。调试不可见叠加时,资料建议先去掉透明度,用纯色背景合成素材以确认几何与时间正确,再单独修复 alpha。
时间窗口 资料指出,在 PTS 被处理的图像/GIF 流上,ffmpeg 的 enable='between(t,a,b)' 不可靠;应使用 split-overlay-concat 模式:把源切成 before/during/after,只对中间段应用叠加(不加 enable 子句),再用 filter_complex concat 三段。资料说明 overlay-gif 在给定 --start/--end 时会在内部执行这一模式。确定叠加时机应从转录中获取,而不是靠拖动时间轴:对 --words 转录并 grep 目标词,读取其 start/end 作为 --start/--end(或 enable 窗口)。
精确定位方法 资料强调不要靠反复渲染和目测。对于静态目标,可用 position-grid:position-grid video.mp4 --at T --spacing 200 -o grid.png(资料提示从 200 开始,100 在缩小渲染时太密难以阅读);读取 grid.png,找到包含目标的 200px 象限;裁剪并放大该区域读取精确标签,示例代码: from PIL import Image img = Image.open("grid.png"); c = img.crop((x0,y0,x1,y1)) c.resize((c.width3, c.height3), Image.NEAREST).save("grid_zoom.png") 然后计算叠加左上角 = 目标中心 − 叠加尺寸/2,并用输出帧验证一次。 对于难以用肉眼锁定或会移动的目标,资料建议使用 dot-probe 方法:用 frame 提取目标帧全分辨率;在实际帧上于候选 (x,y) 放置彩色探针点,围绕目标紧密裁剪并放大(NEAREST),读取哪个点落在目标上,示例代码: from PIL import Image, ImageDraw im = Image.open("frame.png").convert("RGB"); d = ImageDraw.Draw(im) cands = [(x0, y0, (255,0,0)), (x1, y1, (0,255,0)), (x2, y2, (0,128,255))] for (x, y, c) in cands: d.ellipse([x-4,y-4,x+4,y+4], fill=c) # note which color = which (x,y) z = im.crop((cx0,cy0,cx1,cy1)); z.resize((z.width6,z.height6), Image.NEAREST).save("probe.png") 资料称两三轮即可收敛到像素级。还可通过清晰的无歧义邻近特征来转移约束:当目标本身难以辨识但附近特征清晰时,测量容易的那个并转移约束,用清晰的相邻地标确定不清晰目标的共用行或列。之后仍按“叠加左上角 = 目标中心 − 叠加尺寸/2”计算并用帧验证。
移动目标 资料指出,单一静态位置不适用于移动目标。如果目标在叠加窗口内移动,应在窗口起始帧和结束帧分别测量,然后在 PIL 中逐帧合成并在两者之间线性插值位置(提取窗口帧、逐帧粘贴素材、重新编码、拼回)。资料说明 ffmpeg overlay 不易接受随时间变化的位置,静态 x/y 会明显偏离目标;若窗口内测得的漂移较小(约小于 10px),静态位置即可,建议测量两端来判断。
验证 资料建议用 frame 在叠加窗口中间时间戳抽查输出。对于重新编码源的时序/运动正确性,应顺序导出帧(ffmpeg -i out.mp4 -vf fps=10 /tmp/f_%03d.png)而不是依赖单个跳转帧。