1 Star 0 Fork 2

Ce/Smart Restaurant Pricing System based on YOLOv7

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
main.py 50.93 KB
一键复制 编辑 原始数据 按行查看 历史
Ce 提交于 2023-03-31 23:07 . add all files
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173
import sys
import threading
import ctypes
import time
import cv2
import os
import shutil # 复制文件
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID("myappid")
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QIcon, QImage
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QDialog
from PyQt5 import QtCore, QtGui, QtWidgets
from gui_module import warn, instruction, change_info, login_window, home_window
from yolov7_module.yolo_test import detector, model_path
from alipay_module.alipay_test import order_alipay
from db_module.mysql_test import database
# 默认路径
model_path = os.getcwd() + "\\" + model_path # YOLO配置文件相对于项目根目录的位置,从yolo.py文件引用来
log_dir_path = os.getcwd() + "\\log\\"
tmp_dir_path = os.getcwd() + "\\tmp\\"
# 权限列表
permission_list = ["visitor", "user", "administrator"]
# yolo算法的引用
yolo = detector()
# 测试FPS
TEST_FPS = True
# 展示
def show_message(message):
# QMessageBox.information(self, "提示", message, QMessageBox.Ok)
warn_window = myWarn()
warn_window.label_warninfo.setText(message)
warn_window.exec_()
def is_float(s):
s = str(s)
if s.isdigit():
return True
if s.count('.') == 1:
left = s.split('.')[0]
right = s.split('.')[1]
if right.isdigit():
if left.count('-') == 1 and left.startswith('-'):
num = left.split('-')[-1]
if num.isdigit():
return True
elif left.isdigit():
return True
return False
# 更改信息页面
class myChange(change_info.Ui_Dialog, QDialog):
def __init__(self):
super(change_info.Ui_Dialog, self).__init__()
super().__init__()
# 设置窗体无边框
self.setWindowFlags(Qt.FramelessWindowHint)
# 设置背景透明
self.setAttribute(Qt.WA_TranslucentBackground)
# 鼠标拖动初始化函数
self.mouseMoveInit()
# 任务栏相关
self.setWindowTitle('基于YOLOv7的智慧餐厅系统')
self.setupUi(self)
icon = QIcon()
icon.addPixmap(QPixmap(":/新前缀/gui_images/logo.png"), QIcon.Normal, QIcon.Off)
self.setWindowIcon(icon)
self.pushButton_save.clicked.connect(self.save)
self.pushButton_close.clicked.connect(self.close)
self.pushButton_model.clicked.connect(self.choose_model)
self.pushButton_log.clicked.connect(self.choose_log)
self.pushButton_tmp.clicked.connect(self.choose_tmp)
self.username = ""
self.password = ""
self.userid = 0
self.version = 0
self.db = None
self.lineEdit_model.setText(model_path)
self.lineEdit_log.setText(log_dir_path)
self.lineEdit_tmp.setText(tmp_dir_path)
self.lineEdit_model.setEnabled(False)
self.lineEdit_tmp.setEnabled(False)
self.lineEdit_log.setEnabled(False)
def update_user_info(self):
user_tuple = self.db.select_one("userid = " + str(self.userid))
self.username = user_tuple[1]
self.password = user_tuple[2]
self.version = user_tuple[5]
def choose_model(self):
if self.pushButton_model.text() == "选择": # 修改模型页面
filename, filetype = QFileDialog.getOpenFileName(self, "请选择模型配置文件", "", "*.yaml")
if filename == "":
show_message("请选择后缀名为.yaml的配置文件")
else:
self.lineEdit_model.setText(f"{filename}")
else: # 修改用户信息页面
self.lineEdit_model.setEnabled(True)
def choose_log(self):
if self.pushButton_model.text() == "选择": # 修改模型页面
filename = QFileDialog.getExistingDirectory(self, "请选择日志文件保存文件夹")
if filename == "":
show_message("请选择文件夹")
else:
self.lineEdit_log.setText(f"{filename}")
else: # 修改用户信息页面
self.lineEdit_log.setText("")
self.lineEdit_log.setEnabled(True)
self.label_10.setText("请输入原密码")
self.frame_14.setVisible(True)
self.lineEdit_tmp.setText("")
self.lineEdit_tmp.setEnabled(True)
def choose_tmp(self):
filename = QFileDialog.getExistingDirectory(self, "请选择临时文件保存文件夹")
if filename == "":
show_message("请选择文件夹")
else:
self.lineEdit_tmp.setText(f"{filename}")
def save(self):
if self.title.text() == "系统设置":
global model_path
global log_dir_path
global tmp_dir_path
model_path = self.lineEdit_model.text()
log_dir_path = self.lineEdit_log.text()
tmp_dir_path = self.lineEdit_tmp.text()
yolo.changeModel(model_path)
else:
# 修改用户名
if self.lineEdit_model.text() == "":
show_message("请输入用户名!")
self.lineEdit_model.setText(self.username)
self.lineEdit_model.setEnabled(False)
return
elif self.lineEdit_model.text() != self.username: # 用户名改变
find_ret = self.db.select_one("username = '" + self.lineEdit_model.text() + "'")
if find_ret is None:
while True: # 乐观锁插入
ret = self.db.update(
{"username": "'" + self.lineEdit_model.text() + "'", "version": self.version + 1},
"userid = " + str(self.userid) + " and version = " + str(self.version))
if ret["status"] == "success":
self.lineEdit_model.setEnabled(False)
self.version += 1
break
else:
self.update_user_info()
else:
show_message("已存在该用户名,请重新输入!")
self.lineEdit_model.setText(self.username)
self.lineEdit_model.setEnabled(False)
return
# 修改密码
if self.lineEdit_log.text() == self.password: # 原始密码正确
if self.frame_14.isVisible(): # 已经点击修改密码
if self.lineEdit_tmp.text() == "": # 输入新密码为空
show_message("请输入新密码!")
return
else: # 执行更新密码操作
while True:
ret = self.db.update(
{"password": "'" + self.lineEdit_tmp.text() + "'", "version": self.version + 1},
"userid = " + str(self.userid) + " and version = " + str(self.version))
if ret["status"] == "success":
self.version += 1
self.password = self.lineEdit_log.text()
self.lineEdit_log.setEchoMode(QtWidgets.QLineEdit.Password)
self.lineEdit_log.setText(self.password)
self.frame_14.setVisible(False)
break
else:
self.update_user_info()
else:
pass
else:
show_message("请输入正确的原密码!")
return
show_message("保存成功!")
# 鼠标拖动相关
def mouseMoveInit(self):
self.m_flag = False
self.m_Position = None
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton and self.isMaximized() == False:
self.m_flag = True
self.m_Position = event.globalPos() - self.pos() # 获取鼠标相对窗口的位置
event.accept()
self.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor)) # 更改鼠标位置
def mouseMoveEvent(self, event):
if QtCore.Qt.LeftButton and self.m_flag:
self.move(event.globalPos() - self.m_Position) # 更改窗口位置
event.accept()
def mouseReleaseEvent(self, event):
self.m_flag = False
self.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
# 系统介绍UI
class myInstruction(instruction.Ui_Dialog, QDialog):
def __init__(self):
super(instruction.Ui_Dialog, self).__init__()
super().__init__()
# 设置窗体无边框
self.setWindowFlags(Qt.FramelessWindowHint)
# 设置背景透明
self.setAttribute(Qt.WA_TranslucentBackground)
# 鼠标拖动初始化函数
self.mouseMoveInit()
# 任务栏相关
self.setWindowTitle('基于YOLOv7的智慧餐厅系统')
self.setupUi(self)
icon = QIcon()
icon.addPixmap(QPixmap(":/新前缀/gui_images/logo.png"), QIcon.Normal, QIcon.Off)
self.setWindowIcon(icon)
self.pushButton_confirm.clicked.connect(self.confirm)
self.pushButton_close.clicked.connect(self.close)
def confirm(self):
self.close()
# 鼠标拖动相关
def mouseMoveInit(self):
self.m_flag = False
self.m_Position = None
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton and self.isMaximized() == False:
self.m_flag = True
self.m_Position = event.globalPos() - self.pos() # 获取鼠标相对窗口的位置
event.accept()
self.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor)) # 更改鼠标位置
def mouseMoveEvent(self, event):
if QtCore.Qt.LeftButton and self.m_flag:
self.move(event.globalPos() - self.m_Position) # 更改窗口位置
event.accept()
def mouseReleaseEvent(self, event):
self.m_flag = False
self.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
# 提示框UI
class myWarn(warn.Ui_Dialog, QDialog):
def __init__(self):
super(warn.Ui_Dialog, self).__init__()
super().__init__()
# 设置窗体无边框
self.setWindowFlags(Qt.FramelessWindowHint)
# 设置背景透明
self.setAttribute(Qt.WA_TranslucentBackground)
# 鼠标拖动初始化函数
self.mouseMoveInit()
# 任务栏相关
self.setWindowTitle('基于YOLOv7的智慧餐厅系统')
self.setupUi(self)
icon = QIcon()
icon.addPixmap(QPixmap(":/新前缀/gui_images/logo.png"), QIcon.Normal, QIcon.Off)
self.frame_5.setVisible(False)
self.pushButton_cancel.setVisible(False)
self.setWindowIcon(icon)
self.pushButton_confirm.clicked.connect(self.confirm)
self.pushButton_close.clicked.connect(self.close_window)
self.pushButton_cancel.clicked.connect(self.cancel)
self.stopLoadingEvent = threading.Event()
self.stopLoadingEvent.clear()
self.password = ""
self.isCancer = False
def confirm(self):
if self.title.text() == "余额支付":
if self.lineEdit.text() == self.password:
self.stopLoadingEvent.set()
else:
tmp_str = self.label_warninfo.text()
self.label_warninfo.setText("密码错误!")
elif self.title.text() == "在线充值":
tmp_str = self.label_warninfo.text()
if self.lineEdit.text() == "":
self.label_warninfo.setText("请输入要充值的数值!")
elif is_float(self.lineEdit.text()):
if float(self.lineEdit.text()) <= 0:
self.label_warninfo.setText("请输入正数!")
else:
self.stopLoadingEvent.set()
else:
self.label_warninfo.setText("请输入数字!")
else:
self.close()
def close_window(self):
self.lineEdit.setText("")
self.stopLoadingEvent.set()
self.close()
def cancel(self):
self.stopLoadingEvent.set()
self.isCancer = True
# 鼠标拖动相关
def mouseMoveInit(self):
self.m_flag = False
self.m_Position = None
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton and self.isMaximized() == False:
self.m_flag = True
self.m_Position = event.globalPos() - self.pos() # 获取鼠标相对窗口的位置
event.accept()
self.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor)) # 更改鼠标位置
def mouseMoveEvent(self, event):
if QtCore.Qt.LeftButton and self.m_flag:
self.move(event.globalPos() - self.m_Position) # 更改窗口位置
event.accept()
def mouseReleaseEvent(self, event):
self.m_flag = False
self.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
# 基础UI对应文件中的UI_MainWindow类
class myHome(home_window.Ui_Form, QMainWindow):
def __init__(self):
super(home_window.Ui_Form, self).__init__()
super().__init__()
self.setupUi(self) # 自启动
# 设置窗体无边框
self.setWindowFlags(Qt.FramelessWindowHint)
# 设置背景透明
self.setAttribute(Qt.WA_TranslucentBackground)
# 鼠标拖动初始化函数
self.mouseMoveInit()
# 任务栏相关
self.setWindowTitle('基于YOLOv7的智慧餐厅系统')
icon = QIcon()
icon.addPixmap(QPixmap(":/新前缀/gui_images/logo.png"), QIcon.Normal, QIcon.Off)
self.setWindowIcon(icon)
# 设置信号与槽
self.pushButton_set.clicked.connect(self.window_set)
self.pushButton_min.clicked.connect(self.window_min)
self.pushButton_max.clicked.connect(self.window_max)
self.pushButton_close.clicked.connect(self.window_close)
self.pushButton_use.clicked.connect(self.use_instruction)
self.pushButton_file.clicked.connect(self.file_detection)
self.pushButton_photo.clicked.connect(self.photo_detection)
self.pushButton_realtime.clicked.connect(self.realtime_detection)
self.pushButton_recharge.clicked.connect(self.recharge)
self.pushButton_start.clicked.connect(self.start_detection)
self.pushButton_stop.clicked.connect(self.stop_detection)
self.pushButton_photoopen.clicked.connect(self.open_images)
self.pushButton_vedioopen.clicked.connect(self.open_vedio)
self.pushButton_cameraopen.clicked.connect(self.open_camera)
self.pushButton_cameraclose.clicked.connect(self.close_camera)
self.pushButton_phototake.clicked.connect(self.take_photo)
self.pushButton_alipay.clicked.connect(self.use_alipay)
self.pushButton_balancepay.clicked.connect(self.use_balance)
self.pushButton_username.clicked.connect(self.change_username)
# 创建一个关闭工作事件和关闭摄像机事件并设为未触发
self.stopworkEvent = threading.Event()
self.stopworkEvent.clear()
self.stopcameraEvent = threading.Event()
self.stopcameraEvent.clear()
self.stoppayEvent = threading.Event()
self.stoppayEvent.clear()
# 初始化属性
self.isPaying = False
self.isCameraWorking = False
self.isModelWorking = False
self.isRecharging = False
self.alipay = order_alipay()
# 用户信息
self.userid = 0
self.username = "游客"
self.password = ""
self.permission = ""
self.money = 0
self.version = 0 # 乐观锁实现,保证数据同步
# 数据库
self.db = database()
db_conn_result = self.db.init()
self.add_log("连接数据库结果为:" + str(db_conn_result)) # 显示数据库初始化结果
self.initAttribution()
# 显示和可使用相关
self.stackedWidget.setVisible(False)
self.pushButton_stop.setEnabled(False)
self.pushButton_start.setEnabled(False)
# 初始化大多数属性和UI界面展示信息
def initAttribution(self):
# 初始化属性
self.filename = ""
self.filetype = ""
self.frame_before = None # 上一张显示在Label中的原图(cv2读取
self.frame_after = None # 上一张显示在Label中的处理后的图像(cv2读取
self.now = None # 存放当前处理的对象
self.detection_result = None # 存储餐盘识别结果
self.price = 0 # 存储结算价格
self.out = None # 存储当前检测结果的文件
self.out_filename = "" # 存储当前检测结果的临时文件名
self.isCamera = False # 标志是否为实时监测,True为是
self.trade_isFinished = False # 标志是否交易是否结束
self.label_imgafter.clear()
self.label_imgbefore.clear()
# # 中止可能进行的所有线程
if self.isModelWorking:
self.stopworkEvent.set()
if self.isCameraWorking:
self.stopcameraEvent.set()
if self.isPaying:
self.stoppayEvent.set()
# 界面显示相关
self.stackedWidget_2.setCurrentIndex(0)
self.pushButton_stop.setEnabled(False)
self.pushButton_start.setEnabled(False)
self.pushButton_alipay.setEnabled(False)
self.pushButton_balancepay.setEnabled(False)
self.pushButton_start.setText("开始检测")
self.pushButton_stop.setText("停止检测")
self.pushButton_green.setText("GREEN:0")
self.pushButton_silver.setText("SILVER:0")
self.pushButton_orange.setText("ORANGE:0")
self.pushButton_white.setText("WHITE:0")
self.pushButton_red.setText("RED:0")
self.pushButton_yellow.setText("YELLOW:0")
self.label_price.setText("0")
self.pushButton_username.setText(self.username)
self.stackedWidget_2.setVisible(False)
if self.permission == permission_list[2]:
self.pushButton_set.setVisible(True)
else:
self.pushButton_set.setVisible(False)
# 测试,计算FPS
if TEST_FPS:
self.frame_counter = 0 # 视频帧数恢复0
# 将图像自适应放至QLabel框中,同时传进放QLabel框的QFrame框
def cv2_image_show(self, _img, _label_img):
if _img is None:
return
_label_img.clear()
label_width = _label_img.width()
label_height = _label_img.height()
img_width = _img.shape[1]
img_height = _img.shape[0]
w_count = label_width / img_width
h_count = label_height / img_height
count = w_count if w_count < h_count else h_count # 缩放到适应窗口的最小比例
# 压缩图像到QLabel框
img_compress = cv2.resize(_img, None, fx=count, fy=count)
# 将RGB通道转换为qt的BGR通道
frame = cv2.cvtColor(img_compress, cv2.COLOR_BGR2RGB)
img = QImage(frame.data, frame.shape[1], frame.shape[0], frame.shape[1] * 3, QImage.Format_RGB888)
_label_img.setPixmap(QPixmap.fromImage(img))
# 修改用户名信息
def change_username(self):
if self.permission == permission_list[0]:
show_message("游客无需修改信息")
return
self.update_user_info()
self.add_log("访问“用户信息修改”页面")
ui = myChange()
ui.db = self.db
ui.password = self.password
ui.username = self.username
ui.userid = self.userid
ui.version = self.version
ui.title.setText("用户信息修改")
ui.label_9.setText("用户名")
ui.label_10.setText("密码")
ui.label_11.setText("请输入新密码")
ui.pushButton_model.setText("修改")
ui.pushButton_log.setText("修改")
ui.pushButton_tmp.setVisible(False)
ui.frame_14.setVisible(False)
ui.lineEdit_model.setText(str(self.username))
ui.lineEdit_log.setText(self.password)
ui.lineEdit_log.setEchoMode(QtWidgets.QLineEdit.Password)
ui.lineEdit_tmp.setEchoMode(QtWidgets.QLineEdit.Password)
ui.exec_()
# 更新用户信息
def update_user_info(self):
if self.permission != permission_list[0]:
user_tuple = self.db.select_one("userid = " + str(self.userid))
self.username = user_tuple[1]
self.password = user_tuple[2]
self.permission = user_tuple[3]
self.money = user_tuple[4]
self.version = user_tuple[5]
# 余额付款
def use_balance(self):
if self.permission == permission_list[0]:
show_message("游客不能使用余额付款,请使用支付宝付款")
return
self.add_log("点击”余额付款“")
# 等待提示框
self.warn_window = myWarn()
price = round(self.price * 0.9, 2)
self.warn_window.label_warninfo.setText(f"用餐费用为{self.price}元,需支付{price}元(9折)")
self.frame_5.setVisible(True)
self.warn_window.title.setText("余额支付")
self.warn_window.password = self.password
self.warn_window.pushButton_cancel.setVisible(True)
self.warn_window.frame_5.setVisible(True)
th = threading.Thread(target=self.balancepay_work)
self.update_user_info()
th.start()
self.warn_window.exec_()
# 余额支付线程
def balancepay_work(self):
self.isPaying = True
price = round(self.price * 0.9, 2)
# 支付过程
while True:
if self.warn_window.stopLoadingEvent.is_set():
self.warn_window.stopLoadingEvent.clear()
if self.warn_window.isCancer is not True:
while True:
self.update_user_info()
self.warn_window.pushButton_cancel.setVisible(False)
self.warn_window.pushButton_confirm.setVisible(False)
self.warn_window.frame_5.setVisible(False)
self.warn_window.lineEdit.setVisible(False)
if self.money < price:
self.warn_window.label_warninfo.setText("您当前账户的余额不足,请充值或选择支付宝支付!")
self.add_log(f"当前账户的余额不足,请充值或选择支付宝支付;")
break
else:
ret = self.db.update({"money": self.money - price, "version": self.version + 1},
"userid = " + str(self.userid) + " and version = " + str(self.version))
if ret["status"] == "success":
self.warn_window.label_warninfo.setText("支付成功!")
self.add_log(f"余额支付{price}元(9折)成功;")
self.stackedWidget_2.setCurrentIndex(2)
self.version += 1 # 乐观锁
self.money -= price
break
self.isPaying = False
time.sleep(2) # 在关闭前需要等待,期间label设置文字完成,否则close()函数会挂起,子窗口无法关闭
self.warn_window.close()
break
# 支付宝付款
def use_alipay(self):
if self.price == 0:
show_message("当前用餐价格为0元 ")
elif self.pushButton_alipay.text() == "支付宝\n付款":
# self.pushButton_alipay.setText("支付宝\n付款中止")
self.isPaying = True
self.add_log("点击”支付宝付款“")
self.alipay.pay_in_computer(self.price) # 生成交易单号并弹出支付网页
th1 = threading.Thread(target=self.alipay_work) # 订单生成
th1.start()
# 等待提示框
self.warn_window = myWarn()
self.warn_window.label_warninfo.setText("支付进行中,请稍等.")
self.warn_window.pushButton_confirm.setVisible(False)
self.warn_window.pushButton_cancel.setVisible(True)
self.warn_window.title.setText("支付宝付款")
th2 = threading.Thread(target=self.loading_test)
th2.start()
self.warn_window.exec_()
# 支付宝支付线程
def alipay_work(self):
self.isPaying = True
while True: # 每隔2秒轮询支付信息
time.sleep(2)
result = self.alipay.query_pay_result()
if result['code'] == "10000" and result['trade_status'] in ("TRADE_SUCCESS", "TRADE_FINISHED"): # 如果支付成功
self.stackedWidget_2.setCurrentIndex(2)
self.trade_isFinished = True
self.warn_window.stopLoadingEvent.set()
break
elif self.stoppayEvent.is_set(): # 如果支付被中断
self.stoppayEvent.clear()
self.add_log("支付被中断,原因可能包括:手动停止,重新检测,页面切换,应用关闭……")
break
self.isPaying = False
# 等待付款提示框线程
def loading_test(self):
while not self.warn_window.stopLoadingEvent.is_set():
time.sleep(1)
if self.warn_window.label_warninfo.text() == "支付进行中,请稍等.":
self.warn_window.label_warninfo.setText("支付进行中,请稍等..")
elif self.warn_window.label_warninfo.text() == "支付进行中,请稍等..":
self.warn_window.label_warninfo.setText("支付进行中,请稍等...")
elif self.warn_window.label_warninfo.text() == "支付进行中,请稍等...":
self.warn_window.label_warninfo.setText("支付进行中,请稍等.")
self.warn_window.stopLoadingEvent.clear()
if self.trade_isFinished:
self.warn_window.pushButton_confirm.setVisible(True)
self.warn_window.pushButton_cancel.setVisible(False)
self.warn_window.stopLoadingEvent.clear()
if self.warn_window.title.text() == "支付宝付款":
self.warn_window.label_warninfo.setText("支付宝支付" + str(self.price) + "元成功,祝您用餐愉快!")
self.add_log("支付宝支付" + str(self.price) + "元成功;")
elif self.warn_window.title.text() == "余额付款":
self.warn_window.label_warninfo.setText("余额支付" + str(self.price * 0.9) + "元(已按9折计算)成功,祝您用餐愉快!")
self.add_log("支付宝支付" + str(self.price * 0.9) + "元(已按9折计算)成功;")
else: # 支付被中断
self.stoppayEvent.set()
self.warn_window.close()
# 打开图像文件并处理
def open_images(self):
self.filename, self.filetype = QFileDialog.getOpenFileName(self, "选择图像文件", "", "*.png;;*.jpg")
if self.filename == "": # 未打开文件
show_message("请打开图像文件(目前支持.png或.jpg格式)")
else:
self.pushButton_stop.setText("停止检测")
frame = cv2.imread(self.filename) # 读取图像
self.frame_before = frame
self.now = frame
self.cv2_image_show(frame, self.label_imgbefore)
self.pushButton_start.setEnabled(True)
self.add_log("打开图像" + self.filename)
# 打开视频流文件并处理
def open_vedio(self):
self.filename, self.filetype = QFileDialog.getOpenFileName(self, "选择视频文件", "", "*.mp4;;*.avi")
if self.filename == "": # 未打开文件
show_message("请打开视频文件(目前支持.mp4或.avi格式)")
else:
cap = cv2.VideoCapture(self.filename)
if cap.isOpened():
flag, frame = cap.read()
self.now = cv2.VideoCapture(self.filename) # 保存当前处理视频对象
self.frame_before = frame
self.cv2_image_show(frame, self.label_imgbefore)
self.pushButton_start.setEnabled(True)
self.pushButton_stop.setText("停止检测")
self.add_log("打开视频" + self.filename)
else:
show_message("视频" + self.filename + "打开失败")
self.add_log("视频" + self.filename + "打开失败;")
# 打开摄像头
def open_camera(self):
if self.isCamera:
self.pushButton_start.setEnabled(True)
cap = cv2.VideoCapture(0)
if cap.isOpened():
self.now = cap
camera_thread = threading.Thread(target=self.camera_work)
camera_thread.start()
self.pushButton_cameraopen.setEnabled(False)
self.pushButton_cameraclose.setEnabled(True)
self.pushButton_phototake.setEnabled(True)
self.add_log("打开摄像头;")
else:
show_message("摄像头打开失败")
self.add_log("摄像头打开失败;")
# 摄像头工作线程
def camera_work(self):
self.isCameraWorking = True
while self.now is not None and self.now.isOpened():
flag, frame = self.now.read()
if self.stopcameraEvent.is_set():
self.stopcameraEvent.clear()
break
else:
self.frame_before = frame
self.cv2_image_show(frame, self.label_imgbefore)
self.isCameraWorking = False
# 关闭摄像头
def close_camera(self):
self.stopcameraEvent.set()
self.now.release()
self.pushButton_cameraopen.setEnabled(True)
self.pushButton_cameraclose.setEnabled(False)
self.label_imgbefore.clear()
self.label_imgafter.clear()
# 拍照
def take_photo(self):
self.pushButton_cameraclose.setEnabled(False)
self.pushButton_cameraopen.setEnabled(True)
self.now = self.frame_before
self.stopcameraEvent.set()
self.pushButton_start.setEnabled(True) # 截图后,可以进行检测
# 用YOLO算法进行图像检测
def work(self):
self.isModelWorking = True
self.pushButton_stop.setEnabled(True)
if type(self.now) is cv2.VideoCapture:
# 如果当前处理对象是视频流
counter = 1
while self.now is not None and self.now.isOpened():
# 判断关闭工作事件是否已触发
if self.stopworkEvent.is_set() or (self.isCamera and self.stopcameraEvent.is_set()):
break
# 逐帧读取
flag, frame = self.now.read()
if flag:
self.frame_before = frame
self.cv2_image_show(self.frame_before, self.label_imgbefore)
if self.isCamera: # 若是实时摄像头
counter += 1
if counter % 3 == 0: # 跳3帧检测
self.per_frame_detection()
else: # 若是视频文件
self.per_frame_detection()
if TEST_FPS:
self.frame_counter += 1
self.out.write(self.frame_after) # 保存识别后视频帧
else:
self.now.release()
self.out.release() # 释放当前检测视频结果
if TEST_FPS:
# 输出fps
runtime = time.time() - self.starttime
fps = self.frame_counter / runtime
self.add_log(f"视频检测结束,检测fps为{round(fps, 2)}")
self.frame_counter = 0 # 置为空
if self.isCamera:
self.now.release() # 释放当前检测视频结果
else:
# 当前处理对象是图像
self.per_frame_detection()
partition = self.filename.split(".")[1] if self.filename != "" else "jpg"
self.out_filename = tmp_dir_path + str(int(time.time())) + "." + partition
cv2.imwrite(self.out_filename, self.frame_after)
if self.stopworkEvent.is_set():
self.stopworkEvent.clear()
elif self.isCamera and self.stopcameraEvent.is_set(): # 实时监测中摄像头关闭
self.stopcameraEvent.clear()
self.pushButton_start.setText("开始检测")
else: # 如果是自然结束
self.pushButton_start.setText("开始检测")
self.pushButton_stop.setText("导出结果")
self.pushButton_start.setEnabled(False)
self.isModelWorking = False
# 开始探测 or 暂停探测 or 继续探测
def start_detection(self):
if self.frame_before is None:
show_message("请先打开文件或摄像头")
else:
# 创建模型处理线程
self.stackedWidget_2.setVisible(True)
self.pushButton_alipay.setEnabled(True)
self.pushButton_balancepay.setEnabled(True)
if self.pushButton_start.text() == "开始检测":
self.add_log("点击“开始检测”按钮;")
if self.isCamera:
self.stopcameraEvent.set()
self.now = cv2.VideoCapture(0)
self.pushButton_start.setText("暂停检测")
else:
if type(self.now) is cv2.VideoCapture:
# 如果检测的是视频
width = int(self.now.get(cv2.CAP_PROP_FRAME_WIDTH)) # 获取视频的宽度
height = int(self.now.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 获取视频的高度
fps = self.now.get(cv2.CAP_PROP_FPS) # 获取视频的帧率
fourcc = int(self.now.get(cv2.CAP_PROP_FOURCC)) # 视频的编码
# 定义视频输出
self.out_filename = tmp_dir_path + f'{int(time.time())}.mp4'
self.out = cv2.VideoWriter(self.out_filename, fourcc, fps, (width, height))
self.pushButton_start.setText("暂停检测")
if TEST_FPS:
self.starttime = time.time()
th = threading.Thread(target=self.work) # 调用工作线程进行检测
th.start()
elif self.pushButton_start.text() == "继续检测":
self.add_log("点击“继续检测”按钮;")
self.pushButton_start.setText("暂停检测")
if self.isCamera:
self.now = cv2.VideoCapture(0)
th = threading.Thread(target=self.work) # 调用工作线程进行检测
th.start()
else:
# self.pushButton_start.text() == "暂停检测":
self.add_log("点击“暂停检测”按钮;")
self.pushButton_start.setText("继续检测")
self.stopworkEvent.set()
# 停止探测 or 导出结果
def stop_detection(self):
if self.pushButton_stop.text() == "停止检测": # 中止当前探测
self.add_log("点击“停止检测”按钮;")
self.now.release() # 释放当前检测原视频
if not self.isCamera:
self.out.release() # 释放当前检测视频结果
self.pushButton_stop.setText("导出结果")
else:
self.realtime_detection()
else: # 导出结果
self.add_log("点击“导出结果”按钮;")
partition = self.out_filename.split(".")[1]
if partition == "mp4" or partition == "avi":
out_path_tuple = QFileDialog.getSaveFileName(self, "选择结果保存的路径", "./resource/result/", ".mp4;;avi")
else:
out_path_tuple = QFileDialog.getSaveFileName(self, "选择结果保存的路径", "./resource/result/", ".png;;.jpg")
out_path = str(out_path_tuple[0]) + str(out_path_tuple[1])
shutil.copy(self.out_filename, out_path)
self.add_log("保存" + self.filename + "的检测结果至" + out_path)
# 关键:用YOLOv7识别单帧图像
def per_frame_detection(self):
# 待扫描图像应先存在self.frame_before中
self.frame_after, self.detection_result = yolo.model(self.frame_before)
self.cv2_image_show(self.frame_after, self.label_imgafter)
# 展示结果并计算价格
self.pushButton_green.setText("GREEN:" + str(self.detection_result["green"]))
self.pushButton_silver.setText("SILVER:" + str(self.detection_result["silver"]))
self.pushButton_orange.setText("ORANGE:" + str(self.detection_result["orange"]))
self.pushButton_white.setText("WHITE:" + str(self.detection_result["white"]))
self.pushButton_red.setText("RED:" + str(self.detection_result["red"]))
self.pushButton_yellow.setText("YELLOW:" + str(self.detection_result["yellow"]))
self.price = self.detection_result["green"] * 6 + self.detection_result["silver"] * 5 + self.detection_result[
"orange"] * 4 + self.detection_result["white"] * 3 + self.detection_result["red"] * 2 + \
self.detection_result["yellow"] * 1
self.label_price.setText(str(self.price))
if self.price != 0:
# 若有识别结果,则输出结果并导入日志
result_str = "识别结果为:"
for key, value in self.detection_result.items():
if value:
if key == "green":
result_str += "绿色餐盘" + str(value) + "个,"
elif key == "silver":
result_str += "银色餐盘" + str(value) + "个,"
elif key == "orange":
result_str += "橙色餐盘" + str(value) + "个,"
elif key == "white":
result_str += "白色餐盘" + str(value) + "个,"
elif key == "red":
result_str += "红色餐盘" + str(value) + "个,"
elif key == "yellow":
result_str += "黄色餐盘" + str(value) + "个,"
result_str += "总计" + str(self.price) + "元;"
self.add_log(result_str)
# 添加日志并展示
def add_log(self, log_info):
# 获取当前时间
current_time = int(time.time())
localtime = time.localtime(current_time)
# 利用 strftime()函数重新格式化时间
dt = time.strftime('%Y:%m:%d %H:%M:%S', localtime)
info = dt + ": " + log_info
self.textBrowser.append(info) # 文本框逐条添加数据
self.textBrowser.moveCursor(self.textBrowser.textCursor().End) # 文本框显示到底部
# 切换至系统说明页面
def use_instruction(self):
# 摄像头初始化
if self.now is not None and type(self.now) == cv2.VideoCapture:
self.now.release()
self.initAttribution()
self.stackedWidget.setVisible(False)
self.add_log("访问“系统介绍”界面;")
instruction_window = myInstruction()
instruction_window.exec_()
# 切换至文件检测页面
def file_detection(self):
# 摄像头初始化
if self.now is not None and type(self.now) == cv2.VideoCapture:
self.now.release()
self.initAttribution()
self.stackedWidget.setVisible(True)
self.stackedWidget.setCurrentIndex(0)
self.add_log("访问“文件检测”界面;")
# 切换至拍照检测界面
def photo_detection(self):
# 摄像头初始化
if self.now is not None and type(self.now) == cv2.VideoCapture:
self.now.release()
self.initAttribution()
self.stackedWidget.setVisible(True)
self.pushButton_cameraopen.setEnabled(True)
self.pushButton_cameraclose.setEnabled(False)
self.pushButton_phototake.setEnabled(False)
self.pushButton_phototake.setVisible(True)
self.stackedWidget.setCurrentIndex(1)
self.add_log("访问“拍照检测”界面;")
# 切换至实时检测界面
def realtime_detection(self):
# 摄像头初始化
if self.now is not None and type(self.now) == cv2.VideoCapture:
self.now.release()
self.initAttribution()
self.stackedWidget.setVisible(True)
self.pushButton_phototake.setVisible(False)
self.pushButton_cameraopen.setEnabled(True)
self.pushButton_cameraclose.setEnabled(False)
self.stackedWidget.setCurrentIndex(1)
self.isCamera = True
self.add_log("访问“实时检测”界面;")
# 充值功能
def recharge(self):
# 摄像头初始化
if self.now is not None and type(self.now) == cv2.VideoCapture:
self.now.release()
self.initAttribution()
self.stackedWidget.setVisible(False)
self.add_log("访问“在线充值”界面;")
if self.permission == permission_list[0]:
show_message("游客无法充值,请退出系统后再登陆用户账号!")
return
# 等待提示框
self.warn_window = myWarn()
self.warn_window.frame_5.setVisible(True)
self.warn_window.pushButton_cancel.setVisible(False)
self.warn_window.lineEdit.setEchoMode(QtWidgets.QLineEdit.Normal)
self.warn_window.title.setText("在线充值")
self.warn_window.label.setText("请输入您要充值的金额:")
self.warn_window.label_warninfo.setText("您的账户当前剩余金额为" + str(round(self.money, 2)) + "元")
th = threading.Thread(target=self.recharge_work)
th.start()
self.update_user_info()
self.add_log("打开在线充值窗口中,请稍等……")
self.warn_window.exec_()
# 充值线程
def recharge_work(self):
while True:
if self.warn_window.stopLoadingEvent.is_set():
self.warn_window.stopLoadingEvent.clear()
if is_float(self.warn_window.lineEdit.text()): # 开始支付
recharge_money = float(self.warn_window.lineEdit.text())
self.alipay.pay_in_computer(recharge_money) # 生成交易单号并弹出支付网页
while True: # 每隔1秒轮询支付信息
time.sleep(1)
result = self.alipay.query_pay_result()
if result['code'] == "10000" and result['trade_status'] in (
"TRADE_SUCCESS", "TRADE_FINISHED"): # 如果支付成功
ret = self.db.update({"money": self.money + recharge_money, "version": self.version + 1},
"userid = " + str(self.userid) + " and version = " + str(self.version))
if ret["status"] == "success":
self.warn_window.label_warninfo.setText("充值成功!")
self.add_log("成功充值" + str(recharge_money) + "元;")
time.sleep(3)
self.warn_window.close()
self.version += 1 # 乐观锁
self.money += recharge_money
self.file_detection()
break
else:
self.update_user_info()
elif self.warn_window.stopLoadingEvent.is_set(): # 如果支付被中断
self.warn_window.stopLoadingEvent.clear()
self.add_log("充值被中断,原因可能包括:手动停止,重新检测,页面切换,应用关闭……")
break
break
# 鼠标拖动相关
def mouseMoveInit(self):
self.m_flag = False
self.m_Position = None
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton and self.isMaximized() == False:
self.m_flag = True
self.m_Position = event.globalPos() - self.pos() # 获取鼠标相对窗口的位置
event.accept()
self.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor)) # 更改鼠标位置
def mouseMoveEvent(self, event):
if QtCore.Qt.LeftButton and self.m_flag:
self.move(event.globalPos() - self.m_Position) # 更改窗口位置
event.accept()
def mouseReleaseEvent(self, event):
self.m_flag = False
self.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
# 窗口4个按钮相关
def window_set(self):
# 设置权重文件和YOLO对应参数
self.add_log("点击“系统设置”按钮")
ui = myChange()
ui.exec_()
def window_min(self):
# 最小化
self.showMinimized()
def window_max(self):
# 最大化与复原
if self.isMaximized():
self.showNormal()
self.widget.setGeometry(QtCore.QRect(0, 0, 1000, 570))
# 重新显示餐盘图像
self.cv2_image_show(self.frame_before, self.label_imgbefore)
self.cv2_image_show(self.frame_after, self.label_imgafter)
else:
desktop = QApplication.desktop()
rect = desktop.availableGeometry()
self.showMaximized()
self.widget.setGeometry(rect)
# 重新显示餐盘图像
self.cv2_image_show(self.frame_before, self.label_imgbefore)
self.cv2_image_show(self.frame_after, self.label_imgafter)
def window_close(self):
# 摄像头初始化
if self.now is not None and type(self.now) == cv2.VideoCapture:
self.now.release()
self.add_log("退出程序 ")
# 获取当前时间
current_time = int(time.time())
localtime = time.localtime(current_time)
# 利用 strftime()函数重新格式化时间
dt = time.strftime('%Y%m%d_%H%M%S', localtime)
log_path = log_dir_path + "/" + dt + ".txt"
log_file = open(log_path, 'w')
log_file.write(self.textBrowser.toPlainText())
log_file.close()
# 删除temp文件夹下缓存文件
for i in os.listdir(tmp_dir_path):
os.remove(tmp_dir_path + i)
self.close()
class myLogin(login_window.Ui_Form, QMainWindow):
def __init__(self):
super(login_window.Ui_Form, self).__init__()
super().__init__()
self.setupUi(self)
self.setAttribute(Qt.WA_TranslucentBackground)
self.setWindowFlags(Qt.FramelessWindowHint)
self.mouseMoveInit()
self.stackedWidget.setCurrentIndex(0)
# 任务栏相关
self.setWindowTitle('基于YOLOv7的智慧餐厅系统')
icon = QIcon()
icon.addPixmap(QPixmap(":/新前缀/gui_images/logo.png"), QIcon.Normal, QIcon.Off)
self.setWindowIcon(icon)
# 初始化主界面
self.home = myHome()
# 绑定槽函数
self.pushButton_to_login.clicked.connect(lambda: self.stackedWidget.setCurrentIndex(0))
self.pushButton_to_register.clicked.connect(lambda: self.stackedWidget.setCurrentIndex(1))
self.pushButton_login.clicked.connect(self.go_to_home)
self.pushButton_register.clicked.connect(self.register)
self.pushButton_default.clicked.connect(self.go_to_home_default)
def register(self):
username = self.input_username_2.text()
password = self.input_passward_2.text()
re_password = self.input_passward_confirm.text()
if username == "" or password == "" or re_password == "":
show_message("请输入完整信息!")
return
if self.home.db.select_one("username = '" + username + "'") is None:
if password == re_password:
self.home.db.insert("('" + username + "','" + password + "','user',0,0)")
show_message("注册成功!")
self.input_username.setText(username)
self.input_passward.setText(password)
self.stackedWidget.setCurrentIndex(0)
else:
show_message("两次输入的密码不一致")
else:
show_message("该用户名已存在")
def go_to_home_default(self):
self.home.add_log("以游客身份登陆;")
# 设置游客身份
self.home.username = "游客"
self.home.money = 0
self.home.permission = permission_list[0]
self.home.show()
self.close()
def go_to_home(self):
username = self.input_username.text()
password = self.input_passward.text()
if len(username) == 0:
show_message("请输入账号!")
elif len(password) == 0:
show_message("请输入密码!")
else:
user_tuple = self.home.db.select_one("username = '" + username + "'")
if user_tuple is not None:
# (10000000, 'root', '123456', 'administrator', 5000.0, 0)
if user_tuple[2] == password:
self.home.userid = user_tuple[0]
self.home.username = user_tuple[1]
self.home.password = user_tuple[2]
self.home.permission = user_tuple[3]
self.home.money = user_tuple[4]
self.home.version = user_tuple[5]
self.home.pushButton_username.setText(username)
self.home.add_log("以用户(" + username + ")身份登陆;")
self.home.initAttribution()
self.home.show()
self.close()
else:
show_message("密码错误 ")
else:
show_message("该用户名信息不存在 ")
# 鼠标拖动相关
def mouseMoveInit(self):
self.m_flag = False
self.m_Position = None
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton and self.isMaximized() == False:
self.m_flag = True
self.m_Position = event.globalPos() - self.pos() # 获取鼠标相对窗口的位置
event.accept()
self.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor)) # 更改鼠标位置
def mouseMoveEvent(self, event):
if QtCore.Qt.LeftButton and self.m_flag:
self.move(event.globalPos() - self.m_Position) # 更改窗口位置
event.accept()
def mouseReleaseEvent(self, event):
self.m_flag = False
self.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
if __name__ == "__main__":
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
app = QApplication(sys.argv) # 创建一个QApplication,也就是你要开发的软件app
loginWindow = myLogin()
loginWindow.show()
# homeWindow = myHome()
# homeWindow.show()
sys.exit(app.exec_()) # 使用exit()或者点击关闭按钮退出QApplication
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Python
1
https://gitee.com/Cecoming/smart-restaurant-pricing-system-based-on-yolov7.git
git@gitee.com:Cecoming/smart-restaurant-pricing-system-based-on-yolov7.git
Cecoming
smart-restaurant-pricing-system-based-on-yolov7
Smart Restaurant Pricing System based on YOLOv7
master

搜索帮助