Skip to content

U2Net 图片去背景原理 ​

本文介绍 U2Net 用于图片去背景的基本原理,帮助理解后续 Java + ONNX Runtime 服务中的预处理、推理、mask 后处理和 PNG alpha 合成。


一、去背景本质 ​

图片去背景不是简单地按颜色删除背景。真实图片中,主体和背景可能有相近颜色,例如:

  • 白衣服和白墙
  • 黑色头发和暗背景
  • 商品阴影和桌面
  • 半透明玻璃、发丝、毛发边缘

因此去背景通常会被建模为图像分割问题:模型判断每个像素属于前景主体还是背景。

模型输出的不是一张已经透明的图片,而是一张灰度 mask:

text
白色:前景主体
黑色:背景
灰色:半透明边缘或不确定区域

最终透明 PNG 的 alpha 通道来自这张 mask。


二、U2Net 是什么 ​

U2Net 是一种显著性目标检测模型,常用于 Salient Object Detection,也就是从图片中找出最显著的主体区域。

在去背景场景中,可以把 U2Net 理解为:

text
输入:RGB 图片
输出:每个像素属于主体的概率

输出值通常是 0 到 1 之间的浮点数:

text
0.0  接近背景
1.0  接近主体
0.5  边缘、阴影、半透明、不确定区域

将这个概率图转换为 0 到 255 的灰度图后,就可以作为 PNG 的 alpha 通道。


三、U2Net 名字含义 ​

U2Net 的名字来自 U-square Net,可以理解为“U 中套 U”。

传统 U-Net 是一个编码器-解码器结构:

text
输入图片
  ↓
编码器:逐步下采样,提取高级语义
  ↓
解码器:逐步上采样,恢复空间分辨率
  ↓
输出分割图

U2Net 在这个基础上引入了 RSU 模块,即 Residual U-block。每个 RSU 模块内部又是一个小型 U-Net,因此整体结构像是:

text
外层是 U-Net
每个阶段内部还是 U-Net

这种结构可以在不依赖特别深 backbone 的情况下,同时捕获:

  • 局部细节,例如边缘、发丝、轮廓
  • 全局语义,例如图片中哪个区域是主体
  • 多尺度信息,例如大主体和小主体

四、为什么适合去背景 ​

去背景最难的是边缘区域,而不是主体中间区域。

主体中间通常比较容易判断:

text
人物脸部、衣服、商品中心区域 → 前景概率高
天空、墙面、桌面远离主体部分 → 背景概率低

困难区域通常是:

  • 头发边缘
  • 动物毛发
  • 商品阴影
  • 透明或半透明物体
  • 主体和背景颜色接近的位置

U2Net 的多尺度结构可以同时看局部纹理和整体语义,因此比按颜色、边缘检测、传统阈值分割更适合做通用主体抠图。


五、ONNX 推理输入 ​

常见的 U2Net ONNX 模型输入尺寸是:

text
1 x 3 x 320 x 320

含义:

text
1    batch size
3    RGB 三个通道
320  输入高度
320  输入宽度

Java 服务中通常需要做以下预处理:

text
原图
  ↓
resize 到 320x320
  ↓
转为 RGB
  ↓
像素归一化到 0~1
  ↓
按 ImageNet mean/std 标准化
  ↓
HWC 转 CHW
  ↓
封装为 OnnxTensor

示例归一化参数:

java
private static final float[] MEAN = { 0.485f, 0.456f, 0.406f };
private static final float[] STD = { 0.229f, 0.224f, 0.225f };

CHW 排列是模型常见输入格式:

text
R 通道所有像素
G 通道所有像素
B 通道所有像素

而不是图片常见的 HWC 排列:

text
第 1 个像素 RGB
第 2 个像素 RGB
第 3 个像素 RGB

六、ONNX 推理输出 ​

U2Net 通常会输出一张或多张预测图。服务端只需要取第一张主要输出作为 mask。

常见输出形状类似:

text
1 x 1 x 320 x 320

含义:

text
1    batch size
1    单通道 mask
320  mask 高度
320  mask 宽度

Java 中常见取法:

java
if (value instanceof float[][][][] output4d) {
  return output4d[0][0];
}

得到的是:

text
float[320][320]

每个值表示对应位置属于前景的概率。


七、为什么要归一化 mask ​

模型输出值不一定刚好落在 0 到 1 的完整范围内。为了稳定生成 alpha,通常会做 min-max 归一化:

text
normalized = (value - min) / (max - min)

处理后:

text
最暗位置 → 0
最亮位置 → 1
中间值   → 0~1

再转换为 8 位灰度:

text
alpha = normalized * 255

如果不做归一化,可能出现:

  • 背景没有完全透明
  • 主体整体偏透明
  • 不同图片输出强度不稳定

八、从 mask 到透明 PNG ​

U2Net 输出的是 320x320 mask,但原图可能是 1920x1080、800x600 或其他尺寸。因此需要将 mask 缩放回原图大小:

text
mask 320x320
  ↓
resize 到 原图宽高
  ↓
作为 alpha 通道

合成透明 PNG 时,每个像素执行:

text
输出 RGB = 原图 RGB
输出 A   = mask 灰度值

Java 中可以理解为:

java
int rgb = source.getRGB(x, y);
int alpha = alphaMask.getRaster().getSample(x, y, 0);
result.setRGB(x, y, (alpha << 24) | (rgb & 0x00ffffff));

最终必须保存为 PNG:

text
PNG 支持 alpha
JPG 不支持 alpha

九、和 rembg 的关系 ​

rembg 默认也可以使用 U2Net 类模型进行前景分割,并通过 ONNX Runtime 执行推理。Java 版实现的核心思想与 rembg 类似:

text
读取图片
  ↓
模型预测 mask
  ↓
mask 写入 alpha
  ↓
输出透明 PNG

区别在于:

  • rembg 是 Python 生态,封装了 CLI、HTTP API、模型下载、alpha matting 等能力
  • Java 服务需要自己实现图片预处理、ONNX 推理、mask 后处理和 HTTP 接口
  • Java 服务更适合直接集成到 Java 后端、tio-boot 网关或现有 JVM 服务中

十、局限性 ​

基础 U2Net 去背景不是万能的,常见问题包括:

  • 发丝边缘不够细
  • 毛发边缘可能粘连背景
  • 透明物体效果一般
  • 阴影可能被当成主体
  • 多主体图片中可能保留所有显著主体

如果需要更好的边缘效果,可以在 mask 后处理阶段增加:

  • blur 平滑边缘
  • erode/dilate 调整前景范围
  • guided filter 优化 alpha
  • alpha matting 处理发丝和半透明边缘

如果需要更高质量主体分割,也可以尝试 IS-Net、BiRefNet 等模型。


十一、总结 ​

U2Net 去背景的核心不是“删除某种颜色”,而是:

text
用神经网络预测前景概率图
再把概率图作为 PNG alpha 通道

理解这个流程后,Java 实现就可以拆成四个明确步骤:

text
预处理图片 → ONNX 推理 → mask 后处理 → alpha 合成

下一篇文档将基于这个原理,介绍如何使用 tio-boot 搭建 U2Net 去背景 HTTP 服务。

MIT Licensed