vault backup: 2026-06-03 10:30:42

This commit is contained in:
2026-06-03 10:30:42 +08:00
parent 2e207dc8fb
commit b5d9e44f0b
16 changed files with 661 additions and 507 deletions
+38 -23
View File
@@ -1,18 +1,27 @@
# 06 — 精灵图处理管线
---
tags: [image-processing, sprite-sheet, gif, computer-vision, go, algorithm]
create time: 2026-06-03 10:25
---
> **一句话概括**:自动精灵图处理管线 — 背景移除 → 投影检测 → 切割 → 对齐 → GIF 预览,将一张 AI 生成的 Sprite Sheet 无缝转化为可用的逐帧动画资源。
# 06. 精灵图处理管线
## 概述
自动精灵图处理管线 — 背景移除 → 投影检测 → 切割 → 对齐 → GIF 预览,将一张 AI 生成的 Sprite Sheet 无缝转化为可用的逐帧动画资源。
---
## 正文
```mermaid
flowchart LR
A["🖼️ Input PNG<br/>Sprite Sheet"] --> B["🪄 Background<br/>Removal"]
B --> C["📊 Gap<br/>Detection"]
C --> D["✂️ Tile<br/>Extract"]
D --> E["🔍 Filter<br/>MinFill"]
E --> F["📐 Trim<br/>Alpha"]
F --> G["🎯 Align<br/>padToLargest"]
G --> H["🎬 GIF<br/>Preview"]
A["Input PNG"] --> B["Background Removal"]
B --> C["Gap Detection"]
C --> D["Tile Extract"]
D --> E["Filter MinFill"]
E --> F["Trim Alpha"]
F --> G["Align padToLargest"]
G --> H["GIF Preview"]
style A fill:#e3f2fd,stroke:#1976d2
style B fill:#fff3e0,stroke:#f57c00
@@ -26,7 +35,7 @@ flowchart LR
---
## 📋 处理管线总览
## 处理管线总览
AI 生成的 Sprite Sheet 通常包含白色/绿色背景、不均匀间距和尺寸差异。Gen2D 的精灵图处理管线自动完成从"原始 PNG"到"可用动画帧"的全部转换工作,无需用户手动操作。
@@ -42,7 +51,7 @@ AI 生成的 Sprite Sheet 通常包含白色/绿色背景、不均匀间距和
---
## 🪄 步骤 1:背景移除
## 步骤 1:背景移除
AI 生成的图片通常带有纯色背景,管线支持两种模式:
@@ -69,11 +78,12 @@ if gDominance > tolerance*255 → 透明化
- **GreenTolerance** 默认 0.2,控制绿色检测灵敏度
- 适用于绿色背景的 AI 生成图
> 💡 **设计选择**:两种模式互斥,`Process()` 根据 `opts.WhiteBg` / `opts.GreenScreen` 自动选择。
> [!tip] 设计选择
> 两种模式互斥,`Process()` 根据 `opts.WhiteBg` / `opts.GreenScreen` 自动选择。
---
## 📊 步骤 2:切割策略
## 步骤 2:切割策略
管线提供两种切割方式,根据配置自动切换:
@@ -90,6 +100,10 @@ if gDominance > tolerance*255 → 透明化
- 防止突出物(武器/尾巴)被其他行稀释
- 每行段获得独立的列边界,互不干扰
> [!question] 为什么不用简单的阈值分割?
>
> 精灵图中的角色往往有复杂轮廓——比如挥舞的剑可能横跨多个帧的位置。如果仅用固定阈值,剑的连续像素会让算法误判为一帧。**按行段独立分析**的思路是把二维问题拆解为多个一维子问题,每个子问题只关心当前行段的内容,从而避免跨行干扰。
```mermaid
flowchart TB
A["输入图像"] --> B["全局行投影<br/>检测行间隙"]
@@ -124,7 +138,7 @@ flowchart TB
---
## 🔍 步骤 3:过滤 — MinFillRatio
## 步骤 3:过滤 — MinFillRatio
切割后的每个 tile 都计算填充率:
@@ -138,7 +152,7 @@ fillRatio = 非透明像素数 / 总像素数
---
## 📐 步骤 4:裁剪 — trimAlpha
## 步骤 4:裁剪 — trimAlpha
对每个 tile 执行透明边框裁剪:
@@ -148,7 +162,7 @@ fillRatio = 非透明像素数 / 总像素数
---
## 🎯 步骤 5:对齐 — padToLargest
## 步骤 5:对齐 — padToLargest
动画播放时,如果每帧尺寸不同且内容未对齐,会导致角色"抖动"。
@@ -169,7 +183,7 @@ canvasH = maxH * 110% // 最大帧高度 + 10% padding
---
## 🎬 GIF Maker
## GIF Maker
`gifmaker.Encode()` 将处理后的帧序列编码为动画 GIF:
@@ -186,11 +200,12 @@ anim.Disposal = append(anim.Disposal, gif.DisposalBackground)
anim.BackgroundIndex = 0 // 透明色
```
> ⚠️ **DisposalBackground 的重要性**:如果不设置此选项,GIF 播放器会在前一帧基础上叠加新帧,产生"残影"效果。
> [!warning] DisposalBackground 的重要性
> 如果不设置此选项,GIF 播放器会在前一帧基础上叠加新帧,产生"残影"效果。
---
## 📦 Options 配置速查
## Options 配置速查
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
@@ -207,8 +222,8 @@ anim.BackgroundIndex = 0 // 透明色
---
## 🔗 关联文档
## 关联文档
- [← 返回索引](00-index.md)
- [05 — 生成管线](05-generation-pipeline.md) — 管线中 SplitSprite 节点的调用方
- [08 — SSE 实时推送](08-sse-push.md) — 处理进度的实时推送
- [[00-索引]] — 文档导航与架构总览图
- [[05-生成管线]] — 管线中 SplitSprite 节点的调用方
- [[08-SSE实时推送]] — 处理进度的实时推送