আপনার কাছে কয়েকশো প্রোডাক্ট ছবি, হেডশট বা লিস্টিং ছবির একটি ফোল্ডার আছে, আর প্রতিটির ব্যাকগ্রাউন্ড রিমুভ করতে হবে। এডিটরে হাতে করলে সারাদিন ক্লিক করতে হয়। 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 commandNVIDIA 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; ধীর মেশিনে দ্রুত পরীক্ষার জন্য |
silueta | u2net-এর মতোই, 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-সহ 409not_readyউত্তর দেয়। কখনো 202 বডিকে ছবি হিসেবে সেভ করবেন না। - প্রতি অ্যাকাউন্টে মিনিটে 60টি পর্যন্ত প্রসেসিং রিকোয়েস্ট; এর বেশি হলে
Retry-After-সহ 429rate_limitedপাবেন। - একটি
Idempotency-Keyহেডার রিট্রাই নিরাপদ করে: একই রিকোয়েস্টে একই কী আবার চার্জ না করে আসল জবটি ফেরত দেয়। ভিন্ন রিকোয়েস্টে একই কী 409idempotency_key_reusedউত্তর দেয়। - ফলাফল 48 ঘণ্টা পরে মুছে যায়, তাই পাওয়ার সঙ্গে সঙ্গে সেভ করুন।
যে রিট্রাই নিয়ম আপনাকে দুবার পেমেন্ট থেকে বাঁচায়
| রেসপন্স | কী করবেন |
|---|---|
| 200 | ছবি সেভ করুন |
| 202 | জবের ফলাফল পোল করুন; আবার আপলোড করবেন না |
| 400, 401, 402, 413, 422 | রিকোয়েস্ট, কী, ক্রেডিট বা ছবি ঠিক করুন; লুপ করবেন না |
| 429 | Retry-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টি ফ্রি ক্রেডিট পায়। প্রতি ছবিতে ১ ক্রেডিট, কোনো সাবস্ক্রিপশন নেই, আর ক্রেডিটের মেয়াদ ফুরায় না।
ব্যাকগ্রাউন্ড সরানসূত্র
- rembg on GitHub (README: installation, models, edge modes)
- rembg on PyPI (version and Python requirement)
- BRIA RMBG-2.0 model card and license
- ONNX Runtime: Get started and installation matrix
- removebackground.dev API reference and guides
- removebackground.dev OpenAPI 3.1 schema
- Requests: Quickstart (multipart file uploads, timeouts)