nobg
Guides

Removing a background

The three levels of the API — process, predict, and the raw pipeline.

There are three ways to run a model, and they are the same pipeline at three levels of control.

process — no processor

from nobg import AutoModel

model = AutoModel.from_pretrained("feyninc/FeyNobg")
cutout = model.process("input.jpg")
cutout.save("output.png")

process builds the processor the model's own config implies (model.default_processor()), then delegates to predict. For BiRefNet that means the image size comes straight from config.image_size; for SAM3 it also resolves a CLIP tokenizer, which no config.json describes.

predict — your processor

from nobg import AutoProcessor

processor = AutoProcessor.from_pretrained("feyninc/FeyNobg")
cutout = model.predict(processor, "input.jpg")

The processor is the fixed piece of the call, so it comes first; the inputs that vary follow, in decreasing order of how often they are supplied: predict(processor, image, prompt, boxes). BiRefNet's signature stops at image — it takes neither a prompt nor boxes, and passing a third positional argument is a TypeError.

Use predict over process when you already hold a processor, or when a checkpoint's preprocessor_config.json disagrees with its config.image_size: process trusts the model config, predict trusts what you hand it.

What both accept

Prop

Type

Both run under torch.no_grad() in eval mode, on the model's own device and dtype, and restore training mode afterwards if the model was in it. Inputs are moved to match the model, so a CUDA half-precision model needs no manual .to() on the batch.

Already have a preprocessed batch?

predict takes raw images, not a BatchFeature. Passing one raises a TypeError — call the model directly with **inputs instead, as below.

The raw pipeline

When you need the intermediates — the matte itself, the auxiliary outputs, control over device placement:

import torch
from loadimg import load_img

image = load_img("input.jpg").convert("RGB")
inputs = processor(image, return_tensors="pt")

with torch.no_grad():
    outputs = model(pixel_values=inputs["pixel_values"])

alpha = processor.post_process_alpha_matting(
    outputs, target_sizes=[(image.height, image.width)]
)[0]
processor.cutout(image, alpha).save("output.png")

Four steps, and each is replaceable:

Preprocess. processor(images, return_tensors="pt") gives pixel_values of shape (B, 3, image_size, image_size): RGB convert, square bilinear resize, rescale to [0, 1], ImageNet normalization.

Forward. The model returns a dict with logits of shape (B, 1, H, W)raw logits, not sigmoided — plus whatever else that model produces (intermediate_logits for BiRefNet, the instance heads for SAM3).

Post-process. post_process_alpha_matting applies the sigmoid, then bilinearly resizes each matte to its target_sizes entry. Omit target_sizes to keep the model's own resolution. The result is a list of (H, W) tensors in [0, 1], one per image.

Composite. cutout(image, alpha) returns an RGBA image, resizing the matte to the image if the two disagree. Pass refine=True to remove halo fringing first.

Just the matte

If you are compositing yourself — onto a new background, into a video pipeline, as a mask for something else — skip the RGBA step:

alpha = model.process("input.jpg", return_type="alpha")   # (H, W) float tensor in [0, 1]

The returned tensors are on the CPU in float32, at each image's original resolution.

On this page