国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Python 畢業(yè)設計 - 基于 opencv 的人臉識別上課考勤系統(tǒng),附源碼

這篇具有很好參考價值的文章主要介紹了Python 畢業(yè)設計 - 基于 opencv 的人臉識別上課考勤系統(tǒng),附源碼。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

Python 畢業(yè)設計 - 基于 opencv 的人臉識別上課考勤系統(tǒng),附源碼

一、簡介

源碼下載地址https://download.csdn.net/download/2302_77835532/88237252

這個人臉識別考勤簽到系統(tǒng)是基于大佬的人臉識別陌生人報警系統(tǒng)二次開發(fā)的。

項目使用Python實現,基于OpenCV框架進行人臉識別和攝像頭硬件調用,同時也用OpenCV工具包處理圖片。交互界面使用pyqt5實現。

該系統(tǒng)實現了從學生信息輸入、人臉數據錄入、人臉數據訓練,學生信息多條件搜索、修改,多選刪除,人臉數據訓練,人臉識別、追蹤、簽到等完整流程的各項功能。甚至允許生成簽到表格和導出Excel格式簽到表。

根據功能分配,系統(tǒng)分為三個部分實現各部分流程,

  1. 錄入端負責數據導入,
  2. 管理端負責數據刪改查以及人臉數據訓練,
  3. 監(jiān)控端負責人臉識別以及簽到功能。

二、效果圖

監(jiān)控端使用界面如圖所示:

Python 畢業(yè)設計 - 基于 opencv 的人臉識別上課考勤系統(tǒng),附源碼

管理端使用界面如圖所示:

Python 畢業(yè)設計 - 基于 opencv 的人臉識別上課考勤系統(tǒng),附源碼

錄入端使用界面如圖所示:

Python 畢業(yè)設計 - 基于 opencv 的人臉識別上課考勤系統(tǒng),附源碼

三、開發(fā)過程

本系統(tǒng)在原始項目的框架基礎上做了大量修改,針對系統(tǒng)功能的不同以及部分模塊實現的不完整做了補充和優(yōu)化。原項目在功能上實現了完整的人臉數據錄入過程,并已經存在數據管理、數據錄入、核心(Core)三個基本模塊。

監(jiān)控端修改部分

(1)人臉識別實現
在主要部分【核心】的實現上,原項目采用LBPH實現了人臉識別的基本功能,并使用haar-like實現人臉位置捕獲,使用dlib目標追蹤器實現同一畫面下多個人臉的目標追蹤,嘗試主要追蹤,次要捕獲的方式優(yōu)化人臉捕獲的過程。識別速度與畫面幀率很高,

但識別準確率并不理想,并且嚴重受到光照條件影響。【實際使用時證明,若錄入人臉數據時存在單方面光源照射,在識別時,光源位置一旦改變就完全識別不出來了】
并且錄入數據時需要大量人臉數據集【100張人臉圖以上】,才能獲得較高的識別置信度。

二次開發(fā)后,保留原本速度較快的LBPH人臉識別,新增效果更好的dlib_face_recognition_resnet_model深度學習殘差網絡識別模型。實際使用時發(fā)現,雖然實時視頻流幀率明顯降低,但是識別準確率大大提高。

(2)攝像頭啟動與關閉

在原項目中,在攝像頭調用的設計上,錄入端和監(jiān)控端同樣都是用了攝像頭,并進行人臉捕獲,但監(jiān)控端只允許打開和關閉一次攝像頭,之后就禁用了攝像頭控制按鈕,而錄入端則允許隨意多次的打開和關閉攝像頭。

其原因是具體實現上,因為監(jiān)控端需要啟動單獨線程執(zhí)行人臉識別任務,而錄入端沒有人臉識別的復雜處理過程,在一個線程中就可以實現需要的功能。監(jiān)控端開啟攝像頭后,同時啟動人臉識別線程處理單幀圖像,并啟動報警監(jiān)聽線程,設計思路上是報警線程一旦開啟,全程保持監(jiān)聽,直到程序關閉,而關閉攝像頭時代碼實現上只關閉,也只能夠關閉人臉識別線程,對于報警監(jiān)聽線程無法控制。導致如果容許攝像頭二次開啟,人臉識別線程能夠啟動,但作為同一個線程實例的報警監(jiān)聽模塊將被二次啟動,導致程序出錯。

這里的人臉識別線程繼承自QTread類,允許使用.stop()函數控制線程實例的開始與終止,而報警監(jiān)聽模塊則是普通的threading.Thread(),開啟后無法控制關閉,導致出現上述問題。改進方法是將報警監(jiān)聽線程使用QTread實現,使用與人臉識別線程相同的控制方法,攝像頭開啟時啟動,攝像頭關閉時終止,實現二次啟動功能。

(3)報警系統(tǒng)改為簽到系統(tǒng)
因為系統(tǒng)的功能修改前后有所改變,但是實現的技術實際上是一樣的。原始項目的報警功能實際上可以作為簽到系統(tǒng)的監(jiān)聽線程。原始代碼邏輯為,發(fā)現置信度低于閾值的臉即陌生人臉,隨機人臉識別線程通過通信隊列告知報警系統(tǒng)執(zhí)行截圖拍攝、消息推送、報警響鈴等功能。改變?yōu)楹灥较到y(tǒng)后,人臉識別線程將置信度閾值以上【即數據庫中存在并認為可信的臉】,且匹配度最高的人臉作為簽到信號,通過隊列通信發(fā)送給簽到線程,并執(zhí)行之前沒有的數據庫錄入操作。

簡單來說就是,之前是把認不出來的臉進行記錄和報警,轉變?yōu)檎J出來且最像的人臉進行記錄和執(zhí)行聲音提示。

(4)簽到表格的創(chuàng)建
這個屬于簽到系統(tǒng)特有的新增功能,說道考勤簽到就一定會想到教師用來點名的簽到表,因此該簽到系統(tǒng)需要生成一個包含當前課程需要簽到的所有學生信息,通過預處理進行創(chuàng)建,并在人臉識別過程中實時修改記錄簽到信息,主要內容為學生姓名、學號、簽到時間。該功能內建了一個基于MySQL查詢的QTableWidget控件,用于方便用戶之間從數據庫中選擇并創(chuàng)建需要簽到的學生名單。

管理端修改部分

(1)學生信息管理
原始的管理端非常簡陋,存儲信息僅包含學生姓名、faceID、學號這樣的普通信息,想要查詢學生信息也只能進行單人查詢,并且只能通過學號,查詢的唯一目的就是通過學號刪除查詢結果。因此無論是查詢還是刪除都非常簡陋。甚至根本不存在修改信息的功能。

修改后的管理端新增了多條件模糊查詢,并且大大增加了信息維數,允許直接雙擊修改學生信息,并實時同步到數據庫中。同時刪除信息的功能也和信息查詢分離開來,信息查詢結果動態(tài)顯示在QTableWidget控件中【與原項目使用的技術相同,只是做了更大的功能擴展】。支持用戶多選刪除,不不必“查一個,刪一個”。

(2)人臉數據訓練
原項目中的人臉數據訓練功能同樣集成在管理端中,原作者自定義了一個讀取數據集并將其與學生通過faceID進行唯一匹配的函數,也就是LBPH數據訓練中的人臉數據(faces)與分類標簽(labels)。讀取并整理成LBPH.train()所需要的數據結構后即可直接將數據作為參數調用封裝好的函數進行訓練。

值得一提的是,LBPH的數據訓練非??欤词乖谌偃说?,每人人臉數據集平均20張的情況下,訓練時間依然能控制在十幾秒內【但是結果其實并不好】,因此原作者并沒有將其作為單獨的線程來執(zhí)行,而是直接甩給用戶一個提示:訓練期間系統(tǒng)窗口可能會無響應,請耐心等待。。。

這樣的結果是導致用戶體驗極差,會以為程序崩了,其實只是訓練計算時間過長,導致windows消息監(jiān)聽一段時間內無回應,被認為是程序無響應。。。

二次開發(fā)后我將其獨立為一個線程單獨執(zhí)行,并為執(zhí)行函數增加了進度條,讓用戶直觀的看到訓練過程。順便,在代碼實現過程中,發(fā)現大量時間實際上消耗在圖片數據集的讀取上,訓練的過程反倒沒有那么久,因此進度條實際展示的是讀取過程,邏輯上是先進行的數據讀取,再計算特征值,然后繼續(xù)讀取下一個數據集,因此將數據讀取作為進度來衡量不會有時間上的偏差。


三、代碼具體實現

這里就簡單貼一下數據錄入端的代碼。項目完整代碼還請移步本文開始位置的鏈接。

#!/usr/bin/env python3
# Author: kuronekonano <god772525182@gmail.com>
# 人臉信息錄入
import re
import string
import time

import cv2
import pymysql
import shutil

from PyQt5.QtCore import QTimer, QRegExp, pyqtSignal, QThread
from PyQt5.QtGui import QImage, QPixmap, QIcon, QRegExpValidator, QTextCursor
from PyQt5.QtWidgets import QDialog, QApplication, QWidget, QMessageBox, QFileDialog, QProgressBar
from PyQt5.uic import loadUi

import logging
import logging.config
import queue
import threading
import os
import sys
import xlrd
import random

from datetime import datetime


# 用戶取消了更新數據庫操作
class OperationCancel(Exception):
    pass


# 采集過程中出現干擾
class RecordDisturbance(Exception):
    pass


class DataRecordUI(QWidget):
    receiveLogSignal = pyqtSignal(str)
    messagebox_signal = pyqtSignal(dict)

    # 日志隊列
    logQueue = queue.Queue()

    def __init__(self):
        super(DataRecordUI, self).__init__()
        loadUi('./ui/DataRecord.ui', self)  # 讀取UI布局
        self.setWindowIcon(QIcon('./icons/icon.png'))
        self.setFixedSize(1528, 856)

        # OpenCV
        # 攝像頭
        self.cap = cv2.VideoCapture()
        # 分類器
        self.faceCascade = cv2.CascadeClassifier('./haarcascades/haarcascade_frontalface_default.xml')

        # 圖像捕獲
        self.isExternalCameraUsed = False
        self.useExternalCameraCheckBox.stateChanged.connect(
            lambda: self.useExternalCamera(self.useExternalCameraCheckBox))

        self.startWebcamButton.toggled.connect(self.startWebcam)
        self.startWebcamButton.setCheckable(True)

        # 定時器
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.updateFrame)

        # 人臉檢測
        self.isFaceDetectEnabled = False
        self.enableFaceDetectButton.toggled.connect(self.enableFaceDetect)
        self.enableFaceDetectButton.setCheckable(True)

        # 數據庫
        # self.database = 'users'
        self.datasets = './datasets'
        self.isDbReady = False
        self.initDbButton.setIcon(QIcon('./icons/warning.png'))
        self.initDbButton.clicked.connect(self.initDb)

        # 用戶信息
        self.isUserInfoReady = False
        self.userInfo = {'stu_id': '',
                         'cn_name': '',
                         'en_name': '',
                         'stu_grade': '',
                         'stu_class': '',
                         'stu_sex': '',
                         'major': ''}
        self.addOrUpdateUserInfoButton.clicked.connect(self.addOrUpdateUserInfo)
        self.migrateToDbButton.clicked.connect(self.migrateToDb)  # 插入新數據按鍵綁定

        # 人臉采集
        self.startFaceRecordButton.clicked.connect(
            lambda: self.startFaceRecord(self.startFaceRecordButton))  # 開始人臉采集按鈕綁定,并傳入按鈕本身用于結束狀態(tài)控制
        # self.startFaceRecordButton.setCheckable(True)
        self.faceRecordCount = 0  # 已采集照片計數器
        self.minFaceRecordCount = 100  # 最少采集照片數量
        self.isFaceDataReady = False
        self.isFaceRecordEnabled = False
        self.enableFaceRecordButton.clicked.connect(self.enableFaceRecord)  # 按鍵綁定錄入單幀圖像

        # 日志系統(tǒng)
        self.receiveLogSignal.connect(lambda log: self.logOutput(log))  # pyqtsignal信號綁定
        self.messagebox_signal.connect(lambda log: self.message_output(log))
        self.logOutputThread = threading.Thread(target=self.receiveLog, daemon=True)
        self.logOutputThread.start()

        # 批量導入
        self.isImage_path_ready = False
        # self.ImagepathButton.clicked.connect(self.import_images_data)  # 使用同一線程會導致窗口無響應
        self.ImagepathButton.clicked.connect(self.import_image_thread)  # 使用多線程實現圖片導入
        self.isExcel_path_ready = False
        self.ExcelpathButton.clicked.connect(self.import_excel_data)
        self.ImportPersonButton.clicked.connect(self.person_import_thread)

    @staticmethod
    def connect_to_sql():
        conn = pymysql.connect(host='localhost',
                               user='root',
                               password='******',
                               db='mytest',
                               port=3306,
                               charset='utf8')
        cursor = conn.cursor()
        return conn, cursor

    # 單人導入圖片集【主線程】棄用
    def import_person_imageset(self):
        if self.isUserInfoReady:  # 學生信息確認
            stu_id = self.userInfo.get('stu_id')
            self.ImportPersonButton.setIcon(QIcon('./icons/success.png'))
            image_paths = QFileDialog.getOpenFileNames(self, '選擇圖片',
                                                       "./",
                                                       'JEPG files(*.jpg);;PNG files(*.PNG)')
            if not os.path.exists('{}/stu_{}'.format(self.datasets, stu_id)):
                os.makedirs('{}/stu_{}'.format(self.datasets, stu_id))
            image_paths = image_paths[0]
            for index, path in enumerate(image_paths):
                try:
                    img = cv2.imread(path)
                    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 灰度圖
                    faces = self.faceCascade.detectMultiScale(gray, 1.3, 5, minSize=(90, 90))  # 分類器偵測人臉
                    if len(faces) == 0:
                        self.logQueue.put('圖片{}中沒有檢測到人臉!'.format(path))
                        continue
                    for (x, y, w, h) in faces:
                        if len(faces) > 1:
                            raise RecordDisturbance
                        cv2.imwrite('{}/stu_{}/img.{}-{}.jpg'.format(self.datasets, stu_id, index, ''.join(
                            random.sample(string.ascii_letters + string.digits, 4))),
                                    img[y - 20:y + h + 20, x - 20:x + w + 20])  # 灰度圖的人臉區(qū)域
                except RecordDisturbance:
                    logging.error('檢測到多張人臉或環(huán)境干擾')
                    self.logQueue.put('Warning:檢測到圖片{}存在多張人臉或環(huán)境干擾,已忽略。'.format(path))
                    continue
                except Exception as e:
                    logging.error('寫入人臉圖像文件到計算機過程中發(fā)生異常')
                    self.logQueue.put('Error:無法保存人臉圖像,導入該圖片失敗')
                    print(e)
            self.migrateToDbButton.setEnabled(True)  # 允許提交至數據庫
            self.isFaceDataReady = True
        else:
            self.ImportPersonButton.setIcon(QIcon('./icons/error.png'))
            self.ImportPersonButton.setChecked(False)
            self.logQueue.put('Error:操作失敗,系統(tǒng)未檢測到有效的用戶信息')

    # 表格導入學生信息
    def import_excel_data(self):

        excel_paths = QFileDialog.getOpenFileNames(self, '選擇表格',
                                                   "./",
                                                   'EXCEL 文件 (*.xlsx;*.xls;*.xlm;*.xlt;*.xlsm;*.xla)')
        excel_paths = excel_paths[0]
        conn, cursor = self.connect_to_sql()
        error_count = 0
        for path in excel_paths:
            sheets_file = xlrd.open_workbook(path)
            for index, sheet in enumerate(sheets_file.sheets()):
                self.logQueue.put("正在讀取文件:" + str(path) + "的第" + str(index) + "個sheet表的內容...")
                for row in range(sheet.nrows):
                    row_data = sheet.row_values(row)
                    if row_data[1] == '姓名':
                        continue
                    self.userInfo['stu_id'] = row_data[4]
                    self.userInfo['cn_name'] = row_data[1]
                    self.userInfo['en_name'] = row_data[0]
                    self.userInfo['stu_grade'] = '20' + self.userInfo['stu_id'][:2]
                    self.userInfo['stu_class'] = row_data[3].rsplit('-', 1)[1]
                    self.userInfo['stu_sex'] = row_data[5]
                    self.userInfo['major'] = row_data[2]
                    self.userInfo['province'] = row_data[-1]
                    self.userInfo['nation'] = row_data[-2]
                    # print(self.userInfo)
                    try:
                        stu_id = row_data[4]
                        if not os.path.exists('{}/stu_{}'.format(self.datasets, stu_id)):
                            os.makedirs('{}/stu_{}'.format(self.datasets, stu_id))
                        db_user_count = self.commit_to_database(cursor)
                        self.dbUserCountLcdNum.display(db_user_count)  # 數據庫人數計數器
                    except OperationCancel:
                        pass
                    except Exception as e:
                        print(e)
                        logging.error('讀寫數據庫異常,無法向數據庫插入/更新記錄')
                        self.logQueue.put('Error:讀寫數據庫異常,同步失敗')
                        error_count += 1
                self.logQueue.put('導入完畢!其中導入失敗 {} 條信息'.format(error_count))

        cursor.close()
        conn.commit()
        conn.close()

    # 啟用新線程導入圖片,并添加進度條
    def import_image_thread(self):
        self.image_paths = QFileDialog.getOpenFileNames(self, '選擇圖片',
                                                        "./",
                                                        'JEPG files(*.jpg);;PNG files(*.PNG)')
        self.image_paths = self.image_paths[0]
        if len(self.image_paths) != 0:  # 點擊導入但是沒有選擇文件時不需啟動線程
            progress_bar = ActionsImportImage(self)
        print('import success!')

    # 啟用新線程 單人圖片導入 使用進度條
    def person_import_thread(self):
        if self.isUserInfoReady:  # 學生信息確認
            stu_id = self.userInfo.get('stu_id')
            self.ImportPersonButton.setIcon(QIcon('./icons/success.png'))

            image_paths = QFileDialog.getOpenFileNames(self, '選擇圖片',
                                                       "./",
                                                       'JEPG files(*.jpg);;PNG files(*.PNG)')
            self.image_paths = image_paths[0]
            if len(self.image_paths) != 0:  # 點擊導入但是沒有選擇文件時不需啟動線程
                if not os.path.exists('{}/stu_{}'.format(self.datasets, stu_id)):
                    os.makedirs('{}/stu_{}'.format(self.datasets, stu_id))
                progress_bar = ActionsPersonImport(self)
                self.migrateToDbButton.setEnabled(True)  # 允許提交至數據庫
                self.isFaceDataReady = True

        else:
            self.ImportPersonButton.setIcon(QIcon('./icons/error.png'))
            self.ImportPersonButton.setChecked(False)
            self.logQueue.put('Error:操作失敗,系統(tǒng)未檢測到有效的用戶信息')

    # 圖片批量導入【主線程】棄用
    def import_images_data(self):
        image_paths = QFileDialog.getOpenFileNames(self, '選擇圖片',
                                                   "./",
                                                   'JEPG files(*.jpg);;PNG files(*.PNG)')
        image_paths = image_paths[0]
        error_count = 0
        self.logQueue.put('開始讀取圖片數據...')
        for index, path in enumerate(image_paths):
            stu_id = os.path.split(path)[1].split('.')[0]
            # print(stu_id)
            if not os.path.exists('{}/stu_{}'.format(self.datasets, stu_id)):
                text = '命名錯誤!'
                informativeText = '<b>文件 <font color=red>{}</font> 存在問題,數據庫中沒有以該圖片名為學號的用戶。</b>'.format(path)
                DataRecordUI.callDialog(QMessageBox.Critical, text, informativeText, QMessageBox.Ok)
                error_count += 1
                continue
            dstpath = '{}/stu_{}/img.{}.jpg'.format(self.datasets, stu_id, stu_id + '-0')
            try:
                shutil.copy(path, dstpath)
            except:
                text = '命名格式錯誤!'
                informativeText = '<b>文件 <font color=red>{}</font> 命名格式不正確。</b>'.format(path)
                DataRecordUI.callDialog(QMessageBox.Critical, text, informativeText, QMessageBox.Ok)
                error_count += 1
        self.logQueue.put('圖片批量導入完成!其中導入失敗 {} 張圖片'.format(error_count))

    # 是否使用外接攝像頭
    def useExternalCamera(self, useExternalCameraCheckBox):
        if useExternalCameraCheckBox.isChecked():
            self.isExternalCameraUsed = True
        else:
            self.isExternalCameraUsed = False

    # 打開/關閉攝像頭
    def startWebcam(self, status):
        if status:
            if not self.cap.isOpened():
                camID = 1 if self.isExternalCameraUsed else 0 + cv2.CAP_DSHOW
                self.cap.open(camID)
                self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
                self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
                ret, frame = self.cap.read()  # 獲取攝像頭調用結果

                if not ret:
                    logging.error('無法調用電腦攝像頭{}'.format(camID))
                    self.logQueue.put('Error:初始化攝像頭失敗')
                    self.cap.release()
                    self.startWebcamButton.setIcon(QIcon('./icons/error.png'))
                    self.startWebcamButton.setChecked(False)
                else:
                    self.timer.start(5)
                    self.enableFaceDetectButton.setEnabled(True)
                    self.startWebcamButton.setIcon(QIcon('./icons/success.png'))
                    self.startWebcamButton.setText('關閉攝像頭')
        else:
            if self.cap.isOpened():
                if self.timer.isActive():
                    self.timer.stop()
                self.cap.release()
                self.faceDetectCaptureLabel.clear()
                self.faceDetectCaptureLabel.setText('<font color=red>攝像頭未開啟</font>')
                self.startWebcamButton.setText('打開攝像頭')
                self.enableFaceDetectButton.setEnabled(False)
                self.startWebcamButton.setIcon(QIcon())

    # 開啟/關閉人臉檢測
    def enableFaceDetect(self, status):
        if self.cap.isOpened():
            if status:
                self.enableFaceDetectButton.setText('關閉人臉檢測')
                self.isFaceDetectEnabled = True
            else:
                self.enableFaceDetectButton.setText('開啟人臉檢測')
                self.isFaceDetectEnabled = False

    # 采集當前捕獲幀
    def enableFaceRecord(self):
        if not self.isFaceRecordEnabled:
            self.isFaceRecordEnabled = True

    # 開始/結束采集人臉數據
    def startFaceRecord(self, startFaceRecordButton):
        if startFaceRecordButton.text() == '開始采集人臉數據':  # 只能用==判斷,不能用is
            if self.isFaceDetectEnabled:
                if self.isUserInfoReady:  # 學生信息確認
                    self.addOrUpdateUserInfoButton.setEnabled(False)  # 采集人臉數據時禁用修改學生信息
                    if not self.enableFaceRecordButton.isEnabled():  # 啟用單幀采集按鈕
                        self.enableFaceRecordButton.setEnabled(True)
                    self.enableFaceRecordButton.setIcon(QIcon())
                    self.startFaceRecordButton.setIcon(QIcon('./icons/success.png'))
                    self.startFaceRecordButton.setText('結束當前人臉采集')  # 開始采集按鈕狀態(tài)修改為結束采集
                else:
                    self.startFaceRecordButton.setIcon(QIcon('./icons/error.png'))
                    self.startFaceRecordButton.setChecked(False)
                    self.logQueue.put('Error:操作失敗,系統(tǒng)未檢測到有效的用戶信息')
            else:
                self.startFaceRecordButton.setIcon(QIcon('./icons/error.png'))
                self.logQueue.put('Error:操作失敗,請開啟人臉檢測')
        else:  # 根據按鈕文本信息判斷是結束采集還是開始采集
            if self.faceRecordCount < self.minFaceRecordCount:
                text = '系統(tǒng)當前采集了 <font color=blue>{}</font> 幀圖像,采集數據過少會導致較大的識別誤差。'.format(self.faceRecordCount)
                informativeText = '<b>請至少采集 <font color=red>{}</font> 幀圖像。</b>'.format(self.minFaceRecordCount)
                DataRecordUI.callDialog(QMessageBox.Information, text, informativeText, QMessageBox.Ok)

            else:
                text = '系統(tǒng)當前采集了 <font color=blue>{}</font> 幀圖像,繼續(xù)采集可以提高識別準確率。'.format(self.faceRecordCount)
                informativeText = '<b>你確定結束當前人臉采集嗎?</b>'
                ret = DataRecordUI.callDialog(QMessageBox.Question, text, informativeText,
                                              QMessageBox.Yes | QMessageBox.No,
                                              QMessageBox.No)

                if ret == QMessageBox.Yes:
                    self.isFaceDataReady = True  # 結束采集,人臉數據準備完畢
                    if self.isFaceRecordEnabled:
                        self.isFaceRecordEnabled = False
                    self.enableFaceRecordButton.setEnabled(False)  # 結束采集,單幀采集按鈕禁用
                    self.enableFaceRecordButton.setIcon(QIcon())
                    self.startFaceRecordButton.setText('開始采集人臉數據')  # 修改按鈕文本為開始狀態(tài)
                    self.startFaceRecordButton.setEnabled(False)  # 不可重新開始采集
                    self.startFaceRecordButton.setIcon(QIcon())
                    self.migrateToDbButton.setEnabled(True)  # 允許提交至數據庫

    # 定時器,實時更新畫面
    def updateFrame(self):
        ret, frame = self.cap.read()
        # frame = cv2.flip(frame, 1)  # 水平翻轉圖片
        if ret:
            # self.displayImage(frame)  # ?兩次輸出?

            if self.isFaceDetectEnabled:  # 人臉檢測
                detected_frame = self.detectFace(frame)
                self.displayImage(detected_frame)
            else:
                self.displayImage(frame)

    # 檢測人臉
    def detectFace(self, frame):
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # 灰度圖
        faces = self.faceCascade.detectMultiScale(gray, 1.3, 5, minSize=(90, 90))  # 分類器偵測人臉
        # 1.image為輸入的灰度圖像
        # 2.objects為得到被檢測物體的矩形框向量組
        # 3.scaleFactor為每一個圖像尺度中的尺度參數,默認值為1.1。scale_factor參數可以決定兩個不同大小的窗口掃描之間有多大的跳躍,
        # 這個參數設置的大,則意味著計算會變快,但如果窗口錯過了某個大小的人臉,則可能丟失物體。
        # 4.minNeighbors參數為每一個級聯矩形應該保留的鄰近個數,默認為3。
        # minNeighbors控制著誤檢測,默認值為3表明至少有3次重疊檢測,我們才認為人臉確實存。
        # 6.cvSize()指示尋找人臉的最小區(qū)域。設置這個參數過大,會以丟失小物體為代價減少計算量。

        stu_id = self.userInfo.get('stu_id')

        #  遍歷所有人臉,只允許有一個人的臉
        for (x, y, w, h) in faces:
            if self.isFaceRecordEnabled:
                try:  # 創(chuàng)建學號對應的圖片數據集
                    if not os.path.exists('{}/stu_{}'.format(self.datasets, stu_id)):
                        os.makedirs('{}/stu_{}'.format(self.datasets, stu_id))
                    if len(faces) > 1:
                        raise RecordDisturbance

                    cv2.imwrite('{}/stu_{}/img.{}.jpg'.format(self.datasets, stu_id, self.faceRecordCount + 1),
                                frame[y - 20:y + h + 20, x - 20:x + w + 20])  # 灰度圖的人臉區(qū)域
                except RecordDisturbance:
                    self.isFaceRecordEnabled = False
                    logging.error('檢測到多張人臉或環(huán)境干擾')
                    self.logQueue.put('Warning:檢測到多張人臉或環(huán)境干擾,請解決問題后繼續(xù)')
                    self.enableFaceRecordButton.setIcon(QIcon('./icons/warning.png'))
                    continue
                except Exception as e:
                    logging.error('寫入人臉圖像文件到計算機過程中發(fā)生異常')
                    self.enableFaceRecordButton.setIcon(QIcon('./icons/error.png'))
                    self.logQueue.put('Error:無法保存人臉圖像,采集當前捕獲幀失敗')
                else:
                    self.enableFaceRecordButton.setIcon(QIcon('./icons/success.png'))
                    self.faceRecordCount = self.faceRecordCount + 1
                    self.isFaceRecordEnabled = False  # 單幀拍攝完成后馬上關閉
                    self.faceRecordCountLcdNum.display(self.faceRecordCount)  # 更新采集數量
            cv2.rectangle(frame, (x - 5, y - 10), (x + w + 5, y + h + 10), (0, 0, 255), 2)  # 紅色追蹤框

        return frame

源碼下載地址

源碼下載地址https://download.csdn.net/download/u013749113/87897481文章來源地址http://www.zghlxwxcb.cn/news/detail-445808.html

到了這里,關于Python 畢業(yè)設計 - 基于 opencv 的人臉識別上課考勤系統(tǒng),附源碼的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包