fix(camera): relax initial frontal face recognition
This commit is contained in:
@@ -152,7 +152,7 @@ try {
|
||||
for (const key of ['front', 'left', 'right']) {
|
||||
const row = body.capture_diagnostics.views[key];
|
||||
assert.equal(row.mode, 'live'); assert.equal(row.direction_checked, true);
|
||||
assert(row.score >= .4 && row.luma >= 110 && row.luma <= 220);
|
||||
assert(row.score >= (key==='front'?.3:.4) && row.luma >= 110 && row.luma <= 220);
|
||||
assert(Math.abs(row.roll) <= 22);
|
||||
}
|
||||
assert(Math.abs(body.capture_diagnostics.views.front.yaw) <= 18);
|
||||
|
||||
@@ -73,7 +73,11 @@ for (const changes of [{ height: 179 }, { height: 410 }, { x: -10 }, { y: 5 }])
|
||||
const d = face(); Object.assign(d.detection.box, changes); assert(!check(d).ok);
|
||||
}
|
||||
const weak = face(); weak.detection.score = .45; assert(check(weak).ok);
|
||||
weak.detection.score = .35; assert(!check(weak).ok);
|
||||
for(const score of [.3,.35,.3999]){const d=face();d.detection.score=score;assert(check(d).ok,'relaxed front confidence');}
|
||||
const low=face();low.detection.score=.2999;assert.equal(check(low).hint,'请保持面部清晰');
|
||||
for(const target of ['left','right']){const d=face(target==='left'?-45:45);d.detection.score=.35;assert.equal(check(d,{target}).hint,'请保持面部清晰');d.detection.score=.4;assert(check(d,{target}).ok);}
|
||||
assert.equal(Quality.scoreThreshold('front'),.3);assert.equal(Quality.scoreThreshold('left'),.4);assert.equal(Quality.scoreThreshold('right'),.4);
|
||||
weak.detection.score = .29; assert(!check(weak).ok);
|
||||
const obs = check(face()).observation;
|
||||
let held = Quality.hold(null, obs, 1000); assert(!held.ready);
|
||||
held = Quality.hold(held.state, obs, 1400); assert(!held.ready);
|
||||
@@ -116,7 +120,7 @@ assert.equal(Diagnostics.assess(raw).views.right.status, 'valid');
|
||||
const normalized = Diagnostics.normalize({ version: Quality.config.version, secret: 'discard', views: { front: { mode: 'live', yaw: 1, score: .9, luma: Infinity, secret: 'discard' }, left: { mode: 'unchecked', reason: 'model-unavailable' } } });
|
||||
assert.equal(normalized.policy.capture.holdMs, 450);
|
||||
assert.equal(normalized.policy.capture.minFrames, 2);
|
||||
assert.equal(normalized.version, '2026-10-15-pitch-roll-relaxed-v7');
|
||||
assert.equal(normalized.version, '2026-10-16-front-detection-v8');
|
||||
assert.equal(normalized.views.front.luma, undefined);
|
||||
assert(!JSON.stringify(normalized).includes('discard'));
|
||||
assert.equal(Diagnostics.normalize({ version: '<script>' }).version, 'unknown');
|
||||
|
||||
@@ -43,7 +43,7 @@ assert.equal(pattern, 30);
|
||||
// are stubs; the relaxed shared hold policy now requires 450ms/2 frames.
|
||||
let now = 10000, buzzes = 0, captures = 0;
|
||||
const state = {
|
||||
missFrames: 0, MISS_FRAMES_MAX: 3, camVideo: { videoHeight: 600 }, FACE_NEAR: .30, FACE_FAR: .68,
|
||||
missFrames: 0, MISS_FRAMES_MAX: 3, FRONT_MISS_FRAMES_MAX: 6, frontFaceSeen:false, camVideo: { videoHeight: 600 }, FACE_NEAR: .30, FACE_FAR: .68,
|
||||
faceOffsetX: () => 0, CENTER_TOL: .18, CAM_STEPS: [{ target: 'front' }], camStep: 0,
|
||||
HeadPose: { check: () => ({ ok: true }) }, sideYawFlip: false, faceLuma: () => 100,
|
||||
LUMA_DARK: 65, LUMA_BRIGHT: 235, window: {}, setMask: () => {}, setHint: () => {},
|
||||
@@ -113,4 +113,17 @@ for (const nav of [{}, { vibrate: () => false }, { vibrate: () => { throw Error(
|
||||
state.navigator = nav; state.resetAngleHaptic();
|
||||
state.onDetect(face); now += 1000; assert.doesNotThrow(() => state.onDetect(face));
|
||||
}
|
||||
console.log('PASS: rounded contours; 1s invalid-angle cue, 4s throttle, cancellation/lifecycle, unsupported safety; unchanged 450ms/2-frame capture hold');
|
||||
const missingHints=[];state.setHint=text=>missingHints.push(text);
|
||||
state.resetAngleHaptic();state.frontFaceSeen=false;state.missFrames=0;state.CAM_STEPS[0].target='front';
|
||||
const priorCaptures=captures;
|
||||
for(let i=0;i<5;i++)state.onDetect(null);
|
||||
assert.equal(missingHints.length,0,'initial front misses are quiet for five detections');
|
||||
state.onDetect(null);assert.equal(missingHints.at(-1),'未检测到人脸');
|
||||
missingHints.length=0;state.missFrames=0;state.frontFaceSeen=true;
|
||||
state.onDetect(null);state.onDetect(null);assert.equal(missingHints.length,0);
|
||||
state.onDetect(null);assert.equal(missingHints.at(-1),'未检测到人脸','after seeing a front face retain normal missing detection');
|
||||
missingHints.length=0;state.missFrames=0;state.frontFaceSeen=false;state.CAM_STEPS[0].target='right';
|
||||
state.onDetect(null);state.onDetect(null);assert.equal(missingHints.length,0);
|
||||
state.onDetect(null);assert.equal(missingHints.at(-1),'未检测到人脸','side missing threshold unchanged');
|
||||
assert.equal(captures,priorCaptures,'warmup never permits capture without a face');
|
||||
console.log('PASS: initial-front missing tolerance6 vs normal3, no empty capture; angle haptics/lifecycle and unchanged 450ms/2-frame hold');
|
||||
|
||||
Reference in New Issue
Block a user