Python实现简单的人脸打卡系统
源码下载链接:https://pan.baidu.com/s/16uyAqdUbCNbBwR45q1Zoag
提取码: pb4c
最近看到了一个比较有兴趣的东西,这个效果大概就是这个样子。
主要源码
# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import ttk
from tkinter.filedialog import *
import tkinter.messagebox
from PIL import Image, ImageTk
import img_api2
import cv2
import threading
import time
class Login(ttk.Frame):
def __init__(self, win):
ttk.Frame.__init__(self, win)
frame0 = ttk.Frame(self)
frame1 = ttk.Frame(self)
win.title("人脸打卡考勤")
win.minsize(800, 550)
self.center_window()
self.thread_run = None
self.thread_run2 = None
self.camera = None
#开始的画面,可以自行选择图片
self.pilImage = Image.open("img/start.png")
self.tkImage = ImageTk.PhotoImage(image=self.pilImage)
self.image_ctl = tk.Label(frame0, image=self.tkImage)
self.image_ctl.pack()
frame0.pack(side=TOP, fill=tk.Y, expand=1)
frame1.pack(side=TOP, fill=tk.Y, expand=1)
self.facer = ttk.Label(frame1, text='', font=('Times', '20'))
self.facer.pack()
#self.face_button1 = ttk.Button(frame1, text="选择文件", width=15, command=self.file1)
#self.face_button1.pack(side=TOP)
self.url_face_button = ttk.Button(frame1, text="使用相机识别", width=15, command=self.cv_face)
self.url_face_button.pack(side=TOP)
#self.file_pic_button = ttk.Button(frame1, text="本地文件识别", width=15, command=self.file_pic)
#self.file_pic_button.pack(side=TOP)
self.pack(fill=tk.BOTH, expand=tk.YES, padx="10", pady="10")
#使弹出的窗体处于屏幕的中间位置
def center_window(self):
screenwidth = log.winfo_screenwidth()
screenheight = log.winfo_screenheight()
log.update()
width = log.winfo_width()
height = log.winfo_height()
size = '+%d+%d' % ((screenwidth - width)/2, (screenheight - height)/2)
log.geometry(size)
def file1(self):
self.pic_path = askopenfilename(title="选择识别图片", filetypes=[("jpg图片", "*.jpg"), ("png图片", "*.png")])
def cv_face(self):
if self.thread_run:
if self.camera.isOpened():
self.camera.release()
print("关闭摄像头")
self.camera = None
self.thread_run = False
return
if self.camera is None:
self.camera = cv2.VideoCapture(1)
if not self.camera.isOpened():
self.camera = None
print("没有外置摄像头")
self.camera = cv2.VideoCapture(0)
if not self.camera.isOpened():
print("没有内置摄像头")
tkinter.messagebox.showinfo('警告', '摄像头打开失败!')
self.camera = None
return
else:
print("打开内置摄像头")
else:
print("打开外置摄像头")
self.thread = threading.Thread(target=self.video_thread)
self.thread.setDaemon(True)
self.thread.start()
self.thread_run = True
def video_thread(self):
self.thread_run = True
self.thread2 = threading.Thread(target=self.video_pic)
self.thread2.setDaemon(True)
self.thread2.start()
self.thread_run2 = True
while self.thread_run:
_, img_bgr = self.camera.read()
img = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
im = Image.fromarray(img)
w, h = im.size
pil_image_resized = self.resize(w, h, im)
self.imgtk = ImageTk.PhotoImage(image=pil_image_resized)
self.image_ctl.configure(image=self.imgtk)
print("run end")
def video_pic(self):
self.thread_run2 = True
predict_time = time.time()
while self.thread_run2:
if time.time() - predict_time > 2:
print("实时识别中")
_, img_bgr = self.camera.read()
cv2.imwrite("tmp/test.jpg", img_bgr)
self.pic_path = "tmp/test.jpg"
try:
self.file_pic()
except:
pass
predict_time = time.time()
print("video_pic")
pass
def file_pic(self):
self.pic_path2 = "img/mango.jpg"
facestr, result = img_api2.facef(self.pic_path, self.pic_path2)
self.facer.configure(text=str(facestr))
self.pic()
if result > 80:
tkinter.messagebox.showinfo('提示', '打卡成功!')
try:
f=open("打卡记录.txt","r")
fi=open("打卡记录.txt","a")
txt=time.ctime()
fi.write(txt+" Mango 打卡成功 \n")
f.close()
fi.close()
except:
f=open("打卡记录.txt","w")
txt=time.ctime()
f.write(txt+" Mango 打卡成功 \n")
f.close()
# close_window()
# os.system("python3 ./main.py")
else:
tkinter.messagebox.showinfo('提示', '登录失败,请重试!')
def pic(self):
self.pilImage3 = Image.open(self.pic_path)
w, h = self.pilImage3.size
pil_image_resized = self.resize(w, h, self.pilImage3)
self.tkImage3 = ImageTk.PhotoImage(image=pil_image_resized)
self.image_ctl.configure(image=self.tkImage3)
def resize(self, w, h, pil_image):
w_box = 800
h_box = 400
f1 = 1.0*w_box/w
f2 = 1.0*h_box/h
factor = min([f1, f2])
width = int(w*factor)
height = int(h*factor)
return pil_image.resize((width, height), Image.ANTIALIAS)
def close_window():
print("log destroy")
log.destroy()
if __name__ == '__main__':
log = tk.Tk()
login = Login(log)
# close,退出输出destroy
log.protocol('WM_DELETE_WINDOW', close_window)
# 进入消息循环
log.mainloop()
img_api2.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests
import os
import base64
import json
ACCESS_TOKEN = ''
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# ID,KEY的配置信息
INFO_CONFIG = {
'ID': '15788358',
'API_KEY': 'ohtGa5yYoQEZ8Try8lnL99UK',
'SECRET_KEY': 'qaDjyuXkf5MZ28g5C8pwFngDZenhswC3'
}
# URL配置
URL_LIST_URL = {
# ACCESS_TOKEN_URL用于获取ACCESS_TOKEN, POST请求,
# grant_type必须参数,固定为client_credentials,client_id必须参数,应用的API Key,client_secre 必须参数,应用的Secret Key.
'ACCESS_TOKEN_URL': 'https://aip.baidubce.com/oauth/2.0/token?' + 'grant_type=client_credentials&client_id={API_KEYS}&client_secret={SECRET_KEYS}&'.format(
API_KEYS=INFO_CONFIG['API_KEY'], SECRET_KEYS=INFO_CONFIG['SECRET_KEY']),
# 人脸识别
'FACE_PLATE': 'https://aip.baidubce.com/rest/2.0/face/v3/match',
}
class AccessTokenSuper(object):
pass
class AccessToken(AccessTokenSuper):
def getToken(self):
accessToken = requests.post(url=URL_LIST_URL['ACCESS_TOKEN_URL'])
accessTokenJson = accessToken.json()
if dict(accessTokenJson).get('error') == 'invalid_client':
return '获取accesstoken错误,请检查API_KEY,SECRET_KEY是否正确!'
return accessTokenJson
ACCESS_TOKEN = AccessToken().getToken()['access_token']
LICENSE_PLATE_URL = URL_LIST_URL['FACE_PLATE'] + '?access_token={}'.format(ACCESS_TOKEN)
class faceSuper(object):
pass
class face(faceSuper):
def __init__(self, image=None, image2=None):
self.HEADER = {
'Content-Type': 'application/json; charset=UTF-8',
}
if image is not None:
imagepath = os.path.exists(image)
if imagepath == True:
images = image
with open(images, 'rb') as images:
img1 = base64.b64encode(images.read())
else:
print("img1 not exits")
return
if image2 is not None:
imagepath2 = os.path.exists(image2)
if imagepath2 == True:
images2 = image2
with open(images2, 'rb') as images2:
img2 = base64.b64encode(images2.read())
else:
print("img2 not exits")
return
self.img = img1
self.imgs = img2
self.IMAGE_CONFIG1 = {"image": str(img1, 'utf-8'), "image_type": "BASE64"}
self.IMAGE_CONFIG2 = {"image": str(img2, 'utf-8'), "image_type": "BASE64"}
self.IMAGE_CONFIG = json.dumps([self.IMAGE_CONFIG1, self.IMAGE_CONFIG2])
def postface(self):
if (self.img==None and self.imgs==None):
return 'image参数不能为空!'
face = requests.post(url=LICENSE_PLATE_URL, headers=self.HEADER, data=self.IMAGE_CONFIG)
return face.json()
def facef(FA1, FA2):
testAccessToken = AccessToken()
testface = face(image=FA1, image2=FA2)
result_json = testface.postface()
result = result_json['result']['score']
print('人脸相似度:', result)
if result > 80:
print("是同一个人")
else:
print("不是同一个人")
return '人脸相似度:' + str(result), result