Skip to content

Repository files navigation

FootScan

Scan a foot with an ordinary phone camera and generate a 3D-printable, flexible-TPU orthotic insole that sits between the foot and the shoe.

Two flavors, one shared geometry core (proven bit-for-bit identical):

  • Desktop (this folder, Python) — accuracy king: photogrammetry (COLMAP) for the most accurate surface when a PC is available.
  • Mobile (mobile/, an installable PWA) — reach king: fully offline, on-device, no app store, no server — just a web link. Same insole math as desktop. Built for low-resource settings where a clinician or a laptop is hard to reach.

Parity is enforced by a test: python tools/parity_reference.py and node mobile/test/parity.mjs produce the same mesh (same faces, same volume).

 phone photos ──► COLMAP mesh ──► scale & orient ──► clean ──► orthotic ──► insole.stl
   (30–60 shots)   (reconstruct)   (real mm, sole down)        (total-contact)  (print in TPU)

Features

  • Total-contact insole — spreads load over the whole plantar surface.
  • Arch fill, heel cup (side cradle), heel lift (therapeutic raise).
  • Relief wells — tap-to-place offload pockets for prominences / ulcers.
  • Pressure-point smoothing — no sharp ridges on a foot that can't feel them.
  • Real-time 3D preview + top-down pressure map (mobile).
  • Clinical presets, left/right foot, shoe-size readout, STL + spec-sheet export.
  • Flexible-TPU-ready output with a print profile.

60-second try (mobile flavor, no scan, no COLMAP)

python -m http.server 8740 --directory mobile     # then open http://localhost:8740
# Tap a preset → drag the 3D view → switch to the map and tap to add a relief
# well → Download insole.stl.

Run the whole test suite with python tools/run_tests.py.

The orthotic is a total-contact insole: its bottom is a flat plate on the shoe footbed and its top conforms to the underside of the foot, so weight is spread over the whole sole instead of a few bony points. It adds an arch fill, a heel cup, optional relief wells to offload a prominence/ulcer, and smooths the top so there are no sharp pressure ridges.


⚠️ Read this first — Charcot foot & neuropathy safety

This tool was built with Charcot foot (Charcot neuro-osteoarthropathy) in mind, but that case is exactly where you must be most careful:

  • People with Charcot foot almost always have neuropathy — they cannot feel a bad pressure point. A poorly-offloaded insole can cause a pressure ulcer that the wearer never feels until it is infected, and that can end in amputation.
  • A do-it-yourself scan does not know where the bones, ulcers, or at-risk prominences are. The geometry here is only as good as the information you give it (notably the relief-well locations).
  • During an active/acute Charcot episode, offloading is usually total non-weight-bearing or a clinical CROW boot / TCC — not a printed insole.

Use this as a digitiser and prototyping tool, and have any orthotic intended for a neuropathic or Charcot foot reviewed and fitted by a podiatrist or orthotist before it is worn. Relief-well placement should come from a clinician or a plantar-pressure map, not a guess. This software is not a medical device and makes no clinical claims.


Install

python -m pip install -r requirements.txt
# For the photo->mesh step only:
winget install COLMAP.COLMAP        # or https://github.com/colmap/colmap/releases

Pure-Python mesh stack — no open3d/pymeshlab, works on Python 3.14.

Try it now (no scan, no COLMAP)

python -m footscan.cli demo --out out --relief 70,95,20,7
python tools/preview.py out/insole.stl out/preview.png

Builds a synthetic foot, generates out/insole.stl, and renders a thickness map

  • cross-sections so you can see the arch support, heel cup, and relief pocket.

Easiest capture: one photo on a printed scale card (any phone)

No depth sensor, no COLMAP — works on a $40 phone. Recovers the foot's true outline and size in millimetres; the arch/heel contour is a parametric model fitted to that outline (an honest baseline — for a deformed Charcot foot prefer the depth or photogrammetry path, which measure the real contour).

python -m footscan.cli make-card --out out/scale_card.png   # print at 100% scale
# Place the bare foot inside the border, photograph from straight above, then:
python -m footscan.cli photo --image foot.jpg --side right --out out

Four ArUco corner markers let it rectify camera tilt and lock real mm scale. Verified end-to-end by tools/test_photo_capture.py (recovers a known foot's size from a perspective-warped photo to within ~1%).

Real scan workflow (full 3-D, most accurate)

1. Photograph the foot. Best results:

  • Sit with the foot resting (or lightly bearing weight) on a flat, matte, patterned surface (a towel works; blank/shiny floors confuse photogrammetry).
  • Take 30–60 photos in a slow arc around the foot — low, medium, and high angles — keeping ~70% overlap between consecutive shots. Get the sides, the back of the heel, and over the toes. Hold still; good light; no flash.
  • Keep the foot still the whole time (a stack of books to rest it on helps).

2. Reconstruct a mesh:

python -m footscan.cli reconstruct --photos .\photos --workspace .\ws --out out\foot_raw.ply

3. Generate the insole (scale comes from your measured foot length — measure heel-to-longest-toe with a ruler):

python -m footscan.cli insole --mesh out\foot_raw.ply --foot-length-mm 262 --out out

4. Place a relief well (optional, for offloading). First find local coords, then add one or more:

python -m footscan.cli grid   --mesh out\foot_raw.ply --foot-length-mm 262
python -m footscan.cli insole --mesh out\foot_raw.ply --foot-length-mm 262 `
    --relief 70,95,20,7  --relief 30,60,16,5  --out out

--relief x,y,radius,depth (mm), origin at the footprint's min corner, +y = heel→toe.

5. Print out/insole.stl in TPU — see print_profiles/tpu_insole.md.

Tuning knobs (all insole/demo flags)

Flag Default Effect
--foot-length-mm real measurement that sets scale (required for scans)
--base-thickness 4.0 cushion under the contact points (mm)
--heel-cup 12.0 heel side rim that cradles the heel (mm)
--heel-lift 0.0 therapeutic heel raise — lifts the calcaneus, tapering forward (mm)
--heel-lift-runout 80.0 distance over which the heel lift tapers to 0 (mm)
--max-arch-fill 22.0 clamp on arch support height (mm)
--smooth 4.0 gaussian smoothing of the top (mm); higher = gentler
--relief x,y,r,d offload pocket; repeatable
--no-clean off skip mesh cleaning if the input is already clean

Heel lift vs. heel cup (and "extreme" lifts)

  • Heel cup (--heel-cup) is a side rim that hugs the heel laterally.
  • Heel lift (--heel-lift) actually raises the heel — it adds height under the calcaneus and tapers forward over --heel-lift-runout. Use it for Achilles / equinus tightness or a leg-length discrepancy (both common in diabetic feet).

The lift is measured-independent (a prescribed amount you dial in) and is deliberately uncapped, so an extreme raise is possible. Caveats for big lifts:

  • A tall lift turns the insole into a wedge that may not fit a normal shoe — it often belongs in accommodative/extra-depth footwear or a CROW boot.
  • A heel raise meaningfully changes gait and forefoot loading; on a neuropathic / Charcot foot the amount should be clinician-set, and a leg-length lift should account for both feet (only one side is usually raised).
  • For print stability, very tall lifts want a longer --heel-lift-runout (gentler ramp) and more infill — see the print profile.

Project layout

footscan/
  reconstruct.py   photos -> mesh via COLMAP (subprocess wrapper)
  scale_align.py   orient sole-down + scale to real mm from foot length
  clean_mesh.py    largest component, fill holes, Taubin smooth
  meshbuild.py     heightmap -> watertight solid (shared primitive)
  orthotic.py      *** total-contact insole generator (arch/heel/relief) ***
  demo_foot.py     synthetic foot so the pipeline runs with no scan
  cli.py           command-line entry point
tools/preview.py   thickness-map + cross-section renders for sanity checks
print_profiles/    TPU slicer guidance

How the orthotic is built (the core idea)

orthotic.py casts rays upward to sample the foot's underside as a height field U(x,y). Then:

  • top(x,y) = base_thickness + arch_fill + heel_cup − relief_wells, where arch_fill is how far the foot lifts above its lowest contact point (so the insole grows to meet and support the arch),
  • bottom(x,y) = 0 (flat plate on the shoe footbed),
  • the top is gaussian-smoothed (no sharp pressure ridges — vital on a foot that can't feel them), then meshbuild.heightmap_to_solid stitches a watertight solid (top + bottom + silhouette walls).

Roadmap / ideas

  • ArUco scale-board auto-scaling (cv2 helper stubbed in requirements.txt).
  • Import a plantar pressure map (force-plate / pressure-mat image) to place relief wells automatically instead of by hand.
  • Dual-durometer export (soft top zone over a firmer base) for printers/slicers that support modifier meshes.
  • Toe-spring / met-bar parameters; left/right mirroring from a single scan.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages