You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于OpenCV与Python的口鼻距离计算及固定距离跟踪方案问询

嘿,很高兴能帮你解决这两个OpenCV面部特征点的问题,我在实际项目里经常碰到类似的需求,给你一步步拆解~

1. 如何使用OpenCV与Python计算鼻子与嘴巴之间的距离?

要计算鼻子和嘴巴的距离,核心是先定位到这两个部位的特征点,再计算它们的空间距离。这里我推荐用dlib的68点面部关键点检测器,因为它的精度足够,配合OpenCV使用很顺手:

  • 第一步:安装依赖库
    先确保你装了必要的包:

    pip install opencv-python dlib numpy
    

    另外需要下载dlib预训练的68点检测模型(shape_predictor_68_face_landmarks.dat),你可以从dlib的官方模型仓库获取,这个是免费的。

  • 第二步:编写核心代码
    下面是完整的示例,不管是处理静态图片还是摄像头流都适用:

    import cv2
    import dlib
    import numpy as np
    from scipy.spatial import distance as dist
    
    # 加载检测器和关键点预测器
    detector = dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
    
    # 定义关键点索引(dlib的68点对应位置)
    NOSE_TIP = 30  # 鼻子尖的关键点索引
    MOUTH_CENTER = 51  # 上唇中心点的关键点索引(也可以用57下唇中点,看你需求)
    
    # 处理摄像头流的例子(静态图片的话替换成cv2.imread即可)
    cap = cv2.VideoCapture(0)
    
    while True:
        ret, frame = cap.read()
        if not ret:
            break
    
        # 转灰度图,提升检测效率
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        # 检测面部
        faces = detector(gray)
    
        for face in faces:
            # 获取面部关键点
            shape = predictor(gray, face)
            shape_np = np.zeros((68, 2), dtype=int)
            for i in range(68):
                shape_np[i] = (shape.part(i).x, shape.part(i).y)
    
            # 获取鼻子和嘴巴的坐标
            nose_point = shape_np[NOSE_TIP]
            mouth_point = shape_np[MOUTH_CENTER]
    
            # 计算欧氏距离
            nose_mouth_dist = dist.euclidean(nose_point, mouth_point)
    
            # 可视化(可选)
            cv2.circle(frame, (nose_point[0], nose_point[1]), 3, (0, 255, 0), -1)
            cv2.circle(frame, (mouth_point[0], mouth_point[1]), 3, (0, 0, 255), -1)
            cv2.putText(frame, f"Distance: {nose_mouth_dist:.2f}", (10, 30),
                        cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
    
        cv2.imshow("Face Landmarks", frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    
    cap.release()
    cv2.destroyAllWindows()
    

    代码里的关键点索引是dlib标准68点的位置,你可以根据自己的需求调整,比如如果想算鼻子尖到嘴巴底部的距离,就把MOUTH_CENTER换成57。

2. 让面部特征点距离不受摄像头距离影响的解决办法

你现在遇到的问题是,像素距离会随着你和摄像头的远近线性变化——靠近时像素变大,远离时变小。要让距离“恒定”,本质是计算相对比例,也就是用目标距离除以一个面部的固定参考长度(这个长度也会随距离同步变化,所以比例保持不变)。

我常用的方法是选一个稳定的面部参考特征,比如瞳孔间距,因为它在不同距离下的比例几乎不变,步骤如下:

  • 第一步:确定参考特征的关键点
    还是用dlib的68点,左眼的瞳孔中心可以取左眼左右端点(36和39)的中点,右眼瞳孔中心取右眼左右端点(42和45)的中点,这两个点的距离就是瞳孔间距,作为参考长度。

  • 第二步:计算相对比例
    把鼻子到嘴巴的像素距离除以瞳孔间距的像素距离,得到的比例就是恒定的,不管你离摄像头多远,这个比例都不会变。

  • 代码修改示例
    在上面的代码基础上,添加参考距离的计算:

    # 新增瞳孔关键点索引
    LEFT_EYE_LEFT = 36
    LEFT_EYE_RIGHT = 39
    RIGHT_EYE_LEFT = 42
    RIGHT_EYE_RIGHT = 45
    
    # 在循环里,获取面部关键点后:
    # 计算瞳孔中心
    left_eye_center = ((shape_np[LEFT_EYE_LEFT][0] + shape_np[LEFT_EYE_RIGHT][0]) // 2,
                       (shape_np[LEFT_EYE_LEFT][1] + shape_np[LEFT_EYE_RIGHT][1]) // 2)
    right_eye_center = ((shape_np[RIGHT_EYE_LEFT][0] + shape_np[RIGHT_EYE_RIGHT][0]) // 2,
                        (shape_np[RIGHT_EYE_LEFT][1] + shape_np[RIGHT_EYE_RIGHT][1]) // 2)
    
    # 计算瞳孔间距(参考长度)
    eye_dist = dist.euclidean(left_eye_center, right_eye_center)
    
    # 计算相对比例(恒定值)
    normalized_dist = nose_mouth_dist / eye_dist
    
    # 可视化替换成这个比例
    cv2.putText(frame, f"Normalized Distance: {normalized_dist:.2f}", (10, 60),
                cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 2)
    

    这样输出的normalized_dist就是恒定的,比如不管你离摄像头1米还是2米,这个比例都会保持在一个固定区间(比如成人大概是0.8-1.2左右,具体看你选的关键点)。

    另外,你也可以用面部宽度(比如下颌线的两个端点1和17的距离)作为参考,原理是一样的,选哪个取决于你的场景哪个更稳定。

内容的提问来源于stack exchange,提问作者lololo wote

火山引擎 最新活动