This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
FirstPass (phototriage) is a privacy-first, local CLI and visual review tool built for solo wedding and event photographers.
The Problem
3,000 frames come off the memory card after a 10-hour wedding. The photographer only delivers 400.
Culling those photos is 4 to 8 hours of tedious, unpaid labour: eyeballing near-identical burst shots to find the single frame where nobody blinked, discarding motion blur, and grouping reception moments. It is the single most hated task in event photography, and it happens right after the adrenaline of the shoot on a tight delivery deadline.
Who Would Pay For It?
Solo wedding and portrait photographers currently pay $20 to $40 every month for cloud-based culling tools like Aftershoot, Narrative Select, or Imagen.
FirstPass targets this exact market with a clear, honest promise: Not "AI picks your best artistic photos" (a claim photographers mistrust), but "here are the technical rejects (blurs, soft frames, redundant burst tails) isolated with mathematical precision, your keepers filed by category, and zero client photos ever leaving your drive."
Demo
FirstPass separates triage into two deliberate phases: Scan (which writes an audit plan and touches zero originals) and Apply (which safely isolates rejects into quarantine).
The Interactive HTML Review Plan
When phototriage scan runs, it generates an interactive, self-contained report.html with instant previews, sharpness variance diagnostics, and zero-shot category badges:
Quick Walkthrough
# 1. Generate a 28-frame synthetic shoot (blurs, bursts, bokeh, sharp keepers)
python scripts/make_fixtures.py /tmp/demo-shoot
# 2. Scan and triage with local open-weight AI (measures ~50 images/sec on CPU)
phototriage scan /tmp/demo-shoot --ai
# 3. Open the visual plan in your browser to inspect every decision
open /tmp/demo-shoot/.phototriage/report.html
# 4. Preview what will happen without touching files (dry run)
phototriage apply /tmp/demo-shoot --dry-run
# 5. Move rejects safely into quarantine folders (_FirstPass_rejected/)
phototriage apply /tmp/demo-shoot --action move
Code
The complete source code, synthetic benchmark generator, and test suite are available on GitHub:
Big0boy
/
phototriage
Find blurry and near-duplicate photos, and categorize keepers with local open-weight AI.
phototriage (FirstPass)
3,000 frames come off the card. The photographer only wants to look at 400.
Find blurry and near-duplicate photos, and categorize keepers with an open-weight model running entirely on your own machine.
Nothing is uploaded. The only optional network access in an --ai run is the one-time download of open CLIP weights to ~/.cache/huggingface/. After that, the tool works 100% offline. No client photo, thumbnail, or score ever leaves your drive.
Who is this for?
- Solo wedding & event photographers who shoot 2,000–4,000 frames per event and spend 4–8 unpaid hours per shoot manually culling near-identical burst frames.
- Privacy-conscious professionals: Client contracts increasingly prohibit uploading unreleased photos to third-party cloud AI vendors. phototriage runs entirely locally — satisfying privacy clauses with zero marginal cost per image.
- Anyone with large photo shoots looking for an automated, explainable first pass that separates technical failures from keepers without making subjective…
- Language: Python 3.9+
-
Packaging: Installable directly via
pip install -e .with thephototriageCLI entrypoint. -
Test Suite: 43 automated tests running on synthetic in-memory fixtures (
pytest tests -q).
How I Built It
FirstPass was built with a strict hierarchy: cheap mathematical gates first, local open-weight neural networks second, and absolute reversibility at the file level.
[ Camera JPEGs ]
│
â–¼
1. Metadata & Fast Decode (Pillow BOX downsampling)
│
â–¼
2. Tile-Based Focus Scoring (Top 2% Laplacian variance — preserves shallow DOF bokeh)
│
â–¼
3. Dual-Signal Burst Clustering (EXIF time + 64-bit dHash + 16x16 shape correlation guard)
│
â–¼
4. Open-Weight CLIP AI (openai/clip-vit-base-patch32: zero-shot labels + embeddings)
│
â–¼
5. Audit Artifacts (report.html, triage.csv, manifest.json)
│
â–¼
6. Reversible Apply (moves rejects to _FirstPass_rejected/ with collision tracking)
1. Bokeh-Preserving Focus Metric
Standard blur detectors compute global image variance. For wedding photography, that fails completely: a portrait shot at $f/1.4$ has a razor-sharp eye and a creamy, defocused background. Global averaging calls it "soft" and deletes the best photo of the day.
FirstPass divides the image into a $32 \times 32\text{px}$ tile grid, computes Laplacian variance per tile, and averages only the sharpest 2% of tiles. A small off-centre subject (like a bride's face covering 3% of the frame) is preserved, while true motion blur is caught instantly.
2. Dual-Signal Burst Clustering
Bursts taken within a 3.0-second window are grouped, and only the sharpest frame is nominated as the keeper. To prevent fine textures (like confetti, gravel, or lace) from falsely collapsing into identical hashes, FirstPass requires both:
- A 64-bit difference hash (
dHash), AND - A mean-centered, scale-normalized $16 \times 16$ grayscale signature Pearson correlation ($\ge 0.92$).
3. Open-Weight CLIP (openai/clip-vit-base-patch32)
- Powered by open weights licensed under the permissive MIT License.
- Downloaded once (~600 MB) to
~/.cache/huggingface/and runs 100% offline. - Evaluates photos in bounded memory batches against natural language prompts ("a wedding ceremony", "decorations, table settings and details", "two people posing together").
- Critical rule: The model is used to label and organize, never to delete. Deletion decisions are strictly mathematical and explainable.
Why Does Open Innovation Matter?
Open-source and open-weight models aren't just an implementation choice for this project — they are the entire commercial thesis:
- Client Contracts Forbid Closed APIs: Wedding couples sign legally binding contracts. An increasing number of modern contracts explicitly state that raw client photos will not be fed to third-party commercial cloud AI services. Proprietary cloud tools (Aftershoot, Narrative) cannot clear these contract terms. Running an open-weight model locally is the only way a photographer can say: "I can put this in my contract: your photos never leave my machine."
- $0 Marginal Cost Across 90,000 Frames/Year: $3,000\text{ frames} \times 30\text{ weddings} = 90,000\text{ images/year}$. On per-image cloud APIs, token and inference costs eat directly into freelance margins. Locally on the photographer's existing MacBook or laptop, the marginal cost per image is effectively zero.
- Works in the Field with Zero Wi-Fi: Photographers cull on flights, in mountain cabins, or in hotel rooms with terrible Wi-Fi before traveling home. FirstPass requires zero internet connection.
-
Swappable Architecture:
Because CLIP is open, a photographer shooting motorsport or indoor receptions can swap the checkpoint (
--model <HF_ID>) or supply custom label files without asking vendor permission.


Top comments (0)