save
This commit is contained in:
+22
-17
@@ -54,25 +54,30 @@ node server.js # 默认 8080,可用 PORT=xxx 修改
|
||||
|
||||
调试:
|
||||
|
||||
- `http://127.0.0.1:8080/?mock=1` 使用内置样本(`SkinScore.MOCK_RESULT`/`MOCK_SIDE`)跳过真实检测;不加载 face-api、不跑姿态检测,快门手动逐步推进(离线/自动化验证用)。
|
||||
- `http://127.0.0.1:8080/?mock=1` 使用内置样本(`SkinScore.MOCK_RESULT`/`MOCK_SIDE`)跳过真实检测;不加载 face-api、不跑姿态检测,显示快门手动逐步推进(离线/自动化验证用)。
|
||||
- `http://127.0.0.1:8080/?mock=1&screen=report` 直渲 mock 报告页(**仅调试用**,供无头浏览器截图验证布局;档案缺省按 28 岁/干性肌肤);mock 数据源为 `assets/mock/report-fixture.js`(真实案例1三视图检测返回,含 face_maps 图层 data URL 与 marks 坐标),改该文件即可换样本。
|
||||
|
||||
## 拍照交互(引导式自动三连拍)
|
||||
## 拍照交互(动态捕捉自动三连拍)
|
||||
|
||||
三步(顺序对齐 Figma,左右一律以用户本人为准):1/3 正脸(target `front`)→ 2/3 右脸出镜(用户头向自己的左侧转,target `right`,产物作 `right_image`)→ 3/3 左脸出镜(头向自己的右侧转,target `left`,产物作 `left_image`)。送检前 `photosByView` 按 target 重排为 [正, 左, 右]。
|
||||
三步严格按顺序,本步拍到合格照片才进入下一步(左右一律以用户本人为准):1/3 正对屏幕(target `front`)→ 2/3 右脸出镜(用户头向自己的左侧转,target `right`,产物作 `right_image`)→ 3/3 左脸出镜(头向自己的右侧转,target `left`,产物作 `left_image`)。送检前 `photosByView` 按 target 重排为 [正, 左, 右]。页面内没有返回按钮,微信/浏览器返回键经 History API 回到档案页并释放摄像头。
|
||||
|
||||
- **步骤圆点**:顶部三点,当前步高亮、完成步绿色打勾。
|
||||
- **取景蒙版**:内联 SVG(`#cam-mask`)按步骤切换轮廓——正脸步为正脸剪影(含耳部),侧脸步为对应方向的侧脸剪影(鼻朝向与转头方向一致);**轮廓路径由 Figma 拍照示意图(`design/assets/images/*-拍照示意.png` 的 alpha 镂空区)逐像素描摹生成**,坐标为 Figma 375×812 整帧,viewBox 只取 y 86–812(帧顶 86px 是微信导航栏,H5 视口从其下方开始;步骤文案/引导等纵向百分比也以 726 高为基准);框外 85% 黑(SVG mask 镂空,对齐 Figma 图层不透明度),轮廓线 2.5px 半透明白。未检测到人脸时轮廓呼吸动画(1.8s);姿态 ok 时轮廓变绿并停止动效。
|
||||
- **正脸步提示口径**:正脸步角度不合格一律只提示「请正对屏幕」(不再提示左右转头/抬头低头),阈值 |yaw|≤15°、|pitch|≤18°(2026-09-28 产品要求放宽);侧脸步仍按方向提示「请向左/右转头」。
|
||||
- **实时检测**:face-api 从本地 `vendor/faceapi/` 加载(`tinyFaceDetector` + `faceLandmark68Net`)。进入拍照页即开始加载模型(状态提示"检测引擎加载中…"),加载完成前快门为手动模式。检测循环 ~150ms 一帧,`detectSingleFace(video, TinyFaceDetectorOptions({inputSize:416, scoreThreshold:0.3})).withFaceLandmarks()` 后拿 68 特征点调 `HeadPose.check(pos, target, mirrored)`——特征点取自原始帧(预览 CSS 镜像不影响),侧脸步 mirrored 恒 false(个别前置帧已镜像的机型由侧脸自校准翻转 `sideYawFlip`,只动判定不动画面),正脸步只看 |yaw|;连续漏检 ≥3 帧才报"未检测到人脸"(容忍单帧抖动);人脸框高度占比 <26% 提示"请靠近一点"、>58% 提示"请远一点"(以取景框≈42% 屏高标定)。提示一次一条,优先级:无人脸 > 距离 > 角度。
|
||||
- **倒计时自动拍**:姿态 ok 连续维持 ≥600ms 后,先等「保持不动」等在播提示音自然收尾(画面保持绿框+保持不动),再进 3s 倒计时(中央大数字,轮廓保持绿色,数字与「三、二、一」语音同步起播,不再拦腰切断);倒计时中任一帧不 ok 立即取消并回到对应提示。倒计时结束进入白屏补光。
|
||||
- **镜像策略**:前置镜头三步**预览**都镜像(照镜子习惯;Figma 侧脸轮廓即按镜像画面绘制:右脸出镜耳在画面右、左脸出镜耳在画面左);后置镜头预览不镜像,侧脸轮廓随之水平翻转(`.cam-mask.flip`)。**抓帧一律不镜像**:三张照片都是摄像头原始视角,Face++ 左右分区文案(左嘴角纹/左右脸颊)对应用户真实左右,与真值样本同口径。
|
||||
- **白屏补光**:全屏纯白覆盖层瞬间点亮,~300ms 后抓全分辨率帧(原始视角 + 最长边 1280 JPEG),保持 ~300ms 再淡出(总 600–900ms),同步 `navigator.vibrate(30)`。
|
||||
- **手动兜底**:快门任何时刻可拍当前步(同样走白屏补光),不依赖检测;face-api/模型加载失败 → toast"自动识别不可用,已切换手动拍摄",全程手动。系统相机降级模式(getUserMedia 不可用/被拒)维持原样:无检测、无补光。
|
||||
- **相册选图**:相机页「相册」按钮可选当前步的图片(任何模式下可用),与实拍同管线(压 1280 → 推进流程)。
|
||||
- **语音播报**:步骤引导/姿态提示/倒计时/拍摄完成/分析中/失败共 14 条,文案与文件名契约见 `../docs/语音播报内容设计文档_V1.0.md`。WebAudio 单通道、姿态提示同条 4s 去重、解锁后预加载全部条目;流程音(步骤/拍摄完成/倒计时/分析中)排队顺序播放互不截断,姿态提示不截断流程音(期间只挂起最新一条,收尾后补播),失败提示可打断「分析中」。`assets/voice/manifest.json` 清单制(14 条已生成),清单缺失的条目静默跳过。
|
||||
- **无进展提示**:单步 12s 未触发倒计时,底部浮出"识别不到?可点下方快门手动拍摄"(不阻塞流程)。
|
||||
- **资源管理**:离开拍照页(cam-back/完成)停止检测循环、清全部定时器、释放摄像头;`camSeq`(流程)/`camSeqCam`(相机)双令牌防竞态;face-api 模型只加载一次(缓存 promise,失败后下次进入重试)。
|
||||
- **取景蒙版**:内联 SVG(`#cam-mask`)按步骤切换轮廓——正脸步为正脸剪影(含耳部),侧脸步为对应方向的侧脸剪影;**轮廓路径由 Figma 拍照示意图(`design/assets/images/*-拍照示意.png` 的 alpha 镂空区)逐像素描摹生成**,坐标为 Figma 375×812 整帧,viewBox 只取 y 86–812;框外 85% 黑,轮廓线 2.5px 半透明白。检测运行时轮廓内有自上而下的扫描带(`#cam-clip` 由 app.js 复制轮廓生成);未检测到人脸时轮廓呼吸动画;条件合格时轮廓变绿。
|
||||
- **预览缩小 15%**:`#cam-video` 按 `scale(.85)` 显示,手机离脸近一些也能把脸装进轮廓;距离阈值随之按 1/0.85 换算(人脸框高/视频高 <0.30 提示「请靠近一点」、>0.68 提示「请远一点」)。
|
||||
- **动态提示**(一次一条,优先级:无人脸 > 距离 > 居中 > 角度 > 光线):「未检测到人脸」「请靠近一点 / 请远一点」「请将脸部移入取景框」(人脸中心偏离中线 >18% 屏宽)、角度类「请向左转头 / 请向右转头 / 请略微抬头 / 请略微低头」(正脸阈值 |yaw|≤15°、|pitch|≤18°,超出时按超出比例更大的一项给方向;侧脸 yaw 28°–75°、|pitch|≤20°)、光线类「请到光线充足处 / 光线过强,请避开强光」(脸部平均亮度 <65 或 >235)。
|
||||
- **合格即拍**:上述条件全部合格并连续维持 450ms(滤掉一闪而过的合格帧,防运动模糊)立即白屏补光抓拍,**无倒计时、无手动快门**。
|
||||
- **实时检测**:face-api 从本地 `vendor/faceapi/` 加载(`tinyFaceDetector` + `faceLandmark68Net`),进入拍照页开始加载(状态提示「检测引擎加载中…」)。检测循环 ~150ms 一帧,特征点取自原始帧(预览 CSS 镜像不影响),个别前置帧已镜像的机型由侧脸自校准翻转 `sideYawFlip`;连续漏检 ≥3 帧才报「未检测到人脸」。
|
||||
- **镜像策略**:前置镜头预览镜像(照镜子习惯);后置预览不镜像,侧脸轮廓随之翻转(`.cam-mask.flip`)。**抓帧一律不镜像**,三张照片都是摄像头原始视角。
|
||||
- **白屏补光**:全屏纯白覆盖层瞬间点亮,~300ms 后抓全分辨率帧(原始视角 + 最长边 1280 JPEG),保持 ~300ms 再淡出,同步 `navigator.vibrate(30)`。
|
||||
- **快门只在无法实时识别时出现**:系统相机降级(getUserMedia 不可用/被拒,如手机走局域网 HTTP)、face-api/模型加载失败、`?mock=1` 调试。降级与相册选图拿到的照片会先用 face-api 校验(有人脸、正脸/侧脸转头幅度对;系统相机是否镜像因机型而异,侧脸不校验左右),不合格提示重拍、停在本步;模型不可用时放行,由服务端兜底。
|
||||
- **相册选图**:相机页「相册」按钮可选当前步的图片,与降级拍照同管线(压 1280 → 校验 → 推进)。
|
||||
- **语音播报**:步骤引导/姿态提示/拍摄完成/分析中/失败,文案与文件名契约见 `../docs/语音播报内容设计文档_V1.0.md`。新增的提示(居中、抬头/低头、光线)暂无音频,清单缺失的条目静默跳过,只显示文字。
|
||||
- **无进展提示**:单步 12s 仍未拍到,底部浮出「识别不到?请正对镜头,并到光线充足处」(不阻塞流程)。
|
||||
- **资源管理**:离开拍照页停止检测循环、清全部定时器、释放摄像头;`camSeq`(流程)/`camSeqCam`(相机)双令牌防竞态;face-api 模型只加载一次。
|
||||
|
||||
## 档案页与报告页
|
||||
|
||||
- **档案页**:出生年月 / 性别 / 所在地区三个滚轮选择器同一风格(`vendor/mobile-select`,MIT),出生年月自动换算年龄;地区为省–市两级联动,数据为 `js/region-data.js`(由 china-division 2.7.0 `pc.json` 生成,另含港澳台与「海外」)。
|
||||
- **报告页**:无返回按钮与页头标题;总分环形图 + 肌肤年龄与「比实际年龄年轻/大 N 岁」;三维度分数 + 进度条(最低分标红并挂「优先关注」);紧塑力/活力感/稳定力各一张卡,卡内子 Tab 切换;点检测图全屏放大,再点或按返回键回到报告。
|
||||
|
||||
## 检测流程与评分渲染
|
||||
|
||||
@@ -154,7 +159,7 @@ schtasks /create /tn "JuziSkinH5" /tr "\"C:\Windows\System32\cmd.exe\" /c \"D:\j
|
||||
:: 移除: schtasks /delete /tn "JuziSkinH5" /f
|
||||
```
|
||||
|
||||
局域网提测访问 `http://<本机局域网IP>:8088/`。注意:① 首次监听若弹 Windows 防火墙提示需允许 node.exe;② **手机走局域网 HTTP 时 getUserMedia 不可用**,会自动降级为系统相机手动三连拍(分析链路完整),要测引导式自动拍照需在本机浏览器访问 `http://127.0.0.1:8088`,或上 HTTPS。
|
||||
局域网提测访问 `http://<本机局域网IP>:8088/`。注意:① 首次监听若弹 Windows 防火墙提示需允许 node.exe;② **手机走局域网 HTTP 时 getUserMedia 不可用**,会自动降级为系统相机三连拍(照片仍按步校验,分析链路完整),要测动态捕捉自动拍照需在本机浏览器访问 `http://127.0.0.1:8088`,或上 HTTPS。
|
||||
|
||||
nginx 反代示例(静态与 API 都交给 server.js,nginx 只做 HTTPS 终结):
|
||||
|
||||
@@ -180,7 +185,7 @@ server {
|
||||
- 语音 14 条已由 `tools/gen_voice.py` 生成;改文案后重跑脚本并同步 `manifest.json`。
|
||||
- 「了解更多」为开发中占位(Toast 提示);拍照页右下按钮为切换前后镜头(系统相机降级模式下提示在系统相机内切换)。
|
||||
- 产品推荐卡(COREⅡ 双仓精华液)为设计稿固定素材,不随精华推荐档位(25+/35+/50+)变化,待产品提供三档对应素材。
|
||||
- **姿态与距离参数已用模拟摄像头校准**(2026-09-27):以 C3 三视图(+45° 侧脸)生成 Y4M 模拟摄像头视频,闭环修正了 yaw 增益(2.2→3.8)、pitch 基线(0.32→0.45)、check() 双重镜像符号 bug、距离阈值(0.35/0.8→0.26/0.58)、检测参数(320/0.4→416/0.3)与漏检 3 帧容忍;自动三连拍在无头浏览器全程通过(e2e E7)。**真机仍建议复核一次**:不同机型前置镜像策略/取景比例可能微调体验(校准接口:调用方 `mirrored` 标志与 `HeadPose.config`)。
|
||||
- **姿态与距离参数已用模拟摄像头校准**(2026-09-27):以 C3 三视图(+45° 侧脸)生成 Y4M 模拟摄像头视频,闭环修正了 yaw 增益(2.2→3.8)、pitch 基线(0.32→0.45)、check() 双重镜像符号 bug、距离阈值(0.35/0.8→0.26/0.58;2026-10 预览缩小 15% 后按比例换算为 0.30/0.68)、检测参数(320/0.4→416/0.3)与漏检 3 帧容忍;自动三连拍在无头浏览器全程通过(e2e E7)。**真机仍建议复核一次**(尤其 2026-10 新增的居中/亮度阈值):不同机型前置镜像策略/取景比例可能微调体验(校准接口:调用方 `mirrored` 标志与 `HeadPose.config`)。
|
||||
|
||||
## 技术说明
|
||||
|
||||
|
||||
Reference in New Issue
Block a user