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

OpenCV眼睛检测精度优化求助:需精准识别睁眼/闭眼双眼并裁剪

我太懂这种被Haar级联坑的感觉了——尤其是闭眼场景下的误判、检测数量乱跳的问题,确实是传统特征检测算法的硬伤。结合你的代码和遇到的痛点,给你分阶段的优化方案,从低成本调整到长期高精度方案都有:

一、先给Haar级联做精细化调整(低成本快速见效)

你之前调参数的思路是对的,但还可以结合面部区域逻辑和后处理进一步过滤假阳性:

  • 限定眼睛的检测区域
    Haar分类器很容易把鼻孔、颧骨这类凸起区域当成眼睛,你可以只在人脸的上半部分检测——正常人的眼睛绝不会长到脸的下半段。修改这一行代码:
# 只检测人脸上60%的区域
eyes = eyes_cascade.detectMultiScale(img[y:int(y + h*0.6), x:x + w], scaleFactor=1.05, minNeighbors=7)
  • 更精准的参数组合
    别只盯着scaleFactorminNeighbors,结合人脸尺寸限定眼睛的大小范围:
eyes = eyes_cascade.detectMultiScale(
    img[y:int(y + h*0.6), x:x + w],
    scaleFactor=1.05,  # 更小的缩放步长,检测更精细(稍慢但精度提升明显)
    minNeighbors=7,    # 更高的邻居数,过滤假阳性
    minSize=(int(w*0.15), int(w*0.15)),  # 眼睛最小宽度设为人脸宽度的15%
    maxSize=(int(w*0.4), int(w*0.4))      # 眼睛最大宽度设为人脸宽度的40%
)
  • 后处理筛选有效眼睛
    如果检测出多个候选,通过宽高比(眼睛通常宽>高,比例在1.2-2.0之间)过滤,再强制保留最接近的两个;如果只检测到一个,尝试翻转图像补全:
# 过滤符合宽高比的候选眼睛
valid_eyes = []
for (ex, ey, ew, eh) in eyes:
    aspect_ratio = ew / eh
    if 1.2 <= aspect_ratio <= 2.0:
        valid_eyes.append((ex, ey, ew, eh))

# 处理数量异常情况
if len(valid_eyes) > 2:
    # 按面积排序,取前两个最接近的
    valid_eyes.sort(key=lambda e: e[2]*e[3], reverse=True)
    valid_eyes = valid_eyes[:2]
elif len(valid_eyes) == 1:
    # 翻转人脸区域,尝试检测另一只眼
    flipped_face = cv2.flip(img[y:int(y + h*0.6), x:x + w], 1)
    flipped_eyes = eyes_cascade.detectMultiScale(flipped_face, scaleFactor=1.05, minNeighbors=7)
    if flipped_eyes:
        # 把翻转后的坐标转回原图像坐标系
        fx, fy, fw, fh = flipped_eyes[0]
        ex = w - fx - fw
        ey = fy
        valid_eyes.append((ex, ey, fw, fh))

# 用筛选后的眼睛进行裁剪保存
count = 1
for (ex, ey, ew, eh) in valid_eyes:
    cv2.rectangle(img, (x + ex, y + ey), (x + ex + ew, y + ey + eh), (255, 255, 255), 1)
    crop_img = img[y + ey:y + ey + eh, x + ex:x + ex + ew]
    s1 = 'Images/{}.jpg'.format(count)
    count += 1
    cv2.imwrite(s1, crop_img)
二、升级到深度学习模型(长期高精度解决方案)

Haar级联本身对闭眼、侧脸、光线变化的鲁棒性极差,如果你追求稳定的精度,直接换深度学习方案:

  • Dlib面部关键点检测
    Dlib的预训练68点面部关键点模型,可以精准定位双眼(不管睁眼闭眼),几乎不会误判。代码示例:
import dlib

# 初始化检测器和关键点预测器(需要下载shape_predictor_68_face_landmarks.dat模型文件)
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

faces = detector(img)
for face in faces:
    landmarks = predictor(img, face)
    # 提取左眼关键点(36-41号点)并计算 bounding box
    left_eye_points = [(landmarks.part(i).x, landmarks.part(i).y) for i in range(36, 42)]
    left_x = min(p[0] for p in left_eye_points)
    left_y = min(p[1] for p in left_eye_points)
    left_w = max(p[0] for p in left_eye_points) - left_x
    left_h = max(p[1] for p in left_eye_points) - left_y
    left_eye_crop = img[left_y:left_y+left_h, left_x:left_x+left_w]
    cv2.imwrite("Images/1.jpg", left_eye_crop)
    
    # 右眼同理(42-47号点)
    right_eye_points = [(landmarks.part(i).x, landmarks.part(i).y) for i in range(42, 48)]
    right_x = min(p[0] for p in right_eye_points)
    right_y = min(p[1] for p in right_eye_points)
    right_w = max(p[0] for p in right_eye_points) - right_x
    right_h = max(p[1] for p in right_eye_points) - right_y
    right_eye_crop = img[right_y:right_y+right_h, right_x:right_x+right_w]
    cv2.imwrite("Images/2.jpg", right_eye_crop)
三、图像预处理辅助提升效果

在检测前对图像做简单预处理,能让特征更突出:

  • 转灰度图:Haar级联对灰度图的检测效果更好
face_gray = cv2.cvtColor(img[y:int(y + h*0.6), x:x + w], cv2.COLOR_BGR2GRAY)
eyes = eyes_cascade.detectMultiScale(face_gray, ...)
  • 直方图均衡化:提升对比度,让眼睛区域更清晰
face_gray = cv2.equalizeHist(face_gray)

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

火山引擎 最新活动