功能目标
利用手机/平板的前置摄像头检测用户与屏幕的距离,若距离过近,则弹出提醒,提示用户调整观看距离。
实现方案
方案一:红外 ToF(Time-of-Flight)传感器
- 原理:发射红外光测量返回时间,计算深度
- 某些高端手机支持(如部分华为、小米、iPhone)
✅ 优点:
- 精度高,不依赖图像
- 快速、稳定
⚠️ 缺点:
- 并非所有手机都支持,依赖硬件
- Android 上访问受限,不一定开放给三方开发者
方案二:使用面部特征模型 Mediapipe FaceMesh(推荐)
原理:使用 Mediapipe FaceMesh 获取3D人脸坐标,估算Z轴深度
✅ 优点:
- 能识别468个人脸3D关键点
- 还能检测歪头、闭眼、张嘴等行为(可拓展为护眼+防沉迷)
⚠️ 缺点:
- 资源消耗高,模型大
- z 值是相对深度,单位非 cm,距离只能估算(通常 z 越小越靠近)
流程图:
代码示例:(Python)
注意:如需在手机或平板实现,则需要用对应的Android代码实现类似逻辑
import cv2
import mediapipe as mp
import time
# 初始化 mediapipe
mp_face_mesh = mp.solutions.face_mesh
face_mesh = mp_face_mesh.FaceMesh(static_image_mode=False,
max_num_faces=1,
refine_landmarks=True,
min_detection_confidence=0.5,
min_tracking_confidence=0.5)
# 摄像头
cap = cv2.VideoCapture(0)
prev_alert_time = 0
# 持续时间,单位:秒
ALERT_INTERVAL = 5
Z_THRESHOLD = -0.15 # 越小表示越近,你可以根据测试调节
print("摄像头启动,按 ESC 退出...")
while cap.isOpened():
success, frame = cap.read()
if not success:
print("无法读取摄像头帧")
break
# 翻转图像(自拍镜像效果)
frame = cv2.flip(frame, 1)
img_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = face_mesh.process(img_rgb)
if results.multi_face_landmarks:
face_landmarks = results.multi_face_landmarks[0]
img_h, img_w, _ = frame.shape
# 选择鼻尖(landmark #1)作为距离估算点
nose = face_landmarks.landmark[1]
x = int(nose.x * img_w)
y = int(nose.y * img_h)
z = nose.z
# 显示关键点
cv2.circle(frame, (x, y), 5, (0, 255, 0), -1)
# 显示 z 值
cv2.putText(frame, f"Z: {z:.3f}", (x + 10, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
# 判断是否太近
current_time = time.time()
if z < Z_THRESHOLD and (current_time - prev_alert_time) > ALERT_INTERVAL:
prev_alert_time = current_time
cv2.putText(frame, "请与屏幕保持距离!", (50, 50),
cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 0, 255), 3)
# 显示画面
cv2.imshow('Face Distance Estimator', frame)
key = cv2.waitKey(1)
if key == 27: # ESC 键退出
break
cap.release()
cv2.destroyAllWindows()
关于 Z 值的说明:
-
z是 相对于摄像头的深度坐标,不是实际厘米单位 -
它的值是 负数,数值越小表示离摄像头越近
-
通常:
z ≈ -0.2 ~ -0.3:非常近z ≈ -0.1:适中z ≈ 0:远离或检测不到