You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何提取FaceMesh鼻尖顶点坐标并计算与食指指尖距离?

问题描述

已在实时单帧中集成FaceMesh与HandMesh,当前可通过print(results.multi_face_landmarks[0])打印所有FaceMesh顶点坐标,但无法单独提取指定顶点(如第4号鼻尖顶点)的坐标。后续需计算该鼻尖顶点与食指指尖的距离,以此提醒用户纠正摸鼻习惯,现有代码已导入math库用于距离计算,请求指导如何获取指定顶点的坐标。

现有代码如下:

import cv2
import numpy as np
import mediapipe as mp


#################################################################
import math

def calculate_distance(point1, point2):
    x1, y1, z1 = point1
    x2, y2, z2 = point2
    
    distance = math.sqrt((x2 - x1)**2 + (y2 - y1)**2 + (z2 - z1)**2)
    return distance
##################################################################

cap = cv2.VideoCapture(0)

mpDraw = mp.solutions.drawing_utils
mpFaceMesh = mp.solutions.face_mesh
mpHands = mp.solutions.hands

faceMesh = mpFaceMesh.FaceMesh(max_num_faces=2)
handsMesh = mpHands.Hands(max_num_hands=2)

drawSpecFace = mpDraw.DrawingSpec(thickness=1, circle_radius=1)
drawSpecHands = mpDraw.DrawingSpec(thickness=1, circle_radius=1)

both_detected = False  # Initialize detection flag


while True:
    success, img = cap.read()
    imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    results = faceMesh.process(imgRGB)
    if results.multi_face_landmarks:
        for faceLms in results.multi_face_landmarks:
            mpDraw.draw_landmarks(img, faceLms, mpFaceMesh.FACEMESH_CONTOURS, drawSpecFace, drawSpecFace)

            face = results.multi_face_landmarks[0]; 


    results2 = handsMesh.process(imgRGB)
    if results2.multi_hand_landmarks:
        for handLms in results2.multi_hand_landmarks:
            mpDraw.draw_landmarks(img, handLms, mpHands.HAND_CONNECTIONS, drawSpecHands, drawSpecHands)

    # Check if both face and hands are detected
    if results.multi_face_landmarks and results2.multi_hand_landmarks:
        both_detected = True
        cv2.putText(img, "Why Are Your Hands Near Face?", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (34,139,34), 2, cv2.LINE_AA)
    else:
        both_detected = False



    print (results.multi_face_landmarks[0])



    cv2.imshow("Image", img)
    cv2.waitKey(1)

运行结果如图:
运行结果


解决方案

1. 提取指定FaceMesh顶点(鼻尖#4)

FaceMesh的multi_face_landmarks返回的每个face_landmarks对象包含468个顶点,按索引顺序排列。直接通过索引访问目标顶点,提取其x、y、z属性即可:

# 提取第4号鼻尖顶点坐标(归一化值)
nose_tip = results.multi_face_landmarks[0].landmark[4]
nose_point = (nose_tip.x, nose_tip.y, nose_tip.z)

2. 提取HandMesh食指指尖(#8)

HandMesh中食指指尖对应的索引是8,同样通过索引提取坐标:

# 提取食指指尖坐标(归一化值)
index_finger_tip = results2.multi_hand_landmarks[0].landmark[8]
finger_point = (index_finger_tip.x, index_finger_tip.y, index_finger_tip.z)

3. 距离计算与提醒逻辑优化

结合已有的calculate_distance函数,设置距离阈值,当指尖与鼻尖距离小于阈值时触发提醒。


修改后的完整代码
import cv2
import numpy as np
import mediapipe as mp
import math

def calculate_distance(point1, point2):
    x1, y1, z1 = point1
    x2, y2, z2 = point2
    
    distance = math.sqrt((x2 - x1)**2 + (y2 - y1)**2 + (z2 - z1)**2)
    return distance

cap = cv2.VideoCapture(0)

mpDraw = mp.solutions.drawing_utils
mpFaceMesh = mp.solutions.face_mesh
mpHands = mp.solutions.hands

faceMesh = mpFaceMesh.FaceMesh(max_num_faces=2)
handsMesh = mpHands.Hands(max_num_hands=2)

drawSpecFace = mpDraw.DrawingSpec(thickness=1, circle_radius=1)
drawSpecHands = mpDraw.DrawingSpec(thickness=1, circle_radius=1)

# 设置距离阈值(归一化坐标下的阈值,可根据实际情况调整)
DISTANCE_THRESHOLD = 0.1

while True:
    success, img = cap.read()
    if not success:
        break
    imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    img_h, img_w, _ = img.shape

    results = faceMesh.process(imgRGB)
    results2 = handsMesh.process(imgRGB)

    # 绘制FaceMesh和HandMesh
    if results.multi_face_landmarks:
        for faceLms in results.multi_face_landmarks:
            mpDraw.draw_landmarks(img, faceLms, mpFaceMesh.FACEMESH_CONTOURS, drawSpecFace, drawSpecFace)
    if results2.multi_hand_landmarks:
        for handLms in results2.multi_hand_landmarks:
            mpDraw.draw_landmarks(img, handLms, mpHands.HAND_CONNECTIONS, drawSpecHands, drawSpecHands)

    # 当人脸和手都被检测到,计算距离并判断
    if results.multi_face_landmarks and results2.multi_hand_landmarks:
        # 提取鼻尖(索引4)坐标
        nose_tip = results.multi_face_landmarks[0].landmark[4]
        nose_point = (nose_tip.x, nose_tip.y, nose_tip.z)
        
        # 提取食指指尖(索引8)坐标
        index_finger_tip = results2.multi_hand_landmarks[0].landmark[8]
        finger_point = (index_finger_tip.x, index_finger_tip.y, index_finger_tip.z)
        
        # 计算距离
        dist = calculate_distance(nose_point, finger_point)
        
        # 根据距离显示提醒
        if dist < DISTANCE_THRESHOLD:
            cv2.putText(img, "别摸鼻子!", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2, cv2.LINE_AA)
        else:
            cv2.putText(img, "姿势正确", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (34,139,34), 2, cv2.LINE_AA)
    else:
        cv2.putText(img, "未检测到人脸或手", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (128,128,128), 2, cv2.LINE_AA)

    cv2.imshow("Image", img)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

关键说明

  • 所有顶点的x、y是归一化到[0,1]的值,对应图像的宽度和高度;z值代表深度,以相机焦距为基准。
  • 阈值DISTANCE_THRESHOLD可根据实际测试调整,确保提醒逻辑准确。
  • 代码中添加了退出逻辑(按q键退出),避免程序无法正常关闭。

内容的提问来源于stack exchange,提问作者CodeKimchi CK

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 02:35:01