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.

See the results

Example 1 Example 2 Example 3

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]
  1. Convert to RGB. If the image exceeds max_inference_size, downscale it to fit (keeping aspect ratio). This is the working image.
  2. Run the backbone. The category is the argmax of route_logits over categories.
  3. If the category is in birefnet_categories (hard_opaque, flat_scene, vehicle), run BiRefNet. Otherwise run the matting graph with the backbone's f0–f3.
  4. 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

Links

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Space using withoutbg/withoutbg-openweights-onnx 1