【優(yōu)秀畢設(shè)】基于OpenCV的人臉識別打卡/簽到/考勤管理系統(tǒng)(最簡基本庫開發(fā)、可基于樹莓派)
畢設(shè)結(jié)構(gòu)
該系統(tǒng)利用Harr級聯(lián)檢測和LPBH進(jìn)行人臉檢測和訓(xùn)練、識別
利用Tkinter完成界面搭建
利用Flask+HTML完成網(wǎng)絡(luò)實時圖像推流及控制
利用captcha.image 完成驗證碼功能
利用xlsxwriter將數(shù)據(jù)保存為Excel文檔
利用email庫發(fā)送郵件
功能如下圖所示 所有功能均可實現(xiàn)
cv2版本: 推薦4.4.0.46 安裝opencv-python和opencv-contrib-python
部分資源:
download.csdn.net/download/weixin_53403301/85545163
基礎(chǔ)完整資源:
download.csdn.net/download/weixin_53403301/85744946
視頻:
www.bilibili.com/video/BV1Ls4y1d78U/
【優(yōu)秀畢設(shè)開源】基于OpenCV的人臉識別打卡/簽到/考勤管理系統(tǒng)(最簡基本庫開發(fā)、可基于樹莓派)
部分代碼:
# -*- coding: utf-8 -*-
"""
Created on Mon May 31 23:39:19 2021
@author: ZHOU
"""
# -*- coding: utf-8 -*-
import tkinter as tk # 調(diào)用窗口tk
from tkinter import ttk
from tkinter.filedialog import askopenfilename
import tkinter.messagebox
from PIL import Image, ImageTk, ImageDraw, ImageFont # 調(diào)用圖像處理庫pillow
import cv2 # 調(diào)用OpenCV圖像處理庫
import threading # 調(diào)用threading多線程運行庫
import time # 調(diào)用系統(tǒng)時間戳庫
import os # 調(diào)用os多操作系統(tǒng)接口庫
import re
import numpy as np
from captcha.image import ImageCaptcha
import random
import string
import xlsxwriter
import smtplib
import email.mime.multipart
import email.mime.text
from email.mime.application import MIMEApplication
from flask import Flask,render_template, request, Response
import socket
global network_flag
network_flag = 0
local_post = 1212
local_ip = None
for i in range(12):
try:
s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.connect(("8.8.8.8",80))
local_ip = str(s.getsockname()[0])
s.close()
print("Network Enable")
network_flag = 1
break
except:
print("Network Error...")
network_flag = 0
time.sleep(5)
app = Flask(__name__)
star_pic_path = "./star.png"
pic_path = "./dataset"
train_path = "./trainer"
data_path = "./data"
train_nb_path = "/train_nb.txt"
train_time_path = "/train_time.txt"
name_id_path = "/name_id.txt"
email_set_path = "/email_set.txt"
admin_path = "/admin.txt"
yml_path = "/trainer.yml"
temp_path = "./temp"
save_path = "./save"
date_path = "/date.txt"
sign_in_mode_path = "/sign_in_mode.txt"
company_path = "/company.txt"
department_path = "/department.txt"
class_id_path = "/class_id.txt"
global today_temp_path
now_today = time.time()
today_temp_path = "/today_"+str(time.localtime(now_today).tm_year)+"_"+str(time.localtime(now_today).tm_mon)+"_"+str(time.localtime(now_today).tm_mday)+".txt"
cascadePath = "./cascade/haarcascade_frontalface_alt2.xml"
faceCascade = cv2.CascadeClassifier(cascadePath)
font = cv2.FONT_HERSHEY_SIMPLEX
recognizer = cv2.face.LBPHFaceRecognizer_create()
try:
recognizer.read(train_path+yml_path)
except:
print("缺失訓(xùn)練數(shù)據(jù)文件,請先訓(xùn)練數(shù)據(jù)")
cam_flag = 0
global img2
img2 = None
global img_flag
img_flag = 0
global login_flag
login_flag = 0
global doing_change_record_date_flag
doing_change_record_date_flag = 0
global auto_send_flag
auto_send_flag = 0
# -*- coding: utf-8 -*-
"""
Created on Mon Apr 25 23:25:45 2022
@author: 16016
"""
import xlsxwriter
import time
def txt_excel(filename):
fp = open(filename,encoding="utf-8")
x = 0
y = 0
lines = fp.readlines()
today_list = (lines[0].split("\n")[0]).split("-")
xls = xlsxwriter.Workbook('record_' + today_list[0]+"_"+today_list[1]+"_"+today_list[2] + '.xlsx')
sheet = xls.add_worksheet('record_' + today_list[0]+"_"+today_list[1]+"_"+today_list[2])
sheet.write(0,0,"姓名")
for j in lines:
for i in range(1,len(j.split('|'))):
item = j.split('|')[i].strip(' ')
sheet.write(x,y,item)
y += 1 # 另起一列
x += 1 # 另起一行
y = 0 # 初始成第一列
fp.close()
xls.close()
filename = './temp/today_2022_4_25.txt'
xlsname = './save/學(xué)生簽到表'
txt_excel(filename)
<html>
<meta http-equiv="refresh" content="60">
<head>
<title>人臉識別簽到管理系統(tǒng)</title>
</head>
<body>
<h1>人臉識別簽到管理系統(tǒng)</h1>
<form action="/" method="post">
<p><input type="submit" style="font-size:50px" name="send" value="發(fā)送數(shù)據(jù)">
<input type="submit" style="font-size:50px" name="maul" value="刷新網(wǎng)頁"></p>
<p>
<table>
{% for k,v in data_dict.items() %}
<tr>
<td>{{k}}</td>
<td>{{v[0]}}</td>
<td>{{v[1]}}</td>
<td>{{v[2]}}</td>
<td>{{v[3]}}</td>
<td>{{v[4]}}</td>
</tr>
{% endfor %}
</table>
</p>
<p><input type="submit" style="font-size:50px" name="update" value="更新記錄日期">
<input type="submit" style="font-size:50px" name="back" value="回退記錄日期"></p>
</form>
<img src="{{ url_for('video_feed') }}" height="520" style="float:left">
</body>
</html>
# -*- coding: utf-8 -*-
"""
Created on Tue Apr 26 15:16:42 2022
@author: 16016
"""
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import smtplib
import email.mime.multipart
import email.mime.text
from email.mime.application import MIMEApplication
def send_email(file_path,smtp_host, smtp_port, sendAddr, password, recipientAddrs, subject='', content=''):
'''
:param smtp_host: 域名
:param smtp_port: 端口
:param sendAddr: 發(fā)送郵箱
:param password: 郵箱密碼
:param recipientAddrs: 發(fā)送地址
:param subject: 標(biāo)題
:param content: 內(nèi)容
:return: 無
'''
msg = email.mime.multipart.MIMEMultipart()
msg['from'] = sendAddr
msg['to'] = recipientAddrs
msg['subject'] = subject
content = content
txt = email.mime.text.MIMEText(content, 'plain', 'utf-8')
msg.attach(txt)
if file_path != '':
# 添加附件地址
part = MIMEApplication(open(file_path, 'rb').read())
part.add_header('Content-Disposition', 'attachment', filename="name_id.xlsx") # 發(fā)送文件名稱
msg.attach(part)
try:
smtpSSLClient = smtplib.SMTP_SSL(smtp_host, smtp_port) # 實例化一個SMTP_SSL對象
loginRes = smtpSSLClient.login(sendAddr, password) # 登錄smtp服務(wù)器
print(f"登錄結(jié)果:loginRes = {loginRes}") # loginRes = (235, b'Authentication successful')
if loginRes and loginRes[0] == 235:
print(f"登錄成功,code = {loginRes[0]}")
smtpSSLClient.sendmail(sendAddr, recipientAddrs, str(msg))
print(f"mail has been send successfully. message:{str(msg)}")
smtpSSLClient.quit()
else:
print(f"登陸失敗,code = {loginRes[0]}")
except Exception as e:
print(f"發(fā)送失敗,Exception: e={e}")
try:
subject = 'Python 測試郵件'
content = '這是一封來自 Python 編寫的測試郵件。'
send_email('','smtp.qq.com', 465, '', '', '', subject, content)
except Exception as err:
print(err)
主頁面
驗證碼
識別效果
管理頁面
數(shù)據(jù)保存除了用戶信息和簽到信息外 還可以判斷是否遲到、早退并計算工作時長
人臉信息采集
管理
實時數(shù)據(jù)更新
簽到結(jié)果
郵件發(fā)送
網(wǎng)絡(luò)前端效果
實時圖像推流
(在識別時(IN/OUT功能)會推流到網(wǎng)絡(luò)中 管理員通過IP地址可以實現(xiàn)監(jiān)控效果)
附錄:列表的賦值類型和py打包
列表賦值
BUG復(fù)現(xiàn)
閑來無事寫了個小程序 代碼如下:
# -*- coding: utf-8 -*-
"""
Created on Fri Nov 19 19:47:01 2021
@author: 16016
"""
a_list = ['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15']
#print(len(a_list))
#b_list = ['','','','','','','','','','','','','','','','']
c_list = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
#for i in range(16):
if len(a_list):
for j in range(16):
a_list[j]=str(a_list[j])+'_'+str(j)
print("序號:",j)
print('a_list:\n',a_list)
c_list[j]=a_list
print('c_list[0]:\n',c_list[0])
print('\n')
# b_list[j]=a_list[7],a_list[8]
# print(b_list[j])
# 寫入到Excel:
#print(c_list,'\n')
我在程序中 做了一個16次的for循環(huán) 把列表a的每個值后面依次加上"_"和循環(huán)序號
比如循環(huán)第x次 就是把第x位加上_x 這一位變成x_x 我在輸出測試中 列表a的每一次輸出也是對的
循環(huán)16次后列表a應(yīng)該變成[‘0_0’, ‘1_1’, ‘2_2’, ‘3_3’, ‘4_4’, ‘5_5’, ‘6_6’, ‘7_7’, ‘8_8’, ‘9_9’, ‘10_10’, ‘11_11’, ‘12_12’, ‘13_13’, ‘14_14’, ‘15_15’] 這也是對的
同時 我將每一次循環(huán)時列表a的值 寫入到空列表c中 比如第x次循環(huán) 就是把更改以后的列表a的值 寫入到列表c的第x位
第0次循環(huán)后 c[0]的值應(yīng)該是[‘0_0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’, ‘10’, ‘11’, ‘12’, ‘13’, ‘14’, ‘15’] 這也是對的
但是在第1次循環(huán)以后 c[0]的值就一直在變 變成了c[x]的值
相當(dāng)于把c_list[0]變成了c_list[1]…以此類推 最后得出的列表c的值也是每一項完全一樣
我不明白這是怎么回事
我的c[0]只在第0次循環(huán)時被賦值了 但是后面它的值跟著在改變
如圖:
第一次老出bug 賦值以后 每次循環(huán)都改變c[0]的值 搞了半天都沒搞出來
無論是用appen函數(shù)添加 還是用二維數(shù)組定義 或者增加第三個空數(shù)組來過渡 都無法解決
代碼改進(jìn)
后來在我華科同學(xué)的指導(dǎo)下 突然想到賦值可以賦的是個地址 地址里面的值一直變化 導(dǎo)致賦值也一直變化 于是用第二張圖的循環(huán)套循環(huán)深度復(fù)制實現(xiàn)了
代碼如下:
# -*- coding: utf-8 -*-
"""
Created on Fri Nov 19 19:47:01 2021
@author: 16016
"""
a_list = ['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15']
#print(len(a_list))
#b_list = ['','','','','','','','','','','','','','','','']
c_list = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
#for i in range(16):
if len(a_list):
for j in range(16):
a_list[j]=str(a_list[j])+'_'+str(j)
print("序號:",j)
print('a_list:\n',a_list)
for i in range(16):
c_list[j].append(a_list[i])
print('c_list[0]:\n',c_list[0])
print('\n')
# b_list[j]=a_list[7],a_list[8]
# print(b_list[j])
# 寫入到Excel:
print(c_list,'\n')
解決了問題
優(yōu)化
第三次是請教了老師 用copy函數(shù)來賦真值
代碼如下:
# -*- coding: utf-8 -*-
"""
Created on Fri Nov 19 19:47:01 2021
@author: 16016
"""
a_list = ['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15']
#print(len(a_list))
#b_list = ['','','','','','','','','','','','','','','','']
c_list = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
#for i in range(16):
if len(a_list):
for j in range(16):
a_list[j]=str(a_list[j])+'_'+str(j)
print("序號:",j)
print('a_list:\n',a_list)
c_list[j]=a_list.copy()
print('c_list[0]:\n',c_list[0])
print('\n')
# b_list[j]=a_list[7],a_list[8]
# print(b_list[j])
# 寫入到Excel:
#print(c_list,'\n')
同樣能解決問題
最后得出問題 就是指針惹的禍!
a_list指向的是個地址 而不是值 a_list[i]指向的才是單個的值 copy()函數(shù)也是復(fù)制值而不是地址
如果這個用C語言來寫 就直觀一些了 難怪C語言是基礎(chǔ) 光學(xué)Python不學(xué)C 遇到這樣的問題就解決不了
C語言yyds Python是什么垃圾弱智語言
總結(jié)
由于Python無法單獨定義一個值為指針或者獨立的值 所以只能用列表來傳送
只要賦值是指向一個列表整體的 那么就是指向的一個指針內(nèi)存地址 解決方法只有一個 那就是將每個值深度復(fù)制賦值(子列表內(nèi)的元素提取出來重新依次連接) 或者用copy函數(shù)單獨賦值
如圖測試:
部分代碼:
# -*- coding: utf-8 -*-
"""
Created on Sat Nov 20 16:45:48 2021
@author: 16016
"""
def text1():
A=[1,2,3]
B=[[],[],[]]
for i in range(len(A)):
A[i]=A[i]+i
B[i]=A
print(B)
def text2():
A=[1,2,3]
B=[[],[],[]]
A[0]=A[0]+0
B[0]=A
print(B)
A[1]=A[1]+1
B[1]=A
print(B)
A[2]=A[2]+2
B[2]=A
print(B)
if __name__ == '__main__':
text1()
print('\n')
text2()
py打包
Pyinstaller打包exe(包括打包資源文件 絕不出錯版)
依賴包及其對應(yīng)的版本號
PyQt5 5.10.1
PyQt5-Qt5 5.15.2
PyQt5-sip 12.9.0
pyinstaller 4.5.1
pyinstaller-hooks-contrib 2021.3
Pyinstaller -F setup.py 打包exe
Pyinstaller -F -w setup.py 不帶控制臺的打包
Pyinstaller -F -i xx.ico setup.py 打包指定exe圖標(biāo)打包
打包exe參數(shù)說明:
-F:打包后只生成單個exe格式文件;
-D:默認(rèn)選項,創(chuàng)建一個目錄,包含exe文件以及大量依賴文件;
-c:默認(rèn)選項,使用控制臺(就是類似cmd的黑框);
-w:不使用控制臺;
-p:添加搜索路徑,讓其找到對應(yīng)的庫;
-i:改變生成程序的icon圖標(biāo)。
如果要打包資源文件
則需要對代碼中的路徑進(jìn)行轉(zhuǎn)換處理
另外要注意的是 如果要打包資源文件 則py程序里面的路徑要從./xxx/yy換成xxx/yy 并且進(jìn)行路徑轉(zhuǎn)換
但如果不打包資源文件的話 最好路徑還是用作./xxx/yy 并且不進(jìn)行路徑轉(zhuǎn)換
def get_resource_path(relative_path):
if hasattr(sys, '_MEIPASS'):
return os.path.join(sys._MEIPASS, relative_path)
return os.path.join(os.path.abspath("."), relative_path)
而后再spec文件中的datas部分加入目錄
如:
a = Analysis(['cxk.py'],
pathex=['D:\\Python Test\\cxk'],
binaries=[],
datas=[('root','root')],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
而后直接Pyinstaller -F setup.spec即可
如果打包的文件過大則更改spec文件中的excludes 把不需要的庫寫進(jìn)去(但是已經(jīng)在環(huán)境中安裝了的)就行
這些不要了的庫在上一次編譯時的shell里面輸出
比如:文章來源:http://www.zghlxwxcb.cn/news/detail-456682.html
然后用pyinstaller --clean -F 某某.spec文章來源地址http://www.zghlxwxcb.cn/news/detail-456682.html
到了這里,關(guān)于【優(yōu)秀畢設(shè)】基于OpenCV的人臉識別打卡/簽到/考勤管理系統(tǒng)(最簡基本庫開發(fā)、可基于樹莓派)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!