# ๐ŸŽจ Image Pipeline โ€” Napkin Notes ## What the spec wants Seller uploads phone photo โ†’ system auto-standardizes โ†’ consistent product catalogue - Background removal - Colour correction - Lighting normalization - Resize/crop to exact same dimensions - Store processed image against product variant ## What we found (FAFO'd 2026-09-13) ### ๐Ÿฅ‡ Photoroom (recommended for production) - **URL:** https://app.photoroom.com/create (signed up as `celestjux`) - **Docs:** https://docs.photoroom.com/ - **Pricing:** Basic $20/mo (BG removal only) ยท Plus $100/mo (full pipeline) ยท Enterprise custom - **Per image:** $0.02 (Basic) / $0.10 (Plus) - **Apparel-specific features:** - Ghost Mannequin โ€” makes clothes look worn without a real model - Virtual Model โ€” AI fashion models wearing the clothes - Virtual Try-On โ€” customers see clothes on themselves - AI Ironing โ€” smooth wrinkles on clothes - AI Relight โ€” fix lighting - AI Shadows โ€” realistic shadows - Product Staging, AI Backgrounds, AI Beautifier, AI Expand - **Batch:** yes, directory/Google Drive/Sheets - **Sandbox:** 1,000 free watermarked calls + 10 real for testing - **Verdict:** Does EVERYTHING the spec asks in one API call. $100/mo for 1K images. Ghost mannequin + AI ironing = killer for men's apparel. ### ๐Ÿฅˆ Bria AI (good BG removal, lighter features) - **API key:** saved at `~/.bria/credentials` - **Skills installed:** `/root/.claude/skills/bria-skills/` - **Tested:** โœ… BG removal works (RMBG 2.0), 39% transparent pixels on test image - **Features:** BG removal, relighting, upscale, product photography, object editing - **No ghost mannequin, no AI ironing, no virtual try-on** - **Verdict:** Good for BG removal + basic edits. Fallback to Photoroom for apparel-specific stuff. ### ๐Ÿฅ‰ rembg (free, self-hosted, offline) - **Installed:** โœ… via pip, u2net model (170MB) cached at `/root/.rembg/models/` - **Tested:** โœ… works, decent edges, white-on-light handled ok - **Limit:** BG removal ONLY. No colour correction, no lighting, no crop. - **Speed:** ~20s on CPU per image - **Verdict:** Free forever. Good offline fallback. Need OpenCV/Pillow on top for the rest. ### Quick-RMBG / Claude Background Removal Plugin - **Repo:** cloned at `/mnt/playground/Playground_V2/Claude-Background-Removal-Plugin/` - **What it is:** Claude Code skill wrapper around rembg (single/two-pass/batch/Dolphin right-click) - **pipx install blocked** by ctx git shim โ€” not installed yet - **Verdict:** Nice wrapper but not needed if we use Photoroom/Bria for the platform. ## Architecture decision ``` Production: Photoroom Plus API ($100/mo) โ””โ”€ one call = bg removal + lighting + shadows + crop + resize โ””โ”€ ghost mannequin for clothes-on-invisible-model shots โ””โ”€ AI ironing for wrinkle-free product photos Fallback: Bria RMBG 2.0 (free tier / per-image) โ””โ”€ BG removal when Photoroom is down or over quota Offline: rembg + Pillow/OpenCV โ””โ”€ dev/testing, batch processing without API costs ``` ## โœ… BUILT 2026-09-15 evening โ€” the pipe is real, end to end ``` phone/disk photo -> Image Studio (admin page) -> Photoroom /v2/edit -> unattached ActiveStorage blob -> review before/after -> Apply -> Spree product (existing, or created here) ``` - **Admin page:** `/admin/image_studio` (sidebar, between Products and Customers). Multi-upload from the device, background + size presets, per-file before/after, then attach to an existing product **or create a new listing** (name, price, publish toggle). Nothing touches the catalogue until Apply โ€” the result is held as an unattached blob, so Discard is just navigating away. - **CLI:** `scraped-catalogue/photoroom_to_spree.py --slug [--live]` - **Proven live:** a 6.52 MB phone PNG โ†’ 543 KB at 1000ร—1000; and two uploads โ†’ a new published product visible on the storefront at R259.11. ### The architecture question, settled Abang's call, and he was right: **the page is needed.** I had argued for a silent auto-on-upload hook (the spec says *"seller uploads โ†’ system standardises"*), but a seller wants to choose the shot and see the result before it ships. Fully automatic means a bad cutout goes live silently and the customer finds it first. **Manual control at the front, programmatic pipe behind it.** Photoroom's *Shopify Products* connector is a red herring for us โ€” it exists for merchants with no backend. We have one, so the plain API is the simpler path. ### Money, accurately | | Reality | |---|---| | API free tier | **10 images/month**, not 7 days. 9 left as of 2026-09-15 | | Sandbox | 1000/month, free, **every output watermarked** | | 7-day trial | That's the **web app**, a separate meter. Its Batch tool does **250 images at once** through the browser and costs no API credits | | Plus | $100/mo for the full pipeline | ๐Ÿ”ด **Photoroom adds little to the existing 160 products.** They are scraped studio shots already on white โ€” background removal removes a background that is already gone. Across 160 first-images there are only **3 aspect ratios and 4 sizes**; framing is the sole real defect, and Pillow squares them for free, offline. Photoroom earns its money on *phone photos of new stock*, which is exactly what Image Studio is for. ### Still open - [ ] **Batch** โ€” capped at `MAX_PHOTOS = 8`, synchronous, ~3-5s per image. More needs a background job - [ ] Currently on the **sandbox** key, so everything is watermarked. Flip `PHOTOROOM_API_KEY` in the backend `.env` for clean output - [x] ~~Pillow square-and-pad backfill for the existing 160~~ โ€” **scrapped 2026-09-15, measured and unnecessary.** See below. - [ ] Never tested on a real phone photo from Lisa โ€” the actual input this exists for. Ghost mannequin and AI ironing have nothing to work with on a scraped studio shot - [ ] Virtual Try-On โ€” could be a differentiator for the platform - [ ] Self-hosted option โ€” for v2, when volume justifies building our own pipeline ## ๐Ÿ“ Framing survey โ€” 2026-09-15, the backfill that wasn't needed I had the Pillow square-and-pad backfill queued as the next job. Measuring the 160 source images first killed it. The real distribution of **first images**: | Size | Ratio | Count | |---|---|---| | 762ร—1100 | 0.693 | 122 | | 800ร—1200 / 801ร—1200 | 0.667 | 32 | | 1200ร—1800 | 0.667 | 4 | | 1524ร—2200 | 0.693 | 1 | | **2400ร—2400** | **1.000** | **1** | The grid renders at `aspect-[3/4]` (0.75) with `object-cover`. At 0.693 the crop takes 7.6% of the height; at 0.667 it takes 11%. The **entire** inconsistency across 159 products is a 3.4% difference in vertical crop โ€” invisible. Padding them to square would also be self-defeating: a square displayed in a 3/4 frame gets re-cropped, so the padding I just added is what gets cut. ๐Ÿ”ด **One image was genuinely broken** โ€” `129-adidas-lifestyle-barreda-shoes-men-white-jp5928`, the only 1:1 in the catalogue. A square in a 3/4 frame loses **12.5% off each side**, which cut the heel and the toe off the shoe. Its 22 sibling shoe listings are all 762ร—1100 with the subject at 90-95% width and 24-33% height, so it was reframed to match: crop to the subject bbox, scale to 93% width, centre on the source's own background (234,238,239). 186KB โ†’ 65KB. Applied live via `reframe_129.py --apply` (upload at position 1, verify by re-read, then delete the original). **The lesson, not the fix:** the napkin said "3 aspect ratios and 4 sizes, framing is the sole real defect" and I turned that into a 160-file job. The numbers were right and the conclusion was wrong โ€” nobody had checked how far apart those ratios actually were. Measure the spread, not the count. ### Spree API shape โ€” two gotchas that cost a run - **Flat objects, not JSON:API.** `/api/v3/admin/products` returns fields on the object itself (`p["slug"]`), not under `p["attributes"]["slug"]`. The helper in `photoroom_to_spree.py` only survives because its fallback scan happens to use the flat form. - **`per_page` is silently ignored** โ€” it pages on `limit`. Sending `per_page=100` gets you 25 rows and no error, so a scan that stops at page 1 "finds" nothing. Meta key is `pages`, not `total_pages`. **Keys:** `/root/.photoroom/credentials` (chmod 600) on the house box; `PHOTOROOM_API_KEY` in the backend `.env`.