This commit is contained in:
xsl
2026-10-10 14:23:43 +08:00
parent 658b232a39
commit 2a7593b736
11 changed files with 528 additions and 149 deletions
+16 -10
View File
@@ -62,21 +62,21 @@ node server.js # 默认 8080,可用 PORT=xxx 修改
三步严格按顺序,本步拍到合格照片才进入下一步(左右一律以用户本人为准):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;框外 85% 黑,轮廓线 2.5px 半透明白。检测运行时轮廓内有自上而下的扫描带(`#cam-clip` 由 app.js 复制轮廓生成);未检测到人脸时轮廓呼吸动画;条件合格时轮廓变绿。
- **预览缩小 15%**:`#cam-video` 按 `scale(.85)` 显示,手机离脸近一些也能把脸装进轮廓;距离阈值随之按 1/0.85 换算(人脸框高/视频高 <0.30 提示「请靠近一点」、>0.68 提示「请远一点」)。
- **预览缩小 15%**:`#cam-video` 按 `scale(.85)` 显示。距离判定使用 object-fit:cover 和缩放后的屏幕占比(人脸高度占屏高 <26% 提示靠近、>58% 提示远一点),避免横竖视频比例不同导致距离误判。
- **动态提示**(一次一条,优先级:无人脸 > 距离 > 居中 > 角度 > 光线):「未检测到人脸」「请靠近一点 / 请远一点」「请将脸部移入取景框」(人脸中心偏离中线 >18% 屏宽)、角度类「请向左转头 / 请向右转头 / 请略微抬头 / 请略微低头」(正脸阈值 |yaw|≤15°、|pitch|≤18°,超出时按超出比例更大的一项给方向;侧脸 yaw 28°–75°、|pitch|≤20°)、光线类「请到光线充足处 / 光线过强,请避开强光」(脸部平均亮度 <65 或 >235)。
- **合格即拍**:上述条件全部合格并连续维持 450ms(滤掉一闪而过的合格帧,防运动模糊)立即白屏补光抓拍,**无倒计时、无手动快门**。
- **实时检测**:face-api 从本地 `vendor/faceapi/` 加载(`tinyFaceDetector` + `faceLandmark68Net`),进入拍照页开始加载(状态提示「检测引擎加载中…」)。检测循环 ~150ms 一帧,特征点取自原始帧(预览 CSS 镜像不影响),个别前置帧已镜像的机型由侧脸自校准翻转 `sideYawFlip`;连续漏检 ≥3 帧才报「未检测到人脸」。
- **合格即拍**:单人、距离、横纵居中、姿态和光线连续合格 450ms 后立即抓取当前帧,再闪白 180ms 给出反馈。无倒计时;任何丢帧或检测异常都会清空合格时长,防止误拍。
- **实时检测**:本地 face-api 模型,约每 150ms 用 detectAllFaces + landmarks 判断单人及姿态。连续漏检 3 帧才更换文案,但每次漏检均中断可拍摄状态。按原始帧判断真实左右,持续转错方向也不会自动交换左右照片。切换镜头及退出页面作废旧的检测回调。
- **镜像策略**:前置镜头预览镜像(照镜子习惯);后置预览不镜像,侧脸轮廓随之翻转(`.cam-mask.flip`)。**抓帧一律不镜像**,三张照片都是摄像头原始视角。
- **白屏补光**:全屏纯白覆盖层瞬间点亮,~300ms 后抓全分辨率帧(原始视角 + 最长边 1280 JPEG),保持 ~300ms 再淡出,同步 `navigator.vibrate(30)`。
- **快门只在无法实时识别时出现**:系统相机降级(getUserMedia 不可用/被拒,如手机走局域网 HTTP)、face-api/模型加载失败、`?mock=1` 调试。降级与相册选图拿到的照片会先用 face-api 校验(有人脸、正脸/侧脸转头幅度对;系统相机是否镜像因机型而异,侧脸不校验左右),不合格提示重拍、停在本步;模型不可用时放行,由服务端兜底。
- **相册选图**:相机页「相册」按钮可选当前步的图片,与降级拍照同管线(压 1280 → 校验 → 推进)。
- **抓拍反馈**:先抓取已校验的当前帧(原始视角、最长边 1280 JPEG),再显示 180ms 闪白和短振动;不在延迟后抓取可能已经偏离姿态的画面。
- **正式页面无手动快门**:相机权限或模型加载失败时显示重试按钮;仅 `?mock=1` 调试模式保留手动快门。拍摄进度明确显示正脸→右脸→左脸,完成三张后只送检一次。
- **相册选图**:按当前步骤选择照片,压缩后等待模型加载并校验单人、左右朝向和光线;不合格或检查失败均停留本步,不再跳过校验。读取、校验和抓拍期间锁定操作,离开页面使未完成读取失效。
- **语音播报**:步骤引导/姿态提示/拍摄完成/分析中/失败,文案与文件名契约见 `../docs/语音播报内容设计文档_V1.0.md`。新增的提示(居中、抬头/低头、光线)暂无音频,清单缺失的条目静默跳过,只显示文字。
- **无进展提示**:单步 12s 仍未拍到,底部浮出「识别不到?请正对镜头,并到光线充足处」(不阻塞流程)。
- **资源管理**:离开拍照页停止检测循环、清全部定时器、释放摄像头;`camSeq`(流程)/`camSeqCam`(相机)双令牌防竞态;face-api 模型只加载一次。
## 档案页与报告页
- **档案页**:出生年月 / 性别 / 所在地区三个滚轮选择器同一风格(`vendor/mobile-select`,MIT),出生年月自动换算年龄;地区为省–市两级联动,数据为 `js/region-data.js`(由 china-division 2.7.0 `pc.json` 生成,另含港澳台与「海外」)。
- **档案页**:出生年月、性别、省市用统一 mobile-select 滚轮,提供占位提示;按出生月份计算并显示年龄,限制选择结果为 1–99 岁,提交时重新计算以适应跨月。省市联动数据见 `js/region-data.js`;插件行点击已适配 44px 行高与安全区,见 vendor README。
- **报告页**:无返回按钮与页头标题;总分环形图 + 肌肤年龄与「比实际年龄年轻/大 N 岁」;三维度分数 + 进度条(最低分标红并挂「优先关注」);紧塑力/活力感/稳定力各一张卡,卡内子 Tab 切换;点检测图全屏放大,再点或按返回键回到报告。
## 检测流程与评分渲染
@@ -159,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。
局域网提测需设置 HOST=0.0.0.0 并允许对应防火墙端口。手机通过局域网 HTTP 访问时不能使用 getUserMedia,需使用 HTTPS 才能测试动态自动拍照;相册选图入口仍可用且逐步校验。
nginx 反代示例(静态与 API 都交给 server.js,nginx 只做 HTTPS 终结):
@@ -177,7 +177,7 @@ server {
}
```
> **HTTPS 必需**:getUserMedia 相机权限仅在安全上下文可用(localhost 除外)。正式域名必须上 HTTPS,否则前端自动降级为系统相机拍照。
> **HTTPS 必需**:手机自动拍摄要求安全上下文,正式域名必须使用 HTTPS;本机 localhost 例外。相机不可用时页面显示重试与相册入口。
## 已知占位清单
@@ -185,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;2026-10 预览缩小 15% 后按比例换算为 0.30/0.68)、检测参数(320/0.4→416/0.3)与漏检 3 帧容忍;自动三连拍在无头浏览器全程通过(e2e E7)。**真机仍建议复核一次**(尤其 2026-10 新增的居中/亮度阈值):不同机型前置镜像策略/取景比例可能微调体验(校准接口:调用方 `mirrored` 标志与 `HeadPose.config`)。
- **真机复核**:头部姿态系数沿用既有校准,新增多人、屏幕坐标距离/居中与亮度闸门已通过可控浏览器输入测试。前后镜头、不同手机曝光及微信相机权限仍需用真实设备复核;自动化测试不替代硬件实拍。
## 技术说明
@@ -193,3 +193,9 @@ server {
- 图片性能:首屏背景 preload;首屏外 `loading="lazy"`。
- 快门防连点/双流程令牌(camSeq/camSeqCam)防竞态;拍照页取景框外纯黑(对齐 Figma),白字直接落在黑色上。
- face-api.js 0.22.2 与模型全部本地化(`vendor/faceapi/`,约 1.4MB),运行时零外部请求,微信 webview / iOS Safari 弱网与内网部署可用;许可证(MIT / Apache-2.0)见 `vendor/faceapi/README.md`。
## UI 反馈验收
`node h5/test/e2e-feedback.mjs` 验证出生年月、省市联动、自动三连拍的质量闸门与顺序、模型重试、相册校验、图片放大及 320/375/430px 布局。测试拦截分析请求,不调用 Face++。
两个浏览器测试都支持 `BASE_URL`(例如 http://127.0.0.1:8088)、`PLAYWRIGHT_MODULE`(本机 Playwright 的 index.mjs 绝对路径)和 `E2E_OUTPUT_DIR`(截图目录),Windows 与 Linux 均可执行。未指定 Playwright 路径时使用全局安装。