科学护眼,人脸与屏幕的距离监测技术

246 阅读2分钟

功能目标

利用手机/平板的前置摄像头检测用户与屏幕的距离,若距离过近,则弹出提醒,提示用户调整观看距离。

实现方案

方案一:红外 ToF(Time-of-Flight)传感器

  • 原理:发射红外光测量返回时间,计算深度
  • 某些高端手机支持(如部分华为、小米、iPhone)

✅ 优点:

  • 精度高,不依赖图像
  • 快速、稳定

⚠️ 缺点:

  • 并非所有手机都支持,依赖硬件
  • Android 上访问受限,不一定开放给三方开发者

方案二:使用面部特征模型 Mediapipe FaceMesh(推荐)

原理:使用 Mediapipe FaceMesh 获取3D人脸坐标,估算Z轴深度

✅ 优点:

  • 能识别468个人脸3D关键点
  • 还能检测歪头、闭眼、张嘴等行为(可拓展为护眼+防沉迷)

⚠️ 缺点:

  • 资源消耗高,模型大
  • z 值是相对深度,单位非 cm,距离只能估算(通常 z 越小越靠近)

face.png

流程图

屏幕距离计算技术研究报告-流程图.jpg

代码示例:(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:远离或检测不到

官方文档
ai.google.dev/edge/mediap…