Skip to content

抠图把角色内部挖出透明洞:背景非纯色时两层清理同时静默失效 #319

Description

@johnnyzhang-eng

现象

抠图会把角色身体中间的色块变透明 —— 放大看是背景直接从人物内部透出来。用户持续反馈。

根因:两层清理在同一个条件下同时失效

providers/matte.py 有两个后处理层,都依赖 _bg_key(rgb) 取到底色:

作用
_flat_bg_penalty 按颜色做减法,把闭合空隙里残留的底色清掉
_fill_enclosed_holes 把"被主体围住、且整块都不是底色"的透明连通域填回主体

后者正是为这个现象写的 —— 它的 docstring 明写:要解决的问题:u2netp 判错或键控误杀会在主体内部留下透明洞,放大看是背景直接透出来。

_bg_key 有一道前置门槛

if float(corners.std(axis=0).max()) > _BG_FLAT_STD:   # _BG_FLAT_STD = 8.0
    return None

四角采样的标准差超过 8.0 就返回 None,于是:

  • _flat_bg_penalty 返回全 1 → 键控清理整段跳过
  • _fill_enclosed_holes 第一行就 return alpha → 补洞整段跳过

结果:u2net 判错留下的洞,没有任何一层会修。

为什么我们自己测不出来

我们用的母版背景是纯色,四角标准差实测在 0.67–1.23,远低于 8.0,所以两层清理每次都生效

用户上传的角色图常带渐变、噪点、纹理背景 —— 一旦超过 8.0,两层同时静默失效。这是典型的"在我这儿是好的":不是概率问题,是输入分布不同。

这个门槛本身是对的,不该简单调大

_BG_FLAT_STD 存在的理由成立:底色不是纯色时,"哪块是背景"无从判断,硬清理会误杀主体像素。调大阈值只是把误杀的门槛推后,换来另一类坏结果。

真正的问题是:门槛不满足时没有降级路径,直接什么都不做。

建议方向

  1. 补洞与键控清理解耦。补洞的判据是"连通性 + 颜色"两条,其中颜色那条用于否决(腿间空隙整块是底色,实测中位色距 6.2,据此排除)。背景不是纯色时,颜色否决确实失效,但连通性那条仍然可用 —— 可以退化成更保守的策略(只填不与边界连通、且面积小于某阈值的洞),而不是完全不填。
  2. 失效要可见。当前是静默跳过,线上无从知道有多少次生成落进了这条路径。至少要有一个读数(背景是否被判为纯色),落进成色账本,这样才能回答"这个问题影响了多大比例的生成"。
  3. 先量分布再定方案。我们不知道用户实际输入里有多少比例超过 8.0。加读数(第 2 条)攒一批数据,再决定该做保守补洞还是换抠图模型。

验收

  • 构造一组背景带渐变/噪点、且主体内部有洞的样本,确认修复后洞被填上而腿间空隙不被填实(后者是既有测试已覆盖的回归点,不能破)。
  • 成色账本里能读到"本次生成的背景是否被判为纯色"。

相关

_fill_enclosed_holes 的 docstring 记着一条实测教训:只按连通性判会把两腿之间填实(迈步相里两只靴子交叠,把腿间空隙封成不与边界连通的区域)。任何改动都要保住这条。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions