python+openCV+tkinter---人脸识别登录系统

整体代码

# -*- coding:utf-8 -*-
#!/usr/bin/env python
# @Time    : 2020/02/21 9:48
# @Author  : Cxk
# @File    : face_recongnition.py··········

from tkinter.messagebox import * 
from tkinter import *

import cv2, os, math, operator
from PIL import Image
from functools import reduce

def makeFace(facename, msg):
    print(msg)  #显示提示信息
#     cv2.namedWindow("face_recognition")
#     cv2.waitKey(0)
    cap = cv2.VideoCapture(0)  #打开摄像头
    while(cap.isOpened()):  #如果摄像头处于打开状态,则...
        try:
            ret, img = cap.read()  #读取图像
            if ret == True:#读取成功
                cv2.imshow("face_recognition", img)  #显示图像
                k = cv2.waitKey(100)  #每0.1秒读一次键盘
                if k == ord("z") or k == ord("Z"):  #如果输入z
                    cv2.imwrite(facename,img)  #把读取的img保存至facename文件
                    image = cv2.imread(facename)  #读取刚刚保存的facename文件至image变量,作为下面人脸识别函数的参数
                    faces = faceCascade.detectMultiScale(image, scaleFactor=1.1, minNeighbors=5, minSize=(30,30), flags = cv2.CASCADE_SCALE_IMAGE)
                        #print(faces)
                    (x, y, w, h) = (faces[0][0], faces[0][1], faces[0][2], faces[0][3])  #取出第一张人脸区域
#                     print(x,y,w,h)
                    image1 = Image.open(facename).crop((x, y, x+w, y+h))  #抓取人脸区域的图像并存至image1变量
                    image1 = image1.resize((200, 200), Image.ANTIALIAS)  #把取得的人脸区域的分辨率变为200x200
                    image1.save(facename)  #把经过处理的人脸文件保存至facename文件
                    break
        except:
            print("错误")
            continue
    cap.release()  #关闭摄像头
    cv2.destroyAllWindows()   #关闭窗口 
    return

def cxk(number):
    diff=0.0
    recogname = "%s_recogface.jpg"%number #预存的人脸文件
    loginname = "%s_loginface.jpg"%number #登录者的人脸文件
    os.system("cls")  #清屏
    if(os.path.exists(recogname)):#如果预存的人脸文件已存在
        msg = "摄像头打开后按 z 键进行拍照对比!"
        makeFace(loginname, msg)  #创建登录者人脸文件
        pic1 = Image.open(recogname)  #打开预存的人脸文件
        pic2 = Image.open(loginname)  #打开登录者人脸文件
        h1 = pic1.histogram()  #取预存片文件的直方图信息
        h2 = pic2.histogram()    #取登录者图片的直方图信息
        diff = math.sqrt(reduce(operator.add, list(map(lambda a,b: (a-b)**2, h1, h2)))/len(h1)) #计算两个图形差异度
    else:  #如果预存的人脸文件不存在
        diff=200.0
    return diff

        


class LoginPage(object):
    def __init__(self, master=None):
        self.root = master
        winWidth = 650
        winHeight = 400
        screenWidth = self.root.winfo_screenwidth()
        screenHeight = self.root.winfo_screenheight()

        x = int((screenWidth - winWidth) / 2)
        y = int((screenHeight - winHeight) / 2)
        # 设置窗口初始位置在屏幕居中
        self.root.geometry("%sx%s+%s+%s" % (winWidth, winHeight, x, y))
        # 设置窗口图标
        # root.iconbitmap("./image/icon.ico")
        # 设置窗口宽高固定
        self.root.resizable(0, 0)
        self.student_number = StringVar()
        self.student_pw = StringVar() 
        self.createPage()
    
    def createPage(self):
        '''
        登录页面
        1:创建图片组件
        2:根目录基础上添加Frame容器
        3:Frame容器上添加注册控件
        '''
        bm=PhotoImage(file=r'cxk.gif')
        self.lab3=Label(self.root,image=bm)
        self.lab3.bm=bm
        self.lab3.pack()
        
        self.page = Frame(self.root) 
        self.page.pack()
        Label(self.page).grid(row=0, stick=W) 
        Label(self.page, text = '       学号:').grid(row=1, column=0,stick=W, pady=10) 
        Entry(self.page, textvariable=self.student_number).grid(row=1, column=1, stick=E) 
        Label(self.page, text = '       密码:').grid(row=2, column=0,stick=W, pady=10) 
        Entry(self.page, textvariable=self.student_pw, show='*').grid(row=2, column=1, stick=E) 
        Button(self.page, text='学生人脸保存注册', command=self.signup).grid(row=3, column=0)
        Button(self.page, text='学生帐号密码登录',command="#").grid(row=3, column=1) 
        Button(self.page, text='学生人脸识别登录', command=self.student_loginCheck).grid(row=3,column=2) 

    
    def signup(self):
        Student_number=self.student_number.get()
        recogname = "%s_recogface.jpg"%Student_number
        if Student_number=="":
            showinfo(title="错误",message='请输入学生账号!')
        elif(os.path.exists(recogname)):
            showinfo(title="错误",message='该学生已保存人脸信息,可直接登录!')
        else:
            msg = "摄像头打开后按 z 键进行拍照!\n"
            makeFace(recogname, msg)  #建立预存人脸文件
            showinfo(title='确认',message='人脸信息保存成功!')
        
    def student_loginCheck(self):
        try:
            Student_number=self.student_number.get()
            if Student_number=="":
                showinfo(title="错误",message='请输入学生账号!')
            else:
                a=cxk(Student_number)
                if(a <= 100):  #若差度在100内,可通过验证
                    print("通过验证,欢迎使用本系统! diff=%4.2f" % a)
                    self.page.destroy()
                    self.lab3.pack_forget()
                    StudentPage(self.root)
                elif (a==200.0):
                    showinfo(title='错误',message='数据库无该学生人脸信息,请先进行人脸注册!')
                else:
                    print("没有通过验证! diff=%4.2f" % a)
        except:
            showinfo(title='错误',message='输入错误,请重新输入!')
        
class StudentPage(object): 
    def __init__(self, master=None): 
        self.root = master #定义内部变量root 
        self.root.geometry('%dx%d' % (650, 400)) #设置窗口大小 
        self.root.resizable(0,0) #防止用户调整尺寸
        self.createPage() 
    
    def createPage(self): 
        self.menuPage = MenuFrame(self.root) # 创建不同Frame 
    
        
class MenuFrame(Frame): # 继承Frame类 
    def __init__(self, master=None):
        Frame.__init__(self, master) 
        self.root = master #定义内部变量root
        self.createPage()
  
 
    def createPage(self):
        strs="人脸识别登录成功!"
        Label(self.root,text=strs,font=("Arial", 30)).pack()
    
root = Tk() #建立一个根窗口,所有窗口的基础
root.title('学生管理系统')
casc_path = "C:\\Users\\Cxk\\Anaconda3\Lib\site-packages\cv2\data\\haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(casc_path)  #创建识别对象
LoginPage(root)#进入调用登录
root.mainloop()

人脸识别代码

源自邓文渊老师的《毫无障碍学python》--->本书PDF,提取码: t5kk

本人已将老师一部分源码进行更改,整体思路未动,需要老师整书源码的同学私聊我。

import cv2, os, math, operator
from PIL import Image
from functools import reduce

def makeFace(facename, msg):
    print(msg)  #显示提示信息
    cap = cv2.VideoCapture(0)  #打开摄像头
    while(cap.isOpened()):  #如果摄像头处于打开状态,则...
        try:
            ret, img = cap.read()  #读取图像
            if ret == True:#读取成功
                cv2.imshow("face_recognition", img)  #显示图像
                k = cv2.waitKey(100)  #每0.1秒读一次键盘
                if k == ord("z") or k == ord("Z"):  #如果输入z
                    cv2.imwrite(facename,img)  #把读取的img保存至facename文件
                    image = cv2.imread(facename)  #读取刚刚保存的facename文件至image变量,作为下面人脸识别函数的参数
                    faces = faceCascade.detectMultiScale(image, scaleFactor=1.1, minNeighbors=5, minSize=(30,30), flags = cv2.CASCADE_SCALE_IMAGE)
                    (x, y, w, h) = (faces[0][0], faces[0][1], faces[0][2], faces[0][3])  #取出第一张人脸区域
                    image1 = Image.open(facename).crop((x, y, x+w, y+h))  #抓取人脸区域的图像并存至image1变量
                    image1 = image1.resize((200, 200), Image.ANTIALIAS)  #把取得的人脸区域的分辨率变为200x200
                    image1.save(facename)  #把经过处理的人脸文件保存至facename文件
                    break
        except:
            print("错误")
            continue
    cap.release()  #关闭摄像头
    cv2.destroyAllWindows()   #关闭窗口 

def cxk(number):
    diff=0.0
    recogname = "%s_recogface.jpg"%number #预存的人脸文件
    loginname = "%s_loginface.jpg"%number #登录者的人脸文件
    os.system("cls")  #清屏
    if(os.path.exists(recogname)):#如果预存的人脸文件已存在
        msg = "摄像头打开后按 z 键进行拍照对比!"
        makeFace(loginname, msg)  #创建登录者人脸文件
        pic1 = Image.open(recogname)  #打开预存的人脸文件
        pic2 = Image.open(loginname)  #打开登录者人脸文件
        h1 = pic1.histogram()  #取预存片文件的直方图信息
        h2 = pic2.histogram()    #取登录者图片的直方图信息
        diff = math.sqrt(reduce(operator.add, list(map(lambda a,b: (a-b)**2, h1, h2)))/len(h1)) #直方图的相似性度量
    else:  #如果预存的人脸文件不存在
        diff=200.0
    return diff

识别对象

casc_path = "C:\\Users\\Cxk\\Anaconda3\Lib\site-packages\cv2\data\\haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(casc_path)  #创建识别对象

系统登录代码 

窗口代码是本人前段时间发的史上最全面的python学生管理系统教程(一)

登录窗口代码

from tkinter.messagebox import * 
from tkinter import *

class LoginPage(object):
    def __init__(self, master=None):
        self.root = master
        winWidth = 650
        winHeight = 400
        screenWidth = self.root.winfo_screenwidth()
        screenHeight = self.root.winfo_screenheight()

        x = int((screenWidth - winWidth) / 2)
        y = int((screenHeight - winHeight) / 2)
        # 设置窗口初始位置在屏幕居中
        self.root.geometry("%sx%s+%s+%s" % (winWidth, winHeight, x, y))
        # 设置窗口图标
        # root.iconbitmap("./image/icon.ico")
        # 设置窗口宽高固定
        self.root.resizable(0, 0)
        self.student_number = StringVar()
        self.student_pw = StringVar() 
        self.createPage()
    
    def createPage(self):
        '''
        登录页面
        1:创建图片组件
        2:根目录基础上添加Frame容器
        3:Frame容器上添加注册控件
        '''
        bm=PhotoImage(file=r'cxk.gif')
        self.lab3=Label(self.root,image=bm)
        self.lab3.bm=bm
        self.lab3.pack()
        
        self.page = Frame(self.root) 
        self.page.pack()
        Label(self.page).grid(row=0, stick=W) 
        Label(self.page, text = '       学号:').grid(row=1, column=0,stick=W, pady=10) 
        Entry(self.page, textvariable=self.student_number).grid(row=1, column=1, stick=E) 
        Label(self.page, text = '       密码:').grid(row=2, column=0,stick=W, pady=10) 
        Entry(self.page, textvariable=self.student_pw, show='*').grid(row=2, column=1, stick=E) 
        Button(self.page, text='学生人脸保存注册', command=self.signup).grid(row=3, column=0)
        Button(self.page, text='学生帐号密码登录',command="#").grid(row=3, column=1) 
        Button(self.page, text='学生人脸识别登录', command=self.student_loginCheck).grid(row=3,column=2) 

    
    def signup(self):
        Student_number=self.student_number.get()
        recogname = "%s_recogface.jpg"%Student_number
        if Student_number=="":
            showinfo(title="错误",message='请输入学生账号!')
        elif(os.path.exists(recogname)):
            showinfo(title="错误",message='该学生已保存人脸信息,可直接登录!')
        else:
            msg = "摄像头打开后按 z 键进行拍照!\n"
            makeFace(recogname, msg)  #建立预存人脸文件
            showinfo(title='确认',message='人脸信息保存成功!')
        
    def student_loginCheck(self):
        try:
            Student_number=self.student_number.get()
            if Student_number=="":
                showinfo(title="错误",message='请输入学生账号!')
            else:
                a=cxk(Student_number)
                if(a <= 100):  #若差度在100内,可通过验证
                    print("通过验证,欢迎使用本系统! diff=%4.2f" % a)
                    self.page.destroy()
                    self.lab3.pack_forget()
                    StudentPage(self.root)
                elif (a==200.0):
                    showinfo(title='错误',message='数据库无该学生人脸信息,请先进行人脸注册!')
                else:
                    print("没有通过验证! diff=%4.2f" % a)
        except:
            showinfo(title='错误',message='输入错误,请重新输入!')
        
class StudentPage(object): 
    def __init__(self, master=None): 
        self.root = master #定义内部变量root 
        self.root.geometry('%dx%d' % (650, 400)) #设置窗口大小 
        self.root.resizable(0,0) #防止用户调整尺寸
        self.createPage() 
    
    def createPage(self): 
        self.menuPage = MenuFrame(self.root) # 创建不同Frame 
    
        
class MenuFrame(Frame): # 继承Frame类 
    def __init__(self, master=None):
        Frame.__init__(self, master) 
        self.root = master #定义内部变量root
        self.createPage()
  
 
    def createPage(self):
        strs="人脸识别登录成功!"
        Label(self.root,text=strs,font=("Arial", 30)).pack()

根窗口(main) 

root = Tk() #建立一个根窗口,所有窗口的基础
root.title('学生管理系统')
casc_path = "C:\\Users\\Cxk\\Anaconda3\Lib\site-packages\cv2\data\\haarcascade_frontalface_default.xml"
faceCascade = cv2.CascadeClassifier(casc_path)  #创建识别对象
LoginPage(root)#进入调用登录
root.mainloop()

具体流程

  1. 运行登录页面,输入学号进行登录,如果没有输入学号则无法进行登录
  2. 输入学号尝试登录,系统查找是否有该学号预存人脸信息,如无提示进行人脸保存
  3. 用户人脸信息获取函数makeFace(facename, msg),参数一:图片保存地址,参数二:提示信息。保存头像信息如下

  4. 登录运行,检查是否有该学号预存人脸信息,如有开启摄像头进行登录人脸信息获取,将获取到的人脸信息与预存人脸信息进行对比。
  5. 关键部分:获取人脸
    faces = faceCascade.detectMultiScale(image, scaleFactor=1.1, minNeighbors=5, minSize=(30,30), flags = cv2.CASCADE_SCALE_IMAGE)
    (x, y, w, h) = (faces[0][0], faces[0][1], faces[0][2], faces[0][3])  #取出第一张人脸区域
    image1 = Image.open(facename).crop((x, y, x+w, y+h))  #抓取人脸区域的图像并存至image1变量
    image1 = image1.resize((200, 200), Image.ANTIALIAS)  #把取得的人脸区域的分辨率变为200x200

    人脸信息比对

    pic1 = Image.open(recogname)  #打开预存的人脸文件
    pic2 = Image.open(loginname)  #打开登录者人脸文件
    h1 = pic1.histogram()  #取预存片文件的直方图信息
    h2 = pic2.histogram()    #取登录者图片的直方图信息
    diff = math.sqrt(reduce(operator.add, list(map(lambda a,b: (a-b)**2, h1, h2)))/len(h1)) #直方图的相似性度量

    直方图的相似性度量

运行效果

人脸信息预存

人脸识别

总结 

  1. 花了大半天时间研究每一行代码,到直方图对比时头大了,不过还是受益匪浅。
  2. 本来想用图片来代替人脸的,发现每次比对都不成功,人脸能准确获取,但是同一张图片的直方图对比相差总是超过150。
  3. 没具体测试过准确度,但是感觉受外部影响比较打,比如是否戴眼镜,头发是否遮住额头,脸部是否偏移,总体来说超过70%成功率,当然这是在同一时刻测的。
  4. 可以用多线程来启动人脸获取,不然系统界面有时会有卡顿。
  5. 进一步想将人脸信息加密保存至数据库,等有空再试行一下。具体思路想了一下,先将图片转为字符,将字符加密转入数据库,数据库提出解密进行比对,比对成功删除登录人脸信息。不过这样一来好像效率要低到爆炸。。溜了溜了
发布了21 篇原创文章 · 获赞 14 · 访问量 4095

猜你喜欢

转载自blog.csdn.net/Cxk___/article/details/104427685