前言
在现代信息化时代,图形化用户界面(Graphical User Interface, GUI)已经成为各种软件应用和设备交互的主流方式,与传统的命令行界面(CLI)相比,GUI 具有直观性、易用性、交互性、可视化和多任务处理等优势。设计良好的用户交互界面可以让用户以更加直观、友好的方式与计算机系统进行交互,提高用户的满意度和使用体验。本项目将设计一款实用人机交互界面,用户通过界面的按钮、文本框、图表等能够更加便捷地完成人脸采识别、语音交互下单等任务。
下面是界面演示视频。
人工智能系统界面操作视频
一、项目介绍
本项目利用Tkinter模块搭建了一个人工智能系统界面,如图1和图2所示,用户在界面按下按钮或者输入文本框内容,可以与系统进行数据交互,避免通过命令行等繁琐的输入方式来执行程序。本项目设计的界面主要包含以下两大功能。
1.人脸信息验证
界面的左边栏目中用户可进行人脸采集、模型训练、人脸识别验证。
(1)人脸采集。用户首先需要完成人脸采集,输入“用户ID”“用户姓名”后,点击“采集”按钮,可以调取摄像头,完成100张人脸图像的采集。
(2)模型训练。用户需要在“模型名称”中输入对应人脸模型的名字,例如“lyx”,点击“训练”按钮后,系统会自动生成一个命为“lyx.yml”的模型,并自动保存到“FaceRecognition/Model”文件夹下。
(3)人脸识别。用户完成人脸采集与模型训练之后,才能点击“识别”按钮,当人脸识别成功后,系统会调取该用户的人脸图像显示在系统界面上。
当用户按下界面中的“清除”“注销”按钮可以消除已有的信息。
2.订单信息可视化
用户可在界面右边栏目中,通过按下“语音启动”按钮,说出“系统启动”来开启后续操作。系统启动后,会通过语音合成提醒用户完成人脸识别,只有用户的身份信息核实通过后,用户才能够向3位摊主进行下单任务,下单时同样需要用户通过与系统进行语音交互来完成。订单完成后,界面显示用户向每位摊主下单的总数,并通过扇形图展示出来。点击下方的“订单详情”,界面会切换到对每位摊主详细的需求。
二、项目准备
1.Tkinter模块相关组件的知识,可以详看我前面写过的文章
2.准备一个TCP调试助手,用于TCP通信。如果没有,可见文末附件。打开TCP调试助手,设置为服务端,其IP地址为“127.0.0.1”,端口为“2005”,打开开关。
3.安装好相关的库文件,详细见下图,版本是3.75。
4.本项目中的程序人脸识别和语音功能是直接调用已经写好的人脸采集、训练、识别和语音识别、语音合成的函数,可以见人脸识别和语音识别和语音合成这3篇文章,全部的程序都会放在本文末附录。
三、项目实施
备注:界面设计的参考程序建议从后面的主程序往前看,找到对应的功能函数。
1.导入相关库文件
from tkinter import *
from tkinter import ttk
from PIL import Image, ImageTk
import time
import cv2
from playsound import playsound #播放声音
from FaceCollect import GetFace #导入采集程序中的函数
import socket #连接服务器
from FaceTrain import getImagesAndLabels,recognizer #导入训练程序中的函数
import numpy as np
from FaceRecognition import Face #导入识别程序中的函数
from baiduasr import record, asr_updata #语音合成文件中的函数
import baiduasr #语音合成文件
from TTS import tts #语音合成文件
import threading #开启线程所用
import openpyxl #表格处理模块
import matplotlib #绘图
from matplotlib.figure import Figure
2.人脸信息验证功能
# 人脸图片显示函数,所有的人脸图片显示的时候可以加载这个函数
def face_image(face_photo):
global photo1 # 一定要将photo设置成全局变量不然调用显示不出来 image
photo_open1 = Image.open('./' + face_photo + '.jpg') # 打开图片
photo1 = photo_open1.resize((100 , 120)) # 图片尺寸
photo1 = ImageTk.PhotoImage(photo1)
Label(Frame1_3,image=photo1).place(x= 90,y = 10) # 放置人脸图像的标签及位置
#清除函数
def clear(entry1,entry2):
print("文本清除")
entry1.delete(0,END) #清除文本框内容,从第一个字符到最后一个字符
entry2.delete(0,END) #清除文本框内容,从第一个字符到最后一个字符
# 人脸注销函数。function:face_logout
def face_logout():
print("图像注销")
Label(Frame1_3,text = " " , bg = "#DAE3F3").place(x= 100,y = 150) # 用空格顶掉原有的信息
Label(Frame1_3,text = " " , bg = "#DAE3F3").place(x= 100,y = 200) # 用空格顶掉原有的信息
face_image('face')
# 采集函数。function:fece_collect
#利用get()方法获取用户输入的姓名、ID,调用FaceCollect中的Getface函数完成图像采集。
def register():
print("人脸采集")
Name = name.get()
ID = id.get() #获取文本框内容
GetFace(Name,ID) #采集人脸数据
# 人脸训练函数。function:fece_train
#利用get()方法获取用户输入的模型名称,调用FaceTrain中的函数完成人脸模型的训练,生成的模型文件保存到Model文件夹内,并以用户输入的模型名称命名。
def Train():
print("人脸训练")
Moudle = moudle_name1.get() #获取文本框内容
faces, ids = getImagesAndLabels(path) #获取训练程序中的人脸和标签
# 开始训练
recognizer.train(faces, np.array(ids))
# 保存文件
recognizer.write(r'./Model/'+ Moudle +'.yml') #以用户输入的模型名称给生成的模型命名
# 人脸识别函数
#完善“识别”按钮函数。调用FaceRecognition中的Face函数来识别用户身份,并将信息显示在界面。
def face_recognition():
print("人脸识别")
Name,idnum,Confidence = Face() #调用人脸识别函数
print("您的名字是:", Name,"您的ID是:", idnum)
Label(Frame1_3,text=idnum,font=("黑体",15),width=4,bg = "#DAE3F3").place(x=110,y=150)#ID
Label(Frame1_3,text=Name ,font= ("黑体",15),width=4,bg = "#DAE3F3").place(x=110,y=200)#姓名
face_image('image') #设置界面的人脸图像
这段程序即界面左边人脸信息验证部分的功能。
3.语音交互与TCP数据通信
(1)创建socket客户端变量,利用socket_client.send方法向TCP发送数据,该客户端变量是在最下面的主函数中定义的。
(2)执行Start()函数时,首先通过tts合成语音提示用户进行录音,然后进行语音识别,用户说出“系统启动后”,再进行人脸识别,并给TCP客户端发送匹配度指数和“start”指令。
# 向TCP服务端发送数据
def senddata(text):
socket_client.send(text.encode())
# 按下“语音启动”按钮
def Start():
print("系统启动")
global face_flag
tts("开始进行语音识别")
while True:
msg = ''
baiduasr.record() # 录音
data = baiduasr.asr_updata() # 语音识别
t = data.split(',') # 字符串分割
print(t)
for i in range(len(t)):
if '系统启动' in t[i]:
tts("开始进行人脸识别.") #语音合成
Name,idnum,Confidence = Face() #调用人脸识别函数
score = str("{0}".format(round(200 - Confidence))) #匹配度指数
tts("您的名字是:" + Name)
#显示人脸图像代码
faceimg = cv2.imread('./image.jpg')
cv2.imshow('image',faceimg)
cv2.waitKey(3000)
cv2.destroyAllWindows() #摧毁窗口
msg = f'{score}'
senddata(msg) #发送发送匹配指数
tts("人脸识别通过")
face_image('image') #将用户人脸放在界面上
face_flag = 1 # 人脸识别标志置1
Label(Frame1_3,text = idnum ,font = ("黑体",15),width = 4 , bg = "#DAE3F3").place(x= 110,y = 150)#ID
Label(Frame1_3,text = Name ,font = ("黑体",15),width = 4 , bg = "#DAE3F3").place(x= 110,y = 200) #姓名
break
if face_flag == 1: #人脸验证通过后可以开始执行订单指令
msg='start'
print(msg)
senddata(msg) #向TCP发送start
break #人脸识别通过后跳出循环
4.数据信息可视化
人工智能系统界面的订单数据可视化功能,要求实现当用户通过语音完成下单后,在订单分布界面能够显示用户向每位摊主的需求总数,按下“订单详情”按钮,能够切换到新的界面,显示每位摊主的4类物料的需求数量。
(1)定义订单数量函数,用于后于语音识别中判断用户输入的语音信息中的订单数量。
def num(text):
if '一' in text:
return '1'
elif '两' in text:
return '2'
elif '三' in text:
return '3'
elif '四' in text:
return '4'
elif '五' in text:
return '5'
else:
return '0'
(2)定义wait_order函数,该函数在主函数中通过开启threading线程来启动,用于等待接受TCP服务端发送过来“xiadingdan”指令,通过开启线程来持续等待,这样才不会导致界面刷新不出来。初始化各个变量,等待接受TCP服务端发送过来“xiadingdan”的指令后,通过语音交互,让用户向三位摊主分别下单。
#人脸验证通过后,等待PLC发送过来'xiadingdan',用户才能语音下单
def wait_order():
global face_flag
while 1:
if face_flag == 1: #只有人脸验证通过后,接收到的PLC下单指令才有用
while (True):
command = socket_client.recv(1024).decode()
print(command)
time.sleep(0.1)
dingdan_list = ["dingdan"] # 初始化订单的值
order = '' # 初始化每个摊主的订单
sum = 0 #摊主个数
No1 = 0
No2 = 0
No3 = 0
need_list = []
need_new = []
fraces = [] # 扇形图的占比初始值
labels = [] # 扇形图的标签初始值
colors = []
if command == 'xiadingdan':
for k in range(3):
tts("请为"+ str(k+1) +"号位摊主下单")
sum +=1 #摊主个数
tts("开始录音")
baiduasr.record() # 录音
data = baiduasr.asr_updata() # 语音识别
t = data.split(',') # 字符串分割
print(t)
label1 = '0' # 每次给新的摊主下订单需要初始化对应变量
label2 = '0'
label3 = '0'
label4 = '0'
for i in range(len(t)):
if '水果' in t[i]:
label1 = num(t[i])
order = f'{label1},{label2},{label3},{label4}' # 输出
elif '蔬菜' in t[i]:
label2 = num(t[i])
order = f'{label1},{label2},{label3},{label4}' # 输出
elif '服装' in t[i]:
label3 = num(t[i])
order = f'{label1},{label2},{label3},{label4}' # 输出
elif '零食' in t[i]:
label4 = num(t[i])
order = f'{label1},{label2},{label3},{label4}' # 输出
else:
order = '0,0,0,0' #如果没有上述物品或者输入错误,则全部置零
dingdan_list.append(order) # 把每一个向摊主下的单组合到列表dingdan_list
(3)把用户的向每一位摊主下的订单信息order,填写到表格中。然后将用户输入订单信息转为列表dingdan_list,获取每一位摊主的订单需求量。例如dingdan_list=[dingdan,[1,0,0,0],[1,1,1,0],[1,1,1,1]],那么No1=1,No2=3,No1=4。设置绘制扇形图需要的各个变量,这里调用draw_pie函数,其参数frame,colors,fraces,为列表类型,labels为元组类型。
# 填写相关信息到表格
max_row1 = sheet1.max_row # 获取该表格最大行行数
#将表格中的内容为order的值, order为字符串 '0,0,0,0' ,字符长度是6
sheet1.cell(max_row1+1,1).value = str(sum) # 填写到“序号”一栏
sheet1.cell(max_row1+1,2).value = str(sum) + "号" # 填写到“摊主”一栏
sheet1.cell(max_row1+1,3).value = order[0] # 填写到“水果”一栏
sheet1.cell(max_row1+1,4).value = order[2] # 填写到“蔬菜”一栏
sheet1.cell(max_row1+1,5).value = order[4] # 填写到“零食”一栏
sheet1.cell(max_row1+1,6).value = order[6] # 填写到“服装”一栏
sheets.save("Data.xlsx") # 保存表格
#将每个摊位的元素相加,得到总数!
print(dingdan_list)
No1 = int(dingdan_list[1][0]) + int(dingdan_list[1][2]) + int(dingdan_list[1][4]) + int(dingdan_list[1][6]) #1号摊主需求量
No2 = int(dingdan_list[2][0]) + int(dingdan_list[2][2]) + int(dingdan_list[2][4]) + int(dingdan_list[2][6]) #2号摊主需求量
No3 = int(dingdan_list[3][0]) + int(dingdan_list[3][2]) + int(dingdan_list[3][4]) + int(dingdan_list[3][6]) #3号摊主需求量
#print("No1,No2,No3:",No1,No2,No3)
#将各个摊主及其需求量和扇形图对应颜色组合到列表
need_list = [["1号",No1, "#63A0DB"], ["2号",No2 , "#FFC727"] , ["3号" , No3 , "#20EA37" ] ]
#以下操作是为了剔除占比为需求量为0的那部分,需求量为0则不显示在扇形图上
for k in need_list:
if k[1]== 0: #提取列表索引为0的值
continue #不做处理
else:
need_new.append(k) #把值不为0的部分拼接起来,例如[["1号摊主",No1, "#63A0DB"],["2号",No2 , "#FFC727"] ]
for k in need_new: #遍历列表,获得每一个扇形函数的参数,labels参数是标签,fraces是扇形的占比,colors对应的颜色
labels.append(k[0]) # 获取摊主对应的列表
fraces.append(k[1]) # 获取需求量对应占比的列表
colors.append(k[2]) # 获取摊主对应颜色的列表
labels = tuple(labels) # 转为元组,获取摊主对应标签 labels = ("1号","2号","3号")
#print(labels,fraces,colors)
draw_pie(Frame2_1,labels,fraces,colors) # 画扇形图
pie_image() # 扇形图显示函数
Label(Frame2_1,text = str(No1)+ "个", font = ("微软雅黑",12), bg = "#63A0DB" , width = 4 , height = 2 , anchor = 'w').place(x= 160,y = 150)
Label(Frame2_1,text = str(No2)+ "个", font = ("微软雅黑",12), bg = "#FFC727" , width = 4 , height = 2 , anchor = 'w').place(x= 160,y = 250)
Label(Frame2_1,text = str(No3)+ "个", font = ("微软雅黑",12), bg = "#20EA37" , width = 4 , height = 2 , anchor = 'w').place(x= 160,y = 350)
#循环3次后发送最终订单 例如[dingdan,1,0,0,0,0,1,0,0,0,0,1,0]
msg = ",".join(dingdan_list) # 列表转字符串 "dingdan,1,0,0,0,0,1,0,0,0,0,1,0"3
senddata(msg) #发送最终订单
face_flag = 0 #标志位置0
(4)定义扇形图形式函数。该函数用于将生成的扇形图片展示在Frame框架上。
# 扇形图显示函数,所有的扇形图图片显示的时候可以加载这个函数
def pie_image():
global photo3 # 一定要将photo设置成全局变量不然调用显示不出来
# 初始化的图片使用PIL库来加载图像
photo_open3 = Image.open('./pie.png') # 打开扇形图片
photo3 = photo_open3.resize((350 , 350)) # 图片尺寸
photo3 = ImageTk.PhotoImage(photo3)
Label(Frame2_1,image=photo3).place(x= 220,y = 100) # 放置图像
(5)定义draw_pie函数,利用matplotlib模块画扇形图,最后将生成的扇形图片通过savefig()方法保存到与GUI_3.py同目录下,并命名为“pie.png”
# matplotlib模块画扇形图
def draw_pie(frame,labels,fraces , colors):
# Figure创建图像对象,figsize指定画布的大小,(宽度,高度),单位为英寸。
# dpi 指定绘图对象的分辨率,即每英寸多少个像素,默认值为80
fig = Figure(figsize=(4, 4), dpi=100)
# subplot()均等划分画布,如果不想覆盖之前的图,需要使用 add_subplot() 函数
drawPic_a = fig.add_subplot(111)
# 解决汉字乱码问题,使用指定的汉字字体类型(此处为黑体)
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
# 绘制pie()饼状图:labels为每个扇形区域备注一个标签名字,autopct格式化字符串"fmt%pct",百分比格式
drawPic_a.pie(x=fraces, labels=labels, colors = colors , autopct='%0.2f%%')
drawPic_a.set_title('订单分布图') #饼状图命名
fig.savefig('pie.png') # 将扇形图保存到文件夹下
(6)定义订单详情画面,使用Treeview来呈现表格内容。用户按下初始界面的“订单详情”按钮后,能够切换到另外一个框架(Frame4)的组成画面,该画面放置TreeView组件,是一个树状结构和表格的结合体。第一列是树状结构,后几列是列表。创建表格对象tree,第一列为序号,后面几列分别为“摊位”“水果”“蔬菜”“服装”“零食”。用户下单后会将订单信息保存到“Data.xlsx”表格中,在data_monitorh函数中调用“Data.xlsx”工作表的内容,遍历每一行(每一位摊主),获取每一行中各列(4大类物料)的数量,然后通过使用Treeview来呈现表格内容数据。
#订单详情画面,使用Treeview来呈现表格内容
def data_monitor():
print("订单详情")
Frame2_1.pack_forget() # 隐藏Frame3的组件,pack_forget()方法让控件“不再显示”但控件还存在可以再次pack出来
Frame4 = Frame(Frame2,bg="White",height=500,width=600)
Frame4.place(x = 50 , y = 100)
Button(Frame4,text = "返回统计图",bg = "#C1FFC1",font = ("黑体",15),width = 12,height=2, command = Frame4.place_forget).place(x=450,y=430) #返回统计按钮
# 表格。建立标题
tree = ttk.Treeview(Frame4) # 创建表格对象
tree["columns"] = ("序号","摊位","水果","蔬菜","服装","零食") # 定义列
tree.column("序号" , width = 60 ) # 宽度
tree.column("摊位" , width = 60 )
tree.column("水果" , width = 60 )
tree.column("蔬菜" , width = 60 )
tree.column("服装" , width = 60 )
tree.column("零食" , width = 60 )
tree.heading("#0" , text = "序号") # 表格标题
tree.heading("#1" , text = "摊位")
tree.heading("#2" , text = "水果")
tree.heading("#3" , text = "蔬菜")
tree.heading("#4" , text = "服装")
tree.heading("#5" , text = "零食")
tree.place(x=20,y=50)
max_row1 = sheet1.max_row # 获取该表格最大行行数
max_column1 = sheet1.max_column # 获取该表格最大列列数
for i in range(2,max_row1+1): # 从表格第2行开始遍历
b = [] # 设空列表
for j in range(1,max_column1+1): # 遍历每一列,获取每一行的列内容
a = sheet1.cell(i,j).value # 获取每一个单元格的值,
b.append(a) # 字符串转列表
del(b[0]) # 删除第一个序号
tree.insert("", index = END , text = i-1,values=b) # 加载到表格上,text是序号,values是序号后的内容
tree.place(x=20,y=50)
(7)主函数程序设计。增加人脸识别初始标志,创建TCP客户端。使用openpyxl.Workbook()创建工作薄,命名为“Data.xlsx”,然后加载打开表格,在表格第一行的前6列写入相关内容。然后开启线程,用于接收发送过来PLC的指令,更新到界面。
if __name__ == '__main__':
# 创建全局变量
face_flag = 0 #人脸识别标志
global command
# 创建socket客户端变量
socket_client = ''
socket_client = socket.socket()
socket_client.connect(('127.0.0.1',2005))
# 创建一个新表格,用于存储人员信息,每次打开都覆盖原来的表格
workbook = openpyxl.Workbook() # 创建一个工作薄
worksheet = workbook.active # 在工作薄中创建一个工作表
workbook.save("Data.xlsx") # 保存表格到对应路径
# 打开工作表
sheets = openpyxl.load_workbook("Data.xlsx")
# 在表格第一行填写内容
sheet1 = sheets[sheets.sheetnames[0]]
sheet1.cell(1, 1).value = "序号"
sheet1.cell(1, 2).value = "摊位"
sheet1.cell(1, 3).value = "水果"
sheet1.cell(1, 4).value = "蔬菜"
sheet1.cell(1, 5).value = "服装"
sheet1.cell(1, 6).value = "零食"
sheets.save("Data.xlsx") # 保存表格
# 开启线程,用于接收发送过来PLC的指令,更新到界面
thread = threading.Thread(target=wait_order) #定义wait_order函数,等待接受
thread.daemon = True
thread.start()
(8)主程序界面设计。创建窗口,设置窗口的相关属性。
# 人脸训练集路径
path = './Facedata/'
#主界面程序
top = Tk()
top.title("越疆科技")
top.geometry("1200x700")
top.configure(bg = "#F8CBAD") # 窗口背景颜色
# 大标题
Label(top ,text = "人工智能机器人系统集成及应用平台",font = ("宋体",18),fg = "black",bg = "#F8CBAD",width = 35,height = 2).place(x=440,y = 0)
(9)界面放置人脸信息验证的框架Frame1,在Frame1布置3个小框架,分别用于放置人脸采集、训练、识别的按钮或文本框等组件。各个框架中的按钮通过参数command绑定对应的执行函数。
#在第一个框架再里面放置3个框架Frame1_1、Frame1_2、Frame1_3,用于人脸采集、训练、识别
#在第一个框架再里面放置第1个框架
Frame1_1 = Frame(Frame1,bg="#DAE3F3",height=150,width=300)
Frame1_1.place(x = 25 , y = 25)
#利用StringVar接收用户ID输入
var_ID = StringVar()
id = Entry(Frame1_1,textvariable=var_ID, font=('黑体', 13) , width=15) #输入框
id.place(x=100,y=25)
Label(Frame1_1 ,text = "用户ID",font = ("黑体",13),bg = "#DAE3F3", width = 8 ).place(x=20,y=25)
#利用StringVar接收用户姓名输入
var_name = StringVar()
name = Entry(Frame1_1,textvariable=var_name, font=('黑体', 13) , width=15) #输入框
name.place(x=100,y=75)
Label(Frame1_1 ,text = "用户姓名",font = ("黑体",13),bg = "#DAE3F3", width = 8 ).place(x=20,y=75)
#采集、清除按钮
Button(Frame1_1,text = "采集",bg = "#836FFF",font = ("黑体",13),width = 10,command = register).place(x=35,y=110)
Button(Frame1_1,text = "清除",bg = "#836FFF",font = ("黑体",13),width = 10,command = lambda : clear(id,name)).place(x=165,y=110)
#在第一个框架再里面放置第2个框架
Frame1_2 = Frame(Frame1,bg="#DAE3F3",height=100,width=300)
Frame1_2.place(x = 25 , y = 200)
#利用StringVar接收用户输入的模型名称
var_moudle1 = StringVar()
moudle_name1 = Entry(Frame1_2,textvariable=var_moudle1, font=('黑体', 13) , width=15) #输入框
moudle_name1.place(x=100,y=15)
Label(Frame1_2 ,text = "模型名称",font = ("黑体",13),bg = "#DAE3F3", width = 8 ).place(x=20,y=15)
#训练、清除按钮
Button(Frame1_2,text = "训练",bg = "#836FFF",font = ("黑体",13),width = 10,command = Train).place(x=35,y=60)
Button(Frame1_2,text = "清除",bg = "#836FFF",font = ("黑体",13),width = 10,command = lambda : moudle_name1.delete(0,END)).place(x=165,y=60)
#在第一个框架再里面放置第3个框架
Frame1_3 = Frame(Frame1,bg="#DAE3F3",height=275,width=300)
Frame1_3.place(x = 25 , y = 325)
#绘制画布,用于显示信息画布背景为白色
face_image('face') # 初始化人脸图像
#识别用户姓名
Label(Frame1_3 ,text = "用户ID:",font = ("黑体",13),bg = "#DAE3F3", width = 9 ).place(x=20,y=150)
Label(Frame1_3 ,text = "用户姓名:",font = ("黑体",13),bg = "#DAE3F3", width = 9 ).place(x=20,y=200)
#识别、清除按钮
Button(Frame1_3,text = "识别",bg = "#836FFF",font = ("黑体",13),width = 10,command = face_recognition).place(x=35,y=235)
Button(Frame1_3,text = "注销",bg = "#836FFF",font = ("黑体",13),width = 10,command = face_logout).place(x=165,y=235)
(10)界面放置订单详情框架Frame2。放置“语音启动”“退出系统”按钮,放置摊主详情的Lable文字组件。
# 第二个框架:订单信息部分
Frame2 = Frame(top,bg="#B4C7E7",height=625,width=700)
Frame2.place(x = 450 , y = 50)
#系统启动\订单详情按钮
Button(Frame2,text = "语音启动",bg = "#C1FFC1",font = ("黑体",15),width = 12,height=2,command = Start).place(x=150,y=20)
Button(Frame2,text = "退出系统",bg = "#C1FFC1",font = ("黑体",15),width = 12,height=2,command = top.destroy).place(x=400,y=20)
#在Frame2框架再里面放置1个框架
Frame2_1 = Frame(Frame2,bg="white",height=500,width=600)
Frame2_1.place(x = 50 , y = 100)
Label(Frame2_1,text = "订单分布图 ", font = ("微软雅黑",15), bg = "white" , width = 18 , height = 2 ).place(x= 200,y = 10)
Label(Frame2_1,text = "1号摊位需求量: ", font = ("微软雅黑",12), bg = "#63A0DB" , width = 15 , height = 2 ).place(x= 20,y = 150)
Label(Frame2_1,text = "2号摊位需求量: " , font = ("微软雅黑",12), bg = "#FFC727" , width = 15 , height = 2 ).place(x= 20,y = 250)
Label(Frame2_1,text = "3号摊位需求量: " , font = ("微软雅黑",12), bg = "#20EA37" , width = 15 , height = 2 ).place(x= 20,y = 350)
Button(Frame2_1,text = "订单详情",bg = "#C1FFC1",font = ("黑体",15),width = 12,height=2, command = data_monitor).place(x=30,y=430) #返回统计按钮
top.mainloop() #消息循环
五、运行效果
(1)人脸信息验证
依次在界面左边栏目中按照人脸采集、模型训练、人脸识别的顺序来完成人脸信息验证,如下图所示。
(2)语音交互
点击“语音启动”按钮,系统通过语音合成“开始进行语音识别”,通过麦克风说出“系统启动”,然后系统提示“开始进行人脸识别”,人脸验证通过后,可以在界面看到拍摄的人脸图像和对用的ID、姓名。同时,TCP服务端接受到发送的匹配指数和“start”指令。利用TCP客户端发送“xiadingdan”指令,如所示。系统提示分别向3位摊主下订单,例如向1号摊主下单“我要一个水果”,向2号摊主下单“我要一份蔬菜,一个服装。”,向3号摊主下单“我要一个零食”,下单完成后,生成订单列表[‘dingdan’, ‘1,0,0,0’, ‘1,1,1,0’, ‘1,1,1,1’],将发送给TCP服务端。同时,界面将展示订单分布的扇形图。点击“订单详情”按钮。可以看到用户向每位摊主的具体订单列表。