Files
hair/face_analysis/detector.py
T
xslandClaude Opus 4.8 8d3b145111 feat(worker): 接口1 四庭七眼测量真实实现(替换 Mock)
worker 侧从 Mock 替换为真实算法:
- face_analysis 包:detector(MediaPipe 478点) / pose(solvePnP 姿态) /
  calibration(虹膜直径法) / hair_segmenter+bisenet_model(方案B 头发分割) /
  measure(方案A兜底+B/A决策+七眼+换算) / annotation(numpy渐变线+中文标注)
- app.py:/api/v1/face/measure 接真实实现,返回 annotated_image_base64
  (不落盘不拼URL,落盘由网关做);加 X-Internal-Token 鉴权、/health 就绪态、
  可配置分辨率门槛、异常兜底
- 部署:start.sh/run_worker.sh/hair-worker.service 监听 8187;worker_config 示例
- 测试 tests/:Tier1合成真值<1e-6 + Tier2缩放不变 + Tier3叠加 + 错误码集成 +
  数值回归,pytest 24 项全绿
- 文档补实测基线表 + RTX5090/torch 说明

注:worker 为 RTX 5090(sm_120),pinned torch 2.2.2(cu121) 只到 sm_90,
BiSeNet 已自动回退 CPU(方案B 正常);要用 GPU 需换 torch cu128(≥2.7)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 16:07:28 +08:00

62 lines
1.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""MediaPipe Face Mesh 关键点检测封装(单例)。
封装经典 Solutions APImp.solutions.face_mesh),模型权重内置于 pip 包,
无需额外下载。开启 refine_landmarks=True 以获得虹膜点(尺度校准用),
static_image_mode=True 适配单张图片推理,max_num_faces=1 只取最大/首个人脸。
详见技术方案 §8.2。
"""
import cv2
import numpy as np
import mediapipe as mp
mp_face_mesh = mp.solutions.face_mesh
class FaceMeshDetector:
"""MediaPipe Face Mesh 封装,单例模式(模块底部 detector)。"""
def __init__(self):
self.face_mesh = mp_face_mesh.FaceMesh(
static_image_mode=True,
max_num_faces=1, # 仅检测单人(取最大脸)
refine_landmarks=True, # 启用虹膜 + 唇部精细关键点
min_detection_confidence=0.5,
)
def detect(self, image: np.ndarray):
"""检测人脸关键点。
Args:
image: BGR numpy arrayOpenCV 格式)。
Returns:
landmarks: NormalizedLandmarkList.landmark 列表),或检测失败时 None。
"""
rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
results = self.face_mesh.process(rgb)
if results.multi_face_landmarks:
return results.multi_face_landmarks[0]
return None
def close(self):
self.face_mesh.close()
# 全局单例:模块加载时初始化一次,避免每请求重建(重建很慢)。
detector = FaceMeshDetector()
if __name__ == "__main__":
import sys
path = sys.argv[1] if len(sys.argv) > 1 else "tests/fixtures/frontal.jpg"
img = cv2.imread(path)
if img is None:
print(f"无法读取图片: {path}")
sys.exit(1)
lms = detector.detect(img)
if lms is None:
print("detected landmarks: None(未检出人脸)")
sys.exit(1)
print(f"detected landmarks: {len(lms.landmark)}")