Skip to content

Batch background removal with rembg and multiprocessing

pattern

Designers manually removing backgrounds from hundreds of product images using trace tools

pythonrembghuggingfaceimage-processingbackground-removal
20 views

Problem

Design teams manually trace and remove backgrounds from product images using Photoshop or Figma tools. For catalogs with hundreds of images, this takes days of tedious work. Cloud APIs (remove.bg, Canva) charge per image and require uploading potentially sensitive content. You need a fast, free, local solution that runs on CPU with no API keys.

Solution

Single-file Python script using PEP 723 inline dependencies:

# /// script
# requires-python = ">=3.10"
# dependencies = ["rembg[cpu]", "Pillow"]
# ///

"""Batch background removal using rembg (HuggingFace U2-Net model)."""

import argparse
import sys
from multiprocessing import Pool, cpu_count
from pathlib import Path

from PIL import Image
from rembg import remove, new_session

SUPPORTED = {".jpg", ".jpeg", ".png", ".webp", ".bmp"}


def process_image(args: tuple[Path, Path, str]) -> str:
    input_path, output_dir, model = args
    try:
        session = new_session(model)
        img = Image.open(input_path)
        result = remove(img, session=session)

        out_path = output_dir / f"{input_path.stem}.png"
        result.save(out_path)
        return f"OK: {input_path.name}"
    except Exception as e:
        return f"FAIL: {input_path.name} ({e})"


def main():
    parser = argparse.ArgumentParser(description="Batch background removal")
    parser.add_argument("input_dir", type=Path, help="Directory of input images")
    parser.add_argument("output_dir", type=Path, help="Directory for output PNGs")
    parser.add_argument("--model", default="u2net", choices=["u2net", "u2netp", "isnet-general-use"],
                        help="Model to use (u2netp is faster, isnet-general-use is higher quality)")
    parser.add_argument("--workers", type=int, default=max(1, cpu_count() - 1),
                        help="Number of parallel workers")
    args = parser.parse_args()

    args.output_dir.mkdir(parents=True, exist_ok=True)

    files = [f for f in args.input_dir.iterdir() if f.suffix.lower() in SUPPORTED]
    if not files:
        print(f"No supported images found in {args.input_dir}")
        sys.exit(1)

    print(f"Processing {len(files)} images with {args.workers} workers using {args.model}...")

    tasks = [(f, args.output_dir, args.model) for f in files]
    with Pool(args.workers) as pool:
        for result in pool.imap_unordered(process_image, tasks):
            print(result)

    print("Done!")


if __name__ == "__main__":
    main()

Run it:

# With uv (reads inline dependencies automatically)
uv run rembg_batch.py ./product-photos ./transparent-output

# Faster model for quick previews
uv run rembg_batch.py ./photos ./output --model u2netp --workers 8

# Higher quality model for final output
uv run rembg_batch.py ./photos ./output --model isnet-general-use

The first run downloads a 170MB model from HuggingFace. Subsequent runs use the cached model.

Why It Works

rembg wraps HuggingFace's U2-Net segmentation model, which runs inference entirely on the local CPU with no API calls or GPU required. The multiprocessing pool saturates all available CPU cores, processing hundreds of images in minutes rather than days. PEP 723 inline script metadata means no virtual environment setup -- uv run handles dependency installation automatically.

Context

  • Model options: u2net (balanced), u2netp (2x faster, slightly lower quality), isnet-general-use (best quality for complex edges)
  • For images with faces, chain this with the macOS Vision framework face detection for crop-then-remove workflows
  • Output is always PNG with alpha transparency -- convert to WebP with Pillow if file size matters
  • On Apple Silicon Macs, expect roughly 2-4 seconds per image on CPU with u2net
  • Add --alpha-matting flag in rembg for higher quality edges on hair and fur
About this share
Contributormblode
Repositorymblode/shares
CreatedFeb 10, 2026
View on GitHub