Python+OpenCV虹膜检测与直径测量:解决MediaPipe误检问题
基于MediaPipe的实时虹膜检测问题解决与直径测量实现
问题概述
- 眼睛闭合时仍会检测并绘制虹膜圆圈
- 面部移动时出现双重检测圈
- 需要实现虹膜直径的测量
解决方案细节
1. 解决眼睛闭合时的误检测
通过计算上下眼睑的垂直距离判断眼睛状态:
- 提取眼睛上下边界的关键点(左眼:386/374,右眼:159/145)
- 计算两点间的欧氏距离,当距离小于设定阈值时判定为闭眼,跳过虹膜绘制
2. 解决移动时的双重检测圈
- 验证虹膜关键点的置信度(
visibility属性),仅当置信度高于0.5时使用该点数据 - 确保每次循环基于新读取的帧绘制,避免帧残留干扰
3. 虹膜直径测量
- 直接从最小外接圆的半径计算像素直径(
直径 = 2 * 半径) - 将直径数据实时绘制在画面上,若需物理尺寸,可结合摄像头参数与拍摄距离换算
完整修改代码
import cv2 as cv import numpy as np import mediapipe as mp mp_face_mesh = mp.solutions.face_mesh LEFT_EYE = [362, 382, 381, 380, 374, 373, 390, 249, 263, 466, 388, 387, 386, 385, 384, 398] RIGHT_EYE = [33, 7, 163, 144, 145, 153, 154, 155, 133, 173, 157, 158, 159, 160, 161, 246] LEFT_IRIS = [474, 475, 476, 477] RIGHT_IRIS = [469, 470, 471, 472] # 眼睛开合判断关键点:上眼睑/下眼睑 LEFT_EYE_OPENNESS = [386, 374] RIGHT_EYE_OPENNESS = [159, 145] # 闭眼阈值(可根据实际情况调整) EYE_CLOSE_THRESHOLD = 12 cap = cv.VideoCapture(0) with mp_face_mesh.FaceMesh( max_num_faces=1, refine_landmarks=True, min_detection_confidence=0.5, min_tracking_confidence=0.5 ) as face_mesh: while True: ret, frame = cap.read() if not ret: break frame = cv.flip(frame, 1) rgb_frame = cv.cvtColor(frame, cv.COLOR_BGR2RGB) img_h, img_w = frame.shape[:2] results = face_mesh.process(rgb_frame) mask = np.zeros((img_h, img_w), dtype=np.uint8) if results.multi_face_landmarks: face_landmarks = results.multi_face_landmarks[0] mesh_points = np.array([np.multiply([p.x, p.y], [img_w, img_h]).astype(int) for p in face_landmarks.landmark]) # 计算眼睛开合度 left_eye_dist = np.linalg.norm(mesh_points[LEFT_EYE_OPENNESS[0]] - mesh_points[LEFT_EYE_OPENNESS[1]]) right_eye_dist = np.linalg.norm(mesh_points[RIGHT_EYE_OPENNESS[0]] - mesh_points[RIGHT_EYE_OPENNESS[1]]) # 处理左眼虹膜 if left_eye_dist > EYE_CLOSE_THRESHOLD: # 检查虹膜关键点置信度 left_iris_visible = all(face_landmarks.landmark[idx].visibility > 0.5 for idx in LEFT_IRIS) if left_iris_visible: (l_cx, l_cy), l_radius = cv.minEnclosingCircle(mesh_points[LEFT_IRIS]) center_left = np.array([l_cx, l_cy], dtype=np.int32) cv.circle(frame, center_left, int(l_radius), (0, 255, 0), 2, cv.LINE_AA) cv.circle(mask, center_left, int(l_radius), (255, 255, 255), -1, cv.LINE_AA) # 计算并显示左眼虹膜直径 left_diameter = 2 * l_radius cv.putText(frame, f"Left Iris Diameter: {left_diameter:.1f}px", (20, 40), cv.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) # 处理右眼虹膜 if right_eye_dist > EYE_CLOSE_THRESHOLD: # 检查虹膜关键点置信度 right_iris_visible = all(face_landmarks.landmark[idx].visibility > 0.5 for idx in RIGHT_IRIS) if right_iris_visible: (r_cx, r_cy), r_radius = cv.minEnclosingCircle(mesh_points[RIGHT_IRIS]) center_right = np.array([r_cx, r_cy], dtype=np.int32) cv.circle(frame, center_right, int(r_radius), (0, 255, 0), 2, cv.LINE_AA) cv.circle(mask, center_right, int(r_radius), (255, 255, 255), -1, cv.LINE_AA) # 计算并显示右眼虹膜直径 right_diameter = 2 * r_radius cv.putText(frame, f"Right Iris Diameter: {right_diameter:.1f}px", (20, 80), cv.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) cv.imshow('Mask', mask) cv.imshow('Iris Detection', frame) key = cv.waitKey(1) if key == ord('q'): break cap.release() cv.destroyAllWindows()
代码说明
- 眼睛开合判断:通过上下眼睑关键点的距离判断闭眼状态,阈值可根据摄像头分辨率调整
- 置信度验证:过滤低置信度的虹膜关键点,避免移动时的错误检测
- 直径显示:实时计算并绘制虹膜的像素直径,方便直观查看
内容的提问来源于stack exchange,提问作者Roman Bhuvanesh
相关产品推荐
相关产品推荐

