withoutBG Open Weights (ONNX)

Open-source background removal and alpha matting from RGB images. This repository hosts the OSS variant exported as a self-contained ONNX graph for ONNX Runtime.

The graph includes the full WBGNet pipeline β€” upstream encoders, matting head, and OSS refiner β€” so no PyTorch checkpoints are needed at inference time.

Model details

Field Value
Variant oss
Version 4.1.0
Format ONNX (opset 18)
Precision fp32
Max resolution 768
ONNX input tensor 1024 Γ— 1024 (fixed letterbox)
ONNX output tensor 768 Γ— 768
Transformer opt disabled
ORT offline opt extended
Size ~495 MB
SHA256 7873ec427ac6928bc91a3b6e1ddd32715a02d4b85836e78f0afacacee533b82f

Files

Always distribute the ONNX file and its sidecar JSON together:

  • withoutbg-open-weights.onnx β€” inference graph (WBGNet pipeline with OSS upstreams and refiner)
  • withoutbg-open-weights.onnx.json β€” sidecar metadata (I/O names, shapes, SHA256, canvas sizes)

Read the sidecar first. It is the authoritative source for canvas_size (ONNX input letterbox size), output_canvas_size (768 β€” the fixed alpha tensor size), refiner_canvas_size (768 β€” the effective max resolution), input/output names, precision, model version, and SHA256.

Architecture

The OSS variant uses smaller open-source-friendly upstream models:

  • Depth: DepthAnythingV2 vits
  • Foreground segmentation: DINOv3 vits16
  • Semantic: ISNet
  • Matting: shared with the API variant
  • Refiner: OSS refiner baked into the graph at 768px max resolution

The refiner runs inside the ONNX graph. Maximum output resolution is 768px β€” not 1024. Consumers letterbox to the fixed ONNX input tensor (canvas_size in the sidecar) and run a single inference session.

Input / output contract

Max resolution is 768px. Input letterboxing must match canvas_size (1024); the graph returns alpha at output_canvas_size (768). Detail refinement is capped at refiner_canvas_size (768).

The graph expects a letterboxed RGB tensor sized to canvas_size from the sidecar:

Name Shape Dtype Range
Input rgb [1, 3, 1024, 1024] float32 [0, 1], NCHW
Output alpha [1, 1, 768, 768] float32 [0, 1]

Preprocessing (required):

  1. Convert image to RGB.
  2. Read canvas_size from the sidecar (1024 for this export).
  3. Resize longest side to canvas_size, preserve aspect ratio.
  4. Paste at top-left on a black canvas_size Γ— canvas_size canvas.
  5. Normalize to float32 [0, 1], transpose HWC β†’ CHW, add batch dim.

Effective refinement is limited to 768px (refiner_canvas_size in the sidecar).

Postprocessing (required):

  1. Scale the resized image dimensions from canvas_size to output_canvas_size.
  2. Crop alpha to that region on the output tensor (top-left, before padding).
  3. Resize alpha back to the original image dimensions.
  4. Attach as PNG alpha channel for cutout output.

Download

from huggingface_hub import hf_hub_download

model_path = hf_hub_download(
    repo_id="withoutbg/withoutbg-openweights-onnx",
    filename="withoutbg-open-weights.onnx",
)
sidecar_path = hf_hub_download(
    repo_id="withoutbg/withoutbg-openweights-onnx",
    filename="withoutbg-open-weights.onnx.json",
)

Or with the CLI:

hf download withoutbg/withoutbg-openweights-onnx \
  withoutbg-open-weights.onnx \
  withoutbg-open-weights.onnx.json

Usage

from pathlib import Path
import json
import numpy as np
import onnxruntime as ort
from PIL import Image

model_path = Path("withoutbg-open-weights.onnx")
sidecar = json.loads(model_path.with_suffix(model_path.suffix + ".json").read_text())
canvas = sidecar.get("canvas_size", 1024)
output_canvas = sidecar.get("output_canvas_size", sidecar["output_shape"][2])
input_name = sidecar.get("input_name", "rgb")

session = ort.InferenceSession(str(model_path), providers=["CPUExecutionProvider"])

image = Image.open("input.jpg").convert("RGB")
orig_w, orig_h = image.size
scale = canvas / max(orig_w, orig_h)
new_w = max(1, round(orig_w * scale))
new_h = max(1, round(orig_h * scale))

resized = image.resize((new_w, new_h), Image.Resampling.BILINEAR)
padded = Image.new("RGB", (canvas, canvas), (0, 0, 0))
padded.paste(resized, (0, 0))

rgb = np.asarray(padded, dtype=np.float32) / 255.0
rgb = np.transpose(rgb, (2, 0, 1))[None, ...]

alpha_canvas = session.run(None, {input_name: rgb})[0][0, 0]
crop_h = max(1, round(new_h * output_canvas / canvas))
crop_w = max(1, round(new_w * output_canvas / canvas))
alpha_crop = alpha_canvas[:crop_h, :crop_w]
alpha_u8 = np.clip(alpha_crop * 255.0, 0, 255).astype(np.uint8)
alpha = Image.fromarray(alpha_u8, "L").resize((orig_w, orig_h), Image.Resampling.BILINEAR)

out = image.copy()
out.putalpha(alpha)
out.save("output.png")

Runtime dependencies

python >=3.11
numpy
pillow
onnxruntime

For Hugging Face downloads, also install huggingface_hub.

License

Apache-2.0 β€” see withoutbg.com/open-weights-model/license.

Third-party terms

This model uses DINOv3 as an upstream component. See the DINOv3 license.

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