Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

4 语义分割成部件

✅ 已验证 · 代码 code/segment.py · 入口 trace_prepare.py 顶部

目标

把 origin 切成十几个有名字的部件:头发、脸、躯干、裙子、丝带……每个部件之后会成为 .kra 里的一个组。这是全流程的第一刀,切错了后面全错。

边界屏障法,不是颜色分类

三种「按颜色分」的路子都试过,都错:

方法错在哪
逐像素 HSV 规则发梢的粉色判成皮肤
区域均值色整头头发判成皮肤
加金色先验小腿高光吞进头发

原因很简单:一个部件内部的颜色变化(头发从金到粉的渐变)常常比部件之间的差别还大。

segment.regions(img, thr=25, win=7, min_px=300) 走的是另一条路:先找边界(局部对比超过阈值的地方形成屏障),再把屏障围出来的连通区域各自编号。头发内部金→粉是平滑渐变,不构成屏障,天然不会被切开。产出是一张区域标签图和每个区域的 bbox / 中心 / 面积。

区域 → 部件:一张手工核对的表

regions() 切出来的是几十个无名区域。把它们归到部件靠 trace_prepare.py 顶部的 ASSIGN 表:

ASSIGN = [
 ("Hair_Back",   [5, 26, 30, 32, 25]),
 ("Skin_Leg_L",  [58]),
 ...
 ("Hair_Front",  [2, 3, 6, 1]),
]

顺序 = 底→顶 = 遮挡顺序。 后面的部件盖住前面的,所以 Hair_Front 在最后。

这张表是对着 atlas.png(区域伪彩图 + 编号)目视核对写出来的,换一张图必须重做。没有被分配到的区域会并入空间最近的已分配部件。

本书用的 origin 分成 15 个部件:

Hair_Back  Skin_Leg_L  Skin_Leg_R  Skin_Foot  Shoe  Skin_Torso  Skin_Arm  Skin_Face
Dress_Bodice  Dress_Skirt  Dress_Frill  Ribbon_Waist  Ribbon_Hem  Ribbon_Hair  Hair_Front

部件之后的两个集合

同在 trace_prepare.py 顶部:

STRANDY = {"Hair_Back", "Hair_Front"}                         # 哪些部件长发丝
HATCHY  = {"Skin_Face", "Skin_Torso", "Skin_Arm", "Skin_Leg_L", "Skin_Leg_R"}   # 哪些排线

它们决定第 18 章strandhatch 两种笔落在哪。也是换图要改的。

已知的边界

  • 分割在 1x 上做。 部件边界的亚像素位置在这一步就丢了——分割成硬标签图的那一刻,抗锯齿信息没了。第 5 章负责把它捡回来。
  • 眼睛不是独立部件。 它在 Skin_Face 里,靠第 6 章的色阶把它切出来。这在本书的 origin 上够用;五官更复杂的图可能需要把眼睛单独列进 ASSIGN
  • regions() 的三个参数(thr 对比阈值、win 窗口、min_px 最小区域)目前是手调的,没有自动选择。