当前位置 博文首页 > cungudafa的博客:Python+OpenCV4虹膜识别

    cungudafa的博客:Python+OpenCV4虹膜识别

    作者:[db:作者] 时间:2021-09-08 10:24

    前言

    一次拿到SANSUNG手机解锁发现自带一个黑科技:虹膜解锁(虹膜就是眼睛黑黑的那部分);想起以前看过的未来科技大片里面的片段:搜捕罪犯通过黑匣子识别人们的眼球,只要摄像头扫描到过你的眼睛,你的身份即被确定;哇喔,很炫酷的样子。
    日前大火的人脸识别技术因为疫情大家都带上了口罩,为了减少直接触碰的风险,指纹识别也在暗淡,虹膜识别正好互补。虽然识别对于戴眼镜尤其是墨镜不太友好,但各识别方法各有利弊吧。
    查阅信息的时候发现虹膜包含的信息还对应身体健康知识,博大精深,又是一种很好的发展方向,nice。
    在这里插入图片描述
    话题扯远了,直接上思路和代码

    正文

    一、思路

    1. 环境
      这里还是采用最简单可上手的OpenCV,(别呛为什么不用YOLO等等标注识别,我像是有闲心搞学术的吗?不是)
      环境:python3.9+jupyter notebook+opencv4.5.3
    2. 下载识别
      opencv官网,下载识别用的配置文件https://github.com/opencv/opencv/tree/master/data/haarcascades
      这里需要eye眼部检测,意外发现还有eyeglasses戴眼镜的配置文件,强呀强呀!

    Tips:怎么快速下载–浏览器打开想要的xml文件,把地址中的blob改为raw再保存网页即可,github、gitee通用;
    打开:https://github.com/opencv/opencv/blob/master/data/haarcascades/haarcascade_eye.xml
    修改后:https://github.com/opencv/opencv/raw/master/data/haarcascades/haarcascade_eye.xml
    转换并下载:https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_eye.xml

    1. haarcascade介绍
      Haar分类器,如何训练及原理,可以查看一下这篇参考文章,比较详细。
    训练集识别范围
    haarcascade_lefteye_2splits.xml可用来检测睁开或闭着的眼睛
    haarcascade_eye.xml仅可以检测睁开的眼睛
    haarcascade_eye_tree_eyeglasses.xml仅在带被检测者戴眼镜时方可检测

    二、眼睛定位

    先识别人脸,在人脸范围内识别眼睛(这里用的opencv自带,可优化为其他方案dlib,yolo等)

    import numpy as np
    import cv2
    from matplotlib import pyplot as plt
    
    def findeyes(path):
        face_cascade = cv2.CascadeClassifier('/Users/wangyu/Desktop/haarcascade_frontalface_default.xml')
        eye_cascade = cv2.CascadeClassifier('/Users/wangyu/Desktop/haarcascade_eye.xml')
        img = cv2.imread(path)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 灰度处理
        # 人脸识别
        face = face_cascade.detectMultiScale(gray, 2, 2)  # 参数:1、灰度图片, 2、缩放比例, 3、阈值
        print("这张图片中有%d张人脸" % len(face))
        for (x, y, w, h) in face:
            cv2.rectangle(img, (x, y), (x+w, y+h), (255, 255, 0), 2)  # 绘制人脸方框
    
            face_gray = gray[y:y+h, x:x+w]# 在人脸的基础上识别眼睛
            face_color = img[y:y+h, x:x+w]
            # 眼睛识别
            eyes = eye_cascade.detectMultiScale(face_gray)
            print("在这张脸上有%d个眼睛" % len(eyes))
            for (e_x, e_y, e_w, e_h) in eyes:
                cv2.rectangle(face_color, (e_x, e_y), (e_x+e_w, e_y+e_h), (0, 255, 0), 2)  # 绘制眼睛方框
                roi_color = face_color[e_y:e_y+e_h, e_x:e_x+e_w] #裁剪眼睛框图
                #getCircle(roi_color)
        plt.figure(figsize=(10,10))
        plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
        plt.show()
        # cv2.imshow('dst', img)
        # cv2.waitKey(0)
        
    if __name__=="__main__":
        path = '/Users/wangyu/Desktop/lena.jpg'
        findeyes(path)
    
    

    opencv识别结果:
    在这里插入图片描述

    三、虹膜识别

    1.图像去干扰

    识别到眼睛部分,截取眼睛部分图像,并做干扰处理

    1. 高斯模糊
      高斯矩阵的长与宽都是3,标准差取5;高斯矩阵的尺寸越大,标准差越大,处理过的图像模糊程度越大。
    2. 二值化
      把图像的像素转变为0或者255,只有这两个像素值。0白色 1黑色
    3. 腐蚀
      腐蚀操作 开运算:先腐蚀后膨胀,去除孤立的小点,毛刺
    4. 膨胀
      膨胀操作 闭运算:先膨胀后腐蚀,填平小孔,弥合小裂缝
      在这里插入图片描述

    这里读取的图片为全脸图片,如果是纯眼部图,效果会更好!或许还有更优解,欢迎讨论。

    2.检测虹膜

    霍夫梯度法检测圆(Canny边缘检测的最大阈值,检测阶段圆心的累加器阈值,最小圆的半径,最大圆的半径)
    原理参考
    在这里插入图片描述
    在这里插入图片描述

    输入参数为(image,method,dp,min_dist,param1,param2,minRadius,maxRadius)

    参数描述
    image为需要进行霍夫变换的图像
    method为检测方法,一般用CV_HOUGH_GRADIENT,即霍夫梯度法
    dp为检测内侧圆心的累加器图像的分辨率与输入图像之比的倒数。若为1,即累加器和输入图像具有相同的分辨率;若为2,则累加器有输入图像一半的宽度和高度。
    min_dist两个圆之间圆心的最小距离。防止重复画一个圆
    param1默认值100,为传递给canny边缘检测算子的高阈值,低阈值为其一半
    param2默认值100,表示在检测阶段圆心的累加器阈值,它越小,表示可以检测到更多不存在的圆,它越大,表示能检测出来的圆越完美
    minRadius默认值0,圆半径的最小值
    maxRadius默认值0,圆半径的最大值

    在这里插入图片描述

    完整代码:

    import numpy as np
    import cv2
    from matplotlib import pyplot as plt
    
    def findeyes(path):
        face_cascade = cv2.CascadeClassifier('/Users/wangyu/Desktop/haarcascade_frontalface_default.xml')
        eye_cascade = cv2.CascadeClassifier('/Users/wangyu/Desktop/haarcascade_eye.xml')
        img = cv2.imread(path)
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 灰度处理
        # 人脸识别
        face = face_cascade.detectMultiScale(gray, 2, 2)  # 参数:1、灰度图片, 2、缩放比例, 3、阈值
        print("这张图片中有%d张人脸" % len(face))
        for (x, y, w, h) in face:
            cv2.rectangle(img, (x, y), (x+w, y+h), (255, 255, 0), 2)  # 绘制人脸方框
    
            face_gray = gray[y:y+h, x:x+w]# 在人脸的基础上识别眼睛
            face_color = img[y:y+h, x:x+w]
            # 眼睛识别
            eyes = eye_cascade.detectMultiScale(face_gray)
            print("在这张脸上有%d个眼睛" % len(eyes))
            for (e_x, e_y, e_w, e_h) in eyes:
                cv2.rectangle(face_color, (e_x, e_y), (e_x+e_w, e_y+e_h), (0, 255, 0), 2)  # 绘制眼睛方框
                roi_color = face_color[e_y:e_y+e_h, e_x:e_x+e_w] #裁剪眼睛框图
                # 霍夫圆检测虹膜===
                getHoughCircle(roi_color)
        plt.figure(figsize=(10,10))
        plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
        plt.show()
        # cv2.imshow('dst', img)
        # cv2.waitKey(0)
    
        
    def getHoughCircle(img):
        plt.figure(figsize=(15,15))
        plt.subplot(1,4,1) 
        plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))#BGR转RGB
        plt.xlabel(u'img')
        
        
        blur = cv2.GaussianBlur(img, (3, 3), 5) # 高斯模糊,给出高斯模糊矩阵和标准差
        gray = cv2.cvtColor(blur, cv2.COLOR_BGR2GRAY)# 灰度化
    
        # 图像二值化,全局自适应阈值:对输入的单通道矩阵逐像素进行阈值分割
        ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY | cv2.THRESH_TRIANGLE)
        kernel = np.ones((3,3),np.uint8)# 设置卷积核3*3
        erosion = cv2.erode(binary,kernel)# 图像的腐蚀,默认迭代次数
        dst = cv2.dilate(erosion,kernel)# 图像的膨胀
        
        plt.subplot(1,4,2)
        plt.imshow(cv2.cvtColor(dst, cv2.COLOR_BGR2RGB))
        plt.xlabel(u'gray')
        
        # 霍夫梯度法检测圆(Canny边缘检测的最大阈值,检测阶段圆心的累加器阈值,最小圆的半径,最大圆的半径)
        circles = cv2.HoughCircles(dst,cv2.HOUGH_GRADIENT,1,50,param1=100,param2=10,
                                   minRadius=0,maxRadius=200)
        img2 = img
        if circles is None:
            print("未检测到霍夫圆")
        else:
            for i in circles[0:]:# 遍历矩阵每一行的数据
                item = i[0]
                # print(item)
                # cv2.circle(img2,(int(i[0]),int(i[1])),i[2],(0,255,0),2)
                cv2.circle(img2, (int(item[0]), int(item[1])), int(item[2]), (0, 255, 255), 2)
                cv2.circle(img2,(