600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > 简单用Python+OpenCv实现AI人脸识别--(3)—训练人脸识别模型

简单用Python+OpenCv实现AI人脸识别--(3)—训练人脸识别模型

时间:2023-09-20 00:54:21

相关推荐

简单用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'):breakelif sampleNum > 20:breakcap.release()cv2.destroyAllWindows()

采集效果 如下:(ps:图来自原作者)

第二步:使用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#CSDN:/m0_38106923#邮箱:botron.campus@import cv2import numpy as npfrom PyQt5.QtCore import pyqtSignalfrom PyQt5.QtGui import QIcon, QTextCursorfrom PyQt5.QtWidgets import QApplication, QWidget, QMessageBoxfrom PyQt5.QtWidgets import QTableWidgetItem, QAbstractItemViewfrom PyQt5.uic import loadUi######################from datetime import datetime#from ui import DataManage# 自定义数据库记录不存在异常class RecordNotFound(Exception):passclass DataManageUI(QWidget):logQueue = multiprocessing.Queue() # 日志队列receiveLogSignal = pyqtSignal(str) # 日志信号def __init__(self):super(DataManageUI, self).__init__()loadUi('./ui/GUI/DataManage.ui', self)self.setWindowIcon(QIcon('./icons/icon.png'))self.setFixedSize(999, 614)# 设置tableWidget只读,不允许修改self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)# 数据库self.database = './Facedata/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 = Trueelse:self.isEqualizeHistEnabled = False# 初始化/刷新数据库def initDb(self):# 刷新前重置tableWidgetwhile self.tableWidget.rowCount() > 0:self.tableWidget.removeRow(0)try:if not os.path.isfile(self.database):raise FileNotFoundErrorconn = 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 + 1cursor.close()mit()conn.close()return faces, labels# 训练人脸数据def train(self):try:if not os.path.isdir(self.datasets):raise FileNotFoundErrortext = '系统将开始训练人脸数据,界面会暂停响应一段时间,完成后会弹出提示。'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> 系统已生成g:/Practice/spyder/python/Python-OpenCv-AI/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() # 自动滚屏# 系统对话框@staticmethoddef callDialog(icon, text, informativeText, standardButtons, defaultButton=None):msg = QMessageBox()msg.setWindowIcon(QIcon('./icons/icon.png'))msg.setWindowTitle('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())

参考文章:

1./m0_38106923/article/details/88879876

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