Teeth as an extracted blob contour, not a clipped band
The band filled the mouth because a band is the wrong reduction: the bright region is a blob, and reading it as "everything above a line" throws the shape away. Extracting a contour reintroduces the vertex-correspondence problem that made me avoid it, but for a blob there is a way out. Radial sampling from the centroid along N fixed directions makes vertex k always mean "the extent in direction k": correspondence holds by construction, the count is fixed, and temporal smoothing cannot reorder anything. It also yields a star-shaped reduction, which suits flat colour. Tongue rejection, which the band had no way to express: - pixels red relative to their own brightness are dropped (teeth are neutral) - component choice is biased toward the top of the cavity, since area alone picks the tongue when the mouth is wide - separate inner and outer controls: cavity erode pulls the sampled region off the lip edge, blob grow/erode resizes the found blob Also: a knob wired in app.js but missing from index.html threw during wiring and left a blank page with nothing useful in the console - which is exactly what happened to teethDwell in the previous commit. el() now names the missing id, and window.onerror surfaces it in the status line. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
c6daf827d1
commit
9a11eeabc1
7 changed files with 272 additions and 275 deletions
23
index.html
23
index.html
|
|
@ -123,18 +123,27 @@
|
|||
<label class="ctl"><span>anchor avg ±f</span><input type="range" id="smoothWin" min="0" max="8" value="2"><output id="smoothWinv"></output></label>
|
||||
<label class="ctl"><span>closed-mouth cut</span><input type="range" id="apertureThresh" min="0" max="400" value="120"><output id="apertureThreshv"></output></label>
|
||||
<label class="ctl"><span>teeth contrast</span><input type="range" id="teethOn" min="1" max="60" value="16"><output id="teethOnv"></output></label>
|
||||
<label class="ctl"><span>cavity erode</span><input type="range" id="teethErode" min="0" max="40" value="18"><output id="teethErodev"></output></label>
|
||||
<label class="ctl"><span>cavity erode</span><input type="range" id="teethErode" min="0" max="45" value="18"><output id="teethErodev"></output></label>
|
||||
<label class="ctl"><span>blob grow/erode</span><input type="range" id="blobGrow" min="-4" max="4" value="0"><output id="blobGrowv"></output></label>
|
||||
<label class="ctl"><span>tongue reject</span><input type="range" id="tongueReject" min="2" max="40" value="18"><output id="tongueRejectv"></output></label>
|
||||
<label class="ctl"><span>prefer upper</span><input type="range" id="topBias" min="0" max="120" value="60"><output id="topBiasv"></output></label>
|
||||
<label class="ctl"><span>teeth vertices</span><input type="range" id="teethVerts" min="5" max="20" value="10"><output id="teethVertsv"></output></label>
|
||||
<label class="ctl"><span>teeth avg ±f</span><input type="range" id="teethSmooth" min="0" max="4" value="1"><output id="teethSmoothv"></output></label>
|
||||
<label class="ctl"><span>teeth dwell</span><input type="range" id="teethDwell" min="0" max="6" value="1"><output id="teethDwellv"></output></label>
|
||||
<label class="ctl"><span>suggest tolerance</span><input type="range" id="tol" min="2" max="60" value="14"><output id="tolv"></output></label>
|
||||
<div class="legend">
|
||||
<b>contour avg</b> 0 = off, 1 = ±1 frame. Removes per-frame landmark
|
||||
jitter. Push past 2 and it starts eating articulation.<br>
|
||||
<b>anchor avg</b> smooths the head transform only — never the contour.<br>
|
||||
<b>teeth contrast</b> how far apart the dark and bright halves of the
|
||||
cavity must be before the split means anything — Otsu always returns
|
||||
<i>some</i> threshold, so this is what stops it inventing teeth in a dark
|
||||
mouth. <b>erode</b> shrinks the sampled region inward, away from the lip
|
||||
edge. <b>dwell</b> is how many frames a change must persist.<br>
|
||||
<b>teeth contrast</b> gates on how far apart the cavity's dark and bright
|
||||
halves are — Otsu always returns <i>some</i> threshold, so this is what
|
||||
stops it inventing teeth in a dark mouth.
|
||||
<b>cavity erode</b> pulls the sampled region in from the lip edge;
|
||||
<b>blob grow/erode</b> resizes the found blob itself.
|
||||
<b>tongue reject</b> drops pixels that are red relative to their own
|
||||
brightness; <b>prefer upper</b> biases component choice toward the top of
|
||||
the cavity, where teeth are and the tongue is not.
|
||||
<b>dwell</b> is how many frames a presence change must persist.<br>
|
||||
<b>suggest tolerance</b> only affects the Suggest button: max head movement
|
||||
allowed before a new drawing is required.
|
||||
</div>
|
||||
|
|
@ -143,7 +152,7 @@
|
|||
<h2>teeth measurement</h2>
|
||||
<div id="cv-teeth"></div>
|
||||
<div class="legend" id="teethinfo"></div>
|
||||
<div class="legend">green = above threshold · amber = resolved line</div>
|
||||
<div class="legend">green = kept pixels · amber = extracted contour</div>
|
||||
</div>
|
||||
<div class="panel" style="flex:1 1 240px">
|
||||
<h2>palette</h2>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue