Python দিয়ে ব্যাচে ছবির ব্যাকগ্রাউন্ড রিমুভ: rembg বনাম API

পুরো একটি ফোল্ডারের ছবির ব্যাকগ্রাউন্ড রিমুভ করার দুটি সম্পূর্ণ স্ক্রিপ্ট: একটি নিজের হার্ডওয়্যারে ওপেন-সোর্স rembg লাইব্রেরি দিয়ে, আরেকটি এমন HTTP API দিয়ে যা রিট্রাই, রেট লিমিট আর ডুপ্লিকেট চার্জ সঠিকভাবে সামলায়।

২৩ অক্টোবর, ২০২৬ আপডেট · 8 মিনিটে পড়ুন

আপনার কাছে কয়েকশো প্রোডাক্ট ছবি, হেডশট বা লিস্টিং ছবির একটি ফোল্ডার আছে, আর প্রতিটির ব্যাকগ্রাউন্ড রিমুভ করতে হবে। এডিটরে হাতে করলে সারাদিন ক্লিক করতে হয়। Python-এ এটি একটি লুপ, আর আসল সিদ্ধান্ত হলো লুপের ভেতরে কী চলবে: নিজের মেশিনে একটি ওপেন-সোর্স মডেল, নাকি একটি HTTP API।

এই গাইড দুটোই বানায়, এমন পূর্ণ স্ক্রিপ্টসহ যা আজই একটি ফোল্ডারে চালাতে পারেন, আর ব্যাচ জবকে নির্ভরযোগ্য করে এমন অংশগুলো দেখায়: মডেল বাছাই, CPU বনাম GPU, রিট্রাই, রেট লিমিট, idempotency আর ক্র্যাশের পর আবার চালু করা।

অপশন A না অপশন B?

লোকাল মডেল (rembg)HTTP API
খরচফ্রি সফটওয়্যার; খরচ হার্ডওয়্যার আর সময়েপ্রতি ছবি
সেটআপPython 3.11 থেকে 3.13, মডেল ডাউনলোড, ঐচ্ছিক CUDAএকটি API কী আর requests
গতিআপনার CPU বা GPU আর মডেলের ওপর নির্ভর করেসার্ভিস আর প্যারালেল রিকোয়েস্টের ওপর নির্ভর করে
কোয়ালিটিআপনার বাছাই করা মডেলের ওপর নির্ভর করেসার্ভিসের ওপর নির্ভর করে
প্রাইভেসিছবি কখনো আপনার মেশিন ছেড়ে যায় নাছবি তৃতীয় পক্ষের কাছে আপলোড হয়
রক্ষণাবেক্ষণমডেল, ড্রাইভার আর লাইসেন্স আপনি সামলানপ্রোভাইডার সামলায়
যাতে ভালোঅফলাইন কাজ, সংবেদনশীল ছবি, পরীক্ষাপ্রোডাকশন পাইপলাইন, GPU ছাড়া সার্ভার

অনেক টিম দুটোই ব্যবহার করে: পরীক্ষা আর ইন্টারনাল টুলের জন্য লোকাল মডেল, আর প্রোডাকশনের জন্য API, যেখানে অনুমানযোগ্য কোয়ালিটি আর GPU সার্ভার না রাখা বেশি গুরুত্বপূর্ণ।

অপশন A: rembg, ওপেন-সোর্স পথ

rembg একটি MIT-লাইসেন্সড Python লাইব্রেরি আর CLI, যা কয়েকটি ব্যাকগ্রাউন্ড রিমুভাল মডেল একসঙ্গে রেখে ONNX Runtime দিয়ে চালায়। লেখার সময় বর্তমান রিলিজ 2.0.86, আর এর জন্য Python 3.11 বা পরের এবং 3.14-এর আগের ভার্সন লাগে।

ইনস্টল

আপনার হার্ডওয়্যারের সঙ্গে মেলে এমন ব্যাকএন্ড বাছুন। CPU বিল্ড সব জায়গায় চলে:

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

NVIDIA GPU-র জন্য বরং rembg[gpu] ইনস্টল করুন। প্রজেক্ট বলে এর জন্য onnxruntime-gpu আর মিলে যাওয়া CUDA ও cuDNN লাগে, আর সেগুলো ইনস্টল করতে না পারলে CPU বিল্ডে ফিরে যেতে বলে। Linux-এ AMD GPU onnxruntime-rocm-সহ rembg[rocm] ব্যবহার করে।

ONNX Runtime CUDA (বা ROCm) এক্সিকিউশন প্রোভাইডারকে উপলব্ধ বললে rembg সেটি নিজে থেকেই বেছে নেয়, আর CPU-তে ফিরে গেলে সতর্ক করে। ONNX Runtime কী দেখতে পাচ্ছে তা যাচাই করতে:

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

একটি মডেল বাছুন

প্রথম ব্যবহারে মডেল ~/.rembg/models/-এ ডাউনলোড হয় (বদলাতে REMBG_HOME সেট করুন)। প্রজেক্টের তালিকা থেকে কয়েকটি কাজের মডেল:

মডেলনোট
bria-rmbgডিফল্ট। BRIA-র RMBG-2.0, প্রায় 1.02 GB, 1024 x 1024-এ চলে। এর লাইসেন্স বাণিজ্যিক ব্যবহারের জন্য পেইড চুক্তি চায়।
birefnet-generalসাধারণ কাজের BiRefNet মডেল; ভালো নরম কিনারা
birefnet-general-liteসাধারণ কাজের জন্য হালকা BiRefNet
birefnet-portraitমানুষের জন্য টিউন করা
isnet-general-useসাধারণ কাজের IS-Net মডেল
u2netক্লাসিক সাধারণ মডেল; দ্রুত, চৌকো কিনারা
u2netpহালকা u2net; ধীর মেশিনে দ্রুত পরীক্ষার জন্য
siluetau2net-এর মতোই, 43 MB-এ ছোট করা

দুটি বিষয় যতটা মনে হয় তার চেয়ে বেশি গুরুত্বপূর্ণ। প্রথমত, ডিফল্ট মডেল বাণিজ্যিক ব্যবহারের জন্য ফ্রি নয়: মডেলের ওয়েটের নিজস্ব লাইসেন্স থাকে, rembg-এর MIT লাইসেন্স থেকে আলাদা, তাই যে মডেল দিয়ে কাজ চালাবেন তার সোর্স দেখে নিন। দ্বিতীয়ত, নতুন মডেলগুলো (bria-rmbg, birefnet-*, isnet-general-use) নরম, সুগঠিত কিনারা দেয়, আর পুরনো u2net পরিবার তুলনামূলক শক্ত, চৌকো কিনারা দেয়।

কিনারার কোয়ালিটির অপশন

চুল আর লোমের মতো নরম কিনারার পিক্সেল সামলাতে rembg তিনটি উপায় দেয়:

  • ডিফল্ট: প্রোডাক্ট, গাড়ি আর লোগোর মতো শক্ত কিনারার সাবজেক্টের জন্য ঠিক আছে।
  • decontaminate=True (CLI-তে -dc): পুরনো ব্যাকগ্রাউন্ড কিনারার পিক্সেলে যে রঙিন হ্যালো রেখে যায় তা সরায়। এটি শুধু রং বদলায়, মাস্কের আকার কখনো নয়, খরচ খুব কম, আর পুরো ব্যাচে চালু রাখা নিরাপদ।
  • alpha_matting=True (-a): মাস্কের আকার ভুল হলে, যেমন চুল কেটে গেলে, কিনারা নিজেই নতুন করে হিসাব করে। এটি অনেক ধীর আর কখনো কনভার্জ না-ও করতে পারে, সেক্ষেত্রে rembg ডিকনটামিনেট করা কাটআউটে ফিরে যায়।

তদারকি ছাড়া ব্যাচের জন্য প্রজেক্ট -a-এর বদলে -dc-এর পরামর্শ দেয়, কারণ এটি দ্রুত আর ব্যর্থ হতে পারে না। হ্যালো কেন হয় তা ব্যাখ্যা করে আলফা চ্যানেল গাইড।

দ্রুত উপায়: CLI

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

rembg p পুরো একটি ফোল্ডার প্রসেস করে; ফোল্ডারে নজর রেখে নতুন ফাইল আসার সঙ্গে সঙ্গে প্রসেস করতে -w যোগ করুন।

Python স্ক্রিপ্ট

এই ভার্সন মডেল একবার লোড করে, আগে শেষ হওয়া ফাইল বাদ দেয় যাতে থামিয়ে আবার চালু করতে পারেন, আর একটি ফাইল ব্যর্থ হলেও চলতে থাকে:

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:])

python batch_rembg.py photos cutouts birefnet-general দিয়ে চালান। সেশন একবার বানানো জরুরি: মডেল লোড করতে চালানোর চেয়ে অনেক বেশি সময় লাগে, আর rembg README ব্যাচের পারফরম্যান্সের জন্য সেশন আবার ব্যবহারের পরামর্শ দেয়। আউটপুট সবসময় PNG, কারণ ফলাফলে আলফা চ্যানেল থাকে।

যেখানে rembg পিছিয়ে

  • মডেল ডাউনলোডের সময় প্রথম রান ধীর, আর বড় মডেলে অনেক RAM বা VRAM লাগে।
  • উচ্চ কোয়ালিটির মডেলে CPU-র থ্রুপুট সাধারণ মানের। হাজারটিতে নামার আগে 20টি প্রতিনিধিত্বমূলক ছবিতে পরীক্ষা করুন।
  • লাইসেন্স আর ড্রাইভার আপনার দায়িত্ব। rembg আর মডেলের ভার্সন পিন করুন যাতে পরের আপগ্রেড নিঃশব্দে ফলাফল না বদলায়।

অপশন B: একটি HTTP API

API-তে ভারী কাজটা অন্য কারো GPU-তে হয়, আর আপনার স্ক্রিপ্টের কাজ মূলত নেটওয়ার্ক ভালোভাবে সামলানো। উদাহরণে removebackground.dev API ব্যবহার করা হয়েছে কারণ এর কন্ট্রাক্ট /openapi.json-এ OpenAPI 3.1 হিসেবে প্রকাশিত; একই প্যাটার্ন এ ধরনের যেকোনো সার্ভিসে খাটে।

কন্ট্রাক্ট

  • x-api-key হেডারে আপনার কীসহ POST https://removebackground.dev/v1/remove।
  • ছবিটি মাল্টিপার্ট ফিল্ড image_file হিসেবে পাঠান (JPG, PNG বা WebP, 25 MB পর্যন্ত), অথবা image_url-সহ JSON হিসেবে।
  • ঐচ্ছিক ফিল্ডের মধ্যে আছে format (png, jpg বা webp), bg_color, size (preview, medium, hd, full) আর crop।
  • 200 মানে বডিই তৈরি ছবি। 202 মানে প্রায় 55 সেকেন্ড পরেও প্রসেস চলছে: বডি হলো একটি জব id-সহ JSON, আর আপনি GET /v1/jobs/{id}/result পোল করবেন, যা ছবি তৈরি না হওয়া পর্যন্ত Retry-After-সহ 409 not_ready উত্তর দেয়। কখনো 202 বডিকে ছবি হিসেবে সেভ করবেন না।
  • প্রতি অ্যাকাউন্টে মিনিটে 60টি পর্যন্ত প্রসেসিং রিকোয়েস্ট; এর বেশি হলে Retry-After-সহ 429 rate_limited পাবেন।
  • একটি Idempotency-Key হেডার রিট্রাই নিরাপদ করে: একই রিকোয়েস্টে একই কী আবার চার্জ না করে আসল জবটি ফেরত দেয়। ভিন্ন রিকোয়েস্টে একই কী 409 idempotency_key_reused উত্তর দেয়।
  • ফলাফল 48 ঘণ্টা পরে মুছে যায়, তাই পাওয়ার সঙ্গে সঙ্গে সেভ করুন।

যে রিট্রাই নিয়ম আপনাকে দুবার পেমেন্ট থেকে বাঁচায়

রেসপন্সকী করবেন
200ছবি সেভ করুন
202জবের ফলাফল পোল করুন; আবার আপলোড করবেন না
400, 401, 402, 413, 422রিকোয়েস্ট, কী, ক্রেডিট বা ছবি ঠিক করুন; লুপ করবেন না
429Retry-After সেকেন্ড অপেক্ষা করুন, একই কী দিয়ে আবার পাঠান
500, 503, টাইমআউট, কানেকশন বিচ্ছিন্নএকটু থেমে একই কী দিয়ে আবার পাঠান
502ওই ছবিটি ব্যর্থ হয়েছে আর চার্জ হয়নি; লগ করুন

কৌশল হলো idempotency কী-কে নির্ধারিত করা: ছবির বাইট আর অপশনের একটি হ্যাশ। স্ক্রিপ্ট ক্র্যাশ করে আবার চালালে প্রতিটি পুনরায় পাঠানো রিকোয়েস্ট একই কী বহন করে, তাই কিছুই দুবার প্রসেস বা চার্জ হয় না।

Python স্ক্রিপ্ট

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])

REMOVEBG_API_KEY=... python batch_api.py photos cutouts দিয়ে চালান। চারটি ওয়ার্কার সাধারণ শুরু; দ্রুত রেসপন্সে মিনিটের লিমিট পেরিয়ে গেলে 429 হ্যান্ডলিং অপেক্ষা করে একই কী দিয়ে আবার পাঠায়। ফাইলের বদলে URL পাঠাতে 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),
)

URL-এর লম্বা তালিকার জন্য একই API-তে POST /v1/batch আছে, যা 100টি পর্যন্ত ইমেজ URL একটি জব হিসেবে সারিতে রাখে, যা আপনি পোল করবেন।

যেকোনো ব্যাচ জব নির্ভরযোগ্য করা

  • শেষ হওয়া আউটপুট বাদ দিন যাতে আবার চালালে নতুন করে শুরু না হয়ে যেখানে থেমেছিল সেখান থেকে চলে। দুটি স্ক্রিপ্টই এটা করে।
  • নামের সংঘাতে নজর রাখুন। একই ফোল্ডারে shoe.jpg আর shoe.png দুটোই shoe.png হয়ে যায়; ইনপুটের নাম বদলান বা আউটপুটের নামে আসল এক্সটেনশন রাখুন।
  • ব্যর্থতা একটি ফাইলে লগ করুন আর শুধু সেগুলো আবার চালান।
  • সবকিছু প্রসেসের আগে গাঢ় আর হালকা ব্যাকগ্রাউন্ডে 100% জুমে কয়েকটি নমুনা যাচাই করুন।
  • আসল ফাইলে হাত দেবেন না। আলাদা আউটপুট ফোল্ডারে লিখুন।
  • গন্তব্য অনুযায়ী আউটপুট ফরম্যাট বাছুন। ট্রান্সপারেন্সির জন্য PNG বা WebP, মার্কেটপ্লেসের জন্য সাদায় JPG। দেখুন PNG বনাম JPEG বনাম WebP।

প্রশ্ন

rembg কি বাণিজ্যিক ব্যবহারের জন্য ফ্রি?

rembg নিজে MIT-লাইসেন্সড, কিন্তু প্রতিটি মডেলের নিজস্ব লাইসেন্স আছে। ডিফল্ট মডেল, BRIA-র RMBG-2.0 (bria-rmbg), বাণিজ্যিক ব্যবহারের জন্য পেইড চুক্তি চায়, তাই আপনার ব্যবহৃত মডেলের লাইসেন্স দেখুন বা অন্য একটি বাছুন।

rembg কি নিজে থেকেই আমার GPU ব্যবহার করে?

হ্যাঁ, যদি rembg[gpu] ইনস্টল করেন আর ONNX Runtime CUDA প্রোভাইডার লোড করতে পারে (যার জন্য মিলে যাওয়া CUDA আর cuDNN লাগে)। rembg উপলব্ধ থাকলে CUDA বা ROCm ব্যবহার করে আর CPU-তে ফিরে গেলে সতর্ক করে। onnxruntime.get_available_providers() দিয়ে যাচাই করুন।

কোন rembg মডেল সবচেয়ে ভালো কোয়ালিটি দেয়?

নতুন মডেলগুলো, bria-rmbg (ডিফল্ট), birefnet পরিবার আর isnet-general-use, পুরনো u2net পরিবারের চেয়ে নরম আর সুগঠিত কিনারা দেয়। মানুষের জন্য birefnet-portrait ভালো শুরু। নিজের কিছু ছবিতে পরীক্ষা করুন, কারণ সাবজেক্টভেদে ফল আলাদা।

API কল রিট্রাই করার সময় দুবার চার্জ এড়াব কীভাবে?

একটি Idempotency-Key হেডার পাঠান আর একই ছবির প্রতিটি রিট্রাইতে সেটি আবার ব্যবহার করুন। ছবির বাইট আর অপশনের হ্যাশ থেকে এটি বানালে পুরো স্ক্রিপ্ট আবার চালালেও একই কী ব্যবহার হয়।

202 রেসপন্স পেলে আমার স্ক্রিপ্ট কী করবে?

এটিকে ছবি নয়, প্রসেস চলছে হিসেবে ধরুন। JSON বডি থেকে জব id পড়ুন আর GET /v1/jobs/{id}/result পোল করুন, যখনই 409 not_ready উত্তর দেয় তখন Retry-After অনুযায়ী অপেক্ষা করুন। ছবি আবার আপলোড করবেন না।

removebackground.dev API-তে কত দ্রুত রিকোয়েস্ট পাঠানো যায়?

প্রতি অ্যাকাউন্টে মিনিটে 60টি পর্যন্ত প্রসেসিং রিকোয়েস্ট। এর বেশি হলে API Retry-After হেডারসহ 429 rate_limited উত্তর দেয়। অনেক URL-এর জন্য POST /v1/batch প্রতি রিকোয়েস্টে 100টি পর্যন্ত নেয়।

নিজের ছবিতে চেষ্টা করুন

নতুন অ্যাকাউন্ট 50টি ফ্রি ক্রেডিট পায়। প্রতি ছবিতে ১ ক্রেডিট, কোনো সাবস্ক্রিপশন নেই, আর ক্রেডিটের মেয়াদ ফুরায় না।

ব্যাকগ্রাউন্ড সরান

সূত্র