如何用OpenCV和Python提取虹膜轮廓并消除眼睑眉毛干扰
虹膜轮廓提取:去除眼睑和眉毛干扰的解决方案
问题描述
我尝试用Python和OpenCV从眼部图像中绘制虹膜轮廓,步骤如下:
- 通过Hough圆变换定位虹膜区域
- 截取Hough圆外扩2像素的范围,排除无关轮廓(因为Hough圆是完美圆形,我需要精确的虹膜轮廓)
- 对截取图像做阈值处理,放到白色画布上,提取轮廓后绘制到原图
这种方法能得到不错的虹膜轮廓,但同时会画出眼睑和眉毛的轮廓。
示例原图:
得到的结果图:
原代码如下:
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圆检测出的虹膜中心,应集中在虹膜半径的附近(允许小范围偏差)
- 灰度特征:虹膜区域的灰度值通常比眼睑、眉毛更低(颜色更深),可结合灰度阈值进一步过滤
具体步骤
- 优化ROI范围:将原外扩2像素改为内缩1-2像素+外扩2像素,减少眼睑边缘的干扰
- 轮廓筛选时,增加距离中心的距离判断:计算轮廓外接圆圆心到虹膜中心的距离,同时检查轮廓点到中心的距离是否在虹膜半径的合理区间内
- 可选:结合原灰度图的灰度值,过滤掉灰度值过高的轮廓(排除浅色的眼睑、眉毛)
修改后的代码
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
相关产品推荐
相关产品推荐

