Wrap the BGfilter matting pipeline in a long-running FastAPI service (POST /remove-background, GET /healthz) exposing only screen_color and seg_model, matching the birefnet-service request contract. - bgfilter/pipeline.py: add in-memory run_rgb entry returning a MattingResult; allow injecting a shared runner/segmenter. CLI file path (run_image) behaviour is unchanged. - bgfilter/service.py: PipelineManager caches one shared ViTMatte runner and per-backend segmenters, so screen_color/seg_model never reload a model. - app.py: thin FastAPI layer -- param validation, image decode/encode, error codes (400/413/500), timing headers, global asyncio lock. - requirements.txt: fastapi, uvicorn[standard], python-multipart. - README + design doc: HTTP service usage and HF-mirror/proxy/Xet download notes. Verified end-to-end (base ViTMatte + BiRefNet + anime-seg): 11/11 acceptance checks pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
12 KiB
BGfilter 服务版设计与交付需求
本文档给接手实现服务化的 Agent 使用。目标是在 BGfilter-server 仓库内,把现有 BGfilter 抠图算法包装成一个可长期运行的 Python HTTP 服务,接口形态参考当前线上 birefnet-service,但算法仍使用本仓库的 BGfilter 管线。
目标
新增一个服务入口,使调用方可以通过 HTTP 上传图片并得到透明背景 PNG。
服务首版只暴露两个业务参数:
screen_color:可选。背景色先验,格式为#RRGGBB。不传或空值时沿用 BGfilter 默认行为,从图片边框自动检测纯色背景。seg_model:可选。分割模型选择,允许值为birefnet或anime-seg。不传时使用仓库当前默认值birefnet。
其它算法参数首版不要暴露为 HTTP 参数,直接使用当前默认配置:
trimap.mode = directionaldespill.enabled = truemodel.matting_method = vitmattemodel.model_name = hustvl/vitmatte-base-composition-1kmodel.device = cpusegmentation.device = cpusegmentation.input_size = 1024
非目标
- 不把 BGfilter 算法移植到 Rust。
- 不在 HTTP 接口里暴露
trimap_mode、despill、阈值、设备、模型权重名等高级参数。 - 不复用当前线上
birefnet-service的简单 alpha 直出算法;seg_model=birefnet在本服务中只表示 BGfilter 管线里的语义分割后端。 - 不在每次请求里加载并释放模型。
- 不要求首版支持批量图片。
现有算法边界
BGfilter 当前核心入口在:
bgfilter/pipeline.pybgfilter/settings.pybgfilter/config.pybgfilter/segmentation.pybgfilter/vitmatte_infer.py
完整管线是:
输入 RGB
-> 背景色自动检测或使用 screen_color
-> chroma 背景置信度
-> 可选语义分割 mask,默认开启
-> trimap 生成,默认 directional
-> ViTMatte 预测 alpha
-> trimap 强约束
-> chroma-guided alpha suppression
-> alpha 小连通域/孔洞清理
-> pymatting foreground estimation
-> despill 去背景色溢色
-> 输出 RGBA PNG
当前默认分割后端已经是:
segmentation.backend = birefnet
segmentation.model_name = ZhengPeng7/BiRefNet
anime-seg 对应权重为:
segmentation.backend = anime-seg
segmentation.model_name = skytnt/anime-seg
bgfilter/config.py 里已有 _SEG_MODELS 和 override_settings(..., seg_backend=...),服务层应复用这套映射,不要让 HTTP 调用方传 model_name。
HTTP 接口契约
GET /healthz
返回 JSON,用于进程存活和基础配置检查。
建议响应:
{
"ok": true,
"service": "bgfilter",
"version": "0.1.0",
"defaultSegModel": "birefnet",
"device": "cpu"
}
POST /remove-background
请求类型:
multipart/form-data
字段:
file: UploadFile, required
screen_color: string, optional, "#RRGGBB"
seg_model: string, optional, "birefnet" | "anime-seg"
响应:
200 image/png
响应体是透明背景 PNG。建议附带诊断 header:
X-BGFilter-Elapsed-Ms: 总耗时毫秒
X-BGFilter-Seg-Model: 实际使用的 seg_model
X-BGFilter-Screen-Color: 实际请求传入的 screen_color,未传可省略或设为 auto
错误码建议:
400 empty image
400 invalid image
400 invalid screen_color
400 invalid seg_model
413 image too large
500 inference failed
为兼容现有 Rust 调用方,file 字段名必须保持为 file。
参数默认与校验
screen_color:
- 允许省略、空字符串、
null等价于自动检测。 - 非空时必须匹配
#RRGGBB。 - 大小写都可以,内部可以统一为大写或小写。
- 校验失败返回
400 invalid screen_color。
seg_model:
- 允许省略,默认
birefnet。 - 允许值只包括
birefnet、anime-seg。 - 可以兼容内部命名
seg_backend,但 HTTP 对外字段用seg_model。 - 校验失败返回
400 invalid seg_model。
MAX_IMAGE_PIXELS:
- 建议参考线上
birefnet-service,通过环境变量控制,例如BGFILTER_MAX_IMAGE_PIXELS。 - 默认建议先设为
4194304,即约 4MP。 - 超限返回
413 image too large。
模型加载与缓存要求
服务必须做到模型只加载一次或按后端首次懒加载一次,不能每次请求都重新加载模型。
现有 MattingPipeline 已经有实例级懒加载:
self._runner缓存ViTMatteRunnerself._segmenter缓存当前 settings 下的 segmenter
但如果每次请求新建 MattingPipeline(settings),缓存会失效。因此服务版需要持有长期对象。
推荐实现一个 PipelineManager 或等价对象:
长期缓存:
ViTMatteRunner: 按 model_name + device + matting_method 缓存
Segmenter: 按 backend + model_name + device + input_size 缓存
请求级参数:
screen_color: 只影响本次 chroma/despill,不影响模型缓存
seg_model: 选择对应 segmenter;首次使用某后端时加载,之后复用
推荐行为:
服务启动:
可预加载默认 birefnet + ViTMatte,也可懒加载。
第一次 seg_model=birefnet:
加载 BiRefNet segmenter 和 ViTMatte。
后续 seg_model=birefnet:
复用已有 BiRefNet segmenter 和 ViTMatte。
第一次 seg_model=anime-seg:
加载 AnimeSeg segmenter,ViTMatte 继续复用。
后续 seg_model=anime-seg:
复用已有 AnimeSeg segmenter 和 ViTMatte。
可接受的首版简化方案:
- 长期缓存两个
MattingPipeline实例:一个birefnet,一个anime-seg。 - 每个实例内部复用自己的
_runner和_segmenter。 - 如果这样做导致 ViTMatte 被加载两次,应优先改为共享
ViTMatteRunner,因为 ViTMatte 是两条分割后端共同使用的 matting 模型。
更推荐的实现是把 MattingPipeline 改造成可以注入共享 runner/segmenter,或新增服务专用 pipeline runner,避免重复加载 ViTMatte。
并发控制
首版建议采用全局 asyncio.Lock,与当前线上 birefnet-service 类似,保证同一进程内一次只跑一个推理请求。
原因:
- BGfilter 管线包含 ViTMatte、segmenter、pymatting、OpenCV/NumPy 后处理,CPU 和内存压力较大。
- CPU 默认部署时并发推理容易放大延迟和内存。
- 后续确认资源充足后,再考虑按模型或设备拆锁。
如果使用 Uvicorn 多 worker,每个 worker 都会各自加载一份模型,内存会成倍增长。首版建议 --workers 1。
内存入口改造建议
当前 MattingPipeline.run_image(...) 主要面向 CLI 文件输入输出。服务可以先用临时文件桥接,但更推荐新增内存入口,减少磁盘 IO 和临时文件清理风险。
推荐新增内部函数:
run_rgb(rgb: np.ndarray, settings: PipelineSettings, resources/cache) -> result
返回:
corrected_rgb: np.ndarray uint8 HxWx3
alpha: np.ndarray float32 HxW, 0..1
metadata: dict
服务层再把它编码成 PNG:
RGBA = corrected_rgb + alpha
PIL.Image.save(..., format="PNG")
如果首版为了速度使用临时文件:
- 临时目录应使用
tempfile.TemporaryDirectory()。 - 文件名不要使用上传原始文件名。
- 请求结束必须清理。
- 不要把 debug 输出默认打开。
推荐文件结构
可以参考线上 birefnet-service 的简洁形态,在仓库根目录新增:
app.py
requirements.txt
也可以新增:
bgfilter/service.py
用于放 PipelineManager 和内存运行逻辑。app.py 保持薄入口。
推荐分层:
app.py
FastAPI 路由、参数校验、图片 decode/encode、错误码、计时、锁
bgfilter/service.py
PipelineManager、模型缓存、按请求组装 settings、调用算法管线
bgfilter/pipeline.py
尽量保留原 CLI 兼容行为;必要时新增 run_rgb
依赖
现有算法依赖保留。服务化需要补充:
fastapi
uvicorn[standard]
python-multipart
现有 requirements.txt 中已经有:
opencv-python
pillow
numpy
scipy
scikit-image
pymatting
torch
torchvision
transformers
accelerate
safetensors
huggingface_hub
timm
einops
kornia
onnxruntime
tqdm
typer
rich
PyYAML
如果部署在无 GUI Linux 服务器,opencv-python-headless 通常比 opencv-python 更合适,但替换前需要确认现有本地脚本是否依赖 GUI 能力。
环境变量
建议支持:
BGFILTER_CONFIG=configs/default.yaml
BGFILTER_DEVICE=cpu
BGFILTER_MAX_IMAGE_PIXELS=4194304
BGFILTER_PRELOAD=1
HF_HOME=/opt/genarrative-image-host/model-cache/hf
HF_HUB_OFFLINE=1
TRANSFORMERS_OFFLINE=1
OMP_NUM_THREADS=4
MKL_NUM_THREADS=4
BGFILTER_DEVICE 应同时覆盖:
settings.model.devicesettings.segmentation.device
如果机器没有 GPU,默认保持 cpu。
systemd 部署参考
参考当前线上 genarrative-birefnet.service,可以新增:
[Unit]
Description=Genarrative BGfilter background removal service
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/genarrative-image-host/bgfilter-service
Environment=HF_HOME=/opt/genarrative-image-host/model-cache/hf
Environment=HF_HUB_OFFLINE=1
Environment=TRANSFORMERS_OFFLINE=1
Environment=BGFILTER_CONFIG=configs/default.yaml
Environment=BGFILTER_DEVICE=cpu
Environment=BGFILTER_MAX_IMAGE_PIXELS=4194304
Environment=BGFILTER_PRELOAD=1
Environment=OMP_NUM_THREADS=4
Environment=MKL_NUM_THREADS=4
ExecStart=/opt/genarrative-image-host/bgfilter-service/.venv/bin/uvicorn app:app --host 127.0.0.1 --port 18083 --workers 1
Restart=on-failure
RestartSec=5
MemoryMax=8G
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ReadWritePaths=/opt/genarrative-image-host
[Install]
WantedBy=multi-user.target
端口只是建议值。真正接入时由部署方决定。
调用示例
默认参数:
curl -sS \
-F "file=@input.png" \
http://127.0.0.1:18083/remove-background \
-o output.png
指定背景色:
curl -sS \
-F "file=@input.png" \
-F "screen_color=#CFEFFF" \
http://127.0.0.1:18083/remove-background \
-o output.png
切换 Anime Seg:
curl -sS \
-F "file=@input.png" \
-F "seg_model=anime-seg" \
http://127.0.0.1:18083/remove-background \
-o output.png
指定背景色并切换 Anime Seg:
curl -sS \
-F "file=@input.png" \
-F "screen_color=#CFEFFF" \
-F "seg_model=anime-seg" \
http://127.0.0.1:18083/remove-background \
-o output.png
与 Genarrative Rust 服务的接入预期
当前 Genarrative Rust BFF 已有远端抠图调用边界:
POST {GENARRATIVE_EDITOR_BACKGROUND_REMOVAL_BASE_URL}/remove-background
multipart field: file
response: image/png
BGfilter 服务应保持同样的 POST /remove-background 和 file 字段名。Rust 侧后续只需要在 multipart 中追加可选文本字段:
screen_color
seg_model
如果 Rust 侧暂时不传新字段,本服务仍应可用,并按默认 birefnet + 自动背景色 执行。
验收要求
实现完成后至少验证:
GET /healthz返回200和 JSON。POST /remove-background只传file可返回image/png。screen_color=#CFEFFF可正常返回image/png。seg_model=birefnet可正常返回image/png。seg_model=anime-seg可正常返回image/png。- 非法
seg_model返回400。 - 非法
screen_color返回400。 - 空文件或非图片返回
400。 - 超过
BGFILTER_MAX_IMAGE_PIXELS的图片返回413。 - 同一进程连续请求同一
seg_model时不会重复加载对应模型。 - 从
birefnet切到anime-seg后,再切回birefnet,已加载模型可复用。 - Uvicorn
--workers 1下内存不随请求次数持续增长。
建议在日志中打印模型加载事件,但不要每个请求打印完整配置或文件内容。日志中不要输出用户上传图片数据。
完成定义
交付时应包含:
- 可运行的 FastAPI 服务入口。
- 更新后的依赖文件。
- 本地启动命令说明。
- 至少一组 curl 示例。
- 若新增内存入口,应保持原 CLI 文件入口不破坏。
- 若为了服务化调整 pipeline,应保证默认 CLI 行为仍按当前配置工作。
完成后,不看内部代码也应能通过本文档的 HTTP 契约和 curl 示例直接调用服务。