五、PySimpleGUI
pip install pysimplegui
PySimpleGUI 包含了大量的控件(也称为小部件或组件),这些控件可以快速构建用户界面。
1、窗口布局
layout 为一个列表,列表第一行代表窗口主界面的第一行内容
Window 方法创建一个窗口,第一个参数为窗口名字,第二个参数为窗口布局
常用布局方法:
Text :参数为文本内容,在指定位置显示文本
InputText:默认空文本(可用引号后输入默认内容),生成输入框
Button:默认空文本(可用引号后输入按钮名称),生成按钮
key:组合,指定当前控件的关键字,不重复
size:组合,指定当前控件的大小
text_color='red':指定当前控件文本字体为红色
案例:
import PySimpleGUI as sg
定义布局
layout = [[sg.Text('你好'), sg.InputText('在这儿输入内容', text_color='red')],
[sg.Button('提交', size=(5, 2))]
]
创建窗口
window = sg.Window('我的窗口', layout)
事件循环
while True:
event, values = window.read()
点击X和退出按钮,关闭窗口
if event in (None, "关闭"):
break
关闭窗口
window.close()
2、窗口数据
2.1、获取数据
event, values = window.read() 获取窗口的事件和输入数据
event 代表事件,按钮点击后返回该按钮的文本信息
values 返回所有输入内容,一般使用values['key值']来指定获取输入的内容
import PySimpleGUI as sg
定义布局
layout = [[sg.Text('你好'), sg.InputText('在这儿输入内容', text_color='red', key='nr')],
[sg.Button('提交', size=(5, 2))]
]
创建窗口
window = sg.Window('我的窗口', layout)
while True:
event, values = window.read()
id = values['nr']
if event == '提交': # 判断按钮
print(f'id={id}')
break
关闭窗口
window.close()
2.2、更新数据
import PySimpleGUI as sg
layout = [[sg.Text('你好'), sg.InputText('在这儿输入内容', text_color='red', key='nr')],
[sg.Text('更新内容', key="text")],
[sg.Button('提交', size=(5, 2))]
]
window = sg.Window('我的窗口', layout)
while True:
event, values = window.read()
if event is None:
break
id = values['nr']
if event == '提交': # 判断按钮
window['text'].Update(id)
关闭窗口
window.close()
六、pymysql
连接mysql的工具
pip install pymysql
pymysql.Connect(host="localhost",
user="root", # 用户账户
passwd="1234", # 用户密码
database="demo01", # 数据库
charset="utf8"
)
完整案例:
import pymysql
import datetime
连接数据库
def conn():
创建数据库连接
con = pymysql.connect(host="localhost",
user="",
passwd="",
port=,
database="",
charset=""
)
return con
创建游标
def curs(conn1):
cur = conn1.cursor()
return cur
提交并释放资源
def turn_down(conn1, cur1):
提交操作
conn1.commit()
释放资源
cur1.close()
conn1.close()
新增用户信息
def info_add(num1, name1):
conn_add = conn()
curs_add = curs(conn_add)
定义sql
sql = "insert into user_info (user_name, user_num) value (%s, %s)"
运行sql
curs_add.execute(sql, (name1, num1))
执行增删改函数,返回一个受影响的行数数值
num = curs_add.rowcount
turn_down(conn_add, curs_add)
if num > 0:
return "添加成功"
else:
return "添加失败了,请重新尝试"
新增打卡信息
def work_add(num1, type1):
conn_add = conn()
curs_add = curs(conn_add)
date1 = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
定义sql
sql = "insert into user_work (user_num, user_type, user_date) value (%s, %s, %s)"
运行sql
curs_add.execute(sql, (num1, type1, date1))
执行增删改函数,返回一个受影响的行数数值
num = curs_add.rowcount
turn_down(conn_add, curs_add)
if num > 0:
if type1 == 1 or type1 == '1':
return "上班打卡成功"
else:
return "下班打卡成功"
else:
return "打卡失败了"
删用户信息,通过编号或 all 删除数据
def delete(num1=None):
conn_delete = conn()
curs_delete = curs(conn_delete)
if num1 is None:
print("请检查需要删除 num 后在使用")
return
elif num1 == 'all':
sql = "delete from user_info where user_num not in ('1', 1) "
curs_delete.execute(sql)
else:
定义sql
sql = "delete from user_info where user_num = %s"
运行sql
curs_delete.execute(sql, (num1,))
执行增删改函数,返回一个受影响的行数数值
num = curs_delete.rowcount
if num > 0:
print(f"删除成功,{num}行")
else:
print("删除失败了")
turn_down(conn_delete, curs_delete)
更新数据,通过编号更新姓名,编号不可变更
def update(num1=None, name1=None):
conn_update = conn()
curs_update = curs(conn_update)
if name1 is None or num1 is None:
print("请检查需要更改内容后在使用")
else:
定义sql
sql = "update user_info set user_name = %s where user_num= %s"
curs_update.execute(sql, (name1, num1))
num = curs_update.rowcount
if num > 0:
print("更新成功")
else:
print("更新失败了")
turn_down(conn_update, curs_update)
通过编号查询用户信息
def info_query(num=None, name=None):
conn_query = conn()
curs_query = curs(conn_query)
if name is None and num is None:
定义sql
sql = "select * from user_info"
curs_query.execute(sql)
elif name is None:
定义sql
sql = "select * from user_info where user_num = %s"
curs_query.execute(sql, (num,))
elif name is not None:
sql = "select * from user_info where user_name = %s"
curs_query.execute(sql, (name,))
else:
sql = "select * from user_info where user_name = %s and user_num = %s"
curs_query.execute(sql, (name, num))
rs = curs_query.fetchall()
curs_query.close()
conn_query.close()
return rs
查询打卡信息()
def work_query(num1=None, type1=None):
conn_query = conn()
curs_query = curs(conn_query)
date2 = datetime.datetime.now().strftime("%Y-%m-%d")
if num1 is None or num1 == 'all':
定义sql
sql = "select * from user_work where DATE_format(user_date,'%%Y-%%m-%%d') = %s"
curs_query.execute(sql, (date2,))
else:
if type1 is None:
sql = "select * from user_work where user_num = %s and DATE_format(user_date,'%%Y-%%m-%%d') = %s"
curs_query.execute(sql, (num1, date2))
else:
sql = "select * from user_work where user_num = %s and user_type = %s and DATE_format(user_date,'%%Y-%%m-%%d') = %s"
curs_query.execute(sql, (num1, type1, date2))
rs = curs_query.fetchall()
七、结合使用案例
两个文件
databaselink.py 连接数据库
同六案例
mainfile.py 主代码
from guiitemwork.databaselink import *
import PySimpleGUI as sg
import cv2
import face_recognition
import os
import numpy as np
import pandas as pd
将视频窗口缩小
def resized_frame(frame_image):
resized_frame_image = cv2.resize(frame_image, (400, 300))
img_type = cv2.imencode(".png", resized_frame_image)[1].tobytes()
return img_type
判断编号是否存在
def data_warehouse(get_num):
a = info_query(get_num)
if a in (None, ()):
return False
else:
return True
生成一个存放所有脸部数据的列表,元素为元组
known_face_encodings = []
,图片名称,
def load_known_faces():
directory = "datasource"
遍历查找图片
for filename in os.listdir(directory):
图片路径
image_path = os.path.join(directory, filename)
image = face_recognition.load_image_file(image_path)
根据图片识别人脸信息存放到列表
face_encodings = face_recognition.face_encodings(image)
if face_encodings:
以元组形式存放(图片名称, 图片人脸信息)
known_face_encodings.append((filename, face_encodings[0]))
判断识别人脸是否存在列表,列表无数据返回字符串,未匹配返回 False,匹配返回元组(图片名称,图片完整名称)
识别条件,相似度高于百分之起始
def image_warehouse(get_face):
if len(known_face_encodings) > 0:
for face1name, face1 in known_face_encodings:
rs = np.linalg.norm(get_face - face1)
判断图片是否存在,存在返回图片的编号名称和图片完整名称
if rs < 0.3:
imag_name = face1name.split('.')[0]
return imag_name, face1name
elif rs > 0.3 and face1name != known_face_encodings[-1][0]:
continue
else:
return False
else:
return "图片仓库没有数据,请先采集"
信息采集窗口
def collection_platform(window_name):
窗口布局
layout = [
[sg.Text("编号"), sg.InputText(key="num", size=(10, 1))],
[sg.Text("姓名"), sg.InputText(key="name", size=(10, 1))],
[sg.Button("确定", size=(5, 1)), sg.Button("重置输入信息", size=(15, 1))],
[sg.Text("视频窗口")],
[sg.Image(key="video", size=(400, 300))],
]
创建窗口,包含layout 信息
window_collection = sg.Window("信息采集窗口", layout)
关闭上一个窗口
window_name.close()
打开摄像头
cap = cv2.VideoCapture(0)
判断摄像头开启状态,是否能获取信息
if cap.isOpened() is False:
sg.popup("摄像头未开启")
return
打开摄像头
while True:
分析摄像头获取到的信息
ret, frame = cap.read()
img_type = resized_frame(frame)
分析窗口返回数据,每次间隔10毫秒
event, values = window_collection.read(timeout=10)
判断执行操作为关闭窗口,则直接结束程序
if event in (None, sg.sgprint_close):
break
window_collection['video'].update(data=img_type)
重置信息按钮
if event == '重置输入信息':
window_collection['num'].update('')
window_collection['name'].update('')
continue
if event == '确定':
获取编号和姓名
num = values["num"]
name = values["name"]
判断是否输入编号和姓名
if num in (None, '') or name in (None, ''):
sg.popup("请输入编号和姓名")
continue
判断输入的编号是否已存在,不存在则添加,存在则无需录入
else:
user_data = data_warehouse(num)
user_date 存在返回 True
判断不存在则进行收集
if user_data is False:
获取脸部信息
face_list = face_recognition.face_locations(frame, model='hog')
脸部照片获取成功
if face_list not in (None, []):
face0 = face_recognition.face_encodings(frame, num_jitters=3)[0]
判断脸部信息是否存在于内部,不存在则收集
user_image = image_warehouse(face0)
图片仓库返回是否存在等信息
if user_image is False or '没有数据' in user_image:
写入照片仓库
x = cv2.imwrite(f"datasource\\{num}.png", frame)
保存成功则在数据库添加信息,否则不添加
if x is not None:
sg.popup("采集成功")
info_add(num, name)
continue
else:
sg.popup("采集失败,请重新采集")
continue
else:
sg.popup(f"脸部信息已存在,编号为{user_image[0]}")
continue
else:
sg.popup("未检测到脸部信息")
continue
else:
sg.popup(f"({num},{name})的信息已存在,无需重复录入")
continue
cap.release()
manage_platform()
window_collection.close()
信息更新窗口
def update_platform(window_name):
layout = [
[sg.Text("姓名"), sg.InputText(key="name", size=(10, 2))],
[sg.Button("更新姓名信息", size=(10, 1)), sg.Button("更新脸部信息", size=(10, 1))],
[sg.Image(key="video", size=(400, 300))]
]
创建窗口,包含layout 信息和cap信息
window_update = sg.Window("信息更新窗口", layout)
关闭老窗口
window_name.close()
打开摄像头
cap = cv2.VideoCapture(0)
判断摄像头开启状态,是否能获取信息
if cap.isOpened() is False:
sg.popup("摄像头未开启")
return
while True:
分析摄像头获取到的信息
ret, frame = cap.read()
img_type = resized_frame(frame)
分析窗口返回数据,每次间隔10毫秒
event, values = window_update.read(timeout=10)
判断执行操作为关闭窗口,则直接结束程序
if event in (None, sg.sgprint_close):
break
window_update['video'].update(data=img_type)
if event == '更新姓名信息':
name = values["name"]
判断是否输入编号和姓名
if name in (None, ''):
sg.popup("请输入姓名")
continue
else:
face_list = face_recognition.face_locations(frame, model='hog')
脸部照片获取成功
if face_list not in (None, []):
face0 = face_recognition.face_encodings(frame, num_jitters=3)[0]
print('-------', face0)
判断脸部信息是否存在于内部,不存在则收集
user_image = image_warehouse(face0)
图片仓库返回是否存在等信息
if user_image is False or '没有数据' in user_image:
sg.popup("无脸部数据,请先采集")
continue
else:
update(user_image[0], name)
sg.popup(f"编号:{user_image[0]} 的姓名已更新为{name}")
continue
else:
sg.popup("未检测到脸部信息")
continue
if event == '更新脸部信息':
face_list = face_recognition.face_locations(frame, model='hog')
脸部照片获取成功
if face_list in (None, []):
sg.popup("未检测到脸部信息")
continue
else:
face0 = face_recognition.face_encodings(frame, num_jitters=3)[0]
user_image = image_warehouse(face0)
if user_image is False or '没有数据' in user_image:
sg.popup("无脸部数据,请先采集")
continue
else:
x = cv2.imwrite(f"datasource\\{user_image[1]}", frame)
if x is not None:
load_known_faces()
sg.popup(f"编号:{user_image[0]} 的脸部信息更新成功")
continue
else:
sg.popup("更新失败,请重新识别")
continue
cap.release()
window_update.close()
manage_platform()
信息删除窗口
def delete_platform(window_name):
layout = [
[sg.Button("清除该脸部信息", size=(15, 1)), sg.Push(), sg.Button("清除所有脸部信息", size=(15, 1))],
[sg.Image(key="video", size=(400, 300))]
]
创建窗口,包含layout 信息和cap信息
window_delete = sg.Window("信息删除窗口", layout)
window_name.close()
打开摄像头
cap = cv2.VideoCapture(0)
判断摄像头开启状态,是否能获取信息
if cap.isOpened() is False:
sg.popup("摄像头未开启")
return
while True:
分析摄像头获取到的信息
ret, frame = cap.read()
face_list = face_recognition.face_locations(frame, model='hog')
for face_list1 in face_list:
y, w, h, x = face_list1
cv2.rectangle(frame, (x, y), (w, h), (0, 255, 0), 2)
img_type = resized_frame(frame)
分析窗口返回数据,每次间隔10毫秒
event, values = window_delete.read(timeout=10)
判断执行操作为关闭窗口,则直接结束程序
if event in (None, sg.sgprint_close):
break
window_delete['video'].update(data=img_type)
if event == '清除该脸部信息':
if face_list in (None, []):
sg.popup("未检测到脸部信息")
continue
face0 = face_recognition.face_encodings(frame, num_jitters=1)
if face0 in (None, []):
sg.popup("请正面摄像头")
continue
else:
face0 = face0[0]
将脸部信息和仓库信息对比
user_image = image_warehouse(face0)
if len(known_face_encodings) < 1:
sg.popup("没有数据,无需删除")
continue
elif user_image is not False and user_image not in (None, ()):
a4 = info_query(user_image[0])
if a4[0][1] == '101':
sg.popup("管理员不能被删除")
continue
else:
os.remove(f"datasource\\{user_image[1]}")
delete(user_image[0])
sg.popup(f"编号 {a4[0][1]},姓名 {a4[0][2]} 已删除")
load_known_faces()
continue
else:
sg.popup("无该脸部信息,无需删除")
continue
if event == '清除所有脸部信息':
face_list = face_recognition.face_locations(frame, model='hog')
if face_list in (None, []):
sg.popup("请联系管理员操作")
continue
face0 = face_recognition.face_encodings(frame, num_jitters=3)[0]
将脸部信息和仓库信息对比
user_image = image_warehouse(face0)
if user_image is not False:
user_info = info_query(user_image[0])
if user_info[0][1] == '101':
delete('all')
dir_list = os.listdir(f"datasource")
if len(dir_list) == 1:
sg.popup("无额外数据,无需清理")
elif len(dir_list) > 1:
for b in dir_list:
除去管理员脸部信息
if b.split('')[0] == '101':
continue
else:
os.remove(f"datasource\\{b}")
sg.popup("数据清理完毕")
known_face_encodings.clear()
load_known_faces()
continue
else:
sg.popup("请联系管理员操作")
continue
else:
sg.popup("请联系管理员操作")
continue
cap.release()
window_delete.close()
manage_platform()
def clock_platform(window_name, type1):
layout = [[sg.Image(key="video", size=(400, 300))]]
创建窗口,包含layout 信息
window_clock = sg.Window("打卡平台", layout)
关闭老窗口
window_name.close()
打开摄像头
cap = cv2.VideoCapture(0)
判断摄像头开启状态,是否能获取信息
if cap.isOpened() is False:
sg.popup("摄像头未开启")
return
num_time = 0
while True:
ret, frame = cap.read()
face_list = face_recognition.face_locations(frame, model='hog')
for face_list1 in face_list:
y, w, h, x = face_list1
cv2.rectangle(frame, (x, y), (w, h), (0, 255, 0), 2)
img_type = resized_frame(frame)
分析窗口返回数据,每次间隔10毫秒
event, values = window_clock.read(timeout=10)
判断执行操作为关闭窗口,则直接结束程序
if event in (None, sg.sgprint_close):
break
window_clock['video'].update(data=img_type)
num_time += 10
if num_time <= 100:
window_clock.bring_to_front()
continue
else:
if face_list in (None, []):
num_time = 0
continue
else:
face0 = face_recognition.face_encodings(frame, num_jitters=2)
if face0 in (None, []):
sg.popup(f"未识别")
num_time = -100
window_clock.bring_to_front()
continue
else:
face0 = face0[0]
user_image = image_warehouse(face0)
if user_image is not False:
user_info = info_query(user_image[0])
if user_info[0][1] == '101':
sg.popup(f"管理员无需打卡")
num_time = -100
window_clock.bring_to_front()
continue
else:
a5 = work_query(user_info[0][1], type1)
if a5 not in (None, ()):
sg.popup(f"编号 {user_info[0][1]},姓名 {user_info[0][2]} 无需重复打卡")
else:
a4 = work_add(user_info[0][1], type1)
sg.popup(f"编号 {user_info[0][1]},姓名 {user_info[0][2]} {a4}")
num_time = -100
window_clock.bring_to_front()
continue
window_clock.bring_to_front()
cap.release()
window_clock.close()
manage_platform()
def clock_date(window_name):
layout = [[sg.Image(key="video", size=(500, 300))]]
创建窗口,包含layout 信息和cap信息
window_clock = sg.Window("权限校验", layout)
关闭老窗口
window_name.close()
打开摄像头
cap = cv2.VideoCapture(0)
判断摄像头开启状态,是否能获取信息
if cap.isOpened() is False:
sg.popup("摄像头未开启")
return
num_time = 0
while True:
ret, frame = cap.read()
face_list = face_recognition.face_locations(frame, model='hog')
for face_list1 in face_list:
y, w, h, x = face_list1
cv2.rectangle(frame, (x, y), (w, h), (0, 255, 0), 2)
img_type = resized_frame(frame)
分析窗口返回数据,每次间隔10毫秒
event, values = window_clock.read(timeout=10)
if event in (None, sg.sgprint_close):
break
分析摄像头获取到的信息
window_clock['video'].update(data=img_type)
num_time += 10
if num_time <= 100:
continue
else:
face_list = face_recognition.face_locations(frame, model='hog')
if face_list in (None, []):
num_time = 0
continue
else:
face0 = face_recognition.face_encodings(frame, num_jitters=1)[0]
user_image = image_warehouse(face0)
if user_image is not False:
user_info = info_query(user_image[0])
if user_info[0][1] == '101':
rt_data = work_query()
else:
rt_data = work_query(user_info[0][1])
rt_data1 = pd.DataFrame(data=rt_data, columns=['索引', '编号', '打卡类型', '打卡时间'])
rt_data1.drop(columns='索引', inplace=True)
添加打卡姓名
rt_data1['姓名1'] = rt_data1['编号'].apply(lambda x: info_query(x)[0][2])
rt_data1.insert(1, '姓名', rt_data1['姓名1'])
rt_data1.drop(columns='姓名1', inplace=True)
添加打卡类型
rt_data1['打卡类型1'] = np.where(rt_data1['打卡类型'] == 1, '上班打卡', '下班打卡')
rt_data1.drop(columns='打卡类型', inplace=True)
rt_data1.insert(2, '打卡类型', rt_data1['打卡类型1'])
rt_data1.drop(columns='打卡类型1', inplace=True)
cap.release()
work_data_display(window_clock, rt_data1)
break
else:
continue
cap.release()
window_clock.close()
manage_platform()
def work_data_display(window_name, rt_data):
table_data = []
for row in rt_data.itertuples(index=False):
table_data.append([str(row.编号), str(row.姓名), str(row.打卡类型), row.打卡时间.strftime('%Y-%m-%d %H:%M:%S')])
layout_display = [
[sg.Table(values=table_data,
headings=['编号', '姓名', '打卡类型', '打卡时间'],
auto_size_columns=True,
expand_x=True,
expand_y=True,
justification='center',
num_rows=min(25, len(table_data)))]
]
window_display = sg.Window("打卡数据展示", layout_display, size=(500, 300))
window_name.close()
while True:
event, values = window_display.read(timeout=10)
判断执行操作为关闭,则直接结束程序
if event in (None, sg.sgprint_close):
break
window_display.close()
manage_platform()
def manage_platform():
创建视频窗口
layout = [
[sg.Button("采集", size=(10, 2)), sg.Button("更新", size=(10, 2)), sg.Button("删除", size=(10, 2)),],
[sg.Button("上班打卡", size=(10, 2)), sg.Button("下班打卡", size=(10, 2)), sg.Button("打卡数据", size=(10, 2))],
[sg.Button("加载图片信息", size=(10, 2)), sg.Button("关闭", size=(10, 2))]
]
创建窗口,包含layout 信息和cap信息
window_manage = sg.Window("打卡管理平台平台", layout)
while True:
分析窗口返回数据,每次间隔10毫秒
event, values = window_manage.read(timeout=10)
判断执行操作为关闭,则直接结束程序
if event in (None, '关闭', sg.sgprint_close):
break
if event == '采集':
load_known_faces()
collection_platform(window_manage)
continue
if event == '更新':
if len(known_face_encodings) == 0:
load_known_faces()
update_platform(window_manage)
continue
if event == '删除':
if len(known_face_encodings) == 0:
load_known_faces()
delete_platform(window_manage)
continue
if event == '上班打卡':
if len(known_face_encodings) == 0:
load_known_faces()
clock_platform(window_manage, 1)
continue
if event == '下班打卡':
if len(known_face_encodings) == 0:
load_known_faces()
clock_platform(window_manage, 2)
continue
if event == '打卡数据':
if len(known_face_encodings) == 0:
load_known_faces()
clock_date(window_manage)
continue
if event == '加载图片信息':
load_known_faces()
sg.popup("加载完毕")
continue
window_manage.close()
if name == 'main':
manage_platform()