200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > Python+OpenCv实现AI人脸识别身份认证系统(3)——训练人脸识别模型

Python+OpenCv实现AI人脸识别身份认证系统(3)——训练人脸识别模型

时间:2019-06-17 23:27:27

相关推荐

Python+OpenCv实现AI人脸识别身份认证系统(3)——训练人脸识别模型

目录

案例引入

本节项目

最近有小伙伴们一直在催本项目的进度,好吧,今晚熬夜加班编写,在上一节中,实现了人脸数据的采集,在本节中将对采集的人脸数据进行训练,生成识别模型。

案例引入

首先简要讲解数据集训练生成模型的原理,这里使用的是LBPH算法,在OpenCV模块中已经有内嵌的方法cv2.face.LBPHFaceRecognizer_create(),为了方便小伙伴们读懂之后的代码,在这里先举一个简单的人脸模型训练的小案例。

第一步:采集人脸数据,网络上有许多案例Demo,不再赘述,代码如下:

import cv2detector = 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.jpgcv2.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: breakcap.release()cv2.destroyAllWindows()

采集效果 如下:

第二步:使用OpenCV中LBPH算法的方法建立人脸数据模型,代码如下:

import cv2import osimport numpy as npfrom 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': continueimage_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@> import cv2import numpy as np from PyQt5.QtCore import pyqtSignalfrom PyQt5.QtGui import QIcon, QTextCursorfrom PyQt5.QtWidgets import QApplication, QWidget, QMessageBox, QTableWidgetItem, QAbstractItemViewfrom PyQt5.uic import loadUi import loggingimport logging.configimport osimport shutilimport sqlite3import sysimport threadingimport 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 = Falseself.initDbButton.clicked.connect(self.initDb) # 用户管理self.queryUserButton.clicked.connect(self.queryUser)self.deleteUserButton.clicked.connect(self.deleteUser) # 直方图均衡化self.isEqualizeHistEnabled = Falseself.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 = Falseself.initDbButton.setIcon(QIcon('./icons/error.png'))self.logQueue.put('Error:未发现数据库文件,你可能未进行人脸采集') except Exception:logging.error('读取数据库异常,无法完成数据库初始化')self.isDbReady = Falseself.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 = Trueself.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 RecordNotFoundface_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)NameLineEdit.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()mit()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()NameLineEdit.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 = 1conn = sqlite3.connect(self.database)cursor = conn.cursor() # 遍历人脸库 for dir_name in dirs: if not dir_name.startswith('stu_'):continuestu_id = dir_name.replace('stu_', '') try:cursor.execute('SELECT * FROM users WHERE stu_id=?', (stu_id,))ret = cursor.fetchall()if not ret:raise RecordNotFoundcursor.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))continuesubject_dir_path = data_folder_path + '/' + dir_namesubject_images_names = os.listdir(subject_dir_path) for image_name in subject_images_names:if image_name.startswith('.'):continueimage_path = subject_dir_path + '/' + image_nameimage = 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()mit()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())

本项目资源下载地址:/download/m0_38106923/1107

Python+OpenCv实现AI人脸识别身份认证系统(1)——人脸识别原理:

/m0_38106923/article/details/86489773

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。