视频颜值评分叠加(video-face-score)
给现成视频叠加一层「实时颜值评分」HUD:检测人脸关键点 → 多维加权打分 → 渲染柔和评分卡 → 合成新视频(不改动原画面内容)。
版本说明(最近一次重要更新)
v2 · 界面柔和化(2026-09) —— "降 AI 感"的整套能力已落地:
- 默认不画人脸检测框/关键点(ui.mesh=false)
- 容器调成 30%~40% 透明度(card_alpha=0.34 / border=0.32 / divider=0.18 / track=0.16)
- 五态各自独立透明度:normal / hover / loading / results / no_face
- 所有界面文案集中在 ui.copy,可整组替换(语气规则:少技术腔、少对立、不评判)
- 配 make_states_preview.py + build_copy_guide.py:可一键出"五态预览图 + 图文规范 HTML"
v1 · 基础叠加 —— 拆帧→检测→打六个维度分(中位+EMA+过渡不采样)→ 渲染→合成。
评分口径不变(仍是面部几何协调度相对分,非人群百分位)。
> 若需要把界面重新调回"高检测痕迹 / 高不透明度",把 ui.mesh=true + ui.card_alpha=0.74 即可,不用改代码。
何时使用
- 用户要求「在视频里加颜值打分 / 人脸评分 / 评分特效」
- 用户要做「前后对比评分」「妆造效果量化」类内容
- 用户提供了一段人像视频,想要可量化的面部指标叠加层
- 用户要求调整评分界面的视觉调性(去检测痕迹、降不透明度、换文案)
五分钟上手(最低限度的跑通路径)
# 1) 装环境(一键;或手动看下面"依赖"段)
./scripts/install.sh # 类 Unix
.\scripts\install.ps1 # PowerShell
# 2) 自检(确认环境/依赖/字体/配置全部 OK)
python scripts/verify_install.py --python "$VENV/Scripts/python.exe"
# 3) 拆帧 → 分析 → 渲染 → 合成(命令见下方"工作流程"段)
只要 verify_install.py 全绿,下面的工作流程命令都可以直接跑下去。
能力
| 能力 | 说明 |
|---|---|
| 关键点检测 | mediapipe FaceMesh 468 点(含虹膜细化) |
| 评分维度 | 三庭均衡、脸型长宽比、眼距(五眼)、对称协调、皮肤状态、五官神采 —— 六维加权 |
| UI 样式 | card(完整卡片)/ compact(仅总分)/ minimal(单行标签);四角可放;配色/透明度可调 |
| 界面状态 | normal / hover / loading / results / no_face 五态,各自独立容器透明度 |
| 视觉调性 | 默认不画人脸检测框与关键点;容器/描边/分隔线 30%~40%,数字与标签 100% 高对比 |
| 配套文案 | 引导语、评分说明、结果反馈、异常提示全部集中在 ui.copy,可整体替换 |
| 稳定性 | 镜头内关键点复用 + 中位数滤波 + EMA;转场帧不采样 |
| 可配置 | 权重 / 锚点 / 分标尺 / 等级阈值 / 平滑参数 / 外观与文案,全部走 --cfg JSON |
依赖(关键!先读这段再动手)
face_score.py 需要 mediapipe,它对 Python 版本和 protobuf 版本都很挑:
# 1) mediapipe 没有 cp313 wheel(Windows 最高 cp311)——必须用 3.12 及以下
# 若机器上只有 3.13,找现成的 3.12 解释器(如 uv 管理的)建独立 venv
"<python3.12>" -m venv <VENV>
# 2) 用国内镜像,且 --no-deps 绕开 jax(mediapipe 会拖入 jax/jaxlib,体积巨大且常失败)
<VENV>/Scripts/pip.exe install -i https://pypi.tuna.tsinghua.edu.cn/simple --no-deps "mediapipe==0.10.21"
# 3) 手动补齐真正需要的依赖
<VENV>/Scripts/pip.exe install -i https://pypi.tuna.tsinghua.edu.cn/simple \
numpy "protobuf>=4.25,<5" flatbuffers absl-py attrs opencv-contrib-python \
certifi matplotlib sounddevice
⚠️ 两个致命版本点
- 不要用 mediapipe 1.0.x:它已移除 mp.solutions,只有新的 Tasks API(还要额外下模型文件)。0.10.x 自带模型、开箱即用。
- protobuf 必须 <5:装成 5+/6+ 会报 MessageFactory has no attribute 'GetPrototype'。
工作流程
# 0) 拆帧(保留原分辨率;jpg 足够,省一半磁盘)
ffmpeg -y -v error -i INPUT.mp4 -q:v 2 frames_in/%04d.jpg
# 1) 分析(导出每帧指标,用于核对分布 / 定标)
<VENV>/python face_score.py analyze --frames frames_in --dump metrics.json \
[--crop x0,y0,x1,y1] # 画面里有文字栏/水印时,只在该区域内检测
<VENV>/python diag_metrics.py # 按镜头汇总,人工核对
# 2) 渲染叠加层
<VENV>/python face_score.py render --frames frames_in --out frames_out \
--crop x0,y0,x1,y1 --cfg score_cfg.json
# 3) 合成
ffmpeg -y -v error -framerate 30 -i frames_out/%04d.jpg \
-c:v libx264 -pix_fmt yuv420p -crf 17 -r 30 -movflags +faststart OUT.mp4
先 analyze 再 render 是推荐路径:分数分布不对时只调锚点重跑分析,不必反复渲染 490 帧。
界面调性与文案(用户明确要求过:柔和、低视觉权重)
默认配置就是这套调性,改文案/透明度不用动代码:
- 移除检测痕迹 ——
ui.mesh=false(默认)。人脸检测框、关键点、网格都不画,画面只留评分卡片。
需要调试检测是否准时才临时设true。 - 容器走 30%~40%,内容走 100% —— 关键设计取舍:把「容器」与「内容」的透明度拆开控制。
card_alpha(背景叠加)/border_alpha(描边)/divider_alpha(分隔线)/track_alpha(进度条底槽)
落在 0.30~0.40,而数字、等级标签、维度数值、进度条填充保持 255。
同比例淡下去会直接牺牲可读性 —— 这是这类"降视觉权重"需求最容易做错的地方。 - 五态各自参数 ——
ui.states.{normal,hover,loading,results,no_face};ui.state选当前态。
-loading态不露分数:三个呼吸点 + 「正在为你打分……」+ 骨架条(避免出现 0.0 分这种尴尬画面)
-no_face态走draw_notice():柔和提示卡,不显示分数、不画检测框 - 语气规则(写文案时遵守)
- 要:给动作(朝哪站、往哪看、亮一点)、承认局限("只是参考")、说"看/感觉/状态"
- 不要:「击败了 92% 的人」(制造对立)、「检测到 1 张人脸」(技术腔)、「AI 智能精准评分」(不实) - 预览产出 ——
make_states_preview.py出五态对比图,build_copy_guide.py出图文规范 HTML。
硬约束(这些坑都踩过)
- 必须两阶段检测:先用
face_detection(model_selection=1)(全距离模型)框脸,再在局部裁剪图上跑 FaceMesh。
单用 FaceMesh 对全身照/远景的小脸几乎检不出(实测 0/5 → 两阶段 5/5)。 - 输入必须是 C 连续数组:numpy 切片直接喂 FaceMesh 会报
Reference mode is unavailable if 'data' is not c_contiguous,用np.ascontiguousarray()。 - 对称性必须先做脸轴校正:用双眼外角连线求倾角,把所有点旋转回去再算左右对称。否则歪头会被判成"面部不对称"(实测不校正 sym_y=0.118,校正后 0.002)。
- 肤色均匀度用 MAD 不用 std:面部 mask 里常混入镜框、发际、手部等深色像素,标准差会被严重带偏。
- 转场帧不参与评分:淡入淡出时画面是混合态,质感/亮度都会异常(实测质感掉到 1.9),会把分数拉出假低点(64 分)。做法:按"连续高差异段"识别转场 → 转场帧插值、不画网格。
- 锚点必须按本实现的实测尺度校准:教科书的解剖比值(如唇宽/鼻宽≈1.5)套到 FaceMesh 的这套关键点定义上会得到≈1.2,硬套会让整个维度全 0 分。先 analyze 看实测区间,再定锚点。
- 镜头内复用关键点:若片源是「静态图 + 转场」型(资料卡/图文视频),逐帧检测纯属浪费且会引入抖动;同镜头取中位关键点即可(帧间差异 0.05 量级时可放心复用)。
_开头的配置键要跳过:JSON 里写_注释会被当成真实参数(曾导致KeyError: '_注释')。- 均值改中位数:眉眼距、对称偏移这类指标用
median而非mean,抗单点检测偏差。 - 降不透明度后要给结构线留地板值:进度条底槽/骨架条若跟着容器一起降到 <0.10,在亮背景上会完全看不见。
底槽保留max(28/255, trk_px),并让填充色保持高对比 —— 否则界面会失去"有条在走"的信息。 - 改文案要同时改
score_cfg.json与build_copy_guide.py:后者里有独立的 COPY_GROUPS 文案池(用于生成 HTML 规范),单独改一处会让两边不一致。
关于"先调样式再改文案"的常见需求
最常见的三类需求,本 skill 都按"不写代码"的方式支持:
| 用户说法 | 改哪里 |
|---|---|
| 「去掉检测框 / 不要网格」 | score_cfg.json → ui.mesh=false(默认就是) |
| 「卡片背景淡一点 / 数字更清楚」 | score_cfg.json → ui.card_alpha(容器)与 ui.copy.title 字号(脚本里改字号) |
| 「换种语气 / 改个词」 | score_cfg.json → ui.copy.*;再手工同步 build_copy_guide.py 的 COPY_GROUPS |
改完重跑 face_score.py render ... --cfg score_cfg.json 即可,render 不会重新检测,已缓存关键点时秒级返回。
边界与诚实性
- 评分口径:这是「面部几何协调度」的相对分,锚点锚定在实测尺度上,不代表人群百分位,也不是医学/美学权威评估。UI 文案与交付说明里必须讲清楚。
- 正面对称指标不适用于 3/4 侧脸:侧脸时脸缘到中线距离天然不等(实测 0.16 vs 0.07),这类画面分数偏低是方法学局限,不是"人不好看"。
- 不可过度调参凑结论:锚点可以按实测校准,但不应为了制造"改造后分数更高"而反向调参。分数该是多少就报多少,差距小就如实说明"面部几何是固有属性,妆造主要影响皮肤/神采等可变维度"。
- 面部关键点检测对光照/遮挡/大角度敏感,结果只应作为趋势参考。
文件
scripts/face_score.py—— 主程序(analyze / render 双子命令,全参数可配;含五态绘制与未检测提示)scripts/score_cfg.json—— 参数模板(权重、分标尺、等级、平滑、外观、五态透明度、全部文案)scripts/verify_install.py—— 一行命令自检:Python 版本 / mediapipe / protobuf / 字体 / 脚本可解析 / 配置合法scripts/install.sh/scripts/install.ps1—— 一键搭好环境(建 venv、装 mediapipe 0.10.21 + 必需依赖、跑自检)scripts/make_states_preview.py—— 生成五态界面预览对比图(ui.state各态 + 未检测态)scripts/build_copy_guide.py—— 生成《界面调整与配套文案》图文规范 HTMLscripts/diag_metrics.py—— 按镜头汇总指标(镜头分段常量需按实际片源调整,或用脚本内detect_shots的输出)scripts/make_score_chart.py—— 生成六镜头评分汇总图references/01-踩坑与调参.md—— 完整踩坑记录与锚点定标方法references/02-界面文案与调性.md—— 五态参数、全部文案、语气规则