最近开始学习Qt,结合之前学习过的caffe一起搭建了一个人脸识别登录系统的程序,新手可能有理解不到位的情况,还请大家多多指教。

我的想法是用opencv自带的人脸检测算法检测出面部,利用caffe训练好的卷积神经网络来提取特征,通过计算当前检测到的人脸与已近注册的所有用户的面部特征之间的相似度,如果最大的相似度大于一个阈值,就可以确定当前检测到的人脸对应为这个相似度最大的用户了。

###Caffe人脸识别

因为不断有新的用户加入,然而添加新用户后重新调整CNN的网络结构太费时间,所以不能用CNN去判别一个用户属于哪一类。一个训练好的人脸识别网络拥有很强大的特征提取能力(例如这里用到的VGG face),我们finetune预训练的网络时会调整最后一层的分类数目,所以最后一层的目的是为了分类,倒数第二个全连接层(或者前面的)提取到的特征通过简单的计算距离也可以达到很高的准确率,因此可以用计算相似度的方式判断类别。

载入finetune后的VGG模型

代码就不详细解释了,我用的是拿1000个人脸微调后的VGGface,效果比用直接下载来的weight文件好一点,这里可以用原始的权重文件代替。

import caffe

model_def = 'VGG_FACE_deploy.prototxt'

model_weights = 'VGG_Face_finetune_1000_iter_900.caffemodel'

# create transformer for the input called 'data'

net = caffe.Net(model_def, # defines the structure of the model

model_weights, # contains the trained weights

caffe.TEST)

transformer = caffe.io.Transformer({'data': net.blobs['data'].data.shape})

transformer.set_transpose('data', (2,0,1)) # move image channels to outermost dimension

transformer.set_mean('data', np.array([104, 117, 123])) # subtract the dataset-mean value in each channel

transformer.set_raw_scale('data', 255) # rescale from [0, 1] to [0, 255]

transformer.set_channel_swap('data', (2,1,0)) # swap channels from RGB to BGRxpor

计算余弦相似度

import numpy as np

# 计算余弦距离

def cal_cos(A,B):

num = A.dot(B.T) #若为行向量则 A * B.T

print(B.shape)

if B.ndim == 1:

denom = np.linalg.norm(A) * np.linalg.norm(B)

else:

denom = np.linalg.norm(A) * np.linalg.norm(B, axis=1)

#print(num)

cos = num / denom #余弦值

sim = 0.5 + 0.5 * cos #归一化

return sim

def cal_feature(image):

#for i,img_name in enumerate(os.listdir(path)):

#image = caffe.io.load_image(os.path.join(path,img_name))

transformed_image = transformer.preprocess('data', image)

net.blobs['data'].data[0,:,:,:] = transformed_image

output = net.forward()

return net.blobs['fc7'].data[0]

cal_feature函数返回fc7层的输出,也就是image通过网络提取到的特征;A的维度为[1, 4096],为需要检测的目标,B的维度为[n,4096],表示所有已注册的用户的特征,cal_cos返回n个相似度,值越大,越可能是同一个人。

###Opencv人脸检测

检测人脸位置的算法用了opencv自带的人脸检测器。

import cv2

face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

PyQt界面

定义全局变量存储用户的信息,提取到的特征,我用文件的形式将这些信息保存到本地,下一次运行时提前载入。

import sys

import os

import pickle

global ALLFEATURE, NEWFEATURE, tempUsrName, ALLUSER, USRNAME

with open('USRNAME.pickle', 'rb') as f:

USRNAME = pickle.load(f)

with open('ALLUSER.pickle', 'rb') as f:

ALLUSER = pickle.load(f)

ALLFEATURE = np.load('usrfeature.npy')

NEWFEATURE = np.array([])

tempUsrName = {}

设计一个登录界面

用PyQt设计一个界面,实现用户注册,注册时录入照片,用户密码登录,人脸识别登录等功能。

创建一个TabWidget界面

tab1用来实现密码登录,注册,tab2用来实现人脸识别登录。

from PyQt5.QtWidgets import (QWidget, QMessageBox, QLabel, QDialog,

QApplication, QPushButton, QDesktopWidget, QLineEdit, QTabWidget)

from PyQt5.QtGui import QIcon, QPixmap, QImage, QPalette, QBrush

from PyQt5.QtCore import Qt, QTimer

class TabWidget(QTabWidget):

def __init__(self, parent=None):

super(TabWidget, self).__init__(parent)

self.setWindowTitle('Face Recognition')

self.setWindowIcon(QIcon('camera.png'))

self.resize(400, 260)

self.center()

self.mContent = passWordSign()

self.mIndex = faceSign()

self.addTab(self.mContent, QIcon('camera.png'), u"密码登录")

self.addTab(self.mIndex, u"人脸识别")

palette=QPalette()

icon=QPixmap('background.jpg').scaled(400, 260)

palette.setBrush(self.backgroundRole(), QBrush(icon)) #添加背景图片

self.setPalette(palette)

def center(self):

qr = self.frameGeometry()

cp = QDesktopWidget().availableGeometry().center()

qr.moveCenter(cp)

self.move(qr.topLeft())

def closeEvent(self, event):

reply = QMessageBox.question(self, 'Message',

"Are you sure to quit?", QMessageBox.Yes |

QMessageBox.No, QMessageBox.No)

if reply == QMessageBox.Yes:

event.accept()

else:

event.ignore()

if __name__ == '__main__':

app = QApplication(sys.argv)

t = TabWidget()

t.show()

#ex = Example()

sys.exit(app.exec_())

用户注册和密码登录

分别添加两个按钮和两个文本框,文本框用于用户名和密码输入,按钮分别对应事件注册和登录。addPicture用于注册时录入用户照片。

class passWordSign(QWidget):

def __init__(self):

super().__init__()

self.initUI()

def initUI(self):

#self.setGeometry(0, 0, 450, 300)

self.signUpButton = QPushButton(QIcon('camera.png'), 'Sign up', self)

self.signUpButton.move(300, 200)

self.signInButton = QPushButton(QIcon('camera.png'), 'Sign in', self)

self.signInButton.move(200, 200)

self.usrNameLine = QLineEdit( self )

self.usrNameLine.setPlaceholderText('User Name')

self.usrNameLine.setFixedSize(200, 30)

self.usrNameLine.move(100, 50)

self.passWordLine = QLineEdit(self)

self.passWordLine.setEchoMode(QLineEdit.Password)

self.passWordLine.setPlaceholderText('Pass Word')

self.passWordLine.setFixedSize(200, 30)

self.passWordLine.move(100, 120)

self.signInButton.clicked.connect(self.signIn)

self.signUpButton.clicked.connect(self.signUp)

self.show()

def signIn(self):

global ALLFEATURE, NEWFEATURE, tempUsrName, ALLUSER, USRNAME

if self.usrNameLine.text() not in ALLUSER:

QMessageBox.information(self,"Information","用户不存在,请注册")

elif ALLUSER[self.usrNameLine.text()] == self.passWordLine.text():

QMessageBox.information(self,"Information","Welcome!")

else:

QMessageBox.information(self,"Information","密码错误!")

def signUp(self):

global ALLFEATURE, NEWFEATURE, tempUsrName, ALLUSER, USRNAME

if self.usrNameLine.text() in ALLUSER:

QMessageBox.information(self,"Information","用户已存在!")

elif len(self.passWordLine.text()) < 3:

QMessageBox.information(self,"Information","密码太短!")

else:

tempUsrName.clear()

tempUsrName[self.usrNameLine.text()] = self.passWordLine.text()

self.addPicture()

def addPicture(self):

dialog = Dialog(parent=self)

dialog.show()

录入用户人脸

点击sign up按钮后弹出一个对话框,用一个label控件显示摄像头获取的照片。首先用opencv打开摄像头,用自带的人脸检测器检测到人脸self.face后,绘制一个蓝色的框,然后resize到固定的大小(对应网络的输入)。将opencv的图片格式转换为Qlabel可以显示的格式,用Qtimer定时器每隔一段时间刷新图片。检测鼠标点击事件mousePressEvent,点击鼠标后保存当前录入的用户注册信息和对应的特征。关闭摄像头,提示注册成功。

class Dialog(QDialog):

def __init__(self, parent=None):

QDialog.__init__(self, parent)

self.resize(240, 200)

self.label = QLabel(self)

self.label.setFixedWidth(150)

self.label.setFixedHeight(150)

self.label.move(40, 20)

pixMap = QPixmap("face.jpg").scaled(self.label.width(),self.label.height())

self.label.setPixmap(pixMap)

self.label.show()

self.timer = QTimer()

self.timer.start()

self.timer.setInterval(100)

self.cap = cv2.VideoCapture(0)

self.timer.timeout.connect(self.capPicture)

def mousePressEvent(self, event):

global ALLFEATURE, NEWFEATURE, tempUsrName, ALLUSER, USRNAME

self.cap.release()

NEWFEATURE = cal_feature(self.face).reshape([1,-1])

if NEWFEATURE.size > 0:

for key, value in tempUsrName.items():

ALLUSER[key] = value

USRNAME.append(key)

with open('ALLUSER.pickle', 'wb') as f:

pickle.dump(ALLUSER, f)

with open('USRNAME.pickle', 'wb') as f:

pickle.dump(USRNAME, f)

print(ALLFEATURE,NEWFEATURE)

ALLFEATURE = np.concatenate((ALLFEATURE, NEWFEATURE), axis=0)

np.save('usrfeature.npy', ALLFEATURE)

QMessageBox.information(self,"Information","Success!")

def capPicture(self):

if (self.cap.isOpened()):

# get a frame

ret, img = self.cap.read()

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

faces = face_cascade.detectMultiScale(gray, 1.3, 5)

for (x,y,w,h) in faces:

img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)

roi_gray = gray[y:y+h, x:x+w]

roi_color = img[y:y+h, x:x+w]

self.face = cv2.resize(img[y:y+h, x:x+w],(224, 224), interpolation=cv2.INTER_CUBIC)

height, width, bytesPerComponent = img.shape

bytesPerLine = bytesPerComponent * width

# 变换彩色空间顺序

cv2.cvtColor(img, cv2.COLOR_BGR2RGB, img)

# 转为QImage对象

self.image = QImage(img.data, width, height, bytesPerLine, QImage.Format_RGB888)

self.label.setPixmap(QPixmap.fromImage(self.image).scaled(self.label.width(),self.label.height()))

人脸识别登录

登录部分与之前类似,添加一个label控件用来显示图片,两个按钮用来开始检测和选定图片。当最大的相似度大于0.9时,显示登录成功。

class faceSign(QWidget):

def __init__(self):

super().__init__()

self.initUI()

def initUI(self):

self.label = QLabel(self)

self.label.setFixedWidth(260)

self.label.setFixedHeight(200)

self.label.move(20, 15)

self.pixMap = QPixmap("face.jpg").scaled(self.label.width(),self.label.height())

self.label.setPixmap(self.pixMap)

self.label.show()

self.startButton = QPushButton('start', self)

self.startButton.move(300, 50)

self.capPictureButton = QPushButton('capPicture', self)

self.capPictureButton.move(300, 150)

self.startButton.clicked.connect(self.start)

self.capPictureButton.clicked.connect(self.cap)

#self.cap = cv2.VideoCapture(0)

#self.ret, self.img = self.cap.read()

self.timer = QTimer()

self.timer.start()

self.timer.setInterval(100)

def start(self,event):

self.cap = cv2.VideoCapture(0)

self.timer.timeout.connect(self.capPicture)

def cap(self,event):

global ALLFEATURE, NEWFEATURE, tempUsrName, ALLUSER, USRNAME

self.cap.release()

feature = cal_feature(self.face)

#np.save('usrfeature.npy', ALLFEATURE)

sim = cal_cos(feature,np.array(ALLFEATURE))

m = np.argmax(sim)

if max(sim)>0.9:

print(sim, USRNAME)

QMessageBox.information(self,"Information","Welcome," + USRNAME[m])

else:

QMessageBox.information(self,"Information","识别失败!")

self.label.setPixmap(self.pixMap)

def capPicture(self):

if (self.cap.isOpened()):

# get a frame

ret, img = self.cap.read()

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

faces = face_cascade.detectMultiScale(gray, 1.3, 5)

for (x,y,w,h) in faces:

img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)

roi_gray = gray[y:y+h, x:x+w]

roi_color = img[y:y+h, x:x+w]

self.face = cv2.resize(img[y:y+h, x:x+w],(224, 224), interpolation=cv2.INTER_CUBIC)

height, width, bytesPerComponent = img.shape

bytesPerLine = bytesPerComponent * width

# 变换彩色空间顺序

cv2.cvtColor(img, cv2.COLOR_BGR2RGB, img)

# 转为QImage对象

self.image = QImage(img.data, width, height, bytesPerLine, QImage.Format_RGB888)

self.label.setPixmap(QPixmap.fromImage(self.image).scaled(self.label.width(),self.label.height()))

###效果

密码登录,输入合法的密码后点击sign in,显示欢迎。

注册界面

识别界面

登录成功

点击capPicture按钮后,开始计算相似度,大于0.9提示登录成功,并显示用户名。

###缺点和不足

程序用pyinstaller打包后,亲测可以在别的linux电脑下运行。代码和文件可以参考我的Github(没有VGG face的权重),第一次写博客,非常感谢大家的意见。总结一下不足:

1.初始话caffe模型很费时间,所以程序打开时要等一两秒;

2.用户信息用文件的形式保存并不安全,可以用mysql保存到数据库,需要时调出;

3.人脸位置检测可以用faster rcnn代替,再加上对齐;

4.识别很耗费时间,因此不能实时检测,应该可以用多线程解决。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

python带界面的人脸识别_PyQt5+Caffe+Opencv搭建人脸识别登录界面相关推荐

  1. 基于百度云人脸识别API与opencv的人脸识别系统

    基于百度云人脸识别API与opencv的人脸识别系统 简介 弄这个东西是因为参加了学校的项目,第一次开发做的不是很好. 本系统是基于百度云人脸识别API.opencv级联器.PYQT5进行开发.百度云 ...

  2. python制作qq登录界面_Python制作一个仿QQ办公版的图形登录界面

    最近,QQ的办公版本--TIM进行了一次更新升级.本次更新升级大幅修改了界面的样式,看起来更加的清爽.简洁和高效了. 这种界面州的先生还是比较喜欢的,没有QQ那么花里胡哨,也比微信那些残缺的功能更加丰 ...

  3. 用PyQt5+Caffe+Opencv搭建一个人脸识别登录界面

    最近开始学习Qt,结合之前学习过的caffe一起搭建了一个人脸识别登录系统的程序,新手可能有理解不到位的情况,还请大家多多指教. 我的想法是用opencv自带的人脸检测算法检测出面部,利用caffe训 ...

  4. pythonopencv人脸识别考勤_Python+Opencv+Tkinter指纹识别与人脸识别的门禁兼考勤(一)...

    一.设计目标:旨在PC端上搭建一款具有指纹识别与人脸识别功能的门禁兼考勤系统.该系统同时具备普通用户模式.管理员模式与超级管理员模式,下面具体介绍每种模式下的功能. 1)普通用户模式 该模式可分为收集 ...

  5. opencv ocr文字识别_用OpenCV和OCR识别图片中的表格数据

    ♚ 作者: jclian,喜欢算法,热爱分享,希望能结交更多志同道合的朋友,一起在学习Python的道路上走得更远!   在很多时候,我们的数据来源形式是多种多样的,有时候数据(或表格)也会呈现在图片 ...

  6. ajax php登陆界面,实例详解Ajax实现漂亮、安全的登录界面

    本文主要为大家详细介绍了Ajax实现一个漂亮.安全登录界面的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能帮到大家. 登录界面是信息系统提供的必备的功能,是提供给用户提供维护信息的接口 ...

  7. ios 仿电脑qq登录界面_iOS开发UI篇—模仿ipad版QQ空间登录界面

    iOS开发UI篇-模仿ipad版QQ空间登录界面 一.实现和步骤 1.一般ipad项目在命名的时候可以加一个HD,标明为高清版 2.设置项目的文件结构,分为home和login两个部分 3.登陆界面的 ...

  8. python人脸识别opencv_体验opencv进行人脸识别(基于python)

    使用opencv自带的分类器进行人脸识别,python中需要导入cv2模块.如果之前没有安装过这个模块可以用pip工具安装: pip install opencv-python 安装完成后就可以开始编 ...

  9. python人脸识别opencv_Python与OpenCV实时人脸识别

    刚刚开始使用Python写OpenCV的东西,发现关于使用Python写OpenCV的还是比较少的,先整了一个人脸识别的最简单实例,与大家共享! 环境:Python 2.7.4.OpenCV 2.4. ...

最新文章

  1. Redis持久化方法对比分析
  2. python的opencv模块_Python图像识别精讲之OpenCV模块(1)
  3. 51定时器控制4各led,使用回调函数机制
  4. 关于Mysql5.7高版本group by新特性报错
  5. 与 30 家公司过招,得到了这章面试心法
  6. .net core HttpContext(Http上下文)
  7. c++ idea 插件_IDEA的基本使用:让你的IDEA有飞一般的感觉 CSDN 博文精选
  8. 提高代码的运行效率 (4)
  9. 2019蓝桥杯C++B组 年号字串;完全二叉树的权值
  10. 通过MD5校验游戏安装文件完整性实例演示,MD5校验工具Hash使用演示
  11. python七种数据类型
  12. python 归一化方法
  13. Linux下批量tiff转pdf
  14. 怎么把两个pdf合并成一个pdf?
  15. 计算机无法打开注册表,电脑无法打开注册表怎么办
  16. Gitea:从SVN迁移到Git
  17. 读小说赚钱吗?这个年入百万
  18. 干货 | 深度理解数据采集与埋点,提高自主数据分析能力!
  19. web压力測试-Web Bench
  20. Ubuntu 1804 升级内核

热门文章

  1. [转]Sandboxie 的工作原理
  2. [转摘] 我的同学聚会--性格决定命运
  3. eclipse,myeclipse,Tomcat进行JSP开发配置
  4. 如何防止在ListBox中添加很多数据出现不停的刷新?
  5. 情人节表白(持续更新,欢迎收藏)
  6. 求证:为什么当x趋近于0时,(sinx)/x的极限等于1
  7. mysql数据库myisam_MySQL数据库修复方法(MyISAM/InnoDB)
  8. python md5加密_如何用python“优雅”的调用有道翻译?
  9. python刷今日头条阅读量_教你如何提高今日头条号推荐量阅读量播放量
  10. 阿里云申请免费ssl证书并配置nginx