bulk-bg-remove 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. bulk_bg_remove-0.1.0/.agents/plugins/marketplace.json +21 -0
  2. bulk_bg_remove-0.1.0/.claude-plugin/marketplace.json +17 -0
  3. bulk_bg_remove-0.1.0/.claude-plugin/plugin.json +13 -0
  4. bulk_bg_remove-0.1.0/.codex-plugin/plugin.json +29 -0
  5. bulk_bg_remove-0.1.0/.github/workflows/ci.yml +32 -0
  6. bulk_bg_remove-0.1.0/.gitignore +31 -0
  7. bulk_bg_remove-0.1.0/.python-version +1 -0
  8. bulk_bg_remove-0.1.0/AGENTS.md +105 -0
  9. bulk_bg_remove-0.1.0/BENCHMARK.md +202 -0
  10. bulk_bg_remove-0.1.0/CLAUDE.md +1 -0
  11. bulk_bg_remove-0.1.0/LICENSE +21 -0
  12. bulk_bg_remove-0.1.0/PKG-INFO +180 -0
  13. bulk_bg_remove-0.1.0/README.md +144 -0
  14. bulk_bg_remove-0.1.0/agents/bg-reviewer.md +14 -0
  15. bulk_bg_remove-0.1.0/assets/demo.webp +0 -0
  16. bulk_bg_remove-0.1.0/assets/logo-dark.svg +1 -0
  17. bulk_bg_remove-0.1.0/assets/logo-light.svg +1 -0
  18. bulk_bg_remove-0.1.0/assets/showcase.webp +0 -0
  19. bulk_bg_remove-0.1.0/benchmark/images.csv +31 -0
  20. bulk_bg_remove-0.1.0/benchmark/scores.csv +81 -0
  21. bulk_bg_remove-0.1.0/pyproject.toml +82 -0
  22. bulk_bg_remove-0.1.0/scripts/bench.py +206 -0
  23. bulk_bg_remove-0.1.0/scripts/bench_grids.py +154 -0
  24. bulk_bg_remove-0.1.0/scripts/ci.sh +77 -0
  25. bulk_bg_remove-0.1.0/skills/bulk-bg-remove/SKILL.md +281 -0
  26. bulk_bg_remove-0.1.0/skills/bulk-bg-remove/agents/openai.yaml +6 -0
  27. bulk_bg_remove-0.1.0/skills/bulk-bg-remove/references/json-events.md +70 -0
  28. bulk_bg_remove-0.1.0/skills/bulk-bg-remove/references/models.md +111 -0
  29. bulk_bg_remove-0.1.0/skills/bulk-bg-remove/references/reviewer.md +86 -0
  30. bulk_bg_remove-0.1.0/skills/bulk-bg-remove/references/troubleshooting.md +53 -0
  31. bulk_bg_remove-0.1.0/src/bulk_bg_remove/__init__.py +3 -0
  32. bulk_bg_remove-0.1.0/src/bulk_bg_remove/bulk/__init__.py +1 -0
  33. bulk_bg_remove-0.1.0/src/bulk_bg_remove/bulk/events.py +28 -0
  34. bulk_bg_remove-0.1.0/src/bulk_bg_remove/bulk/models.py +137 -0
  35. bulk_bg_remove-0.1.0/src/bulk_bg_remove/bulk/plan.py +262 -0
  36. bulk_bg_remove-0.1.0/src/bulk_bg_remove/bulk/runner.py +438 -0
  37. bulk_bg_remove-0.1.0/src/bulk_bg_remove/bulk/sample.py +165 -0
  38. bulk_bg_remove-0.1.0/src/bulk_bg_remove/bulk/scan.py +219 -0
  39. bulk_bg_remove-0.1.0/src/bulk_bg_remove/bulk/session.py +407 -0
  40. bulk_bg_remove-0.1.0/src/bulk_bg_remove/bulk/verify.py +89 -0
  41. bulk_bg_remove-0.1.0/src/bulk_bg_remove/cli.py +298 -0
  42. bulk_bg_remove-0.1.0/src/bulk_bg_remove/console.py +272 -0
  43. bulk_bg_remove-0.1.0/src/bulk_bg_remove/core/__init__.py +1 -0
  44. bulk_bg_remove-0.1.0/src/bulk_bg_remove/core/compositing.py +24 -0
  45. bulk_bg_remove-0.1.0/src/bulk_bg_remove/core/finish.py +171 -0
  46. bulk_bg_remove-0.1.0/src/bulk_bg_remove/core/io.py +122 -0
  47. bulk_bg_remove-0.1.0/src/bulk_bg_remove/core/matting.py +157 -0
  48. bulk_bg_remove-0.1.0/src/bulk_bg_remove/core/pipeline.py +94 -0
  49. bulk_bg_remove-0.1.0/src/bulk_bg_remove/doctor.py +107 -0
  50. bulk_bg_remove-0.1.0/src/bulk_bg_remove/domain.py +15 -0
  51. bulk_bg_remove-0.1.0/src/bulk_bg_remove/engine/__init__.py +1 -0
  52. bulk_bg_remove-0.1.0/src/bulk_bg_remove/engine/model.py +96 -0
  53. bulk_bg_remove-0.1.0/src/bulk_bg_remove/formats.py +74 -0
  54. bulk_bg_remove-0.1.0/src/bulk_bg_remove/paths.py +77 -0
  55. bulk_bg_remove-0.1.0/src/bulk_bg_remove/ui/__init__.py +1 -0
  56. bulk_bg_remove-0.1.0/src/bulk_bg_remove/ui/launch.py +46 -0
  57. bulk_bg_remove-0.1.0/src/bulk_bg_remove/ui/server.py +401 -0
  58. bulk_bg_remove-0.1.0/src/bulk_bg_remove/ui/static/index.html +452 -0
  59. bulk_bg_remove-0.1.0/tests/conftest.py +27 -0
  60. bulk_bg_remove-0.1.0/tests/fakes.py +59 -0
  61. bulk_bg_remove-0.1.0/tests/test_auto_model.py +134 -0
  62. bulk_bg_remove-0.1.0/tests/test_compositing.py +47 -0
  63. bulk_bg_remove-0.1.0/tests/test_finish.py +139 -0
  64. bulk_bg_remove-0.1.0/tests/test_finish_verify.py +71 -0
  65. bulk_bg_remove-0.1.0/tests/test_formats.py +61 -0
  66. bulk_bg_remove-0.1.0/tests/test_io.py +81 -0
  67. bulk_bg_remove-0.1.0/tests/test_matting.py +117 -0
  68. bulk_bg_remove-0.1.0/tests/test_models.py +55 -0
  69. bulk_bg_remove-0.1.0/tests/test_paths.py +57 -0
  70. bulk_bg_remove-0.1.0/tests/test_plan.py +125 -0
  71. bulk_bg_remove-0.1.0/tests/test_real_model.py +59 -0
  72. bulk_bg_remove-0.1.0/tests/test_review.py +136 -0
  73. bulk_bg_remove-0.1.0/tests/test_runner.py +201 -0
  74. bulk_bg_remove-0.1.0/tests/test_scan.py +33 -0
  75. bulk_bg_remove-0.1.0/tests/test_session_and_cli.py +217 -0
  76. bulk_bg_remove-0.1.0/tests/test_shop.py +115 -0
  77. bulk_bg_remove-0.1.0/tests/test_ui.py +177 -0
  78. bulk_bg_remove-0.1.0/uv.lock +1442 -0
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "bulk-bg-remove",
3
+ "interface": {
4
+ "displayName": "Bulk BG Remove"
5
+ },
6
+ "plugins": [
7
+ {
8
+ "name": "bulk-bg-remove",
9
+ "source": {
10
+ "source": "url",
11
+ "url": "https://github.com/Btike/bulk-bg-remove.git",
12
+ "ref": "main"
13
+ },
14
+ "policy": {
15
+ "installation": "AVAILABLE",
16
+ "authentication": "ON_INSTALL"
17
+ },
18
+ "category": "Productivity"
19
+ }
20
+ ]
21
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
3
+ "name": "bulk-bg-remove",
4
+ "description": "Remove image backgrounds locally and in bulk. No uploads, no API keys.",
5
+ "owner": {
6
+ "name": "Btike",
7
+ "url": "https://github.com/Btike"
8
+ },
9
+ "plugins": [
10
+ {
11
+ "name": "bulk-bg-remove",
12
+ "description": "Cut out every photo in a folder with BiRefNet, on your own machine. Lossless transparent PNG/WebP, originals untouched.",
13
+ "source": "./",
14
+ "category": "productivity"
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "bulk-bg-remove",
3
+ "version": "0.1.0",
4
+ "description": "Remove image backgrounds locally and in bulk: one photo or whole folders, with BiRefNet. No uploads, no API keys, originals untouched.",
5
+ "author": {
6
+ "name": "Btike",
7
+ "url": "https://github.com/Btike"
8
+ },
9
+ "homepage": "https://github.com/Btike/bulk-bg-remove",
10
+ "repository": "https://github.com/Btike/bulk-bg-remove",
11
+ "license": "MIT",
12
+ "keywords": ["background-removal", "remove-background", "transparent-png", "birefnet", "bulk", "images"]
13
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "bulk-bg-remove",
3
+ "version": "0.1.0",
4
+ "description": "Remove image backgrounds locally and in bulk: one photo or whole folders, with BiRefNet. No uploads, no API keys, originals untouched.",
5
+ "author": {
6
+ "name": "Btike",
7
+ "url": "https://github.com/Btike"
8
+ },
9
+ "homepage": "https://github.com/Btike/bulk-bg-remove",
10
+ "repository": "https://github.com/Btike/bulk-bg-remove",
11
+ "license": "MIT",
12
+ "keywords": ["background-removal", "remove-background", "transparent-png", "birefnet", "bulk", "images"],
13
+ "skills": "./skills/",
14
+ "interface": {
15
+ "displayName": "Bulk BG Remove",
16
+ "shortDescription": "Remove image backgrounds locally, in bulk",
17
+ "longDescription": "Cut out the subject of one photo or whole folders on your own machine with BiRefNet. Lossless transparent PNG or WebP in a new <name>-no-bg folder; originals are never touched.",
18
+ "developerName": "Btike",
19
+ "category": "Productivity",
20
+ "capabilities": ["Instructions"],
21
+ "websiteURL": "https://github.com/Btike/bulk-bg-remove",
22
+ "defaultPrompt": [
23
+ "Remove the background from every photo in this folder.",
24
+ "Make a transparent PNG of this product photo.",
25
+ "Cut out the people in these HEIC photos."
26
+ ],
27
+ "brandColor": "#0d1117"
28
+ }
29
+ }
@@ -0,0 +1,32 @@
1
+ # Hosted CI for when the repo is public (public repos get free Actions minutes).
2
+ # While the repo is private every job is skipped, so it uses no minutes:
3
+ # run scripts/ci.sh locally instead.
4
+ name: ci
5
+
6
+ on:
7
+ push:
8
+ branches: [main]
9
+ pull_request:
10
+ workflow_dispatch: # run it by hand from the Actions tab
11
+
12
+ jobs:
13
+ test:
14
+ if: ${{ !github.event.repository.private }}
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ os: [ubuntu-latest, macos-latest, windows-latest]
19
+ python: ["3.11", "3.12", "3.13"]
20
+ runs-on: ${{ matrix.os }}
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - uses: astral-sh/setup-uv@v6
24
+ with:
25
+ python-version: ${{ matrix.python }}
26
+ - run: uv lock --check
27
+ - run: uv run --locked ruff check .
28
+ - run: uv run --locked ruff format --check .
29
+ - run: uv run --locked mypy
30
+ - run: uv run --locked pytest -q
31
+ env:
32
+ BULK_BG_REMOVE_REAL_MODEL: "1" # also run the real-model smoke test
@@ -0,0 +1,31 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ .venv/
5
+ *.egg-info/
6
+ build/
7
+ dist/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ .mypy_cache/
11
+
12
+ # Env / secrets — never commit
13
+ .env
14
+ .env.local
15
+ *.key
16
+
17
+ # Local runtime output and test images
18
+ storage/
19
+ *-no-bg/
20
+ .playwright-mcp/
21
+
22
+ # Downloaded model weights
23
+ *.onnx
24
+ .u2net/
25
+
26
+ # OS
27
+ .DS_Store
28
+ Thumbs.db
29
+
30
+ # Local CI environments and builds
31
+ .ci/
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,105 @@
1
+ # AGENTS.md — bulk-bg-remove
2
+
3
+ Remove image backgrounds in bulk, 100% locally, without touching a single subject
4
+ pixel. One engine, two entry points: a CLI/agent mode and a local drag-and-drop UI.
5
+
6
+ > Status: v0.1 under construction. Sections marked _(planned)_ do not exist yet.
7
+
8
+ ## Stack
9
+ - **Python 3.11–3.13**, managed by **uv** (`.python-version` pins 3.12 for development)
10
+ - **rembg** (ONNX Runtime) with **BiRefNet** (MIT) — default model `birefnet-general-lite`
11
+ - **Pillow + numpy** — imaging; **pillow-heif** for HEIC/HEIF; **pymatting + scipy** — edge matting
12
+ - **FastAPI + Uvicorn** — local UI server
13
+ - **rich** — terminal logs · **psutil** — capacity probes
14
+ - **pytest · ruff · mypy (strict)** — quality gates
15
+
16
+ ## Commands
17
+ - Install / sync: `uv sync`
18
+ - Tests: `uv run pytest`
19
+ - Lint: `uv run ruff check . && uv run ruff format --check .`
20
+ - Typecheck: `uv run mypy`
21
+ - Run: `uv run bulk-bg-remove PATH [--profile KIND] [--yes] [--json] [--clean-edges|--fast-edges]`
22
+ (`--model` defaults to `auto`; `--sample-sheet` with `--dry-run` writes a contact sheet)
23
+ - Check a machine: `uv run bulk-bg-remove doctor [--json]`
24
+ - **CI runs locally**: `scripts/ci.sh` (lock, ruff, mypy, tests on Python 3.11–3.13, wheel
25
+ build, plugin manifests); `--quick` for lint, types and tests only; `--linux` adds the suite
26
+ on Linux x86_64 in Docker with the real-model smoke test (~10 min, emulated: run it before a
27
+ merge or release). Hosted CI (`.github/workflows/ci.yml`, Linux/macOS/Windows) is skipped
28
+ while the repo is private. Run the full script before every commit.
29
+ - Linux arm64 VMs on Apple M4/M5 (Docker, UTM, Lima) advertise SVE the chip cannot run:
30
+ numba and ONNX Runtime die with SIGILL there. Test Linux as x86_64; the runner reports a
31
+ SIGILL crash in plain words (`crash_reason` in `bulk/runner.py`).
32
+
33
+ ## Structure
34
+ - `src/bulk_bg_remove/core/` — pure image logic: `io.py`, `matting.py`, `compositing.py`,
35
+ `finish.py` (opt-in shop finishing), `pipeline.py`.
36
+ No CLI/UI/runner imports.
37
+ - `src/bulk_bg_remove/engine/model.py` — rembg session wrapper (load once per worker, reuse).
38
+ - `src/bulk_bg_remove/domain.py` — shared domain types.
39
+ - `src/bulk_bg_remove/bulk/` — the four phases: scan → plan → run → verify, plus `session.py`
40
+ (shared by CLI and UI), `events.py` (the JSON event contract), `models.py` (`--model auto`:
41
+ per-profile scores from the blind-judged bench) and `sample.py` (contact sheet for agents)
42
+ - `src/bulk_bg_remove/ui/` — local server + single-file page
43
+ - `skills/bulk-bg-remove/` — the agent skill (`SKILL.md` + `references/`); plugin manifests in
44
+ `.claude-plugin/`, `.codex-plugin/` and `.agents/plugins/`. The `--json` event contract is
45
+ documented in `references/json-events.md`: update it with any event change.
46
+ - `tests/` — unit tests for pure logic, integration tests with a fake model, and one
47
+ real-model smoke test (`test_real_model.py`, `silueta`, 43 MB download) that runs only with
48
+ `BULK_BG_REMOVE_REAL_MODEL=1` — set by `scripts/ci.sh --linux` and in hosted CI on
49
+ Linux, macOS and Windows.
50
+
51
+ ## Quality contract (do not break)
52
+ - NEVER resample or re-encode the subject's RGB. Only the alpha mask is resized
53
+ (Lanczos); compositing copies RGB verbatim — see `core/compositing.py`. The one
54
+ opt-in exception is `--clean-edges`, which recolours semi-transparent edge pixels only.
55
+ - Output keeps the exact input dimensions. PNG is always lossless; WebP uses
56
+ `lossless=True, exact=True`.
57
+ - The other opt-in exception is finishing (`core/finish.py`: `--background`, `--square`,
58
+ `--pad`, `--size`, `--shop`): it blends edge pixels onto a colour, crops, resamples or
59
+ writes JPEG only when asked. Review sheets keep judging the transparent cut-out (a
60
+ preview saved before finishing), never the finished image.
61
+ - Originals are never modified, moved or deleted. Output always goes to a new
62
+ `<name>-no-bg/` folder.
63
+
64
+ ## Conventions
65
+ - Strict typing (mypy strict, no `Any` escape hatches), frozen dataclasses, named exports.
66
+ - English only: code, comments, docs, UI copy, terminal output.
67
+ - Minimal dependencies — justify every new one.
68
+ - New logic ships with tests: unit for pure logic, integration for runner/CLI/UI.
69
+ - Conventional Commits on feature branches; never commit to `main` directly.
70
+
71
+ ## Gotchas
72
+ - `bulk/models.py` scores come from `scripts/bench.py` plus blind vision judging (see
73
+ `references/models.md`). Re-run both before changing a score or adding a model; every
74
+ ranked model needs a measured entry in `MODEL_PEAK_GB`.
75
+ - rembg downloads model weights on first use to `~/.u2net/` (needs network once, ~224 MB).
76
+ - RAM is the real limit. Measured peak per worker without matting (CPU, tuned session):
77
+ `birefnet-general-lite` 9.4 GB · other BiRefNet variants 11.6 · `isnet-general-use` 2.4 ·
78
+ `u2net` 1.8 · `silueta` 0.7 (all 11 in `bulk/plan.py`). Nearly constant per model: each
79
+ model infers at a fixed size whatever the photo size.
80
+ - Edge matting adds ~0.35 GB per matted MP plus ~2.3 GB per million uncertain-band pixels
81
+ (a 4 MP wire chair: 4.9 GB; a product shot: 1.8 GB). `core/matting.py` shrinks the matting
82
+ resolution to fit a budget the worker sets from free RAM (0.6–3 GB), re-measuring after each
83
+ step (the eroded band shrinks slower than the area). Scaling the matte back to full
84
+ resolution costs ~0.03 GB/MP more (~0.065 with `--clean-edges`), outside that budget. The
85
+ start floor counts 0.6 GB of matting (lite: ~12 GB for 12 MP photos); parallel sizing, 3 GB.
86
+ - A long-lived worker's RSS creeps to ~3x one image's peak (heap fragmentation from images
87
+ of different sizes; `gc` and malloc pressure relief do not help). Workers restart when RSS
88
+ ends an image more than 1 GB above the model's peak (`recycle_above_gb`). Measured on the
89
+ edge-heavy bench: lite 15.7 → 12.3 GB, silueta 9.1 → 3.9 GB. They only restart while free RAM
90
+ is below reserve + full matting + margin (~5.5 GB): a reload costs ~2 s per image.
91
+ - Worker stdout goes to devnull: pymatting prints harmless "incomplete Cholesky" warnings there.
92
+ - On CPU a second worker adds only ~25% throughput (ONNX already uses every core);
93
+ more workers are slower. `OMP_NUM_THREADS` sets intra-op threads per worker.
94
+ - `rembg.remove(..., only_mask=True)` silently ignores `alpha_matting`. Edge matting is
95
+ done by `core/matting.py` instead — never pass matting flags to rembg.
96
+ - Matting runs at ≤ 4 MP; sure foreground/background come from the full-resolution
97
+ mask. Keep the trimap erosion separable (row pass + column pass): a square
98
+ structure is ~40× slower on large photos.
99
+ - CoreML is listed by onnxruntime on macOS but BiRefNet does not compile to it; treat
100
+ it as CPU.
101
+ - 16-bit greyscale must be scaled, not converted: Pillow's `I;16 -> RGB` clips to white.
102
+ - Bench: results in `BENCHMARK.md` + `benchmark/` (scores, image credits; photos stay out of
103
+ git). `scripts/bench.py INPUT RESULTS [--model M ...]` writes
104
+ before/after sheets, time per image and peak RAM; `scripts/bench_grids.py` makes blind
105
+ grids (models as letters) and close-ups for judging.
@@ -0,0 +1,202 @@
1
+ # Benchmark
2
+
3
+ How well each background-removal model works, how fast it is and how much RAM
4
+ it needs, measured on 80 hard images and judged blind. These numbers drive
5
+ `--model auto` and the skill's model guide.
6
+
7
+ **In short**
8
+
9
+ - The default, `birefnet-general-lite`, scores **7.9/10** overall, against 8.0 for
10
+ `birefnet-general`, at **3.2 s per product photo** against 5.6 s.
11
+ - On 35 real product catalogue photos it scores **8.6/10**, the best of the 11
12
+ models, and never 3 or less.
13
+ - With **3.4 GB of free RAM**, `silueta` still scores 8.1 on clean product shots.
14
+ On hair, fur and plants the light models drop to ~5 against 7.6, so the skill
15
+ asks before using one.
16
+ - The cut-out reviewer flags **8 of 9** cut-outs the judges scored 5 or less.
17
+
18
+ ## Setup
19
+
20
+ - **Machine:** Apple M5 (4 performance cores), 34 GB RAM, CPU only (ONNX Runtime).
21
+ - **Engine:** `bulk-bg-remove` 0.1.0, one worker, edge matting on (the default),
22
+ everything else at defaults. Times are per image and include matting.
23
+ - **Models:** the 11 local models rembg ships with permissive licences.
24
+ Excluded: `bria-rmbg` (non-commercial licence), `withoutbg` and `atlascloud`
25
+ (cloud APIs, not local), `birefnet-general-fp16` (needs extra packages),
26
+ `birefnet-cod` (camouflage research model), `sam` (needs prompts).
27
+
28
+ ## Images (80 judged)
29
+
30
+ | Set | Images | What it tests |
31
+ |---|---|---|
32
+ | edges | 10 | hair, fur, wire, bristles, branches, a dandelion |
33
+ | materials | 8 | glass, chrome, black on black, white on white, hard shadows |
34
+ | composition | 9 | groups, crowds, a logo, a cartoon, a shelf, a landscape with no subject |
35
+ | formats | 18 | HEIC, AVIF, WebP, TIFF, BMP, CMYK, 16-bit grey, palette PNG, ICC, EXIF rotation, a wrong extension, existing alpha, 180 px, 45 MP, a 5:1 panorama |
36
+ | catalogue | 35 | real product catalogue photos (cleaning products, mostly on white) |
37
+
38
+ The 27 photos in the first three sets, and the sources of the 45 MP,
39
+ panorama and portrait format tests, are public (CC0, CC BY, CC BY-SA or public
40
+ domain, from Wikimedia Commons); authors, licences and links are in
41
+ [`benchmark/images.csv`](benchmark/images.csv). The catalogue photos belong to
42
+ a company and are not redistributed; they appear as `catalogue-NN`, and the
43
+ other 14 format tests were made from them.
44
+
45
+ ## Judging
46
+
47
+ Each image got one comparison grid: the original plus the 11 cut-outs on a
48
+ checkerboard, labelled A–K in a fixed shuffled order, so the judge could not
49
+ tell which model made which cut-out. The judge, a vision model (Claude), also
50
+ looked at full-resolution crops of the hardest regions, on black, white and
51
+ checkerboard. Every image was zoomed into.
52
+
53
+ Scores are 0–10 for how usable the cut-out is as a professional product or
54
+ portrait asset: **10** clean, complete subject, fine edges kept, no background
55
+ left · **7** small fixable flaws · **4** visible flaws (halo, chunks of
56
+ background, missing parts) · **1** unusable · **0** empty.
57
+
58
+ Every score, with the image's content tags, is in
59
+ [`benchmark/scores.csv`](benchmark/scores.csv).
60
+
61
+ ## Results
62
+
63
+ Mean score per set (0–10), images scored 3 or less, speed and RAM. RAM is the
64
+ model alone and the free RAM the planner asks for before a run on 12 MP photos
65
+ (model, image buffers, edge matting and a 1.5 GB reserve).
66
+
67
+ | Model | All (80) | edges (10) | materials (8) | composition (9) | formats (18) | catalogue (35) | ≤ 3 | s/img catalogue | s/img edges | Model RAM | Free RAM needed |
68
+ |---|---|---|---|---|---|---|---|---|---|---|---|
69
+ | `birefnet-general` | **8.0** | 7.0 | 7.8 | 6.8 | 8.4 | 8.4 | 1 | 5.6 | 9.6 | 11.6 GB | 14.3 GB |
70
+ | `birefnet-general-lite` (default) | **7.9** | 6.2 | 7.6 | 6.6 | 8.3 | 8.6 | 2 | 3.2 | 6.5 | 9.4 GB | 12.1 GB |
71
+ | `birefnet-hrsod` | **7.7** | 6.4 | 7.4 | 6.6 | 8.1 | 8.3 | 3 | 5.6 | 9.7 | 11.6 GB | 14.3 GB |
72
+ | `birefnet-massive` | **7.6** | 5.3 | 7.0 | 6.0 | 8.3 | 8.5 | 4 | 5.6 | 9.0 | 11.6 GB | 14.3 GB |
73
+ | `birefnet-dis` | **7.5** | 5.5 | 7.2 | 5.7 | 7.9 | 8.4 | 4 | 5.5 | 7.9 | 11.6 GB | 14.3 GB |
74
+ | `isnet-general-use` | **6.7** | 5.2 | 5.4 | 3.6 | 7.9 | 7.6 | 11 | 1.3 | 7.8 | 2.4 GB | 5.1 GB |
75
+ | `silueta` | **6.6** | 4.5 | 5.1 | 4.1 | 7.8 | 7.5 | 11 | 0.4 | 6.1 | 0.7 GB | 3.4 GB |
76
+ | `u2net` | **6.5** | 4.4 | 5.6 | 4.2 | 7.8 | 7.3 | 8 | 0.5 | 3.3 | 1.8 GB | 4.5 GB |
77
+ | `birefnet-portrait` | **6.5** | 5.6 | 3.5 | 4.0 | 7.7 | 7.4 | 15 | 5.5 | 12.4 | 11.6 GB | 14.3 GB |
78
+ | `u2net_human_seg` | **4.6** | 3.2 | 2.8 | 3.1 | 7.0 | 4.5 | 37 | 0.8 | 3.2 | 1.8 GB | 4.5 GB |
79
+ | `isnet-anime` | **2.2** | 0.5 | 2.0 | 2.2 | 1.4 | 3.1 | 64 | 1.2 | 1.3 | 2.2 GB | 4.9 GB |
80
+
81
+ All 11 models processed all 82 files with no failures (two catalogue files
82
+ sharing a name were timed but not judged).
83
+
84
+ ### By kind of image (what `--model auto` uses)
85
+
86
+ Images grouped by their content tags into the profiles an agent picks from.
87
+ `auto` takes the highest score that fits in free RAM, and asks before using a
88
+ model more than 0.5 points below the best.
89
+
90
+ | Profile | n | Best | Next | Light models (~3.5–5 GB free) |
91
+ |---|---|---|---|---|
92
+ | `uniform` — products, objects | 39 | lite 8.6 · general 8.6 | hrsod 8.5 · massive 8.5 | u2net 8.1 · silueta 8.1 · isnet 7.7 |
93
+ | `complex` — hair, fur, plants, thin parts | 32 | general 7.6 | lite 7.4 · hrsod 7.3 | isnet 6.0 · silueta 5.2 · u2net 5.2 |
94
+ | `people` | 8 | general 7.8 | dis 7.4 · massive 7.2 | u2net 6.0 · silueta 5.8 · isnet 5.2 |
95
+ | `scene` — cluttered | 6 | general 6.3 | hrsod 5.7 | u2net 4.0 · silueta 4.0 · isnet 3.7 |
96
+ | `drawing` | 1 | isnet-anime 9.0 | lite 8.0 | — |
97
+
98
+ ## RAM
99
+
100
+ Peak resident memory of a worker on the edge-heavy set, before and after
101
+ bounding edge matting and restarting workers whose heap had grown (both in
102
+ v0.1.0):
103
+
104
+ | Model | Before | After | Planner's figure |
105
+ |---|---|---|---|
106
+ | `birefnet-general-lite` | 15.7 GB | 12.3 GB | 12.6 GB |
107
+ | `birefnet-general` | 17.5 GB | 14.4 GB | 14.8 GB |
108
+ | `silueta` | 9.1 GB | 3.9 GB | 3.9 GB |
109
+ | `u2net` | 9.3 GB | 5.1 GB | 5.0 GB |
110
+
111
+ Edge matting costs ~0.35 GB per matted megapixel plus ~2.3 GB per million
112
+ pixels in the uncertain band, so a wire chair needs far more than a bottle.
113
+ 18 of the 20 re-checked cut-outs came out pixel-identical after the change.
114
+
115
+ ## The cut-out reviewer
116
+
117
+ Three reviewers (the skill's `bg-reviewer` guide, nothing else) looked at the
118
+ 62 default-model cut-outs of the edges, materials, composition and catalogue
119
+ sets, without the judges' scores.
120
+
121
+ | | |
122
+ |---|---|
123
+ | Bad cut-outs (judge score ≤ 5) flagged | **8 of 9** |
124
+ | Good cut-outs (≥ 8) flagged | 5 of 45 (2 only for `--clean-edges`) |
125
+ | Proposed fixes that the judges score higher | 5 of 11 measurable (e.g. 5 → 8 on long fur, plants, curly hair) |
126
+ | …the same | 3 |
127
+ | …1 point lower | 3, all on cut-outs already ≥ 7 |
128
+
129
+ Because a second pass can make a good cut-out worse, the skill runs fixes into
130
+ a separate folder and keeps the new cut-out only when the reviewer judges it
131
+ better.
132
+
133
+ ## End-to-end: a fresh agent, no context
134
+
135
+ A new Claude Code session, with only the plugin installed and no other
136
+ context, got one request: *"use the bulk-bg-remove skill to remove the
137
+ background from every photo in this folder"*, on a 248-image test folder (the
138
+ benchmark sets plus 151 catalogue photos and a deliberately messy folder). It
139
+ was allowed to run the engine and to copy files, nothing else.
140
+
141
+ - It installed the engine, looked at the sample sheet, picked `uniform` for the
142
+ folder and ran it in the background: **247 of 248 done**; the one failure was
143
+ a truncated file, reported as damaged. Non-images, a GIF, a hidden file and an
144
+ earlier output folder were listed as skipped, each with its reason.
145
+ - It split 21 review sheets across **4 `bg-reviewer` subagents** in parallel,
146
+ redid the flagged images in a side folder, had a fresh reviewer compare old
147
+ and new, and kept the new version for 4 of them (a handler's arm gone from a
148
+ dog, a wine glass stem recovered, a cutter tip and a jug shoulder restored).
149
+ - It reported what it could not fix (a colour tint on a dandelion and a plant,
150
+ two see-through metal handles) and what the user should decide (placeholder
151
+ "no photo" images, scenes with no clear subject, a 180 px original).
152
+
153
+ What it surfaced, and what changed since: agent file readers ignore
154
+ transparency and show the original background in the output PNG, so
155
+ reviewers now get flattened close-ups on black and white (`zoom`); and fixes
156
+ now go to a `<name>-retry-no-bg` folder next to the output instead of `/tmp`,
157
+ which needed extra approval to copy from.
158
+
159
+ A second fresh session with those fixes, from a clean install, did the same
160
+ job with close-ups: **5 reviewers**, 214 cut-outs fine, 20 redone in one
161
+ round with four different fixes (`--profile complex`, `--model
162
+ birefnet-general`, `--clean-edges`, `--model birefnet-portrait`), **8 kept**
163
+ because they were clearly better (long fur, curly and loose hair, a cat, a
164
+ wine glass, three catalogue products), 12 kept as they were and reported.
165
+ Every redone file differed from the first pass; none was copied over without
166
+ a reviewer's `keep: new`.
167
+
168
+ A third fresh session tested the shop flow from a clean install. The only
169
+ request was *"use the bulk-bg-remove skill to remove the background from every
170
+ photo in this folder; they are for my online store"*. It picked `--shop` on its
171
+ own and processed **247 of 248**: every output was a 2000×2000 white JPEG
172
+ carrying the `--shop` finish in its metadata. Five reviewers found 17 to
173
+ redo. The agent redid them with the same finishing flags and kept **9** that
174
+ were clearly better. In its report it listed the 5 that a second pass did not
175
+ fix, the placeholders and scenes that do not belong in a shop, and the small
176
+ originals that `--size 2000` had to enlarge, offering `--size 1000` as an
177
+ option. The whole session cost about $5.70 in model usage, most of it for
178
+ looking at review close-ups.
179
+
180
+ ## Caveats
181
+
182
+ - One judge (a vision model) per image, no second opinion: read gaps under
183
+ ~0.5 points as ties.
184
+ - Small samples behind some rows: `drawing` has 1 image, `scene` 6, `people` 8.
185
+ - The catalogue set is one product line (cleaning products, mostly on white);
186
+ fashion, food or jewellery may differ.
187
+ - One machine, CPU only, one worker. No GPU timings.
188
+ - `--clean-edges` and `--fast-edges` were not scored.
189
+
190
+ ## Reproduce
191
+
192
+ ```bash
193
+ uv sync
194
+ # 1. Run every model on a folder of photos (times, peak RAM, before/after sheets)
195
+ uv run python scripts/bench.py PHOTOS RESULTS --model birefnet-general-lite --model silueta ...
196
+ # 2. Blind grids for judging (models shown as letters; GRIDS/index.json maps them back)
197
+ uv run python scripts/bench_grids.py PHOTOS RESULTS GRIDS
198
+ # 3. Close-ups of one region while judging
199
+ uv run python scripts/bench_grids.py --zoom GRIDS wine-glass ORIGINAL,A,B 0.2 0.1 0.8 0.6
200
+ ```
201
+
202
+ The public photos can be downloaded from the links in `benchmark/images.csv`.
@@ -0,0 +1 @@
1
+ @AGENTS.md
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Btike
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,180 @@
1
+ Metadata-Version: 2.5
2
+ Name: bulk-bg-remove
3
+ Version: 0.1.0
4
+ Summary: Remove image backgrounds locally and in bulk: an agent skill for Claude Code, Codex and any agent, plus the engine behind it.
5
+ Project-URL: Homepage, https://github.com/Btike/bulk-bg-remove
6
+ Project-URL: Repository, https://github.com/Btike/bulk-bg-remove
7
+ Project-URL: Issues, https://github.com/Btike/bulk-bg-remove/issues
8
+ Project-URL: Benchmark, https://github.com/Btike/bulk-bg-remove/blob/main/BENCHMARK.md
9
+ Author: Btike
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: agent-skill,background-removal,birefnet,bulk,claude-code,codex,image-processing,rembg,remove-background,transparent-png
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Console
15
+ Classifier: Environment :: Web Environment
16
+ Classifier: Intended Audience :: End Users/Desktop
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Multimedia :: Graphics
23
+ Requires-Python: <3.14,>=3.11
24
+ Requires-Dist: fastapi>=0.110
25
+ Requires-Dist: numpy>=1.26
26
+ Requires-Dist: pillow-heif>=0.18
27
+ Requires-Dist: pillow>=11.3
28
+ Requires-Dist: psutil>=5.9
29
+ Requires-Dist: pymatting>=1.1
30
+ Requires-Dist: python-multipart>=0.0.9
31
+ Requires-Dist: rembg[cpu]>=2.0.86
32
+ Requires-Dist: rich>=13.7
33
+ Requires-Dist: scipy>=1.11
34
+ Requires-Dist: uvicorn>=0.29
35
+ Description-Content-Type: text/markdown
36
+
37
+ <p align="center">
38
+ <picture>
39
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Btike/bulk-bg-remove/main/assets/logo-dark.svg">
40
+ <img src="https://raw.githubusercontent.com/Btike/bulk-bg-remove/main/assets/logo-light.svg" width="200" alt="bulk-bg-remove logo: a pixel-art monitor showing a green vase with a pink tulip on a transparency checkerboard">
41
+ </picture>
42
+ </p>
43
+
44
+ <h1 align="center">bulk-bg-remove</h1>
45
+
46
+ <p align="center"><em>Every photo in the folder. No background. Nothing leaves your machine.</em></p>
47
+
48
+ <p align="center">
49
+ <img alt="works with" src="https://img.shields.io/badge/works%20with-Claude%20Code%20·%20Codex%20·%20any%20agent-0d1117?style=flat-square">
50
+ <img alt="license" src="https://img.shields.io/badge/license-MIT-0d1117?style=flat-square">
51
+ <a href="https://pypi.org/project/bulk-bg-remove/"><img alt="PyPI" src="https://img.shields.io/pypi/v/bulk-bg-remove?style=flat-square&color=0d1117&label=pypi"></a>
52
+ </p>
53
+
54
+ <p align="center">
55
+ <img src="https://raw.githubusercontent.com/Btike/bulk-bg-remove/main/assets/demo.webp" width="880" alt="Demo: an agent is asked to remove the background from every photo in a folder; a bottle of olive oil loses its background, a reviewer catches background left by a cat's ear and keeps the redone cut-out, the products switch between white, mint and rose backgrounds and land in an online store">
56
+ </p>
57
+
58
+ <p align="center"><strong>Other skills run a model. This one checks every cut-out and redoes the bad ones.</strong></p>
59
+
60
+ <p align="center">
61
+ <strong>11 models benchmarked on 80 hard images, judged blind at zoom.</strong><br>
62
+ The default scored <strong>8.6/10 on real product catalogue photos</strong>, the best of the 11, at <strong>3.2 s per photo</strong> on a laptop CPU.<br>
63
+ <sub>Apple M5, CPU only, one worker. Method, every score and the RAM numbers: <a href="https://github.com/Btike/bulk-bg-remove/blob/main/BENCHMARK.md">BENCHMARK.md</a>.</sub>
64
+ </p>
65
+
66
+ ## What it is
67
+
68
+ An agent skill plus the engine behind it. Ask your coding agent to *"remove the
69
+ background from every photo in this folder"* and it:
70
+
71
+ 1. installs the engine (one `uv tool install`, ~500 MB with Python),
72
+ 2. checks your machine (free RAM, formats) and plans the run,
73
+ 3. looks at a sample, picks the best model that fits your free RAM (BiRefNet when there is
74
+ room), and cuts out every image in a queue or in parallel depending on RAM and CPU,
75
+ 4. has a second agent, with fresh eyes, review every cut-out on black and on white,
76
+ redo the bad ones with a better setting and keep whichever version is better,
77
+ 5. tells you what worked, what failed and why.
78
+
79
+ Output goes to a new `<name>-no-bg/` folder next to the input. Originals are never
80
+ touched, and the subject's pixels are copied bit for bit: only the alpha channel is new.
81
+
82
+ Selling online? `--shop` puts every product on white, square, 2000 px and ready to
83
+ upload; `--background "#E6F6EA"` uses your brand colour instead.
84
+
85
+ <p align="center">
86
+ <img src="https://raw.githubusercontent.com/Btike/bulk-bg-remove/main/assets/showcase.webp" width="880" alt="Four before-and-after pairs: three friends by train tracks, a black camera on black, a bottle of olive oil, and a white bicycle against a wall, each cut out onto a transparency checkerboard">
87
+ </p>
88
+
89
+ Reads JPG, PNG, HEIC, WebP, AVIF, TIFF and BMP (by content, not extension), follows
90
+ EXIF rotation, and handles CMYK, 16-bit and 45 MP photos.
91
+
92
+ ## Install
93
+
94
+ Any agent ([skills CLI](https://github.com/vercel-labs/skills), needs Node.js 22.20 or newer):
95
+
96
+ ```bash
97
+ npx skills add Btike/bulk-bg-remove
98
+ ```
99
+
100
+ <details>
101
+ <summary>Claude Code</summary>
102
+
103
+ ```
104
+ /plugin marketplace add Btike/bulk-bg-remove
105
+ ```
106
+ ```
107
+ /plugin install bulk-bg-remove@bulk-bg-remove
108
+ ```
109
+ </details>
110
+
111
+ <details>
112
+ <summary>Codex</summary>
113
+
114
+ ```bash
115
+ codex plugin marketplace add Btike/bulk-bg-remove
116
+ codex plugin add bulk-bg-remove@bulk-bg-remove
117
+ ```
118
+ </details>
119
+
120
+ <details>
121
+ <summary>Just the command, no agent</summary>
122
+
123
+ ```bash
124
+ uv tool install bulk-bg-remove
125
+ bulk-bg-remove ~/Pictures/products # → ~/Pictures/products-no-bg/
126
+ bulk-bg-remove # opens a drag-and-drop page in your browser
127
+ ```
128
+ </details>
129
+
130
+ ## Which model it picks
131
+
132
+ You do not choose: the agent looks at a few of your photos, tells the engine
133
+ what kind they are, and the engine takes the best model for that kind that
134
+ fits in your free RAM. Scores are from a [blind-judged benchmark](https://github.com/Btike/bulk-bg-remove/blob/main/BENCHMARK.md) (0–10):
135
+
136
+ | Your photos | Best model | With little RAM (~4 GB free) |
137
+ |---|---|---|
138
+ | Products, objects | `birefnet-general-lite` 8.6 | `silueta` 8.1, used on its own |
139
+ | Hair, fur, plants, wires | `birefnet-general` 7.6 | `silueta` 5.2, only if you say yes |
140
+ | People | `birefnet-general` 7.8 | `silueta` 5.8, only if you say yes |
141
+ | Busy scenes | `birefnet-general` 6.3 | `silueta` 4.0, only if you say yes |
142
+ | Drawings, anime | `isnet-anime` 9.0 | needs ~5 GB free |
143
+
144
+ ## Options
145
+
146
+ | Flag | What it does |
147
+ |---|---|
148
+ | `--profile uniform\|complex\|people\|scene\|drawing` | what the photos are; the model follows |
149
+ | `--model NAME` | force a model instead of `auto` |
150
+ | `--format webp\|jpg` | smaller lossless files (PNG by default); JPEG only with a background |
151
+ | `--shop` | ready for a shop: white, square, product filling ~85%, 2000 px, JPEG |
152
+ | `--background white\|#RRGGBB` | a solid colour behind the subject |
153
+ | `--square` · `--pad PCT` · `--size PX` | square canvas · margin around the subject · longest side |
154
+ | `--clean-edges` | remove the old background's colour halo from hair and fur edges |
155
+ | `--fast-edges` | skip edge matting: faster, coarser hair |
156
+ | `--review-sheets` | sheets and close-ups for reviewing the cut-outs |
157
+ | `--only FILE` | redo just some images, keeping their output names |
158
+ | `--dry-run --json` | scan and plan only; one JSON event per line for agents |
159
+ | `doctor` | check the machine, and what `auto` would pick right now |
160
+
161
+ ## Requirements
162
+
163
+ - Tested on macOS (Apple silicon), Linux and Windows, with a real-model run on each in CI
164
+ (Python 3.11–3.13). CPU by default; CUDA with `onnxruntime-gpu`.
165
+ - **3.5 GB of free RAM** is enough for product photos: the engine picks the best
166
+ model that fits (about 12 GB gets the best ones). For hair, fur and plants a
167
+ light model is clearly worse, so the agent asks before using one.
168
+ - The model downloads once (~220 MB). After that everything runs offline.
169
+
170
+ ## Credits
171
+
172
+ Built on [rembg](https://github.com/danielgatis/rembg) and
173
+ [BiRefNet](https://github.com/ZhengPeng7/BiRefNet). Showcase and demo photos (CC0, via
174
+ Wikimedia Commons): Priscilla Du Preez, Dennis Klein, margenauer, Natasza Remesz,
175
+ Mona Magnussen, Tiko Giorgadze, Dmitry Ratushny. The demo film is drawn in code (GSAP, rendered frame by
176
+ frame in headless Chromium) from the engine's real output.
177
+
178
+ ## License
179
+
180
+ MIT — see [LICENSE](https://github.com/Btike/bulk-bg-remove/blob/main/LICENSE).