У вас есть папка с несколькими сотнями фото товаров, портретов или снимков для объявлений, и с каждого нужно удалить фон. Вручную в редакторе на это уйдёт день кликов. В Python хватит цикла, и настоящий выбор в том, что работает внутри цикла: открытая модель на вашей машине или HTTP API.
В этом руководстве мы соберём оба варианта, с полными скриптами, которые можно запустить на папке уже сегодня, и разберём то, от чего зависит надёжность пакетной обработки: выбор модели, CPU или GPU, повторные попытки, лимиты запросов, идемпотентность и продолжение работы после сбоя.
Вариант A или вариант B?
| Локальная модель (rembg) | HTTP API | |
|---|---|---|
| Стоимость | Бесплатный софт; платите железом и временем | За каждое изображение |
| Настройка | Python от 3.11 до 3.13, загрузка моделей, по желанию CUDA | API-ключ и requests |
| Скорость | Зависит от CPU или GPU и модели | Зависит от сервиса, параллельные запросы |
| Качество | Зависит от выбранной модели | Зависит от сервиса |
| Конфиденциальность | Изображения не покидают вашу машину | Изображения загружаются третьей стороне |
| Обслуживание | Модели, драйверы и лицензии на вас | На стороне провайдера |
| Подходит для | Офлайн-работы, чувствительных изображений, экспериментов | Продакшн-конвейеров, серверов без GPU |
Многие команды используют оба: локальную модель для экспериментов и внутренних инструментов, API в продакшне, где предсказуемое качество и отсутствие GPU-серверов важнее.
Вариант A: rembg, путь open source
rembg представляет собой Python-библиотеку и CLI под лицензией MIT, которые оборачивают несколько моделей удаления фона и запускают их через 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Для GPU NVIDIA установите вместо этого rembg[gpu]. В проекте отмечают, что для этого нужен onnxruntime-gpu и подходящие версии CUDA и cuDNN, и советуют вернуться к сборке для CPU, если их не удаётся установить. Видеокарты AMD на Linux используют rembg[rocm] с onnxruntime-rocm.
rembg автоматически выбирает провайдер выполнения CUDA (или ROCm), когда ONNX Runtime сообщает, что он доступен, и предупреждает, если откатывается на CPU. Чтобы проверить, что видит ONNX Runtime:
import onnxruntime
print(onnxruntime.get_available_providers()) # look for CUDAExecutionProviderВыбор модели
Модели скачиваются при первом использовании в ~/.rembg/models/ (задайте REMBG_HOME, чтобы изменить путь). Несколько полезных из списка проекта:
| Модель | Примечания |
|---|---|
bria-rmbg | По умолчанию. RMBG-2.0 от BRIA, около 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 |
Два момента важнее, чем кажется. Во-первых, модель по умолчанию не бесплатна для коммерческого использования: у весов моделей свои лицензии, отдельные от лицензии MIT самого rembg, поэтому проверяйте источник той модели, с которой выходите в продакшн. Во-вторых, новые модели (bria-rmbg, birefnet-*, isnet-general-use) дают мягкие края правильной формы, а старое семейство u2net обычно даёт более жёсткие и грубые края.
Настройки качества краёв
У rembg три способа обработки мягких краевых пикселей, например волос и шерсти:
- По умолчанию: подходит для объектов с чёткими краями, таких как товары, машины и логотипы.
decontaminate=True(-dcв CLI): убирает цветной ореол, который старый фон оставляет в краевых пикселях. Меняет только цвет, никогда не форму маски, почти ничего не стоит и его можно смело оставлять включённым для всего пакета.alpha_matting=True(-a): заново оценивает сам край, когда форма маски неверна, например обрезаны пряди. Работает гораздо медленнее и может не сойтись, и тогда rembg откатывается к вырезке с очисткой краёв.
Для пакетов без присмотра проект рекомендует -dc, а не -a, потому что он быстрее и не может завершиться ошибкой. Почему появляются ореолы, объясняет руководство по альфа-каналу.
Быстрый способ: 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. Важно создать сессию один раз: загрузка модели занимает гораздо больше времени, чем её запуск, и README rembg рекомендует переиспользовать сессию для производительности при пакетной обработке. На выходе всегда PNG, потому что у результата есть альфа-канал.
Где rembg не дотягивает
- Первый запуск медленный, пока скачивается модель, а большим моделям нужно много RAM или VRAM.
- Производительность на CPU скромная с качественными моделями. Проверьте на 20 типичных изображениях, прежде чем браться за тысячу.
- Лицензии и драйверы на вас. Зафиксируйте версии rembg и модели, чтобы будущее обновление незаметно не изменило результаты.
Вариант B: HTTP API
С API вся тяжёлая работа идёт на чужих GPU, а ваш скрипт в основном должен правильно обращаться с сетью. В примере используется API removebackground.dev, потому что его контракт опубликован в OpenAPI 3.1 по адресу /openapi.json; те же приёмы подходят для любого похожего сервиса.
Контракт
POST https://removebackground.dev/v1/removeс ключом в заголовкеx-api-key.- Отправьте изображение как multipart-поле
image_file(JPG, PNG или WebP до 25 MB) или как JSON сimage_url. - Необязательные поля:
format(png,jpgилиwebp),bg_color,size(preview,medium,hd,full) иcrop. - 200 значит, что в теле ответа готовое изображение. 202 значит, что обработка идёт дольше примерно 55 секунд: в теле ответа JSON с
idзадачи, и вы опрашиваетеGET /v1/jobs/{id}/result, который отвечает 409not_readyсRetry-After, пока изображение не готово. Никогда не сохраняйте тело ответа 202 как изображение. - До 60 запросов на обработку в минуту на аккаунт; сверх этого вы получите 429
rate_limitedсRetry-After. - Заголовок
Idempotency-Keyделает повторы безопасными: тот же ключ с тем же запросом возвращает исходную задачу, а не списывает кредиты снова. Тот же ключ с другим запросом даёт 409idempotency_key_reused. - Результаты удаляются через 48 часов, поэтому сохраняйте их сразу.
Правила повторов, чтобы не платить дважды
| Ответ | Что делать |
|---|---|
| 200 | Сохранить изображение |
| 202 | Опрашивать результат задачи; не загружать повторно |
| 400, 401, 402, 413, 422 | Исправить запрос, ключ, кредиты или изображение; не повторять в цикле |
| 429 | Подождать Retry-After секунд, отправить снова с тем же ключом |
| 500, 503, таймаут, обрыв соединения | Выждать паузу и отправить снова с тем же ключом |
| 502 | Это изображение не обработалось, и кредиты не списаны; запишите в лог |
Хитрость в том, чтобы ключ идемпотентности был детерминированным: хеш байтов изображения плюс параметры. Если скрипт упадёт и вы запустите его снова, каждая повторная отправка несёт тот же ключ, и ничего не обрабатывается и не оплачивается дважды.
Скрипт на 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, но у каждой модели своя лицензия. Модель по умолчанию, RMBG-2.0 от BRIA (bria-rmbg), требует платного соглашения для коммерческого использования, поэтому проверьте лицензию своей модели или выберите другую.
rembg сам использует мою видеокарту?
Да, если установить 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?
Считать, что обработка ещё идёт, а не что это изображение. Возьмите id задачи из JSON-тела и опрашивайте GET /v1/jobs/{id}/result, выжидая Retry-After каждый раз, когда приходит 409 not_ready. Не загружайте изображение повторно.
С какой скоростью можно отправлять запросы к API removebackground.dev?
До 60 запросов на обработку в минуту на аккаунт. Сверх этого API отвечает 429 rate_limited с заголовком Retry-After. Для множества 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)