Inspiration

In medical deserts and humanitarian settings, opticians are rare or out of reach, yet usable corrective lenses exist: donations, end-of-line stock, lenses taken from used glasses. The expensive part of a pair of glasses is the frame and the fitting. A recycled lens also has its own shape, and one prescription can pair two different shapes, one per eye, so a standard frame doesn't fit. Opticians use a costly tracer to measure a lens outline. We wanted to replace that machine with a phone, and the frame with a few dollars of 3D-printer filament. This is our answer to the OptiFrame challenge from Santé Numérique Sans Frontières.

What it does

EightEye is a mobile web app that takes a person from a lens to a printable frame in a few steps:

  • Photograph each lens, left and right, on a plain surface next to a standard bank card. The card gives the app a known size (85.6 × 53.98 mm).
  • The app straightens the photo into a top-down view, finds the lens outline, and shows its width (A), height (B) and perimeter in millimetres, with an overlay so you can check what it "saw".
  • It generates a 3D frame whose rims follow each lens's exact shape, even when the left and right lenses differ, joined by a bridge (18 mm by default) and with temple tenons that have pin holes.
  • You get a 3D preview you can rotate, a downloadable STL for printing, and a 1:1 SVG contour sheet to print and lay the real lens on.
  • Each frame is checked for a watertight mesh, a single connected body and printability without excessive supports, and the app warns you if something is off.

How we built it

We split the work into three layers joined by a shared JSON contract: lens outlines in millimetres plus eye, orientation and bridge width.

  • Vision (OpenCV, NumPy): We detect the card by colour and edge cues, check its aspect ratio against a real card, refine the corners by line fitting, and apply a perspective transform to a top-down view at a fixed scale. A transparent lens is hard to threshold, so we segment it from edge gradients instead of brightness. We try several gradient thresholds, close and fill the rim, filter by area, aspect ratio and solidity, then refine the rim with 720 rays and a dynamic-programming edge search. A Fourier-smoothed contour gives a robust A and B using the ISO 8624 "boxing" convention.
  • Geometry (Shapely, trimesh, manifold3d): The outline is repaired, resampled, smoothed with an FFT low-pass and recentred on its boxing centre. The two lenses are placed with the chosen bridge gap. Each rim is the lens grown by a clearance plus a wall. We add the bridge and tenons, extrude, and cut the openings with manifold boolean operations. The openings have a ledge, a pocket and a stepped 45° entry lip, so each lens clicks in and stays put and the frame prints without supports.
  • API (FastAPI): One endpoint measures two photos and returns the contract and overlays. A second turns the contract into a base64 STL, a 1:1 SVG and a validation report.
  • Frontend (React, TypeScript, Vite, three.js via React Three Fiber): A mobile-first flow with in-app camera capture and a file-picker fallback, result overlays, an interactive STL viewer and download buttons.

Challenges we ran into

  • Transparent lenses. Reflections, shadows and low-contrast edges break classic thresholding, so we moved to gradient-based edge detection with fallbacks.
  • Millimetre accuracy from a phone. Perspective, card detection and the choice of a reference object all affect the scale. We kept the contour as a polygon in millimetres so it serves both the measurement and the 3D generation.
  • Two different lenses. Left and right lenses can differ in shape and may be photographed back side up. We had to handle placement, mirroring and the nasal side correctly.
  • A printable frame. The frame has to be one closed body with clearance for a slightly domed lens, and it must print without supports. That drove the flat-extrusion design and the stepped lip.
  • Integration and camera access. Three layers built in parallel had to agree on one contract, and browsers only allow camera access over HTTPS, so we tested through tunnels.

Accomplishments that we're proud of

  • A working chain from a phone photo to a downloadable STL, running end to end in a mobile web app.
  • A frame generator that handles two different lens shapes, adds a bridge and tenons, and snaps the lens in.
  • Automatic checks on every frame (watertight, single body, overhang) with plain-language warnings and error messages.
  • A 1:1 printable SVG contour sheet with a scale bar, so anyone can verify the outline with the real lens and a printer.
  • No account and no API key needed.

What we learned

  • A transparent object shows up in its edges, not its surface, so gradients matter more than brightness.
  • Keeping one clean contract between vision, geometry and interface let three people work in parallel.
  • Manufacturing constraints such as overhangs and clearance shape the 3D design as much as the measurement does.
  • Verifying scale early and showing an overlay of what the algorithm sees saves a lot of debugging.

What's next for EightEye

  • Train or fine-tune a segmentation model on a purpose-built dataset (real, synthetic and augmented photos) for harder cases. Our current segmentation is classical computer vision.
  • Validate measurements against calipers on real lenses, then print frames and tune the clearance and lip on actual lenses.
  • Compare several photos of the same lens, and overlay the measured contour on the generated rim with the gap in millimetres.
  • Host it permanently on HTTPS and present it to the optometry and AI-for-impact communities the challenge points to.

Built With

Share this project:

Updates

Submission history