Python+OpenCv实现AI人脸识别身份认证系统(3)——训练人脸识别模型
目录
案例引入
本节项目
最近有小伙伴们一直在催本项目的进度,好吧,今晚熬夜加班编写,在上一节中,实现了人脸数据的采集,在本节中将对采集的人脸数据进行训练,生成识别模型。
案例引入
首先简要讲解数据集训练生成模型的原理,这里使用的是LBPH算法,在OpenCV模块中已经有内嵌的方法cv2.face.LBPHFaceRecognizer_create(),为了方便小伙伴们读懂之后的代码,在这里先举一个简单的人脸模型训练的小案例。
第一步:采集人脸数据,网络上有许多案例Demo,不再赘述,代码如下:
- import cv2
- detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
- cap = cv2.VideoCapture(0)
- sampleNum = 0
- #输入人脸图像数据类别
- Id = input('enter your id: ')
- while True:
- ret, img = cap.read()
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
- faces = detector.detectMultiScale(gray, 1.3, 5)
- for (x, y, w, h) in faces:
- cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
- sampleNum = sampleNum + 1
- #命名规则为User.[ID].[SampleNumber].jpg
- #如果是2号人的第十张照片,我们可以将它命名为User.2.10.jpg
- cv2.imwrite("dataSet/User." + str(Id) + '.' + str(sampleNum) + ".jpg", gray[y:y + h, x:x + w]) #
- cv2.imshow('frame', img)
- if cv2.waitKey(1) & 0xFF == ord('q'):
- break
- elif sampleNum > 20:
- break
- cap.release()
- cv2.destroyAllWindows()
采集效果 如下:
第二步:使用OpenCV中LBPH算法的方法建立人脸数据模型,代码如下:
- import cv2
- import os
- import numpy as np
- from PIL import Image
- #初始化识别器和人脸检测器
- '''
- 如果face.LBPHFaceRecognizer_create或createLBPHFaceRecognizer显示不存在
- 则需要下载opencv-contrib-python pip install opencv-contrib-python
- '''
- # recognizer = cv2.createLBPHFaceRecognizer()
- detector = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
- recognizer = cv2.face.LBPHFaceRecognizer_create()
- '''
- 遍历图片路径,导入图片和id,添加到list
- '''
- def get_images_and_labels(path):
- image_paths = [os.path.join(path, f) for f in os.listdir(path)]
- face_samples = []
- ids = []
- for image_path in image_paths:
- #灰度图片
- image = Image.open(image_path).convert('L')
- #将图片转换成了Numpy数组
- image_np = np.array(image, 'uint8')
- #为了获取到id,我们将图片的路径分裂一下并获取相关信息
- if os.path.split(image_path)[-1].split(".")[-1] != 'jpg':
- continue
- image_id = int(os.path.split(image_path)[-1].split(".")[1])
- faces = detector.detectMultiScale(image_np)
- #将图片和id都添加在list中
- for (x, y, w, h) in faces:
- face_samples.append(image_np[y:y + h, x:x + w])
- ids.append(image_id)
- return face_samples, ids
- #让LBPH识别器去训练
- faces, Ids = get_images_and_labels('dataSet')
- recognizer.train(faces, np.array(Ids))
- recognizer.save('trainner.yml')
运行程序即可便捷快速生成模型文件“trainner.yml”, 打开模型文件,可以看到人脸数据信息,如下图所示:
本节项目
接下来看看本节训练人脸识别模型小案例吧,只不过是在上面代码的基础添加了图像预处理、数据库操作和GUI操作而已,导入第二节采集到的人脸数据,点击训练即可,当人脸数据类别较多时,可以使用数据库进行查询或者删除操作,效果如下:
确定无误后即可训练模型,效果如下:
训练仅需几秒即可,训练过程中程序会暂停响应,训练成功后就会生成所需模型,大功告成~
最后分享本节实现代码~
- #!/usr/bin/env python3
- # Author: winterssy <winterssy@foxmail.com>
- import cv2
- import numpy as np
- from PyQt5.QtCore import pyqtSignal
- from PyQt5.QtGui import QIcon, QTextCursor
- from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox, QTableWidgetItem, QAbstractItemView
- from PyQt5.uic import loadUi
- import logging
- import logging.config
- import os
- import shutil
- import sqlite3
- import sys
- import threading
- import multiprocessing
- from datetime import datetime
- # 自定义数据库记录不存在异常
- class RecordNotFound(Exception):
- pass
- class DataManageUI(QWidget):
- logQueue = multiprocessing.Queue() # 日志队列
- receiveLogSignal = pyqtSignal(str) # 日志信号
- def __init__(self):
- super(DataManageUI, self).__init__()
- loadUi('./ui/DataManage.ui', self)
- self.setWindowIcon(QIcon('./icons/icon.png'))
- self.setFixedSize(931, 577)
- # 设置tableWidget只读,不允许修改
- self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
- # 数据库
- self.database = './FaceBase.db'
- self.datasets = './datasets'
- self.isDbReady = False
- self.initDbButton.clicked.connect(self.initDb)
- # 用户管理
- self.queryUserButton.clicked.connect(self.queryUser)
- self.deleteUserButton.clicked.connect(self.deleteUser)
- # 直方图均衡化
- self.isEqualizeHistEnabled = False
- self.equalizeHistCheckBox.stateChanged.connect(
- lambda: self.enableEqualizeHist(self.equalizeHistCheckBox))
- # 训练人脸数据
- self.trainButton.clicked.connect(self.train)
- # 系统日志
- self.receiveLogSignal.connect(lambda log: self.logOutput(log))
- self.logOutputThread = threading.Thread(target=self.receiveLog, daemon=True)
- self.logOutputThread.start()
- # 是否执行直方图均衡化
- def enableEqualizeHist(self, equalizeHistCheckBox):
- if equalizeHistCheckBox.isChecked():
- self.isEqualizeHistEnabled = True
- else:
- self.isEqualizeHistEnabled = False
- # 初始化/刷新数据库
- def initDb(self):
- # 刷新前重置tableWidget
- while self.tableWidget.rowCount() > 0:
- self.tableWidget.removeRow(0)
- try:
- if not os.path.isfile(self.database):
- raise FileNotFoundError
- conn = sqlite3.connect(self.database)
- cursor = conn.cursor()
- res = cursor.execute('SELECT * FROM users')
- for row_index, row_data in enumerate(res):
- self.tableWidget.insertRow(row_index)
- for col_index, col_data in enumerate(row_data):
- self.tableWidget.setItem(row_index, col_index, QTableWidgetItem(str(col_data)))
- cursor.execute('SELECT Count(*) FROM users')
- result = cursor.fetchone()
- dbUserCount = result[0]
- except FileNotFoundError:
- logging.error('系统找不到数据库文件{}'.format(self.database))
- self.isDbReady = False
- self.initDbButton.setIcon(QIcon('./icons/error.png'))
- self.logQueue.put('Error:未发现数据库文件,你可能未进行人脸采集')
- except Exception:
- logging.error('读取数据库异常,无法完成数据库初始化')
- self.isDbReady = False
- self.initDbButton.setIcon(QIcon('./icons/error.png'))
- self.logQueue.put('Error:读取数据库异常,初始化/刷新数据库失败')
- else:
- cursor.close()
- conn.close()
- self.dbUserCountLcdNum.display(dbUserCount)
- if not self.isDbReady:
- self.isDbReady = True
- self.logQueue.put('Success:数据库初始化完成,发现用户数:{}'.format(dbUserCount))
- self.initDbButton.setText('刷新数据库')
- self.initDbButton.setIcon(QIcon('./icons/success.png'))
- self.trainButton.setToolTip('')
- self.trainButton.setEnabled(True)
- self.queryUserButton.setToolTip('')
- self.queryUserButton.setEnabled(True)
- else:
- self.logQueue.put('Success:刷新数据库成功,发现用户数:{}'.format(dbUserCount))
- # 查询用户
- def queryUser(self):
- stu_id = self.queryUserLineEdit.text().strip()
- conn = sqlite3.connect(self.database)
- cursor = conn.cursor()
- try:
- cursor.execute('SELECT * FROM users WHERE stu_id=?', (stu_id,))
- ret = cursor.fetchall()
- if not ret:
- raise RecordNotFound
- face_id = ret[0][1]
- cn_name = ret[0][2]
- except RecordNotFound:
- self.queryUserButton.setIcon(QIcon('./icons/error.png'))
- self.queryResultLabel.setText('<font color=red>Error:此用户不存在</font>')
- except Exception as e:
- logging.error('读取数据库异常,无法查询到{}的用户信息'.format(stu_id))
- self.queryResultLabel.clear()
- self.queryUserButton.setIcon(QIcon('./icons/error.png'))
- self.logQueue.put('Error:读取数据库异常,查询失败')
- else:
- self.queryResultLabel.clear()
- self.queryUserButton.setIcon(QIcon('./icons/success.png'))
- self.stuIDLineEdit.setText(stu_id)
- self.cnNameLineEdit.setText(cn_name)
- self.faceIDLineEdit.setText(str(face_id))
- self.deleteUserButton.setEnabled(True)
- finally:
- cursor.close()
- conn.close()
- # 删除用户
- def deleteUser(self):
- text = '从数据库中删除该用户,同时删除相应人脸数据,<font color=red>该操作不可逆!</font>'
- informativeText = '<b>是否继续?</b>'
- ret = DataManageUI.callDialog(QMessageBox.Warning, text, informativeText, QMessageBox.Yes | QMessageBox.No,
- QMessageBox.No)
- if ret == QMessageBox.Yes:
- stu_id = self.stuIDLineEdit.text()
- conn = sqlite3.connect(self.database)
- cursor = conn.cursor()
- try:
- cursor.execute('DELETE FROM users WHERE stu_id=?', (stu_id,))
- except Exception as e:
- cursor.close()
- logging.error('无法从数据库中删除{}'.format(stu_id))
- self.deleteUserButton.setIcon(QIcon('./icons/error.png'))
- self.logQueue.put('Error:读写数据库异常,删除失败')
- else:
- cursor.close()
- conn.commit()
- if os.path.exists('{}/stu_{}'.format(self.datasets, stu_id)):
- try:
- shutil.rmtree('{}/stu_{}'.format(self.datasets, stu_id))
- except Exception as e:
- logging.error('系统无法删除删除{}/stu_{}'.format(self.datasets, stu_id))
- self.logQueue.put('Error:删除人脸数据失败,请手动删除{}/stu_{}目录'.format(self.datasets, stu_id))
- text = '你已成功删除学号为 <font color=blue>{}</font> 的用户记录。'.format(stu_id)
- informativeText = '<b>请在右侧菜单重新训练人脸数据。</b>'
- DataManageUI.callDialog(QMessageBox.Information, text, informativeText, QMessageBox.Ok)
- self.stuIDLineEdit.clear()
- self.cnNameLineEdit.clear()
- self.faceIDLineEdit.clear()
- self.initDb()
- self.deleteUserButton.setIcon(QIcon('./icons/success.png'))
- self.deleteUserButton.setEnabled(False)
- self.queryUserButton.setIcon(QIcon())
- finally:
- conn.close()
- # 检测人脸
- def detectFace(self, img):
- gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
- if self.isEqualizeHistEnabled:
- gray = cv2.equalizeHist(gray)
- face_cascade = cv2.CascadeClassifier('./haarcascades/haarcascade_frontalface_default.xml')
- faces = face_cascade.detectMultiScale(gray, scaleFactor=1.3, minNeighbors=5, minSize=(90, 90))
- if (len(faces) == 0):
- return None, None
- (x, y, w, h) = faces[0]
- return gray[y:y + w, x:x + h], faces[0]
- # 准备图片数据
- def prepareTrainingData(self, data_folder_path):
- dirs = os.listdir(data_folder_path)
- faces = []
- labels = []
- face_id = 1
- conn = sqlite3.connect(self.database)
- cursor = conn.cursor()
- # 遍历人脸库
- for dir_name in dirs:
- if not dir_name.startswith('stu_'):
- continue
- stu_id = dir_name.replace('stu_', '')
- try:
- cursor.execute('SELECT * FROM users WHERE stu_id=?', (stu_id,))
- ret = cursor.fetchall()
- if not ret:
- raise RecordNotFound
- cursor.execute('UPDATE users SET face_id=? WHERE stu_id=?', (face_id, stu_id,))
- except RecordNotFound:
- logging.warning('数据库中找不到学号为{}的用户记录'.format(stu_id))
- self.logQueue.put('发现学号为{}的人脸数据,但数据库中找不到相应记录,已忽略'.format(stu_id))
- continue
- subject_dir_path = data_folder_path + '/' + dir_name
- subject_images_names = os.listdir(subject_dir_path)
- for image_name in subject_images_names:
- if image_name.startswith('.'):
- continue
- image_path = subject_dir_path + '/' + image_name
- image = cv2.imread(image_path)
- face, rect = self.detectFace(image)
- if face is not None:
- faces.append(face)
- labels.append(face_id)
- face_id = face_id + 1
- cursor.close()
- conn.commit()
- conn.close()
- return faces, labels
- # 训练人脸数据
- def train(self):
- try:
- if not os.path.isdir(self.datasets):
- raise FileNotFoundError
- text = '系统将开始训练人脸数据,界面会暂停响应一段时间,完成后会弹出提示。'
- informativeText = '<b>训练过程请勿进行其它操作,是否继续?</b>'
- ret = DataManageUI.callDialog(QMessageBox.Question, text, informativeText,
- QMessageBox.Yes | QMessageBox.No,
- QMessageBox.No)
- if ret == QMessageBox.Yes:
- face_recognizer = cv2.face.LBPHFaceRecognizer_create()
- if not os.path.exists('./recognizer'):
- os.makedirs('./recognizer')
- faces, labels = self.prepareTrainingData(self.datasets)
- face_recognizer.train(faces, np.array(labels))
- face_recognizer.save('./recognizer/trainingData.yml')
- except FileNotFoundError:
- logging.error('系统找不到人脸数据目录{}'.format(self.datasets))
- self.trainButton.setIcon(QIcon('./icons/error.png'))
- self.logQueue.put('未发现人脸数据目录{},你可能未进行人脸采集'.format(self.datasets))
- except Exception as e:
- logging.error('遍历人脸库出现异常,训练人脸数据失败')
- self.trainButton.setIcon(QIcon('./icons/error.png'))
- self.logQueue.put('Error:遍历人脸库出现异常,训练失败')
- else:
- text = '<font color=green><b>Success!</b></font> 系统已生成./recognizer/trainingData.yml'
- informativeText = '<b>人脸数据训练完成!</b>'
- DataManageUI.callDialog(QMessageBox.Information, text, informativeText, QMessageBox.Ok)
- self.trainButton.setIcon(QIcon('./icons/success.png'))
- self.logQueue.put('Success:人脸数据训练完成')
- self.initDb()
- # 系统日志服务常驻,接收并处理系统日志
- def receiveLog(self):
- while True:
- data = self.logQueue.get()
- if data:
- self.receiveLogSignal.emit(data)
- else:
- continue
- # LOG输出
- def logOutput(self, log):
- time = datetime.now().strftime('[%Y/%m/%d %H:%M:%S]')
- log = time + ' ' + log + '\n'
- self.logTextEdit.moveCursor(QTextCursor.End)
- self.logTextEdit.insertPlainText(log)
- self.logTextEdit.ensureCursorVisible() # 自动滚屏
- # 系统对话框
- @staticmethod
- def callDialog(icon, text, informativeText, standardButtons, defaultButton=None):
- msg = QMessageBox()
- msg.setWindowIcon(QIcon('./icons/icon.png'))
- msg.setWindowTitle('OpenCV Face Recognition System - DataManage')
- msg.setIcon(icon)
- msg.setText(text)
- msg.setInformativeText(informativeText)
- msg.setStandardButtons(standardButtons)
- if defaultButton:
- msg.setDefaultButton(defaultButton)
- return msg.exec()
- if __name__ == '__main__':
- logging.config.fileConfig('./config/logging.cfg')
- app = QApplication(sys.argv)
- window = DataManageUI()
- window.show()
- sys.exit(app.exec())
本项目资源下载地址:https://download.csdn.net/download/m0_38106923/11072010
Python+OpenCv实现AI人脸识别身份认证系统(1)——人脸识别原理:
https://blog.csdn.net/m0_38106923/article/details/86489773
Python+OpenCv实现AI人脸识别身份认证系统(3)——训练人脸识别模型相关推荐
- Python+OpenCV实现AI人脸识别身份认证系统(3)—训练人脸识别模型
目录 案例引入 本节项目 最近有小伙伴们一直在催本项目的进度,好吧,今晚熬夜加班编写,在上一节中,实现了人脸数据的采集,在本节中将对采集的人脸数据进行训练,生成识别模型. 案例引入 首先简要讲解数据集 ...
- Python+OpenCv实现AI人脸识别身份认证系统(2)——人脸数据采集、存储
原 Python+OpenCv实现AI人脸识别身份认证系统(2)--人脸数据采集.存储 2019年07月02日 08:47:52 不脱发的程序猿 阅读数 602更多 所属专栏: 人脸识别身份认证系统设 ...
- Python+OpenCV实现AI人脸识别身份认证系统(4)—人脸识别
本篇博文是Python+OpenCV实现AI人脸识别身份认证系统的收官之作,在人脸识别原理到数据采集.存储和训练识别模型基础上,实现人脸识别,废话少说,上效果图: 案例引入 在Python+OpenC ...
- Python+OpenCv实现AI人脸识别身份认证系统(1)——人脸识别原理
原 Python+OpenCv实现AI人脸识别身份认证系统(1)--人脸识别原理 置顶 2019年07月02日 08:47:40 不脱发的程序猿 阅读数 1255更多 所属专栏: 人脸识别身份认证系统 ...
- PyQt5 + Python3.7 + OpenCV人脸识别身份认证系统(附源码)
基于PyQt5 + Python3.7 + OpenCV实现的人脸识别身份认证系统,附源码. 技术选型 PyQt5 + Python3.7 + OpenCV 功能概述 实现人员注册,信息修改,人脸识别 ...
- Python+OpenCV实现AI人脸识别身份认证系统(2)—人脸数据采集、存储
目录 实现原理 实施步骤 实现程序 了解人脸检测.识别的原理后,让我们开始人脸识别系统的设计吧~ 首先展示下数据采集.存储的界面设计: 实现原理
- Python+OpenCV实现AI人脸识别身份认证系统(1)—人脸识别原理
目录 人脸识别流程 第一步:人脸检测,找出所有的面孔 第二步:脸部的不同姿势
- Python+OpenCV人脸识别身份认证系统设计:专栏总述
本专栏依托于Python编程语言,在内容上尽可能涵盖了人脸识别的各个技术模块,从人脸数据采集.数据预处理.数据分析.人脸识别模型的训练到最后的人脸识别,均有详细的操作步骤和注释代码,能帮助学习者从零开 ...
- Django的身份认证系统
1 . 在Django中使用身份认证系统 Django的身份认证系统实际上是一个app,该app叫做django.contrib.auth,它在django contrib模块下 使用时只需要在set ...
最新文章
- 博士一次性最高给140万安家费!还享副教授待遇,这所高校为了引进人才!拼了...
- .NET 通用权限设计
- TabActivity 切换到后台遇到的问题
- JZOJ 4421. aplusb
- maven集成spring_Maven集成测试和Spring Restful Services
- server sql 众数_sql 语句系列(众数中位数与百分比)[八百章之第十五章]
- linux下安装mysql5.7方法与常见问题
- centos删除gnome_自定义你的 GNOME 桌面主题 | Linux 中国
- html5好看的大方框,这个样式导致HTML5的视频中的按钮变成一个方框。求解决…...
- linux下mysql允许远程连接
- PostgreSQL 10 新特性, 流式接收端在线压缩redo
- 从入门到狂热,特征工程必学的几项资源
- mysql数据库导出txt文件_mysql数据库导出表数据 为.txt文件
- i.MX6UL IO分析
- HTTP协议-get与post请求
- 编辑器生成静态网页_使用静态网站生成器的7个理由
- 写出HTML的基本结构 做简要说明,北京市顺义区2017年--2018年届高三二模语文试题(卷)与答案解析.doc...
- 木兰天池全新景观2013闪亮登场
- 「订单」业务的设计与实现
- 广州小学计算机教师待遇,给大家详细的分享一下广州市各区在编教师的待遇到底有多少?一个月的工资大概有多少,到底高不高?...
热门文章
- 苏格拉底与柏拉图麦穗的故事
- android适配和新文件及作用
- npm ERR! cb() never called! 解决办法
- 5G千兆网关助力重工业能耗监测系统
- Android模拟器模拟打电话,发短信
- ARCore⭐二、从零到放置物体
- 金融量化ushare模块
- Java file outside of soure root 导入项目时idea无法识别为java文件
- Spark2.X管理与开发
- 计算思维就是指计算机程序 即计算机的思维,[数学思维在计算机程序设计中的体现]计算机思维的本质是指...