withoutBG Open Weights (ONNX)
Open-source background removal and alpha matting from RGB images, exported as an ONNX bundle for ONNX Runtime. No PyTorch checkpoints are needed at inference time.
A trained router looks at each image and picks the branch suited to it:
- Fine strands, soft detail, transparency → the withoutBG matting model (Depth Anything V2 small depth + ConvNeXt-fused matting), trained and maintained by withoutBG.
- Hard opaque objects, flat scenes, vehicles → BiRefNet segmentation.
Only the selected branch runs, and its alpha is upsampled to the image's native resolution. The open-weights release ships no edge refiner; refined edges are part of the Cloud API.
- Try it live: withoutBG on Hugging Face Spaces
- Website: withoutbg.com/open-model
- Benchmarks: withoutbg.com/open-model/results
See the results
Open Weights results → · Cloud API results → · Compare →
Model details
| Field | Value |
|---|---|
| Variant | oss |
| Version | 10.8.0 |
| Pipeline | routed (sidecar schema 3) |
| Format | ONNX (opset 18), 3 graphs |
| Precision | fp32 |
| Max inference size | 4096 × 4096 (larger images are downscaled first) |
| Router | DINOv3 ConvNeXt base @ 448², 6 categories |
| Matting branch | DepthAnythingV2 vits (dav2s) @ 518² + ConvNeXtFusedMattingUNet @ 448² |
| BiRefNet branch | BiRefNet (general) @ 1024² |
| Size | ~1.5 GB total |
Files
Always distribute all four files together:
| File | Contents | Size |
|---|---|---|
withoutbg-open-weights-backbone.onnx |
Shared ConvNeXt backbone → router logits + features for matting | ~350 MB |
withoutbg-open-weights.onnx |
Matting branch: depth + ConvNeXt-fused matting (reuses backbone features) | ~104 MB |
birefnet-general.onnx |
BiRefNet branch | ~1.04 GB |
withoutbg-open-weights.onnx.json |
Sidecar: files, SHA256, input sizes and resize modes, router categories | — |
Read the sidecar first. It is the authoritative source for every graph's file name,
SHA256, input/output names, input size and interpolation, the router categories, and
which of them route to BiRefNet (birefnet_categories).
Pipeline
All graph inputs are float32 RGB in [0, 1], NCHW, and a square stretch of the
whole working image (no letterbox, no padding).
| Graph | Inputs | Output |
|---|---|---|
backbone (router) |
rgb_matting [1, 3, 448, 448] (bilinear, no antialias) |
route_logits [1, 6], f0–f3 |
matting (coarse) |
rgb_depth [1, 3, 518, 518] (bicubic, antialias), rgb_matting (same as backbone), f0–f3 |
coarse_alpha [1, 1, 448, 448] |
BiRefNet (birefnet) |
rgb [1, 3, 1024, 1024] (bilinear, no antialias) |
alpha [1, 1, 1024, 1024] |
- Convert to RGB. If the image exceeds
max_inference_size, downscale it to fit (keeping aspect ratio). This is the working image. - Run the backbone. The category is the argmax of
route_logitsovercategories. - If the category is in
birefnet_categories(hard_opaque,flat_scene,vehicle), run BiRefNet. Otherwise run the matting graph with the backbone'sf0–f3. - Upsample the branch alpha bilinearly (
align_corners=False) to the working size and clamp to[0, 1]. Resize to the original size if step 1 downscaled.
Bilinear resizes match PyTorch F.interpolate(mode="bilinear", align_corners=False)
without antialiasing. The bicubic depth input matches PyTorch with antialias=True, which
PIL reproduces on float ("F" mode) channels.
Download
hf download withoutbg/withoutbg-openweights-onnx --local-dir withoutbg-open-weights
Or in Python:
from huggingface_hub import snapshot_download
bundle = snapshot_download(
repo_id="withoutbg/withoutbg-openweights-onnx",
allow_patterns=["*.onnx", "*.onnx.json"],
)
Usage
The reference host is RoutedPipeline in
withoutbg-inference. It verifies
every file's SHA256 and runs the pipeline above:
import json
from pathlib import Path
from PIL import Image
from withoutbg_openweights.edge_pipeline import RoutedPipeline
bundle = Path("withoutbg-open-weights")
sidecar = json.loads((bundle / "withoutbg-open-weights.onnx.json").read_text())
pipeline = RoutedPipeline(sidecar, bundle, providers=["CPUExecutionProvider"])
image = Image.open("input.jpg").convert("RGB")
matte, route = pipeline.estimate_alpha_with_route(image) # route: {"category", "pipeline"}
image.putalpha(matte)
image.save("output.png")
Standalone, with only numpy, pillow and onnxruntime (run from the bundle folder):
import json
from pathlib import Path
import numpy as np
import onnxruntime as ort
from PIL import Image
bundle = Path(".") # folder holding the four files
sidecar = json.loads((bundle / "withoutbg-open-weights.onnx.json").read_text())
providers = ["CPUExecutionProvider"]
sessions = {
name: ort.InferenceSession(str(bundle / sidecar[name]["file"]), providers=providers)
for name in ("router", "coarse", "birefnet")
}
def bilinear(x, height, width):
"""(C, H, W) -> (C, height, width); torch bilinear, align_corners=False, no antialias."""
def axis(src, dst):
pos = np.maximum((np.arange(dst) + 0.5) * (src / dst) - 0.5, 0.0)
i0 = pos.astype(np.int64)
return i0, np.minimum(i0 + 1, src - 1), (pos - i0).astype(np.float32)
_, h, w = x.shape
r0, r1, rl = axis(h, height)
c0, c1, cl = axis(w, width)
rows = x[:, r0] * (1 - rl)[:, None] + x[:, r1] * rl[:, None]
return rows[:, :, c0] * (1 - cl) + rows[:, :, c1] * cl
def feed(rgb, spec):
"""Square-stretch native (H, W, 3) float RGB as each graph input's spec says."""
feeds = {}
for name, s in spec["inputs"].items():
if s["interpolation"] == "bicubic": # antialiased; PIL "F" mode matches torch
x = np.stack([np.asarray(Image.fromarray(np.ascontiguousarray(rgb[..., c]))
.resize((s["size"],) * 2, Image.Resampling.BICUBIC))
for c in range(3)])
else:
x = bilinear(np.ascontiguousarray(rgb.transpose(2, 0, 1)), s["size"], s["size"])
feeds[name] = np.ascontiguousarray(x[None], dtype=np.float32)
return feeds
image = Image.open("input.jpg").convert("RGB")
w, h = image.size
max_w, max_h = sidecar["max_inference_size"]
if w > max_w:
w, h = max_w, int(max_w / (image.width / image.height))
if h > max_h:
w, h = int(max_h * (image.width / image.height)), max_h
work = image.resize((w, h)) if (w, h) != image.size else image
rgb = np.asarray(work, dtype=np.float32) / 255.0
# 1. Route: shared ConvNeXt backbone -> category logits + features.
router = sidecar["router"]
router_feeds = feed(rgb, router)
logits, *feats = sessions["router"].run([router["logits_name"], *router["feature_names"]], router_feeds)
category = router["categories"][int(np.argmax(logits[0]))]
# 2. Run only the selected branch.
if category in router["birefnet_categories"]:
spec = sidecar["birefnet"]
alpha = sessions["birefnet"].run([spec["output_name"]], feed(rgb, spec))[0][0]
else:
spec = sidecar["coarse"]
feeds = {**router_feeds, **feed(rgb, {"inputs": {"rgb_depth": spec["inputs"]["rgb_depth"]}})}
feeds.update(zip(spec["feature_names"], feats))
alpha = sessions["coarse"].run([spec["output_name"]], feeds)[0][0]
# 3. Upsample to the working size, then to the original size.
alpha = np.clip(bilinear(alpha, h, w), 0.0, 1.0)[0]
matte = Image.fromarray(np.clip(alpha * 255.0 + 0.5, 0, 255).astype(np.uint8))
matte = matte.resize(image.size, Image.Resampling.BILINEAR)
out = image.copy()
out.putalpha(matte)
out.save("output.png")
print(category, "->", "birefnet" if category in router["birefnet_categories"] else "matting")
Runtime dependencies
python >=3.10
numpy
pillow
onnxruntime
For Hugging Face downloads, also install huggingface_hub.
More than weights
This repo hosts the ONNX weights. Same open-weights technology powers ready-made surfaces:
| Surface | Choose when |
|---|---|
| Python package | You want to embed withoutBG in scripts, notebooks, or backends |
| Docker / self-host | You want an HTTP API or browser UI on your own server (CPU or NVIDIA GPU) |
| Mac app | You want a native desktop cutout tool, with an optional Local API for plugins and scripts |
| GIMP plugin | You edit in GIMP 3 and want a private, mask-first workflow via Mac Local API or Docker |
| Space | You want to try a browser demo |
| Cloud API | You need maximum quality without running inference yourself |
License
The withoutBG Open Weights model is distributed under the withoutBG Open Weights license. See LICENSE and withoutbg.com/open-model/license.
Built with DINOv3.
Third-party terms
This bundle includes upstream components under their respective licenses. See THIRD_PARTY_NOTICES.md.
| Component | Used in | License |
|---|---|---|
| DINOv3 | Router backbone, matting | DINOv3 License |
| Depth Anything V2 (small) | Matting branch depth | Apache-2.0 |
| BiRefNet (ZhengPeng7) | birefnet-general.onnx |
MIT |


