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

如何编写OpenCV函数判断用户视线方向:左、右或正对摄像头

基于OpenCV的视线方向判断实现方案

现有代码问题梳理

当前代码已完成人脸椭圆绘制、眼睛矩形标记及最优人脸/眼睛筛选,但存在两个核心问题:

  • 坐标逻辑混乱:筛选左右眼时错误将局部坐标转为全局坐标判断,导致筛选条件失真
  • 缺失瞳孔定位逻辑:Haar级联仅能检测眼眶范围,而瞳孔位置才是判断视线方向的核心依据

实现步骤与修改后代码

1. 修复左右眼筛选逻辑

直接用人脸局部坐标判断:左眼处于人脸左半区域,右眼处于右半区域,同时限定在人脸的上半部分(排除脸颊误检),避免全局坐标干扰。

2. 添加瞳孔检测

对眼睛区域做灰度阈值处理,提取最暗区域作为瞳孔(瞳孔是眼睛中亮度最低的部分),通过轮廓识别定位瞳孔中心。

3. 视线判断逻辑

基于瞳孔在眼眶中的相对位置判断方向:

  • 左眼:瞳孔偏左(相对比例<0.3)→视线左;居中(0.3-0.7)→正对;偏右(>0.7)→视线右
  • 右眼:瞳孔偏左(相对比例<0.3)→视线右;居中(0.3-0.7)→正对;偏右(>0.7)→视线左
  • 综合双眼结果输出最终判断

修改后的完整代码

import cv2
import glob

def draw(color_face, list_of_coordinates):
    if not list_of_coordinates:
        return
    # 绘制眼睛框
    eye_x, eye_y, eye_width, eye_height = list_of_coordinates[0]
    topleft = (eye_x, eye_y)
    bottomright = (eye_x + eye_width, eye_y + eye_height)
    cv2.rectangle(color_face, topleft, bottomright, (0, 255, 255), 2)

def detect_pupil(eye_gray):
    # 阈值处理提取瞳孔(最暗区域)
    _, thresh = cv2.threshold(eye_gray, 30, 255, cv2.THRESH_BINARY_INV)
    # 寻找轮廓
    contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    if not contours:
        return None
    # 取面积最大的轮廓作为瞳孔
    largest_contour = max(contours, key=cv2.contourArea)
    x, y, w, h = cv2.boundingRect(largest_contour)
    # 返回瞳孔在眼睛区域的相对中心坐标
    pupil_center_x = x + w//2
    return pupil_center_x

def judge_gaze(left_eye, right_eye, face_gray):
    gaze_result = "正对"
    # 处理左眼
    if left_eye:
        le_x, le_y, le_w, le_h = left_eye
        eye_gray = face_gray[le_y:le_y+le_h, le_x:le_x+le_w]
        pup_x = detect_pupil(eye_gray)
        if pup_x is not None:
            ratio = pup_x / le_w
            if ratio < 0.3:
                gaze_result = "向左"
            elif ratio > 0.7:
                gaze_result = "向右"
    # 处理右眼,修正判断逻辑
    if right_eye:
        re_x, re_y, re_w, re_h = right_eye
        eye_gray = face_gray[re_y:re_y+re_h, re_x:re_x+re_w]
        pup_x = detect_pupil(eye_gray)
        if pup_x is not None:
            ratio = pup_x / re_w
            if ratio < 0.3:
                gaze_result = "向右"
            elif ratio > 0.7:
                gaze_result = "向左"
    return gaze_result

# 加载级联分类器
eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_eye.xml')
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

images = glob.glob('faces1/*.png')

for image in images[1:]:
    img = cv2.imread(image)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # OpenCV默认读取为BGR格式,修正颜色转换
    
    # 检测人脸并筛选最大的人脸
    faces = face_cascade.detectMultiScale(gray, 1.085, 2)
    if not faces:
        continue
    good_x, good_y, greatest_width, greatest_height = max(faces, key=lambda f: f[2]*f[3])
    
    # 提取人脸区域
    face_gray = gray[good_y:good_y+greatest_height, good_x:good_x+greatest_width]
    color_face = img[good_y:good_y+greatest_height, good_x:good_x+greatest_width]
    
    # 检测眼睛
    eyes = eye_cascade.detectMultiScale(face_gray, 1.085, 2)
    good_left_eyes = []
    good_right_eyes = []
    
    # 筛选左右眼(基于人脸局部坐标)
    face_mid_x = greatest_width // 2
    face_upper_y = greatest_height // 2
    for eye in eyes:
        e_x, e_y, e_w, e_h = eye
        # 限定眼睛在人脸的上半部分
        if e_y + e_h < face_upper_y:
            if e_x + e_w < face_mid_x:
                good_left_eyes.append(eye)
            elif e_x > face_mid_x:
                good_right_eyes.append(eye)
    
    # 绘制眼睛
    draw(color_face, good_left_eyes)
    draw(color_face, good_right_eyes)
    
    # 判断视线方向并打印
    left_eye = good_left_eyes[0] if good_left_eyes else None
    right_eye = good_right_eyes[0] if good_right_eyes else None
    gaze_dir = judge_gaze(left_eye, right_eye, face_gray)
    print(f"视线方向: {gaze_dir}")
    
    # 绘制人脸椭圆
    center = (good_x + greatest_width//2, good_y + greatest_height//2)
    axes = (greatest_height//3, greatest_height//2)
    cv2.ellipse(img, center, axes, 0, 0, 359, (0, 0, 100), 3)
    
    # 添加视线方向文本
    cv2.putText(img, gaze_dir, (good_x, good_y-10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
    
    cv2.imshow('Gaze Detection', img)
    cv2.waitKey(10000)
    break

cv2.destroyAllWindows()

关键优化说明

  • 修正了COLOR_RGB2GRAY的错误,OpenCV读取图片默认是BGR格式,需用COLOR_BGR2GRAY转换
  • 瞳孔检测使用简单阈值,光线复杂场景可替换为cv2.adaptiveThreshold提升鲁棒性
  • 视线判断的比例阈值(0.3、0.7)可根据测试样本调整,优化判断准确率

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 18:02:52