U2Net 图片去背景原理
本文介绍 U2Net 用于图片去背景的基本原理,帮助理解后续 Java + ONNX Runtime 服务中的预处理、推理、mask 后处理和 PNG alpha 合成。
一、去背景本质
图片去背景不是简单地按颜色删除背景。真实图片中,主体和背景可能有相近颜色,例如:
- 白衣服和白墙
- 黑色头发和暗背景
- 商品阴影和桌面
- 半透明玻璃、发丝、毛发边缘
因此去背景通常会被建模为图像分割问题:模型判断每个像素属于前景主体还是背景。
模型输出的不是一张已经透明的图片,而是一张灰度 mask:
白色:前景主体
黑色:背景
灰色:半透明边缘或不确定区域
最终透明 PNG 的 alpha 通道来自这张 mask。
二、U2Net 是什么
U2Net 是一种显著性目标检测模型,常用于 Salient Object Detection,也就是从图片中找出最显著的主体区域。
在去背景场景中,可以把 U2Net 理解为:
输入:RGB 图片
输出:每个像素属于主体的概率
输出值通常是 0 到 1 之间的浮点数:
0.0 接近背景
1.0 接近主体
0.5 边缘、阴影、半透明、不确定区域
将这个概率图转换为 0 到 255 的灰度图后,就可以作为 PNG 的 alpha 通道。
三、U2Net 名字含义
U2Net 的名字来自 U-square Net,可以理解为“U 中套 U”。
传统 U-Net 是一个编码器-解码器结构:
输入图片
↓
编码器:逐步下采样,提取高级语义
↓
解码器:逐步上采样,恢复空间分辨率
↓
输出分割图
U2Net 在这个基础上引入了 RSU 模块,即 Residual U-block。每个 RSU 模块内部又是一个小型 U-Net,因此整体结构像是:
外层是 U-Net
每个阶段内部还是 U-Net
这种结构可以在不依赖特别深 backbone 的情况下,同时捕获:
- 局部细节,例如边缘、发丝、轮廓
- 全局语义,例如图片中哪个区域是主体
- 多尺度信息,例如大主体和小主体
四、为什么适合去背景
去背景最难的是边缘区域,而不是主体中间区域。
主体中间通常比较容易判断:
人物脸部、衣服、商品中心区域 → 前景概率高
天空、墙面、桌面远离主体部分 → 背景概率低
困难区域通常是:
- 头发边缘
- 动物毛发
- 商品阴影
- 透明或半透明物体
- 主体和背景颜色接近的位置
U2Net 的多尺度结构可以同时看局部纹理和整体语义,因此比按颜色、边缘检测、传统阈值分割更适合做通用主体抠图。
五、ONNX 推理输入
常见的 U2Net ONNX 模型输入尺寸是:
1 x 3 x 320 x 320
含义:
1 batch size
3 RGB 三个通道
320 输入高度
320 输入宽度
Java 服务中通常需要做以下预处理:
原图
↓
resize 到 320x320
↓
转为 RGB
↓
像素归一化到 0~1
↓
按 ImageNet mean/std 标准化
↓
HWC 转 CHW
↓
封装为 OnnxTensor
示例归一化参数:
private static final float[] MEAN = { 0.485f, 0.456f, 0.406f };
private static final float[] STD = { 0.229f, 0.224f, 0.225f };
CHW 排列是模型常见输入格式:
R 通道所有像素
G 通道所有像素
B 通道所有像素
而不是图片常见的 HWC 排列:
第 1 个像素 RGB
第 2 个像素 RGB
第 3 个像素 RGB
六、ONNX 推理输出
U2Net 通常会输出一张或多张预测图。服务端只需要取第一张主要输出作为 mask。
常见输出形状类似:
1 x 1 x 320 x 320
含义:
1 batch size
1 单通道 mask
320 mask 高度
320 mask 宽度
Java 中常见取法:
if (value instanceof float[][][][] output4d) {
return output4d[0][0];
}
得到的是:
float[320][320]
每个值表示对应位置属于前景的概率。
七、为什么要归一化 mask
模型输出值不一定刚好落在 0 到 1 的完整范围内。为了稳定生成 alpha,通常会做 min-max 归一化:
normalized = (value - min) / (max - min)
处理后:
最暗位置 → 0
最亮位置 → 1
中间值 → 0~1
再转换为 8 位灰度:
alpha = normalized * 255
如果不做归一化,可能出现:
- 背景没有完全透明
- 主体整体偏透明
- 不同图片输出强度不稳定
八、从 mask 到透明 PNG
U2Net 输出的是 320x320 mask,但原图可能是 1920x1080、800x600 或其他尺寸。因此需要将 mask 缩放回原图大小:
mask 320x320
↓
resize 到 原图宽高
↓
作为 alpha 通道
合成透明 PNG 时,每个像素执行:
输出 RGB = 原图 RGB
输出 A = mask 灰度值
Java 中可以理解为:
int rgb = source.getRGB(x, y);
int alpha = alphaMask.getRaster().getSample(x, y, 0);
result.setRGB(x, y, (alpha << 24) | (rgb & 0x00ffffff));
最终必须保存为 PNG:
PNG 支持 alpha
JPG 不支持 alpha
九、和 rembg 的关系
rembg 默认也可以使用 U2Net 类模型进行前景分割,并通过 ONNX Runtime 执行推理。Java 版实现的核心思想与 rembg 类似:
读取图片
↓
模型预测 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 去背景的核心不是“删除某种颜色”,而是:
用神经网络预测前景概率图
再把概率图作为 PNG alpha 通道
理解这个流程后,Java 实现就可以拆成四个明确步骤:
预处理图片 → ONNX 推理 → mask 后处理 → alpha 合成
下一篇文档将基于这个原理,介绍如何使用 tio-boot 搭建 U2Net 去背景 HTTP 服务。
