"""pytest 公共夹具与合成关键点工具。""" import os import numpy as np import pytest FIXTURES = os.path.join(os.path.dirname(__file__), "fixtures") OUTPUT = os.path.join(os.path.dirname(__file__), "output") os.makedirs(OUTPUT, exist_ok=True) def fixture(name): return os.path.join(FIXTURES, name) class _LM: """模拟 MediaPipe landmark.x/.y/.z(归一化坐标)。""" def __init__(self, x, y, z=0.0): self.x, self.y, self.z = x, y, z def build_synthetic_landmarks(px_per_cm=50.0, W=1000, H=1000): """按已知 cm 几何摆放关键点,返回 (landmarks_list, ground_truth_dict)。 坐标与 px_per_cm 都由测试设定,故每段 cm/占比真值已知,测量数学应分毫不差。 """ cx = W / 2 def Y(cm_from_top): return (cm_from_top * px_per_cm) / H def X(px): return px / W gt = { "top_court_cm": 4.0, "upper_court_cm": 5.0, "middle_court_cm": 6.0, "lower_court_cm": 5.0, "eye_width_cm": 3.0, "inter_eye_cm": 3.4, "face_width_cm": 14.0, "px_per_cm": px_per_cm, } y_hairtop = 2.0 y_hairline = y_hairtop + gt["top_court_cm"] y_brow = y_hairline + gt["upper_court_cm"] y_nose = y_brow + gt["middle_court_cm"] y_chin = y_nose + gt["lower_court_cm"] lm = {i: _LM(X(cx), 0.0) for i in range(478)} # 纵向中轴点 lm[9] = _LM(X(cx), Y(y_brow)); lm[151] = _LM(X(cx), Y(y_brow)) lm[94] = _LM(X(cx), Y(y_nose)) lm[152] = _LM(X(cx), Y(y_chin)) # 七眼横向点 ew = gt["eye_width_cm"] * px_per_cm ie = gt["inter_eye_cm"] * px_per_cm fw = gt["face_width_cm"] * px_per_cm eye_y = Y(y_brow + 2.0) lm[133] = _LM(X(cx - ie / 2), eye_y); lm[33] = _LM(X(cx - ie / 2 - ew), eye_y) lm[362] = _LM(X(cx + ie / 2), eye_y); lm[263] = _LM(X(cx + ie / 2 + ew), eye_y) lm[234] = _LM(X(cx - fw / 2), eye_y); lm[454] = _LM(X(cx + fw / 2), eye_y) # 虹膜边缘点:直径 = 1.17cm * px_per_cm,使尺度可被精确反解 d = 1.17 * px_per_cm lm[469] = _LM(X(cx - ie / 2 - ew / 2 - d / 2), eye_y) lm[471] = _LM(X(cx - ie / 2 - ew / 2 + d / 2), eye_y) lm[474] = _LM(X(cx + ie / 2 + ew / 2 - d / 2), eye_y) lm[476] = _LM(X(cx + ie / 2 + ew / 2 + d / 2), eye_y) return [lm[i] for i in range(478)], gt @pytest.fixture def oversize_file(tmp_path): """1006 用例:>1MB 的占位文件(无需合法图片,只看字节数)。""" p = tmp_path / "oversize.bin" p.write_bytes(b"\x00" * 1_100_000) return p