本地视频 → 序列帧动画精灵图
一句话:把你电脑上的一段视频 / GIF(不管是拍的、下的,还是本地 AI 模型生成的),
变成游戏引擎里能直接用的「序列帧精灵图」——全程在你自己的机器上跑,不上云。
⚠️ 项目性质说明:本文档所属的
fs7744/meowcute
项目仅用于个人实验与研究,不是商业产品、不提供任何保证,也不构成可用于生产的方案。
文中涉及到的模型权重、脚本与流程仅作技术探索与学习用途;若用于实际项目或商用,
请自行核验相关模型与素材的许可证与授权。
1. 先搞懂三个词
很多人第一次听到「序列帧精灵图」会懵,其实拆开看就三样东西:
- 精灵图(Sprite Sheet):把很多张小图按网格拼成的一张大图。游戏里角色的所有动作帧都塞在一张 PNG 里,引擎按坐标「切」出来播放,省内存、加载快。
- 序列帧(Sequence Frames):上面那些小图是有顺序的——第 1 张抬脚、第 2 张迈步……按顺序循环播放,看着就像在动。本质就是小时候的手翻书 / 翻页动画。
- 本地(Local):指整个过程不调用任何云端 API。视频在你硬盘上,计算在你 CPU/GPU 上,成品也留在你机器里。好处是:不花钱、不联网、素材不外泄、想跑几遍跑几遍。
把它们连起来:本地视频 → 拆成一摞帧 → 挑出关键帧 → 拼成一张精灵图 → 循环播放验证。这就是本工具做的事。
2. 为什么要把「视频」变成「精灵图」?
视频和精灵图其实是同一段动作的两种存法:
| 视频(mp4 / gif) | 精灵图(png + 索引) | |
|---|---|---|
| 播放者 | 播放器 / 浏览器 | 游戏引擎 |
| 能不能套骨骼 | 不能 | 能(配合骨骼动画) |
| 能不能逐帧改 | 难 | 容易(单独导出每帧) |
| 进 Unity / Godot | 要转 | 直接吃 |
所以当你手上已经有了「想要的动作」(比如一段走路、挥剑、待机),但缺的是「游戏里能用的素材」时,这条路就派上用场了:
- 复用现成动作:录屏、动捕片段、别处下载的 GIF,不用重新手绘每一帧。
- AI 生成的动作也能用:用本地运行的视频模型(如 HunyuanVideo、Wan)生成一段动画,再转成精灵图——创意和预览很快,正式素材也能落地。
- 像素 / 复古风兜底:拼出来的帧可以再走像素精修,直接当 16-bit 像素素材。
3. 整条流水线长什么样

┌─────────────┐ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐ ┌──────────┐
│ ① 选择视频 │ → │ ② 拆解帧 + 挑帧 │ → │ ③ 精灵图 │ → │ ④ 动画预览 │ → │ 导出成品 │
│ 视频 / GIF │ │ 两把筛子去重 │ │ 网格拼接+索引 │ │ 循环播放看效果 │ │ PNG/JSON │
└─────────────┘ └──────────────┘ └─────────────┘ └──────────────┘ └──────────┘
每一步都对应一个画布节点,可以单独调参数,也可以整条一键跑。
① 选择视频
导入 mp4 / mov / webm / gif,先原地播一遍确认片段对不对——别等拆完才发现导错了片。
② 拆解帧 + 挑帧
把视频按「帧率上限(默认 12fps)」「最大帧数(默认 120)」「起止时间」拆成一摞帧。
然后两把筛子帮你把 200 帧压到 20 帧左右:
- 跳帧步长(step):每 N 帧只留 1 张。动作慢就调大,动作快就调小。
- 近似度过滤(simPct):和上一张「长得差不多」的自动丢掉。阈值 0 表示不过滤;拆完节点会告诉你「这段素材帧间差异的中位数」,照着它调最省事。
筛完之后最后还是你说了算——逐张勾选 / 反选 / 只留筛选结果。为什么不让程序自动抽 8 张就完事?因为「哪几个姿势构成一个完整循环」是审美决定,只有你自己看得到。
③ 精灵图
选中的帧按网格拼成一张 PNG,附带一份索引 JSON(记录每帧坐标 + 锚点)。
cols = 0时自动排成接近正方形的网格(ceil(√帧数)),不会拉成一条超长条。- 可设帧间距(给 Unity 自动切片留 2px 透明间隔)和外边距。
- 共享缩放:所有帧按同一比例缩放,抬腿的帧不会被莫名放大,整段循环里角色尺寸恒定。
- 锚点(pivot)默认底部居中,方便在引擎里对齐脚底。
④ 动画预览
画布上按你设的帧率(默认 12fps)循环播放,可调显示倍率、逐帧步进,检查动作顺不顺、接缝对不对。
4. 背后那点「魔法」(通俗版)
近似度为什么能「拖滑杆即时出结果」?
后端给每一帧算了一份 16×16 灰度的「指纹」(256 字节的 base64)。前端拿到这串指纹,在浏览器里实时比较两帧的差异,完全不用再回后端。所以你拖阈值滑块,去重结果立刻刷新。
白底视频抠出来为什么会有「白边」?
白色背景的视频,人物边缘的像素其实是「角色色 + 背景白」的混合色(不是半透明,是混色)。普通抠图只按颜色距离判断,会把这种混色边当成背景留下,看着就是不干净的白圈。
本工具改用混合比例判据:|边缘色 - 背景| / |角色内侧色 - 背景| < 0.85 的就判定为溢色、修掉。这样不管白底灰底,边缘都能清干净。
为什么「共享缩放」很重要?
如果每张帧单独缩放到固定单元格,抬腿那一帧因为动作幅度大,角色会被放大;不抬腿的帧又偏小。循环播放时角色会一胀一缩。共享缩放先算出「所有帧里角色的最大包围盒」,统一按它缩放,尺寸就稳了。
5. 项目经验:我们做这个工具时踩过的坑
下面这些不是教科书结论,是实打实调出来的。每一个都附带当时的现象、根因和修复后的实测,给后来者省时间。
坑 1:白底视频抠出来一圈白边,怎么都去不干净
- 现象:白色背景的人物视频,抠完边缘总留一圈白,看着很脏。
- 先误诊:以为是半透明羽化没处理好。结果量化发现
hard=True时 alpha 严格 0/255,半透明像素占比实测 0.0%——白边不是羽化问题。 - 真根因:那圈像素的 RGB 本身就是「角色色 × α + 白底 ×(1−α)」的混色,不是半透明。旧判据用绝对颜色距离(门槛 50),但一个混了 40% 白的边缘像素到白底的距离约 200,永远判不进来。换「离背景近还是离内侧近」也不行:α≈0.5 的混色像素两边等距,越该修越判不出。
- 修法:改用混合比例判据
|边缘色 − 背景| / |角色内侧色 − 背景| < 0.85(混进 >15% 背景才修),一套阈值通吃深底/浅底/彩底。 - 实测(用户素材 640² 白底 21 帧):去污像素
1716 → 3994;边缘环均值 RGB[75,74,76] → [13,11,13](白边变回描边色),环里「距白底 < 40」的占比0.5% → 0.1%。
坑 2:近似度去重,「连续静止段」压不掉
- 现象:视频里常有连续 5 帧几乎不动(起步/停步),但逐帧比对只丢掉了 4 帧,整段静止还占着位置。
- 根因:判据是「和上一帧比」。一旦某帧和前一帧差很小就被删,但静止段里每一帧都「约等于上一帧」,结果只丢掉少量。
- 修法:判据改成「和上一张保留帧比」。连续不动的整段会被压成 1 帧。
- 顺带一个交互教训:过滤只改显示,不自动改已勾选。否则你精心挑好的 12 帧,手一滑滑杆就全被换掉——这点绝对不能接受,必须点了「应用筛选结果」才采纳。
坑 3:去重凭什么能「拖滑杆零延迟」?
- 做法:拆帧时后端给每一帧算一份 16×16 灰度的「指纹」(256 字节 base64),120 帧总共才约 30KB。前端拿到指纹在浏览器里实时算两帧差异,完全不回后端。所以拖阈值滑块,结果立刻刷新。
- 为什么不用大模型/不回后端:去重是高频交互(拖一次滑杆算一遍),一旦走网络就会有几百毫秒卡顿,体验直接废掉。指纹够小、足够分辨「是不是同一个姿势」,再大只是浪费。
坑 4:cols=0 差点把精灵图拉成 2736×136 的超长条
- 现象:21 帧、128px 单元格,如果一行排完,得到
2736×136(长宽比 20:1)的横条。某些引擎/采样不友好,看着也诡异。 - 修法:
cols=0语义改成「自动方形」——列数取ceil(√帧数),21 帧变成 5×5 的656×656,显存一样但采样友好。要横排(Godot hframes / Unity 单行)就在节点上显式给列数,UI 提供「自动方形 / 横排一行」两个按钮。注意:老的spritesheet节点保持一行排完(那是每方向一条横条,语义不同)。
坑 5:像素提示词写「对齐网格线」,模型真画出格子
- 现象:想让出图是像素块,提示词写「边界严格对齐网格线」,结果模型在每块之间画出了网格线/格子边框,像 Excel 表格而不是连续画面。
- 修法:改成「边界落在网格上、但不要画出网格线本身」,并补一句「整幅图是连续的画面,不是一个一个方格」。出图立刻干净了。
- 教训:提示词里「不要画 X」比「对齐 X」安全得多;模型会把抽象约束具象化成你没想到的东西。
坑 6:长任务一测就卡死,原来是测试方式错了
- 现象:用接口测试工具跑「拆帧 + 全帧抠图」,进度停在「21 帧就绪」再也不动,
doneAt永不设置。但直接await跑同一个函数 20 秒就完事。 - 根因:测试客户端(TestClient)每个请求新建一个事件循环,后台协程随请求结束被丢弃。秒级任务没问题,但抠图/视频这类长任务会永久卡死。
- 规矩:秒级任务可用测试客户端;长任务(抠图、视频生成)必须拉起真实服务再验证(项目里有
tools/test_clip_api.py:临时数据目录 + 随机端口,跑完 kill,不污染数据)。
坑 7:视频生成模型,别让它当正式生产的唯一来源
- 现象:用 HunyuanVideo / Wan 直接生成「行走视频」再拆帧,做出来会闪烁、角色漂移、耗时还忽长忽短(重试机制会让一次任务跑三次视频生成)。
- 定位:视频模型适合做动作探索 / 预览,不适合当正式游戏精灵的唯一生产方式。同一段动作,正式生产应走「角色参考图 → 标准 2D 骨骼 → 确定性渲染精灵帧」,动作能套到多个角色、可编辑、不漂移。
- 分工:本工具把视频定位成「动作来源」——不管是拍的、下的、还是 AI 生成的,转成精灵图后再进引擎或像素精修。这条分工最稳。
6. 上手小抄
- 循环动画首尾别选重复姿势:末帧和首帧太像,播起来会「卡一下」。
- 先播再拆:源片段确认对了再动手,省得拆完发现导错片。
- 信任自己的眼睛做最后一刀:筛子只是帮你减负,真正挑哪些帧由你定。
- 要做透明底素材:默认就开了 u2net 抠图;白底视频记得留意上面的「白边」处理已经帮你做了。
- 要进 Unity / Godot:留 2px 帧间距 + 用导出的索引 JSON,引擎自动切片最省事。
- 多方向行走:这条链是「已有一段视频 → 转精灵图」;要做八方向,可用画布里的「行走视频 / 序列帧 / 精灵整图」节点自己搭。
7. 它和「AI 生成正式素材」的关系
视频生成模型适合做动作探索,不一定适合当正式游戏精灵的唯一生产方式
(会有闪烁、角色漂移、耗时波动)。本工具把视频定位成「动作来源」,
转成精灵图后再进引擎或像素精修——这条分工更稳。
如果你想要的是「角色参考图 → 标准骨骼 → 确定性渲染精灵帧」的正式生产链路,
见同目录的技术评审文档 Meowcute 视频生成序列帧方案分析.md。
8. 一句话总结
本地视频转序列帧精灵图 = 把你已有的(或本地 AI 生成的)动作视频,
离线拆帧、挑帧、拼图,变成游戏能直接吃的精灵图与索引文件。
不联网、不花钱、素材不出本机,挑哪几帧永远是你说了算。

浙公网安备 33010602011771号