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

如何用OpenCV和Python提取虹膜轮廓并消除眼睑眉毛干扰

虹膜轮廓提取:去除眼睑和眉毛干扰的解决方案

问题描述

我尝试用Python和OpenCV从眼部图像中绘制虹膜轮廓,步骤如下:

  1. 通过Hough圆变换定位虹膜区域
  2. 截取Hough圆外扩2像素的范围,排除无关轮廓(因为Hough圆是完美圆形,我需要精确的虹膜轮廓)
  3. 对截取图像做阈值处理,放到白色画布上,提取轮廓后绘制到原图

这种方法能得到不错的虹膜轮廓,但同时会画出眼睑和眉毛的轮廓。

示例原图:
输入眼部图像

得到的结果图:
带干扰轮廓的结果图

原代码如下:

import cv2 as cv2
import numpy as np

def image_processing(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    img_blur = cv2.medianBlur(gray, 5)
    
    #creating white image the same size as the sample image
    white_image = np.full((image.shape[0], image.shape[1]), 255, dtype=np.uint8)
    
    #detecting the iris region using hough circles
    circles = cv2.HoughCircles(img_blur, cv2.HOUGH_GRADIENT, 1, 20, param1 = 200, param2 = 20, minRadius = 0)
    inner_circle = np.uint16(np.around(circles[0][0])).tolist()

    #adding the eye region on the white canvas 
    cv2.circle(white_image, (inner_circle[0], inner_circle[1]), inner_circle[2]+2, (0, 0, 0), -1)
    roi = cv2.bitwise_or(gray,white_image)
    
    #thresholding result
    roi_blur = cv2.medianBlur(roi, 5)
    ret, thresh = cv2.threshold(roi, 127, 255, cv2.THRESH_BINARY)

    return thresh

def find_countours(image):
    img = image
    
    #finding hte contours
    contours,hierarchy = cv2.findContours(img,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    
    #this iterates through the contours and removes the ones under or over a certain area to remove reflections being highlighted
    list_contours = []
    for contour in contours:
        if cv2.contourArea(contour) > 100 and cv2.contourArea(contour) < 50000:
            list_contours.append(contour)
            
    return list_contours

#this funciton gets the center of the eye
def get_center(image):
    img= image
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    img_blur = cv2.medianBlur(gray, 5)
    
    circles = cv2.HoughCircles(img_blur, cv2.HOUGH_GRADIENT, 1, 20, param1 = 200, param2 = 20, minRadius = 0)
    inner_circle = np.uint16(np.around(circles[0][0])).tolist()

    center =(inner_circle[0],inner_circle[1])
    
    return center

#this function draws the iris contour and the center of the eye
def draw_image(image,contours,center):
    img = image
    cont = contours
    cv2.drawContours(img, cont, -1, (0,255,0), 1)
    cv2.drawMarker(img, center, (0, 255, 0), cv2.MARKER_CROSS, 15, 1) 
    cv2.imshow("Result Image", img)
    cv2.waitKey(0)

image = cv2.imread('eye.jpg')
center = get_center(image)
processed_image = image_processing(image)
contours = find_countours(processed_image)
draw_image(image,contours,center)

核心问题:如何去除眼睑和眉毛的轮廓,只保留虹膜轮廓?


解决方案

核心思路

利用虹膜的两个关键特征筛选轮廓:

  • 距离特征:虹膜轮廓上的点距离Hough圆检测出的虹膜中心,应集中在虹膜半径的附近(允许小范围偏差)
  • 灰度特征:虹膜区域的灰度值通常比眼睑、眉毛更低(颜色更深),可结合灰度阈值进一步过滤

具体步骤

  1. 优化ROI范围:将原外扩2像素改为内缩1-2像素+外扩2像素,减少眼睑边缘的干扰
  2. 轮廓筛选时,增加距离中心的距离判断:计算轮廓外接圆圆心到虹膜中心的距离,同时检查轮廓点到中心的距离是否在虹膜半径的合理区间内
  3. 可选:结合原灰度图的灰度值,过滤掉灰度值过高的轮廓(排除浅色的眼睑、眉毛)

修改后的代码

import cv2 as cv2
import numpy as np

def image_processing(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    img_blur = cv2.medianBlur(gray, 5)
    
    white_image = np.full((image.shape[0], image.shape[1]), 255, dtype=np.uint8)
    
    # 检测虹膜圆
    circles = cv2.HoughCircles(img_blur, cv2.HOUGH_GRADIENT, 1, 20, param1=200, param2=20, minRadius=0)
    inner_circle = np.uint16(np.around(circles[0][0])).tolist()
    cx, cy, radius = inner_circle[0], inner_circle[1], inner_circle[2]

    # 优化ROI:内缩1像素+外扩2像素,只保留虹膜边缘环形区域
    cv2.circle(white_image, (cx, cy), radius + 2, (0, 0, 0), -1)
    cv2.circle(white_image, (cx, cy), radius - 1, (255, 255, 255), -1)
    roi = cv2.bitwise_or(gray, white_image)
    
    # 自适应高斯阈值,适配不同光照条件
    roi_blur = cv2.medianBlur(roi, 5)
    thresh = cv2.adaptiveThreshold(roi_blur, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 11, 2)

    return thresh, (cx, cy, radius)

def find_iris_contours(image, center, radius, gray_img):
    cx, cy = center
    max_dist_deviation = radius * 0.2  # 允许的距离偏差(20%)
    
    # 只检索最外层轮廓,减少嵌套干扰
    contours, hierarchy = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    iris_contours = []
    
    for contour in contours:
        area = cv2.contourArea(contour)
        # 过滤面积不合理的轮廓(过小或过大)
        if area < 100 or area > radius * radius * np.pi * 1.2:
            continue
        
        # 计算轮廓的外接圆圆心,判断与虹膜中心的距离
        (cnt_cx, cnt_cy), cnt_r = cv2.minEnclosingCircle(contour)
        dist_to_center = np.sqrt((cnt_cx - cx)**2 + (cnt_cy - cy)**2)
        if dist_to_center > radius * 0.3:
            continue
        
        # 可选:通过区域平均灰度过滤浅色干扰(眼睑/眉毛)
        mask = np.zeros_like(gray_img)
        cv2.drawContours(mask, [contour], -1, 255, -1)
        avg_gray = cv2.mean(gray_img, mask=mask)[0]
        if avg_gray > 100:  # 阈值可根据实际图像调整
            continue
        
        iris_contours.append(contour)
    
    return iris_contours

def draw_image(image, contours, center):
    img = image.copy()
    cv2.drawContours(img, contours, -1, (0,255,0), 1)
    cv2.drawMarker(img, center, (0, 255, 0), cv2.MARKER_CROSS, 15, 1) 
    cv2.imshow("Result Image", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

# 主流程
image = cv2.imread('eye.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
processed_image, (cx, cy, radius) = image_processing(image)
iris_contours = find_iris_contours(processed_image, (cx, cy), radius, gray)
draw_image(image, iris_contours, (cx, cy))

关键改进点说明

  • 优化ROI范围:通过双层圆筛选出虹膜边缘的环形区域,大幅减少眼睑、眉毛的纳入范围
  • 自适应阈值:替换固定阈值为自适应高斯阈值,更好应对不同光照下的虹膜与背景差异
  • 多维度轮廓筛选:结合面积、距离中心的距离、区域平均灰度三个条件,精准过滤干扰轮廓
  • 简化轮廓检索:使用cv2.RETR_EXTERNAL只检索最外层轮廓,避免嵌套轮廓的干扰

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 23:45:03