Ta bort bakgrund på många bilder med Python: rembg eller ett API

Två kompletta skript för att ta bort bakgrunden från en hel mapp med bilder: ett med open source-biblioteket rembg på din egen hårdvara, och ett med ett HTTP-API som hanterar omförsök, hastighetsgränser och dubbeldebitering korrekt.

Uppdaterad 23 oktober 2026 · 8 min läsning

Du har en mapp med några hundra produktbilder, porträtt eller annonsbilder, och alla behöver få bakgrunden borttagen. Att göra det för hand i en bildredigerare är en dag av klickande. I Python är det en loop, och det verkliga valet är vad som körs i loopen: en open source-modell på din egen dator, eller ett HTTP-API.

Den här guiden bygger båda, med kompletta skript som du kan köra på en mapp redan i dag, och tar upp det som gör ett massjobb pålitligt: modellval, CPU eller GPU, omförsök, hastighetsgränser, idempotens och att fortsätta efter en krasch.

Alternativ A eller alternativ B?

Lokal modell (rembg)HTTP-API
KostnadGratis programvara; du betalar med hårdvara och tidPer bild
InstallationPython 3.11 till 3.13, nedladdning av modeller, valfritt CUDAEn API-nyckel och requests
HastighetBeror på din CPU eller GPU och modellenBeror på tjänsten, parallella anrop
KvalitetBeror på modellen du väljerBeror på tjänsten
IntegritetBilderna lämnar aldrig din datorBilderna laddas upp till en tredje part
UnderhållDu sköter modeller, drivrutiner och licenserLeverantören gör det
Bra förArbete offline, känsliga bilder, experimentProduktionsflöden, servrar utan GPU

Många team använder båda: en lokal modell för experiment och interna verktyg, ett API för produktion där förutsägbar kvalitet och inga GPU-servrar väger tyngre.

Alternativ A: rembg, open source-vägen

rembg är ett MIT-licensierat Python-bibliotek och CLI som paketerar flera modeller för bakgrundsborttagning och kör dem med ONNX Runtime. När detta skrivs är den aktuella versionen 2.0.86, och den kräver Python 3.11 eller senare och tidigare än 3.14.

Installera

Välj den backend som passar din hårdvara. CPU-versionen fungerar överallt:

python -m venv .venv && source .venv/bin/activate
pip install "rembg[cpu]"        # library only
pip install "rembg[cpu,cli]"    # library plus the rembg command

För NVIDIA-GPU:er, installera rembg[gpu] i stället. Projektet påpekar att det kräver onnxruntime-gpu plus matchande CUDA och cuDNN, och föreslår att du faller tillbaka på CPU-versionen om du inte kan installera dem. AMD-GPU:er på Linux använder rembg[rocm] med onnxruntime-rocm.

rembg väljer automatiskt CUDA- (eller ROCm-) providern när ONNX Runtime rapporterar att den finns, och varnar om den faller tillbaka på CPU. Så kontrollerar du vad ONNX Runtime ser:

import onnxruntime
print(onnxruntime.get_available_providers())  # look for CUDAExecutionProvider

Välj en modell

Modellerna laddas ner vid första användningen till ~/.rembg/models/ (ändra med REMBG_HOME). Några användbara från projektets lista:

ModellKommentar
bria-rmbgStandard. BRIA:s RMBG-2.0, cirka 1,02 GB, körs i 1024 x 1024. Licensen kräver ett betalt avtal för kommersiell användning.
birefnet-generalBiRefNet-modell för allmänt bruk; bra mjuka kanter
birefnet-general-liteLättare BiRefNet för allmänt bruk
birefnet-portraitAnpassad för personer
isnet-general-useIS-Net-modell för allmänt bruk
u2netDen klassiska allmänna modellen; snabbare, grövre kanter
u2netpLätt u2net; snabba tester på långsamma datorer
siluetaSamma som u2net, krympt till 43 MB

Två saker är viktigare än de ser ut. För det första: standardmodellen är inte gratis för kommersiell användning. Modellvikter har egna licenser, skilda från rembgs MIT-licens, så kontrollera källan för den modell du levererar med. För det andra ger de nyare modellerna (bria-rmbg, birefnet-*, isnet-general-use) mjuka, välformade kanter, medan den äldre u2net-familjen tenderar att ge fastare, grövre kanter.

Alternativ för kantkvalitet

rembg har tre sätt att hantera mjuka kantpixlar som hår och päls:

  • Standard: bra för motiv med skarpa kanter som produkter, bilar och logotyper.
  • decontaminate=True (-dc i CLI): tar bort den färgade gloria som den gamla bakgrunden lämnar i kantpixlarna. Det ändrar bara färgen, aldrig maskens form, kostar väldigt lite och kan vara på för en hel omgång.
  • alpha_matting=True (-a): uppskattar själva kanten på nytt när maskens form är fel, till exempel avklippta hårstrån. Det är mycket långsammare och kan misslyckas, och då faller rembg tillbaka på en dekontaminerad friläggning.

För obevakade omgångar rekommenderar projektet -dc framför -a eftersom det är snabbare och inte kan misslyckas. Guiden om alfakanaler förklarar varför glorior uppstår.

Det snabba sättet: CLI

rembg p -m birefnet-general -dc photos/ cutouts/

rembg p bearbetar en hel mapp; lägg till -w för att bevaka mappen och bearbeta nya filer när de dyker upp.

Python-skriptet

Den här versionen laddar modellen en gång, hoppar över filer som redan är klara så att du kan stoppa och starta om, och fortsätter när en fil misslyckas:

import sys
from pathlib import Path

from rembg import new_session, remove

EXTS = {".jpg", ".jpeg", ".png", ".webp"}


def main(in_dir: str, out_dir: str, model: str = "birefnet-general") -> None:
    src_dir, dst_dir = Path(in_dir), Path(out_dir)
    dst_dir.mkdir(parents=True, exist_ok=True)
    session = new_session(model)  # load the model once, reuse it for every image

    files = sorted(p for p in src_dir.iterdir() if p.suffix.lower() in EXTS)
    for i, src in enumerate(files, 1):
        dst = dst_dir / f"{src.stem}.png"
        if dst.exists():
            continue  # resume where a previous run stopped
        try:
            out = remove(src.read_bytes(), session=session, decontaminate=True)
            dst.write_bytes(out)
            print(f"[{i}/{len(files)}] ok      {src.name}")
        except Exception as e:  # one bad file shouldn't stop the batch
            print(f"[{i}/{len(files)}] failed  {src.name}: {e}")


if __name__ == "__main__":
    main(*sys.argv[1:])

Kör det med python batch_rembg.py photos cutouts birefnet-general. Att skapa sessionen en gång spelar roll: att ladda en modell tar mycket längre tid än att köra den, och rembgs README rekommenderar att sessionen återanvänds för bättre prestanda vid massbearbetning. Resultaten blir alltid PNG eftersom de har en alfakanal.

Där rembg inte räcker till

  • Första körningen är långsam medan modellen laddas ner, och stora modeller kräver mycket RAM eller VRAM.
  • Genomströmningen på CPU är blygsam med de högkvalitativa modellerna. Testa med 20 representativa bilder innan du satsar på tusen.
  • Licenser och drivrutiner är ditt ansvar. Lås versionerna av rembg och modellerna så att en senare uppgradering inte ändrar resultaten i det tysta.

Alternativ B: ett HTTP-API

Med ett API görs det tunga arbetet på någon annans GPU:er, och ditt skript handlar mest om att hantera nätverket väl. Exemplet använder removebackground.devs API eftersom dess kontrakt är publicerat som OpenAPI 3.1 på /openapi.json; samma mönster gäller för alla liknande tjänster.

Kontraktet

  • POST https://removebackground.dev/v1/remove med din nyckel i headern x-api-key.
  • Skicka bilden som multipart-fältet image_file (JPG, PNG eller WebP, upp till 25 MB), eller som JSON med image_url.
  • Valfria fält är bland annat format (png, jpg eller webp), bg_color, size (preview, medium, hd, full) och crop.
  • 200 betyder att svaret är den färdiga bilden. 202 betyder att den fortfarande bearbetas efter cirka 55 sekunder: svaret är JSON med ett jobb-id, och du frågar GET /v1/jobs/{id}/result, som svarar 409 not_ready med Retry-After tills bilden är klar. Spara aldrig ett 202-svar som en bild.
  • Upp till 60 bearbetningsanrop per minut per konto; över det får du 429 rate_limited med Retry-After.
  • En header Idempotency-Key gör omförsök säkra: samma nyckel med samma anrop returnerar det ursprungliga jobbet i stället för att debitera igen. Samma nyckel med ett annat anrop ger 409 idempotency_key_reused.
  • Resultaten raderas efter 48 timmar, så spara dem när du får dem.

Regler för omförsök så att du inte betalar två gånger

SvarVad du ska göra
200Spara bilden
202Fråga efter jobbets resultat; ladda inte upp igen
400, 401, 402, 413, 422Rätta anropet, nyckeln, krediterna eller bilden; loopa inte
429Vänta Retry-After sekunder, skicka igen med samma nyckel
500, 503, timeout, bruten anslutningVänta och skicka igen med samma nyckel
502Den bilden misslyckades och debiterades inte; logga den

Tricket är att göra idempotensnyckeln deterministisk: en hash av bildens byte plus alternativen. Om skriptet kraschar och du kör det igen har varje nytt anrop samma nyckel, så inget bearbetas eller debiteras två gånger.

Python-skriptet

import hashlib
import mimetypes
import os
import sys
import time
from concurrent.futures import ThreadPoolExecutor, as_completed
from pathlib import Path

import requests

API = os.environ.get("REMOVEBG_API", "https://removebackground.dev")
KEY = os.environ["REMOVEBG_API_KEY"]  # keep the key out of your code
OPTIONS = {"format": "png", "size": "full"}  # or {"format": "jpg", "bg_color": "ffffff"}
WORKERS = 4  # the API allows 60 processing requests a minute
EXTS = {".jpg", ".jpeg", ".png", ".webp"}
RETRYABLE = {429, 500, 503}


def idempotency_key(data: bytes) -> str:
    # Same image + same options = same key, so a rerun never pays twice.
    h = hashlib.sha256(data)
    h.update(repr(sorted(OPTIONS.items())).encode())
    return h.hexdigest()


def wait(res, default=2.0):
    try:
        return float(res.headers.get("Retry-After", default))
    except ValueError:
        return default


def save(res, dst: Path) -> Path:
    if res.status_code != 200 or not res.headers.get("Content-Type", "").startswith("image/"):
        raise RuntimeError(f"HTTP {res.status_code}: {res.text[:300]}")
    dst.write_bytes(res.content)
    return dst


def process(src: Path, dst: Path) -> Path:
    data = src.read_bytes()
    mime = mimetypes.guess_type(src.name)[0] or "application/octet-stream"
    headers = {"x-api-key": KEY, "Idempotency-Key": idempotency_key(data)}

    for attempt in range(6):
        try:
            res = requests.post(
                f"{API}/v1/remove",
                files={"image_file": (src.name, data, mime)},
                data=OPTIONS,
                headers=headers,
                timeout=(10, 120),
            )
        except (requests.ConnectionError, requests.Timeout):
            time.sleep(2 ** attempt)  # same key: safe to resend
            continue
        if res.status_code in RETRYABLE:
            time.sleep(wait(res, 2 ** attempt))
            continue
        break
    else:
        raise RuntimeError("gave up after retries")

    if res.status_code != 202:
        return save(res, dst)  # 200 is the image; 4xx and 502 raise

    # 202: still processing. Poll the same job; never upload the image again.
    job_id = res.json()["id"]
    deadline = time.monotonic() + 600
    while time.monotonic() < deadline:
        time.sleep(wait(res))
        try:
            res = requests.get(f"{API}/v1/jobs/{job_id}/result", headers=headers, timeout=30)
        except (requests.ConnectionError, requests.Timeout):
            continue  # reading a job is free and safe to repeat
        if res.status_code == 409 and res.json()["error"]["code"] == "not_ready":
            continue
        if res.status_code >= 500:
            continue
        return save(res, dst)
    raise TimeoutError(f"job {job_id} still running; fetch it later")


def main(in_dir: str, out_dir: str) -> None:
    src_dir, dst_dir = Path(in_dir), Path(out_dir)
    dst_dir.mkdir(parents=True, exist_ok=True)
    ext = ".jpg" if OPTIONS.get("format") == "jpg" else "." + OPTIONS.get("format", "png")
    todo = [
        (p, dst_dir / (p.stem + ext))
        for p in sorted(src_dir.iterdir())
        if p.suffix.lower() in EXTS and not (dst_dir / (p.stem + ext)).exists()
    ]
    print(f"{len(todo)} images to process")

    failed = []
    with ThreadPoolExecutor(max_workers=WORKERS) as pool:
        jobs = {pool.submit(process, s, d): s for s, d in todo}
        for fut in as_completed(jobs):
            src = jobs[fut]
            try:
                print("ok    ", src.name, "->", fut.result().name)
            except Exception as e:
                failed.append(src.name)
                print("failed", src.name, e)
    print(f"done: {len(todo) - len(failed)} ok, {len(failed)} failed")


if __name__ == "__main__":
    main(sys.argv[1], sys.argv[2])

Kör det med REMOVEBG_API_KEY=... python batch_api.py photos cutouts. Fyra workers är en försiktig början; om snabba svar tar dig över minutgränsen väntar hanteringen av 429 och skickar igen med samma nyckel. För att skicka URL:er i stället för filer, skicka JSON:

res = requests.post(
    f"{API}/v1/remove",
    json={"image_url": "https://example.com/shoe.jpg", "format": "png"},
    headers={"x-api-key": KEY, "Idempotency-Key": "shoe-front-v1"},
    timeout=(10, 120),
)

För långa listor med URL:er har samma API POST /v1/batch, som köar upp till 100 bild-URL:er som ett jobb som du frågar efter.

Gör alla massjobb robusta

  • Hoppa över färdiga resultat så att en ny körning fortsätter i stället för att börja om. Båda skripten gör det.
  • Se upp för namnkrockar. shoe.jpg och shoe.png i samma mapp blir båda shoe.png; byt namn på indata eller ta med den ursprungliga filändelsen i utdatanamnet.
  • Logga misslyckanden till en fil och kör bara om dem.
  • Stickprova ett urval i 100 % zoom på mörka och ljusa bakgrunder innan du bearbetar allt.
  • Låt originalen vara orörda. Skriv till en separat utdatamapp.
  • Välj utdataformat efter destinationen. PNG eller WebP för transparens, JPG på vitt för marknadsplatser. Se PNG, JPEG eller WebP.

Frågor

Är rembg gratis för kommersiell användning?

rembg i sig är MIT-licensierat, men varje modell har en egen licens. Standardmodellen, BRIA:s RMBG-2.0 (bria-rmbg), kräver ett betalt avtal för kommersiell användning, så kontrollera licensen för modellen du använder eller välj en annan.

Använder rembg min GPU automatiskt?

Ja, om du installerar rembg[gpu] och ONNX Runtime kan ladda CUDA-providern (vilket kräver matchande CUDA och cuDNN). rembg använder CUDA eller ROCm när de finns och varnar när den faller tillbaka på CPU:n. Kontrollera onnxruntime.get_available_providers().

Vilken rembg-modell ger bäst kvalitet?

De nyare modellerna, bria-rmbg (standard), birefnet-familjen och isnet-general-use, ger mjukare och bättre formade kanter än den äldre u2net-familjen. birefnet-portrait är en bra start för personer. Testa ett urval av dina egna bilder, eftersom resultaten varierar med motivet.

Hur undviker jag att debiteras två gånger när jag gör om API-anrop?

Skicka en header Idempotency-Key och återanvänd den vid varje omförsök för samma bild. Härleder du den från en hash av bildens byte och alternativen återanvänder till och med en ny körning av hela skriptet samma nycklar.

Vad ska mitt skript göra med ett 202-svar?

Behandla det som att bilden fortfarande bearbetas, inte som en bild. Läs jobbets id från JSON-svaret och fråga GET /v1/jobs/{id}/result, och vänta Retry-After varje gång det svarar 409 not_ready. Ladda inte upp bilden igen.

Hur snabbt kan jag skicka anrop till removebackground.devs API?

Upp till 60 bearbetningsanrop per minut per konto. Över det svarar API:t 429 rate_limited med en header Retry-After. För många URL:er tar POST /v1/batch emot upp till 100 per anrop.

Prova med din egen bild

Nya konton får 50 gratis krediter. En kredit per bild, ingen prenumeration, och krediterna går aldrig ut.

Ta bort en bakgrund

Källor