Skip to content

Commit c1731bc

Browse files
committed
Document the augmentation result and re-record the demo
The demo GIF now walks through the crew board too. Both READMEs carry the testB numbers and the honest part of them: augmentation fixed Stage 1's weakest result, not the headline - end-to-end body fat barely moves (2.82 -> 2.84%) because Stage 2's own error dominates once measurements are this close.
1 parent 09c9163 commit c1731bc

3 files changed

Lines changed: 69 additions & 3 deletions

File tree

‎README.md‎

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ against real **DXA scans**. Everything runs on the device — no upload, no API.
99
<p align="center"><sub>Demo recorded from the real app using its built-in sample body — a real BodyM subject with
1010
known tape measurements. Live camera capture isn't shown. <a href="https://rishabcv-eng.github.io/bodycomp/">Try it live →</a></sub></p>
1111

12-
**2.82% mean absolute error against clinical DXA**, beating the standard
13-
tape-measure formula (3.17%) without needing a tape.
12+
**2.84% mean absolute error against clinical DXA** in good conditions, 2.96% in
13+
harder ones — at or below the best tape-measure formula (3.16%), without the tape.
1414

1515
```
1616
photo pair ──▶ segmentation ──▶ Stage 1 ──▶ circumferences ──▶ Stage 2 ──▶ body fat %, lean mass
@@ -19,7 +19,7 @@ photo pair ──▶ segmentation ──▶ Stage 1 ──▶ circumferences ─
1919

2020
| | |
2121
|---|---|
22-
| **Body fat, end to end** | 2.82% MAE vs DXA |
22+
| **Body fat, end to end** | 2.84% MAE vs DXA |
2323
| **Waist from silhouette** | 1.97 cm MAE |
2424
| **Interval coverage** | 80.5% (claimed 80%) |
2525
| **Model size / latency** | 1.4 MB, ~16 ms in-browser |
@@ -92,6 +92,7 @@ is how wrong numbers ship:
9292
| `scan_steps_test.mjs` | stepped capture state machine | 18 checks pass |
9393
| `overlay_test.mjs` | contour, mesh and chord geometry | 26 checks pass |
9494
| `plan_test.mjs` | plan maths and safety floors | 30 checks pass |
95+
| `progress_test.mjs` | history, crew board, goals, ranking | 61 checks pass |
9596

9697
### A bug worth keeping
9798

@@ -106,6 +107,39 @@ above the ankles, it has lost the legs. Both implementations now carry the check
106107
and both reject the photo.
107108

108109

110+
## Closing the generalisation gap with augmentation
111+
112+
The honest weakness of the first build: Stage 1 beat the height-and-weight baseline
113+
by 41% on testA but only **3% on testB** — different subjects, harder conditions.
114+
The model leaned on clean capture.
115+
116+
The fix came from an earlier measurement. `reports/mask_robustness.csv` had already
117+
established *which* mask defects cost accuracy at inference; `src/augmented_stage1.py`
118+
trains on those same defects — dilation, erosion, boundary noise, a mis-thresholded
119+
matte — so the model meets imperfect masks during fitting instead of first meeting
120+
one in the wild. Test splits stay clean, so the comparison is like for like.
121+
122+
| testB (400 subjects) | clean-only | + augmented | |
123+
|---|---|---|---|
124+
| Waist | 3.245 | **3.033** | −0.213 cm |
125+
| Hip | 2.226 | **2.108** | −0.119 cm |
126+
| Chest | 2.760 | **2.675** | −0.085 cm |
127+
| Thigh | 1.702 | **1.586** | −0.117 cm |
128+
| Upper arm | 1.226 | **1.220** | −0.006 cm |
129+
130+
**Every measurement improved on the harder split**, and four of five on testA too
131+
(waist there cost +0.05 cm — the one trade).
132+
133+
Retrained at full size, the gap narrows further: waist on testB goes from 3.18 cm to
134+
**2.95 cm**, turning a 3% gain over baseline into **10.4%**. Hip improves from 11% to
135+
**21%**, thigh to **17%**.
136+
137+
What it does *not* do is move the end-to-end body-fat number much (2.82% → 2.84% on
138+
testA): Stage 2's own error dominates once measurements are this close. Better
139+
measurements are still worth having — they are what the plan, the ranking and the
140+
trend are built on — but the honest summary is that this fixed Stage 1's weakest
141+
result, not the headline. The shipped app uses these models.
142+
109143
## A leaderboard that costs no privacy
110144

111145
A shared leaderboard needs accounts, a server and a database of other people's body

‎app/README.md‎

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,38 @@ few percentile places.
288288

289289
The demo body is never written to history — it's someone else's measurement.
290290

291+
### Crew board — a real leaderboard, still no server
292+
293+
Phones get shared: roommates, siblings, a couple training together. So history
294+
belongs to a **person**, not to the browser (`js/progress.js`), and the people on
295+
the board are the people holding the phone. `readCrew()` migrates an existing
296+
single-history install into one profile named "You" without losing a scan.
297+
298+
**Ranked by progress since each person's own first scan, not by who is leanest.**
299+
Ranking on absolute body fat means whoever started leanest wins forever, and the
300+
person who most needs the motivation is bottom of a board they can never climb.
301+
Someone who went 31% → 27% outranks someone who went 18% → 17.6%.
302+
303+
Each person keeps their own height, weight, age and sex, restored when you switch
304+
to them. That one is not cosmetic: **height is the ruler for every measurement**,
305+
so a leftover height would silently measure the next person against someone
306+
else's scale. The bug existed until a profile switch was actually tested.
307+
308+
### Next milestone, and when you'll get there
309+
310+
`js/goals.js` turns a rank into something to chase:
311+
312+
- **The next rung** — Top half, Top quarter, Top tenth — with the exact body fat
313+
that reaches it, taken from the user's own age-and-sex percentile curve.
314+
- **An ETA**, from a least-squares fit over recent scans. It refuses to answer
315+
when the trend is flat, going the wrong way, or further out than six months:
316+
fat loss is not linear across a year, and a date built on that would be fiction.
317+
The wording stays vague on purpose — "about 6 weeks away, early November".
318+
- **Body-fat age**, the age whose median body fat matches yours. Reported
319+
coarsely because the median curve flattens: for men it only moves from 27.3 to
320+
27.8 between 30 and 59, so half a point could swing an exact age by twenty
321+
years. Showing one year would imply precision that isn't there.
322+
291323
### Share card
292324

293325
`js/share.js` draws a 1080×1350 card on a canvas from numbers already on screen —

‎docs/demo.gif‎

33 KB
Loading

0 commit comments

Comments
 (0)