人物抠图 → 透明 PNG
何时用
用户给一张图(自拍、游戏截图、插画)说「抠出来」「去掉背景」「只放上半身」「换掉原来的头像」。 先不要手工画蒙版,也不要用 ImageGen 重绘(会改变人物样貌);走 rembg 分割 + 规则裁剪。
环境准备(只做一次)
python3 -m venv ~/.venvs/cutout
PY=~/.venvs/cutout/bin/python3 # 任意隔离 venv;不要装进系统 Python
$PY -m pip install rembg onnxruntime # 首次运行会自动下载 u2net.onnx(176MB,约 30s)
依赖装在隔离 venv 里,不要污染系统 Python。u2net 模型缓存在 ~/.rembg/models/,之后无需重下。
流程
- 分割:
remove(img, session=new_session('u2net'), alpha_matting=True, alpha_matting_foreground_threshold=240, alpha_matting_background_threshold=10, alpha_matting_erode_size=6)—— alpha_matting 能保住头发丝边缘。 - 多主体择一:画面里常有多个角色(人 + 宠物/同伴)。对 α 通道做
scipy.ndimage.label连通域,打印每块的area / bbox / h / w,取纵向跨度最大的一块 (人物通常最高);单像素噪点块直接忽略。 - 纵向宽度剖面:按身高 20 等分,打印每段的
width与fill,据此判断结构。 例:动森人物头占 0–45%、颈 45–55%、肩臂 55–75%、躯干到 100%。 真人比例不同,务必实际打印后再决定裁到哪。 - 裁上半身:从头顶取到身高的 N%(证件照一般取到胸下/手臂下方,约 0.75–0.8; 真人半身像常取 0.5–0.55)。
- 规整画布:缩放到目标框(如 480×600 = 4:5),底部对齐居中粘贴, 透明底。证件照/头像位底部对齐比居中更像照片。
看不到图时的自检(关键)
会话里如果读图被过滤,用 ASCII 把 α 通道打出来,30 行 × 40 字符足够判断轮廓对不对:
rows, cols = 30, 40
m = block.mean()/255
' ' if m<0.15 else '.' if m<0.4 else '*' if m<0.75 else '#'
看三件事:顶是不是头(上窄中宽)、脖子有没有收窄、底部是不是肩/手臂而不是被拦腰截断。 一眼看不出「人头 + 肩膀」就别交,回到第 3 步调比例。
落到前端
- PNG 放进
public/,用绝对路径/assets/...引用(Vite 静态资源)。 - 替换 SVG 头像组件时:
<img>加object-fit: contain, 再补filter: drop-shadow(...),抠图才不会像浮在纸上的贴纸。 - 被替换掉的 SVG 组件文件先留着别删,用户可能要回退。
坑
- vite
dev/build在沙箱里会因rm被拦截而失败(报emptyDir或loadCachedDepOptimizationMetadata)。重跑时放行沙箱即可,不是代码问题。 - rembg 首次跑的进度条会刷满屏,用
grep -v "%|"过滤输出。