GUI库PySimpleGUI
1. 简介
图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)是指采用图形方式显示的计算机操作用户界面。图形用户界面是一种人与计算机通信的界面显示格式,允许用户使用鼠标等输入设备操纵屏幕上的图标或菜单选项,以选择命令、调用文件、启动程序或执行其它一些日常任务。用户界面通常包括许多视觉元素,如图标、按钮、图形、显示文本和多种输入控件,如复选框、文本输入框等。如何给AI应用程序编写一个图形用户界面?那么就需要选择一个简单好用的GUI开发工具。
Python作为一个容易上手,简单方便的开源编程语言,第三方的开发工具数不胜数,在GUI这个方向同样有很多的工具可以选择。比较常用的GUI开发工具有Tkinter、PyQt、wxPython、Gtk+、Kivy、FLTK和OpenGL等,其中最常用是Tkinter。Tkinter的优点在于是Python内置标准库,无需额外安装,兼容性好,但缺点在于实现效果较为普通,开发体验不好。比较受程序员推崇的是PyQt和wxPython,功能强大,界面优美,相关教程也很多,可惜学习曲线有些陡峭。在比较了多款GUI开发工具之后,我们最终推荐使用PySimpleGUI。
PySimpleGUI的优势还在于其内置了多个GUI框架。目前已经集成了tkinter、PyQt、wxPython和 Remi等四种。其中Remi是一个Web界面开发库。如果想要将普通的GUI界面更换为Web界面,只要将前面的导入库“import PySimpleGUI as sg”一句改为“import PySimpleGUIWeb as sg”,其他代码都不需要改变,体现了“一次编写、处处运行”的理念。
本文涉及的部分代码见XEdu帮助文档配套项目集:https://www.openinnolab.org.cn/pjlab/project?id=64f54348e71e656a521b0cb5&sc=645caab8a8efa334b3f0eb24#public
PySimpleGUI
底层框架: 使用的是 Python 的标准 GUI 库
tkinter作为其底层实现。目标平台: 桌面环境。通过它,你可以轻松地为 Windows、Mac 和 Linux 创建原生应用程序。
特点:
简单的 API,允许快速构建应用程序。
提供了大量的小部件,如按钮、文本框、列表框等。
可以轻松地与其他 Python 库集成。
官方GitHub仓库地址:https://github.com/PySimpleGUI/PySimpleGUI
PySimpleGUIWeb
底层框架: 使用
Remi作为其底层实现,它是一个 Python GUI 库,允许你创建的 GUI 在 web 浏览器中运行。目标平台: Web 浏览器。它旨在为那些想要一个简单的方法来创建 web 应用程序的开发者提供解决方案。
特点:
不需要深入了解 web 开发或 HTML/CSS/JavaScript 的知识。
可以在任何支持的浏览器中运行,无需客户端安装。
API 与其他
PySimpleGUI版本相似,使得从桌面应用迁移到 web 应用变得简单。
官方GitHub仓库地址:https://github.com/PySimpleGUI/PySimpleGUI/tree/master/PySimpleGUIWeb
选择PySimpleGUI还是PySimpleGUIWeb?
在选择使用哪个版本之前,你应该首先确定你的应用程序的需求。如果你需要一个轻量级的桌面应用程序,PySimpleGUI 可能是更好的选择。如果你希望你的应用程序可以在浏览器中运行,那么 PySimpleGUIWeb 更适合。
3.示例代码
以下是一个基本的 PySimpleGUI 示例:
# 导入库
import PySimpleGUI as sg
# 设计窗体布局,用列表来定义每一个元素。
layout = [
[sg.Text('请输入你的名字:')],
[sg.Input(key='in')],
[sg.Button('确认'), sg.Button('取消')],
[sg.Text('输出:'), sg.Text(key='out')]
]
# 创建窗体
window = sg.Window('PySimpleGUI 范例', layout)
# 监视窗体的事件,并响应。
while True:
# event为按钮的名称,values为一个字典
event, values = window.read()
print(event,values)
if event in (None, '取消'):
window['in'].update('')
window['out'].update('')
else:
if values:
s = '欢迎你,' + values['in']
window['out'].update(s)
# 关闭窗体
window.close()
上面这段代码一个简单的PySimpleGUI应用程序,它创建了一个包含文本和按钮的窗口。当用户点击”确定”按钮或关闭窗口时,程序将结束。这段代码中最核心的部分在于窗体设计和窗体事件控制部分。其中“window.read()”返回的信息中,event为按钮的名称,values则为一个字典,键名是控件的名称。仔细观察PySimpleGUI代码,会发现和Arduino、掌控板之类开源硬件程序的运行逻辑非常类似——用一个无限循环来处理输入和输出窗体事件。该代码的运行效果如下,界面样式中规中矩,看起来并不丑。

4. 借助PySimpleGUI部署简易AI应用
只需准备好模型后,使用PySimpleGUI创建一个带GUI的简单AI应用。考虑到计算机视觉(CV)方向的模型都需要结合摄像头,界面中得显示实时画面,那就需要借助Image类型的对象,然后在窗体事件控制部分中实时更新画面。
示例1:带窗体的摄像头实时推理的程序(图像分类)
下面是一段使用PySimpleGUIWeb与OpenCV来显示实时的摄像头图像并对其进行实时推理。在推理过程中,使用的是ONNX模型,推理的代码是借助XEdu团队推出的模型部署工具BaseDeploy,代码较为简洁。关于基于MMEdu训练的模型转换为ONNX的说明可见最后一步:AI模型转换与部署。
# 带窗体的摄像头程序,自动推理
# 模型为1000分类预训练模型(MobielNet)
import PySimpleGUIWeb as sg
from XEdu.hub import Workflow as wf
import cv2
model = wf(task='cls_imagenet')
def my_inf(frame):
result1 = model.inference(frame)
result2 = model.format_output()
return result2
#背景色
sg.theme('LightGreen')
#定义窗口布局
layout = [
[sg.Image(filename='', key='image',size=(600, 400))],
[sg.Button('关闭', size=(20, 1))],
[sg.Text('推理结果:',key='res')]
]
#窗口设计
window = sg.Window('OpenCV实时图像处理',layout,size=(600, 500))
#打开内置摄像头
cap = cv2.VideoCapture(1)
while True:
event, values = window.read(timeout=0, timeout_key='timeout')
#实时读取图像,重设画面大小
ret, frame = cap.read()
imgSrc = cv2.resize(frame, (600,400))
res = my_inf(frame)
if res:
print('推理结果为:',res)
window['res'].update('推理结果:'+res['预测类别'])
#画面实时更新
imgbytes = cv2.imencode('.png', imgSrc)[1].tobytes()
window['image'].update(data=imgbytes)
if event in (None, '关闭'):
break
# 退出窗体
cap.release()
window.close()
示例2:带窗体的摄像头实时推理的程序(目标检测)
一般来说,目标检测的代码会在推理画面上显示检测出来的目标,并且绘制一个矩形。因而,BaseDeploy的推理函数会返回识别后的画面。
# 带窗体的摄像头程序,自动推理
# 模型为80类目标检测预训练模型(SSD_Lite)
import PySimpleGUIWeb as sg
from XEdu.hub import Workflow as wf
import cv2
model = wf(task='mmedu',checkpoint='det.onnx')
def my_inf(frame):
global model
res1, img = model.inference(frame,img_type='cv2')
# 转换推理结果
res2 = model.format_output()
if len(res2) == 0:
return None,None
classes = []
print(res2)
# 提取预测结果
for res in res2:
classes.append(res['预测值'])
return str(classes),img
#背景色
sg.theme('LightGreen')
#定义窗口布局
layout = [
[sg.Image(filename='', key='image',size=(600, 400))],
[sg.Button('关闭', size=(20, 1))],
[sg.Text('推理结果:',key='res')]
]
# 建立窗体
window = sg.Window('OpenCV实时图像处理',layout,size=(600, 500))
#打开摄像头
cap = cv2.VideoCapture(0)
while True:
event, values = window.read(timeout=0, timeout_key='timeout')
if event in (None, '关闭'):
break
# 实时读取图像
ret, frame = cap.read()
res, img = my_inf(frame)
if res:
window['res'].update('推理结果:'+res)
newimg = img
else:
newimg = frame
# 实时更新画面
newimg = cv2.resize(newimg, (600,400))
imgbytes = cv2.imencode('.png', newimg)[1].tobytes()
window['image'].update(data=imgbytes)
# 退出窗体
cap.release()
window.close()