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

基于 opencv 的人臉識(shí)別上課考勤系統(tǒng),附源碼,可作為畢業(yè)設(shè)計(jì)

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

基于 opencv 的人臉識(shí)別上課考勤系統(tǒng),附源碼,可作為畢業(yè)設(shè)計(jì)

一、簡(jiǎn)介

這個(gè)人臉識(shí)別考勤簽到系統(tǒng)是基于大佬的人臉識(shí)別陌生人報(bào)警系統(tǒng)二次開(kāi)發(fā)的。

項(xiàng)目使用Python實(shí)現(xiàn),基于OpenCV框架進(jìn)行人臉識(shí)別和攝像頭硬件調(diào)用,同時(shí)也用OpenCV工具包處理圖片。交互界面使用pyqt5實(shí)現(xiàn)。

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

根據(jù)功能分配,系統(tǒng)分為三個(gè)部分實(shí)現(xiàn)各部分流程,

  1. 錄入端負(fù)責(zé)數(shù)據(jù)導(dǎo)入,
  2. 管理端負(fù)責(zé)數(shù)據(jù)刪改查以及人臉數(shù)據(jù)訓(xùn)練,
  3. 監(jiān)控端負(fù)責(zé)人臉識(shí)別以及簽到功能。

二、效果圖

源碼下載地址

源碼下載地址https://download.csdn.net/download/u013749113/87897481

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

基于 opencv 的人臉識(shí)別上課考勤系統(tǒng),附源碼,可作為畢業(yè)設(shè)計(jì)

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

基于 opencv 的人臉識(shí)別上課考勤系統(tǒng),附源碼,可作為畢業(yè)設(shè)計(jì)

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

基于 opencv 的人臉識(shí)別上課考勤系統(tǒng),附源碼,可作為畢業(yè)設(shè)計(jì)

三、開(kāi)發(fā)過(guò)程

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

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

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

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

二次開(kāi)發(fā)后,保留原本速度較快的LBPH人臉識(shí)別,新增效果更好的dlib_face_recognition_resnet_model深度學(xué)習(xí)殘差網(wǎng)絡(luò)識(shí)別模型。實(shí)際使用時(shí)發(fā)現(xiàn),雖然實(shí)時(shí)視頻流幀率明顯降低,但是識(shí)別準(zhǔn)確率大大提高。

(2)攝像頭啟動(dòng)與關(guān)閉

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

其原因是具體實(shí)現(xiàn)上,因?yàn)楸O(jiān)控端需要啟動(dòng)單獨(dú)線程執(zhí)行人臉識(shí)別任務(wù),而錄入端沒(méi)有人臉識(shí)別的復(fù)雜處理過(guò)程,在一個(gè)線程中就可以實(shí)現(xiàn)需要的功能。監(jiān)控端開(kāi)啟攝像頭后,同時(shí)啟動(dòng)人臉識(shí)別線程處理單幀圖像,并啟動(dòng)報(bào)警監(jiān)聽(tīng)線程,設(shè)計(jì)思路上是報(bào)警線程一旦開(kāi)啟,全程保持監(jiān)聽(tīng),直到程序關(guān)閉,而關(guān)閉攝像頭時(shí)代碼實(shí)現(xiàn)上只關(guān)閉,也只能夠關(guān)閉人臉識(shí)別線程,對(duì)于報(bào)警監(jiān)聽(tīng)線程無(wú)法控制。導(dǎo)致如果容許攝像頭二次開(kāi)啟,人臉識(shí)別線程能夠啟動(dòng),但作為同一個(gè)線程實(shí)例的報(bào)警監(jiān)聽(tīng)模塊將被二次啟動(dòng),導(dǎo)致程序出錯(cuò)。

這里的人臉識(shí)別線程繼承自QTread類,允許使用.stop()函數(shù)控制線程實(shí)例的開(kāi)始與終止,而報(bào)警監(jiān)聽(tīng)模塊則是普通的threading.Thread(),開(kāi)啟后無(wú)法控制關(guān)閉,導(dǎo)致出現(xiàn)上述問(wèn)題。改進(jìn)方法是將報(bào)警監(jiān)聽(tīng)線程使用QTread實(shí)現(xiàn),使用與人臉識(shí)別線程相同的控制方法,攝像頭開(kāi)啟時(shí)啟動(dòng),攝像頭關(guān)閉時(shí)終止,實(shí)現(xiàn)二次啟動(dòng)功能。

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

簡(jiǎn)單來(lái)說(shuō)就是,之前是把認(rèn)不出來(lái)的臉進(jìn)行記錄和報(bào)警,轉(zhuǎn)變?yōu)檎J(rèn)出來(lái)且最像的人臉進(jìn)行記錄和執(zhí)行聲音提示。

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

管理端修改部分

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

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

(2)人臉數(shù)據(jù)訓(xùn)練
原項(xiàng)目中的人臉數(shù)據(jù)訓(xùn)練功能同樣集成在管理端中,原作者自定義了一個(gè)讀取數(shù)據(jù)集并將其與學(xué)生通過(guò)faceID進(jìn)行唯一匹配的函數(shù),也就是LBPH數(shù)據(jù)訓(xùn)練中的人臉數(shù)據(jù)(faces)與分類標(biāo)簽(labels)。讀取并整理成LBPH.train()所需要的數(shù)據(jù)結(jié)構(gòu)后即可直接將數(shù)據(jù)作為參數(shù)調(diào)用封裝好的函數(shù)進(jìn)行訓(xùn)練。

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

這樣的結(jié)果是導(dǎo)致用戶體驗(yàn)極差,會(huì)以為程序崩了,其實(shí)只是訓(xùn)練計(jì)算時(shí)間過(guò)長(zhǎng),導(dǎo)致windows消息監(jiān)聽(tīng)一段時(shí)間內(nèi)無(wú)回應(yīng),被認(rèn)為是程序無(wú)響應(yīng)。。。

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


三、代碼具體實(shí)現(xiàn)

這里就簡(jiǎn)單貼一下數(shù)據(jù)錄入端的代碼。項(xiàng)目完整代碼還請(qǐng)移步本文開(kāi)始位置的鏈接。

#!/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


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


# 采集過(guò)程中出現(xiàn)干擾
class RecordDisturbance(Exception):
    pass


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

    # 日志隊(duì)列
    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)

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

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

        # 數(shù)據(jù)庫(kù)
        # 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)  # 插入新數(shù)據(jù)按鍵綁定

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

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

        # 批量導(dǎo)入
        self.isImage_path_ready = False
        # self.ImagepathButton.clicked.connect(self.import_images_data)  # 使用同一線程會(huì)導(dǎo)致窗口無(wú)響應(yīng)
        self.ImagepathButton.clicked.connect(self.import_image_thread)  # 使用多線程實(shí)現(xiàn)圖片導(dǎo)入
        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

    # 單人導(dǎo)入圖片集【主線程】棄用
    def import_person_imageset(self):
        if self.isUserInfoReady:  # 學(xué)生信息確認(rèn)
            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))  # 分類器偵測(cè)人臉
                    if len(faces) == 0:
                        self.logQueue.put('圖片{}中沒(méi)有檢測(cè)到人臉!'.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('檢測(cè)到多張人臉或環(huán)境干擾')
                    self.logQueue.put('Warning:檢測(cè)到圖片{}存在多張人臉或環(huán)境干擾,已忽略。'.format(path))
                    continue
                except Exception as e:
                    logging.error('寫入人臉圖像文件到計(jì)算機(jī)過(guò)程中發(fā)生異常')
                    self.logQueue.put('Error:無(wú)法保存人臉圖像,導(dǎo)入該圖片失敗')
                    print(e)
            self.migrateToDbButton.setEnabled(True)  # 允許提交至數(shù)據(jù)庫(kù)
            self.isFaceDataReady = True
        else:
            self.ImportPersonButton.setIcon(QIcon('./icons/error.png'))
            self.ImportPersonButton.setChecked(False)
            self.logQueue.put('Error:操作失敗,系統(tǒng)未檢測(cè)到有效的用戶信息')

    # 表格導(dǎo)入學(xué)生信息
    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) + "個(gè)sheet表的內(nèi)容...")
                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)  # 數(shù)據(jù)庫(kù)人數(shù)計(jì)數(shù)器
                    except OperationCancel:
                        pass
                    except Exception as e:
                        print(e)
                        logging.error('讀寫數(shù)據(jù)庫(kù)異常,無(wú)法向數(shù)據(jù)庫(kù)插入/更新記錄')
                        self.logQueue.put('Error:讀寫數(shù)據(jù)庫(kù)異常,同步失敗')
                        error_count += 1
                self.logQueue.put('導(dǎo)入完畢!其中導(dǎo)入失敗 {} 條信息'.format(error_count))

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

    # 啟用新線程導(dǎo)入圖片,并添加進(jìn)度條
    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:  # 點(diǎn)擊導(dǎo)入但是沒(méi)有選擇文件時(shí)不需啟動(dòng)線程
            progress_bar = ActionsImportImage(self)
        print('import success!')

    # 啟用新線程 單人圖片導(dǎo)入 使用進(jìn)度條
    def person_import_thread(self):
        if self.isUserInfoReady:  # 學(xué)生信息確認(rèn)
            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:  # 點(diǎn)擊導(dǎo)入但是沒(méi)有選擇文件時(shí)不需啟動(dòng)線程
                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)  # 允許提交至數(shù)據(jù)庫(kù)
                self.isFaceDataReady = True

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

    # 圖片批量導(dǎo)入【主線程】棄用
    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('開(kāi)始讀取圖片數(shù)據(jù)...')
        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 = '命名錯(cuò)誤!'
                informativeText = '<b>文件 <font color=red>{}</font> 存在問(wèn)題,數(shù)據(jù)庫(kù)中沒(méi)有以該圖片名為學(xué)號(hào)的用戶。</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 = '命名格式錯(cuò)誤!'
                informativeText = '<b>文件 <font color=red>{}</font> 命名格式不正確。</b>'.format(path)
                DataRecordUI.callDialog(QMessageBox.Critical, text, informativeText, QMessageBox.Ok)
                error_count += 1
        self.logQueue.put('圖片批量導(dǎo)入完成!其中導(dǎo)入失敗 {} 張圖片'.format(error_count))

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

    # 打開(kāi)/關(guān)閉攝像頭
    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()  # 獲取攝像頭調(diào)用結(jié)果

                if not ret:
                    logging.error('無(wú)法調(diào)用電腦攝像頭{}'.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('關(guān)閉攝像頭')
        else:
            if self.cap.isOpened():
                if self.timer.isActive():
                    self.timer.stop()
                self.cap.release()
                self.faceDetectCaptureLabel.clear()
                self.faceDetectCaptureLabel.setText('<font color=red>攝像頭未開(kāi)啟</font>')
                self.startWebcamButton.setText('打開(kāi)攝像頭')
                self.enableFaceDetectButton.setEnabled(False)
                self.startWebcamButton.setIcon(QIcon())

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

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

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

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

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

    # 定時(shí)器,實(shí)時(shí)更新畫面
    def updateFrame(self):
        ret, frame = self.cap.read()
        # frame = cv2.flip(frame, 1)  # 水平翻轉(zhuǎn)圖片
        if ret:
            # self.displayImage(frame)  # ??jī)纱屋敵觯?/span>

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

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

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

        #  遍歷所有人臉,只允許有一個(gè)人的臉
        for (x, y, w, h) in faces:
            if self.isFaceRecordEnabled:
                try:  # 創(chuàng)建學(xué)號(hào)對(duì)應(yīng)的圖片數(shù)據(jù)集
                    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('檢測(cè)到多張人臉或環(huán)境干擾')
                    self.logQueue.put('Warning:檢測(cè)到多張人臉或環(huán)境干擾,請(qǐng)解決問(wèn)題后繼續(xù)')
                    self.enableFaceRecordButton.setIcon(QIcon('./icons/warning.png'))
                    continue
                except Exception as e:
                    logging.error('寫入人臉圖像文件到計(jì)算機(jī)過(guò)程中發(fā)生異常')
                    self.enableFaceRecordButton.setIcon(QIcon('./icons/error.png'))
                    self.logQueue.put('Error:無(wú)法保存人臉圖像,采集當(dāng)前捕獲幀失敗')
                else:
                    self.enableFaceRecordButton.setIcon(QIcon('./icons/success.png'))
                    self.faceRecordCount = self.faceRecordCount + 1
                    self.isFaceRecordEnabled = False  # 單幀拍攝完成后馬上關(guān)閉
                    self.faceRecordCountLcdNum.display(self.faceRecordCount)  # 更新采集數(shù)量
            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文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-480806.html

到了這里,關(guān)于基于 opencv 的人臉識(shí)別上課考勤系統(tǒng),附源碼,可作為畢業(yè)設(shè)計(jì)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 計(jì)算機(jī)畢業(yè)設(shè)計(jì):基于python人臉識(shí)別考勤系統(tǒng) OpenCV+Dlib(包含文檔+源碼+部署教程)

    計(jì)算機(jī)畢業(yè)設(shè)計(jì):基于python人臉識(shí)別考勤系統(tǒng) OpenCV+Dlib(包含文檔+源碼+部署教程)

    [畢業(yè)設(shè)計(jì)]2023-2024年最新最全計(jì)算機(jī)專業(yè)畢設(shè)選題推薦匯總 感興趣的可以先收藏起來(lái),還有大家在畢設(shè)選題,項(xiàng)目以及論文編寫等相關(guān)問(wèn)題都可以給我留言咨詢,希望幫助更多的人?。 Python語(yǔ)言、dlib、OpenCV、Pyqt5界面設(shè)計(jì)、sqlite3數(shù)據(jù)庫(kù) 方法實(shí)現(xiàn)、實(shí)現(xiàn)步驟 1、實(shí)例化人臉檢測(cè)

    2024年02月04日
    瀏覽(33)
  • 【優(yōu)秀畢設(shè)】基于OpenCV的人臉識(shí)別打卡/簽到/考勤管理系統(tǒng)(最簡(jiǎn)基本庫(kù)開(kāi)發(fā)、可基于樹(shù)莓派)

    【優(yōu)秀畢設(shè)】基于OpenCV的人臉識(shí)別打卡/簽到/考勤管理系統(tǒng)(最簡(jiǎn)基本庫(kù)開(kāi)發(fā)、可基于樹(shù)莓派)

    【優(yōu)秀畢設(shè)】基于OpenCV的人臉識(shí)別打卡/簽到/考勤管理系統(tǒng)(最簡(jiǎn)基本庫(kù)開(kāi)發(fā)、可基于樹(shù)莓派) 該系統(tǒng)利用Harr級(jí)聯(lián)檢測(cè)和LPBH進(jìn)行人臉檢測(cè)和訓(xùn)練、識(shí)別 利用Tkinter完成界面搭建 利用Flask+HTML完成網(wǎng)絡(luò)實(shí)時(shí)圖像推流及控制 利用captcha.image 完成驗(yàn)證碼功能 利用xlsxwriter將數(shù)據(jù)保存

    2024年02月06日
    瀏覽(26)
  • python人臉識(shí)別考勤系統(tǒng) 考勤簽到系統(tǒng) OpenCV 大數(shù)據(jù) 畢業(yè)設(shè)計(jì)(源碼)?

    python人臉識(shí)別考勤系統(tǒng) 考勤簽到系統(tǒng) OpenCV 大數(shù)據(jù) 畢業(yè)設(shè)計(jì)(源碼)?

    畢業(yè)設(shè)計(jì):2023-2024年計(jì)算機(jī)專業(yè)畢業(yè)設(shè)計(jì)選題匯總(建議收藏) 畢業(yè)設(shè)計(jì):2023-2024年最新最全計(jì)算機(jī)專業(yè)畢設(shè)選題推薦匯總 ?? 感興趣的可以先收藏起來(lái),點(diǎn)贊、關(guān)注不迷路,大家在畢設(shè)選題,項(xiàng)目以及論文編寫等相關(guān)問(wèn)題都可以給我留言咨詢,希望幫助同學(xué)們順利畢業(yè)?。

    2024年02月19日
    瀏覽(96)
  • OpenCV+ Qt Designer 開(kāi)發(fā)人臉識(shí)別考勤系統(tǒng)

    OpenCV+ Qt Designer 開(kāi)發(fā)人臉識(shí)別考勤系統(tǒng)

    本系統(tǒng)是一個(gè)基于OpenCV和 Qt Designer 的人臉識(shí)別考勤系統(tǒng),主要功能是自動(dòng)識(shí)別攝像頭中的人臉,并把人臉對(duì)應(yīng)的姓名和打卡時(shí)間存儲(chǔ)到數(shù)據(jù)庫(kù)中,方便管理人員進(jìn)行考勤管理。本系統(tǒng)使用 face_recognition 庫(kù)進(jìn)行人臉識(shí)別,使用 PyQt5 開(kāi)發(fā)界面,然后把界面與代碼進(jìn)行整合。 系統(tǒng)

    2024年02月06日
    瀏覽(21)
  • Linux畢業(yè)設(shè)計(jì):基于OpenCV和QT庫(kù)實(shí)現(xiàn)的人臉識(shí)別考勤/門禁系統(tǒng)(arm嵌入式ubuntu)

    Linux畢業(yè)設(shè)計(jì):基于OpenCV和QT庫(kù)實(shí)現(xiàn)的人臉識(shí)別考勤/門禁系統(tǒng)(arm嵌入式ubuntu)

    ????????本文介紹:Linux上以opencv和qt庫(kù)實(shí)現(xiàn)的人臉識(shí)別系統(tǒng),可應(yīng)用于考勤、門禁等場(chǎng)景,具有人臉?shù)浫搿h除、人臉檢測(cè)、識(shí)別、用戶管理等完整功能??蛇\(yùn)行于ARM嵌入式linux、ubuntu即純軟件、ARM+PC組合等多種方式,應(yīng)用場(chǎng)景多樣且易于移植各個(gè)平臺(tái)。 畢業(yè)設(shè)計(jì)題目匯

    2024年02月04日
    瀏覽(28)
  • 基于Python的人臉識(shí)別課堂考勤系統(tǒng)(畢設(shè))

    基于Python的人臉識(shí)別課堂考勤系統(tǒng)(畢設(shè))

    一個(gè)菜鳥(niǎo)搞畢業(yè)設(shè)計(jì)的過(guò)程分享,可能對(duì)迷茫的你起到一點(diǎn)點(diǎn)作用! 在著手開(kāi)發(fā)項(xiàng)目之前我們一定要對(duì)系統(tǒng)進(jìn)行一個(gè)初步的規(guī)劃,比如系統(tǒng)可以實(shí)現(xiàn)什么功能,是否需要開(kāi)發(fā)GUI頁(yè)面(大部分導(dǎo)師都會(huì)讓你搞一個(gè),僅僅少的導(dǎo)師不用你搞),如果需要可以對(duì)GUI頁(yè)面就行一個(gè)簡(jiǎn)單

    2023年04月08日
    瀏覽(19)
  • python人臉識(shí)別考勤系統(tǒng) dlib+OpenCV和Pyqt5、數(shù)據(jù)庫(kù)sqlite 人臉識(shí)別系統(tǒng) 計(jì)算機(jī) 畢業(yè)設(shè)計(jì) 源碼

    python人臉識(shí)別考勤系統(tǒng) dlib+OpenCV和Pyqt5、數(shù)據(jù)庫(kù)sqlite 人臉識(shí)別系統(tǒng) 計(jì)算機(jī) 畢業(yè)設(shè)計(jì) 源碼

    Python語(yǔ)言、dlib、OpenCV、Pyqt5界面設(shè)計(jì)、sqlite3數(shù)據(jù)庫(kù) 本系統(tǒng)使用dlib作為人臉識(shí)別工具,dlib提供一個(gè)方法可將人臉圖片數(shù)據(jù)映射到128維度的空間向量,如果兩張圖片來(lái)源于同一個(gè)人,那么兩個(gè)圖片所映射的空間向量距離就很近,否則就會(huì)很遠(yuǎn)。因此,可以通過(guò)提取圖片并映射到

    2024年02月08日
    瀏覽(23)
  • 基于Springboot+百度AI人工智能人臉識(shí)別考勤系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)

    基于Springboot+百度AI人工智能人臉識(shí)別考勤系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)

    基于Springboot+百度AI人工智能人臉識(shí)別考勤系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn) ?博主介紹: 《Vue.js入門與商城開(kāi)發(fā)實(shí)戰(zhàn)》《微信小程序商城開(kāi)發(fā)》圖書作者,CSDN博客專家,在線教育專家,CSDN鉆石講師;專注大學(xué)生畢業(yè)設(shè)計(jì)教育和輔導(dǎo)。 所有項(xiàng)目都配有從入門到精通的基礎(chǔ)知識(shí)視頻課程,免費(fèi)

    2024年02月05日
    瀏覽(99)
  • 基于java和百度智能AI的人臉識(shí)別考勤簽到系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)

    基于java和百度智能AI的人臉識(shí)別考勤簽到系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)

    ?博主介紹 :黃菊華老師《Vue.js入門與商城開(kāi)發(fā)實(shí)戰(zhàn)》《微信小程序商城開(kāi)發(fā)》圖書作者,CSDN博客專家,在線教育專家,CSDN鉆石講師;專注大學(xué)生畢業(yè)設(shè)計(jì)教育和輔導(dǎo)。 所有項(xiàng)目都配有從入門到精通的基礎(chǔ)知識(shí)視頻課程,免費(fèi) 項(xiàng)目配有對(duì)應(yīng)開(kāi)發(fā)文檔、開(kāi)題報(bào)告、任務(wù)書、

    2024年02月05日
    瀏覽(28)
  • JAVA基于百度AI接口的人臉識(shí)別考勤簽到系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)(Springboot框架)

    JAVA基于百度AI接口的人臉識(shí)別考勤簽到系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)(Springboot框架)

    ?博主介紹 :黃菊華老師《Vue.js入門與商城開(kāi)發(fā)實(shí)戰(zhàn)》《微信小程序商城開(kāi)發(fā)》圖書作者,CSDN博客專家,在線教育專家,CSDN鉆石講師;專注大學(xué)生畢業(yè)設(shè)計(jì)教育和輔導(dǎo)。 所有項(xiàng)目都配有從入門到精通的基礎(chǔ)知識(shí)視頻課程,免費(fèi) 項(xiàng)目配有對(duì)應(yīng)開(kāi)發(fā)文檔、開(kāi)題報(bào)告、任務(wù)書、

    2024年02月04日
    瀏覽(34)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包