No description
Find a file
2026-09-10 23:37:42 +02:00
.agents/skills chore: add agent skills, docs, and project context 2026-09-10 23:12:00 +02:00
docs docs(map): record resolution of End-to-end verification and documentation update 2026-09-10 23:37:42 +02:00
static refactor: address review feedback on multipart field compatibility and form serialization 2026-09-10 23:32:40 +02:00
tests refactor: parameterize e2e tests and add CLI stdout assertions 2026-09-10 23:37:23 +02:00
.gitignore chore: add agent skills, docs, and project context 2026-09-10 23:12:00 +02:00
AGENTS.md chore: add agent skills, docs, and project context 2026-09-10 23:12:00 +02:00
app.py refactor: address review feedback on multipart field compatibility and form serialization 2026-09-10 23:32:40 +02:00
cleaner.py feat: add end-to-end verification and update documentation (#5) 2026-09-10 23:35:52 +02:00
CONTEXT.md chore: add agent skills, docs, and project context 2026-09-10 23:12:00 +02:00
gemini-only.yml chore: add agent skills, docs, and project context 2026-09-10 23:12:00 +02:00
mise.toml chore: add agent skills, docs, and project context 2026-09-10 23:12:00 +02:00
pytest.ini chore: add pytest.ini with pythonpath for direct test execution 2026-09-10 23:15:54 +02:00
README.md feat: add end-to-end verification and update documentation (#5) 2026-09-10 23:35:52 +02:00
requirements.txt feat: implement FastAPI backend and /api/clean endpoint (#3) 2026-09-10 23:24:36 +02:00
skills-lock.json chore: add agent skills, docs, and project context 2026-09-10 23:12:00 +02:00
unwrap_clothes.py refactor: address code review feedback on image info extraction and rescaling 2026-09-10 23:20:47 +02:00

Garment photo cleaner (unwrap-clothes)

Web application and CLI tool that cleans up second-hand clothing photos for marketplace listings (Vinted, eBay, Depop). It removes fabric wrinkles, places garments on studio backdrops (warm beige or bright white), and preserves garment shapes, colors, prints, buttons, and defects.

Uses OpenRouter's Image API with meta/muse-image.

Requirements

  • Python 3.9 or higher
  • OpenRouter API key with image generation credits

Install dependencies:

pip install -r requirements.txt

Set your API key (optional if provided in the Web UI or via --api-key):

export OPENROUTER_API_KEY="sk-or-v1-..."

Web UI

Start the local server:

python3 app.py

The application runs at http://127.0.0.1:8000.

Web UI capabilities

  • Drag-and-drop photo upload: Drop an image onto the upload zone or click to select from your filesystem.
  • Preset selector buttons: Switch between Warm beige and Bright white studio backdrop presets with a single click.
  • Editable prompt: Customize the full prompt text directly before sending.
  • OpenRouter model selection: Defaults to meta/muse-image, with full support for any OpenRouter image model.
  • API key management: Pass an API key directly in the UI or let the server fall back to the OPENROUTER_API_KEY environment variable.
  • Lanczos restoration toggle and badge: Enable or disable automatic upscaling back to source photo dimensions; inspect original and model resolution badges on results.
  • Side-by-side comparison: View the original photo and the cleaned result side-by-side.
  • Generation cost display: Displays the exact API cost reported by OpenRouter (e.g. $0.01).
  • One-click download: Download the cleaned photo with <original_name>_clean.<ext> naming.

CLI usage

Basic run with default soft beige background:

python3 unwrap_clothes.py shirt.jpg

Output saves next to the source photo as shirt_clean.jpg.

CLI options

Select a white background:

python3 unwrap_clothes.py shirt.jpg --bg white

Custom output path:

python3 unwrap_clothes.py shirt.jpg -o /path/to/listing_photo.jpg

Custom background description:

python3 unwrap_clothes.py shirt.jpg --bg "Soft cool grey studio background, even lighting"

Keep native model resolution (skip automatic upscale to input dimensions):

python3 unwrap_clothes.py shirt.jpg --no-restore-res

Override the model:

python3 unwrap_clothes.py shirt.jpg --model meta/muse-image

Pass API key explicitly:

python3 unwrap_clothes.py shirt.jpg --api-key "sk-or-v1-..."

Project architecture

  • cleaner.py: Core image processing module. Handles background preset prompts, image dimension and format detection via Pillow (get_image_info), Lanczos resolution restoration (restore_resolution_bytes), OpenRouter API calls (call_openrouter_images), and the complete cleaning workflow (clean_garment).
  • app.py: FastAPI application providing HTTP REST endpoints (POST /api/clean, GET /api/health) and serving the static single-page web UI from static/.
  • unwrap_clothes.py: Command-line interface wrapping clean_garment for standalone terminal execution and batch processing.
  • static/index.html: Responsive single-page application frontend featuring drag-and-drop photo upload, preset selectors, side-by-side comparison, and one-click downloads without external framework dependencies.

Testing

Run the test suite with pytest:

pytest

The suite covers:

  • tests/test_cleaner.py: Unit tests for resolution restoration, image dimension detection, base64 encoding/decoding, and OpenRouter API error handling.
  • tests/test_app.py: Backend tests for FastAPI routes, input validation, environment key fallback, and response payloads.
  • tests/test_ui.py: Frontend verification checking DOM structure, controls, and script logic in static/index.html.
  • tests/test_unwrap_clothes.py: CLI argument parsing, backwards-compatible exports, and exit codes.
  • tests/test_e2e.py: End-to-end integration tests verifying FastAPI POST /api/clean (including Lanczos restoration to source dimensions) and CLI subprocess invocation against a mocked OpenRouter service.

Why meta/muse-image is the default

Other image models on OpenRouter run into policy or cost issues on second-hand clothing photos:

  1. openai/gpt-5-image-mini: OpenAI's input image filter rejects photos with licensed character artwork (such as Winnie the Pooh, Disney, or cartoon prints), returning HTTP 400 safety errors regardless of prompt phrasing.
  2. qwen/qwen-image-3: Alibaba moderation frequently blocks full garment photos, and Qwen 3 Pro costs roughly $0.08 per image.
  3. meta/muse-image: Accepts photos of branded and character clothing, costs $0.01 per image, and finishes in 15 to 25 seconds.

Resolution handling

meta/muse-image caps output at roughly 1.3 to 1.8 MP (for example, 1376x1824) regardless of the size parameters passed to the API.

To avoid downsized uploads on marketplaces that expect high-resolution smartphone photos (such as 3024x4032), the tool automatically resizes the generated image back to the source file's exact dimensions using Lanczos interpolation. This preserves the aspect ratio and frame size of the original photo.

Known limitations

  • Garments that are physically folded or bunched over themselves in the photo remain bunched. Generative editing smooths surface wrinkles, but will not unfold fabric that covers other parts of the garment.
  • Small text on labels and complex repeating patterns can drift slightly from the original during generation.