# -*- coding: utf-8 -*-# @Time : 2021年3月6日 15:36# @Author : PeterH# @Email : peterhuang0323@outlook.com# @File : visual_interface.py# @Software: PyCharm# @Brief :# 解决 exe 打包 Can't get source for 的问题 start ======# https://github.com/pytorch/vision/issues/1899#issuecomment-598200938import torch.jitdef script_method(fn, _rcb=None):return fndef script(obj, optimize=True, _frames_up=0, _rcb=None):return objtorch.jit.script_method = script_methodtorch.jit.script = script# 解决 exe 打包 Can't get source for 的问题 end ======import osimport timeimport sysfrom pathlib import Pathfrom GPUtil import GPUtilfrom PyQt5.QtCore import QThread, pyqtSignal, QUrl, pyqtSlot, QTimer, QDateTime, Qtfrom PyQt5.QtMultimedia import QMediaPlayer, QMediaContentfrom PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialogfrom PyQt5.QtGui import QColor, QBrush, QIcon, QPixmapfrom PyQt5.QtChart import QDateTimeAxis, QValueAxis, QSplineSeries, QChartimport torchfrom UI.main_window import Ui_MainWindowfrom detect_visual import YOLOPredictfrom utils.datasets import img_formatsCODE_VER = "V2.0"PREDICT_SHOW_TAB_INDEX = 0REAL_TIME_PREDICT_TAB_INDEX = 1def get_gpu_info():"""获取 GPU 信息:return:"""gpu_list = []# GPUtil.showUtilization()# 获取多个GPU的信息,存在列表里for gpu in GPUtil.getGPUs():# print('gpu.id:', gpu.id)# print('GPU总量:', gpu.memoryTotal)# print('GPU使用量:', gpu.memoryUsed)# print('gpu使用占比:', gpu.memoryUtil * 100) # 内存使用率# print('gpu load:', gpu.load * 100) # 使用率# 按GPU逐个添加信息gpu_list.append({"gpu_id": gpu.id,"gpu_memoryTotal": gpu.memoryTotal,"gpu_memoryUsed": gpu.memoryUsed,"gpu_memoryUtil": gpu.memoryUtil * 100,"gpu_load": gpu.load * 100})return gpu_listclass PredictDataHandlerThread(QThread):"""打印信息的线程"""predict_message_trigger = pyqtSignal(str)def __init__(self, predict_model):super(PredictDataHandlerThread, self).__init__()self.running = Falseself.predict_model = predict_modeldef __del__(self):self.running = False# self.destroyed()def run(self):self.running = Trueover_time = 0while self.running:if self.predict_model.predict_info != "":self.predict_message_trigger.emit(self.predict_model.predict_info)self.predict_model.predict_info = ""over_time = 0time.sleep(0.01)over_time += 1if over_time > 100000:self.running = Falseclass PredictHandlerThread(QThread):"""进行模型推理的线程"""def __init__(self, input_player, output_player, out_file_path, weight_path,predict_info_plain_text_edit, predict_progress_bar, fps_label,button_dict, input_tab, output_tab, input_image_label, output_image_label,real_time_show_predict_flag):super(PredictHandlerThread, self).__init__()self.running = False'''加载模型'''self.predict_model = YOLOPredict(weight_path, out_file_path)self.output_predict_file = ""self.parameter_source = ''# 传入的QT插件self.input_player = input_playerself.output_player = output_playerself.predict_info_plainTextEdit = predict_info_plain_text_editself.predict_progressBar = predict_progress_barself.fps_label = fps_labelself.button_dict = button_dictself.input_tab = input_tabself.output_tab = output_tabself.input_image_label = input_image_labelself.output_image_label = output_image_label# 是否实时显示推理图片self.real_time_show_predict_flag = real_time_show_predict_flag# 创建显示进程self.predict_data_handler_thread = PredictDataHandlerThread(self.predict_model)self.predict_data_handler_thread.predict_message_trigger.connect(self.add_messages)def __del__(self):self.running = False# self.destroyed()def run(self):self.predict_data_handler_thread.start()self.predict_progressBar.setValue(0) # 进度条清零for item, button in self.button_dict.items():button.setEnabled(False)image_flag = os.path.splitext(self.parameter_source)[-1].lower() in img_formatsqt_input = Noneqt_output = Noneif not image_flag and self.real_time_show_predict_flag:qt_input = self.input_image_labelqt_output = self.output_image_label# tab 设置显示第二栏self.input_tab.setCurrentIndex(REAL_TIME_PREDICT_TAB_INDEX)self.output_tab.setCurrentIndex(REAL_TIME_PREDICT_TAB_INDEX)with torch.no_grad():self.output_predict_file = self.predict_model.detect(self.parameter_source,qt_input=qt_input,qt_output=qt_output)if self.output_predict_file != "":# 将 str 路径转为 QUrl 并显示self.input_player.setMedia(QMediaContent(QUrl.fromLocalFile(self.parameter_source))) # 选取视频文件self.input_player.pause() # 显示媒体self.output_player.setMedia(QMediaContent(QUrl.fromLocalFile(self.output_predict_file))) # 选取视频文件self.output_player.pause() # 显示媒体# tab 设置显示第一栏self.input_tab.setCurrentIndex(PREDICT_SHOW_TAB_INDEX)self.output_tab.setCurrentIndex(PREDICT_SHOW_TAB_INDEX)# video_flag = os.path.splitext(self.parameter_source)[-1].lower() in vid_formatsfor item, button in self.button_dict.items():if image_flag and item in ['play_pushButton', 'pause_pushButton']:continuebutton.setEnabled(True)# self.predict_data_handler_thread.running = False@pyqtSlot(str)def add_messages(self, message):if message != "":self.predict_info_plainTextEdit.appendPlainText(message)if ":" not in message:# 跳过无用字符returnsplit_message = message.split(" ")# 设置进度条if "video" in message:percent = split_message[2][1:-1].split("/") # 提取图片的序号value = int((int(percent[0]) / int(percent[1])) * 100)value = value if (int(percent[1]) - int(percent[0])) > 2 else 100self.predict_progressBar.setValue(value)else:self.predict_progressBar.setValue(100)# 设置 FPSsecond_count = 1 / float(split_message[-1][1:-2])self.fps_label.setText(f"--> {second_count:.1f} FPS")class MainWindow(QMainWindow, Ui_MainWindow):def __init__(self, weight_path, out_file_path, real_time_show_predict_flag: bool, parent=None):super(MainWindow, self).__init__(parent)self.setupUi(self)self.setWindowTitle("Intelligent Monitoring System of Construction Site Software " + CODE_VER)self.showMaximized()'''按键绑定'''# 输入媒体self.import_media_pushButton.clicked.connect(self.import_media) # 导入self.start_predict_pushButton.clicked.connect(self.predict_button_click) # 开始推理# 输出媒体self.open_predict_file_pushButton.clicked.connect(self.open_file_in_browser) # 文件中显示推理视频# 下方self.play_pushButton.clicked.connect(self.play_pause_button_click) # 播放self.pause_pushButton.clicked.connect(self.play_pause_button_click) # 暂停self.button_dict = dict()self.button_dict.update({"import_media_pushButton": self.import_media_pushButton,"start_predict_pushButton": self.start_predict_pushButton,"open_predict_file_pushButton": self.open_predict_file_pushButton,"play_pushButton": self.play_pushButton,"pause_pushButton": self.pause_pushButton,"real_time_checkBox": self.real_time_checkBox})'''媒体流绑定输出'''self.input_player = QMediaPlayer() # 媒体输入的widgetself.input_player.setVideoOutput(self.input_video_widget)self.input_player.positionChanged.connect(self.change_slide_bar) # 播放进度条self.output_player = QMediaPlayer() # 媒体输出的widgetself.output_player.setVideoOutput(self.output_video_widget)'''初始化GPU chart'''self.series = QSplineSeries()self.chart_init()'''初始化GPU定时查询定时器'''# 使用QTimer,0.5秒触发一次,更新数据self.timer = QTimer(self)self.timer.timeout.connect(self.draw_gpu_info_chart)self.timer.start(1000)# 播放时长, 以 input 的时长为准self.video_length = 0self.out_file_path = out_file_path# 推理使用另外一线程self.predict_handler_thread = PredictHandlerThread(self.input_player,self.output_player,self.out_file_path,weight_path,self.predict_info_plainTextEdit,self.predict_progressBar,self.fps_label,self.button_dict,self.input_media_tabWidget,self.output_media_tabWidget,self.input_real_time_label,self.output_real_time_label,real_time_show_predict_flag)self.weight_label.setText(f" Using weight : ****** {Path(weight_path[0]).name} ******")# 界面美化self.gen_better_gui()self.media_source = "" # 推理媒体的路径self.predict_progressBar.setValue(0) # 进度条归零'''check box 绑定'''self.real_time_checkBox.stateChanged.connect(self.real_time_checkbox_state_changed)self.real_time_checkBox.setChecked(real_time_show_predict_flag)self.real_time_check_state = self.real_time_checkBox.isChecked()def gen_better_gui(self):"""美化界面:return:"""# Play 按钮play_icon = QIcon()play_icon.addPixmap(QPixmap("./UI/icon/play.png"), QIcon.Normal, QIcon.Off)self.play_pushButton.setIcon(play_icon)# Pause 按钮play_icon = QIcon()play_icon.addPixmap(QPixmap("./UI/icon/pause.png"), QIcon.Normal, QIcon.Off)self.pause_pushButton.setIcon(play_icon)# 隐藏 tab 标题栏self.input_media_tabWidget.tabBar().hide()self.output_media_tabWidget.tabBar().hide()# tab 设置显示第一栏self.input_media_tabWidget.setCurrentIndex(PREDICT_SHOW_TAB_INDEX)self.output_media_tabWidget.setCurrentIndex(PREDICT_SHOW_TAB_INDEX)# 设置显示图片的 label 为黑色背景self.input_real_time_label.setStyleSheet("QLabel{background:black}")self.output_real_time_label.setStyleSheet("QLabel{background:black}")def real_time_checkbox_state_changed(self):"""切换是否实时显示推理图片:return:"""self.real_time_check_state = self.real_time_checkBox.isChecked()self.predict_handler_thread.real_time_show_predict_flag = self.real_time_check_statedef chart_init(self):"""初始化 GPU 折线图:return:"""# self.gpu_info_chart._chart = QChart(title="折线图堆叠") # 创建折线视图self.gpu_info_chart._chart = QChart() # 创建折线视图# chart._chart.setBackgroundVisible(visible=False) # 背景色透明self.gpu_info_chart._chart.setBackgroundBrush(QBrush(QColor("#FFFFFF"))) # 改变图背景色# 设置曲线名称self.series.setName("GPU Utilization")# 把曲线添加到QChart的实例中self.gpu_info_chart._chart.addSeries(self.series)# 声明并初始化X轴,Y轴self.dtaxisX = QDateTimeAxis()self.vlaxisY = QValueAxis()# 设置坐标轴显示范围self.dtaxisX.setMin(QDateTime.currentDateTime().addSecs(-300 * 1))self.dtaxisX.setMax(QDateTime.currentDateTime().addSecs(0))self.vlaxisY.setMin(0)self.vlaxisY.setMax(100)# 设置X轴时间样式self.dtaxisX.setFormat("hh:mm:ss")# 设置坐标轴上的格点self.dtaxisX.setTickCount(5)self.vlaxisY.setTickCount(10)# 设置坐标轴名称self.dtaxisX.setTitleText("Time")self.vlaxisY.setTitleText("Percent")# 设置网格不显示self.vlaxisY.setGridLineVisible(False)# 把坐标轴添加到chart中self.gpu_info_chart._chart.addAxis(self.dtaxisX, Qt.AlignBottom)self.gpu_info_chart._chart.addAxis(self.vlaxisY, Qt.AlignLeft)# 把曲线关联到坐标轴self.series.attachAxis(self.dtaxisX)self.series.attachAxis(self.vlaxisY)# 生成 折线图self.gpu_info_chart.setChart(self.gpu_info_chart._chart)def draw_gpu_info_chart(self):"""绘制 GPU 折线图:return:"""# 获取当前时间time_current = QDateTime.currentDateTime()# 更新X轴坐标self.dtaxisX.setMin(QDateTime.currentDateTime().addSecs(-300 * 1))self.dtaxisX.setMax(QDateTime.currentDateTime().addSecs(0))# 当曲线上的点超出X轴的范围时,移除最早的点remove_count = 600if self.series.count() > remove_count:self.series.removePoints(0, self.series.count() - remove_count)# 对 y 赋值# yint = random.randint(0, 100)gpu_info = get_gpu_info()yint = gpu_info[0].get("gpu_load")# 添加数据到曲线末端self.series.append(time_current.toMSecsSinceEpoch(), yint)def import_media(self):"""导入媒体文件:return:"""self.media_source = QFileDialog.getOpenFileUrl()[0]self.input_player.setMedia(QMediaContent(self.media_source)) # 选取视频文件# 设置 output 为一张图片,防止资源被占用path_current = str(Path.cwd().joinpath("area_dangerous1円.jpg"))self.output_player.setMedia(QMediaContent(QUrl.fromLocalFile(path_current)))# 将 QUrl 路径转为 本地路径strself.predict_handler_thread.parameter_source = self.media_source.toLocalFile()self.input_player.pause() # 显示媒体image_flag = os.path.splitext(self.predict_handler_thread.parameter_source)[-1].lower() in img_formatsfor item, button in self.button_dict.items():if image_flag and item in ['play_pushButton', 'pause_pushButton']:button.setEnabled(False)else:button.setEnabled(True)# self.output_player.setMedia(QMediaContent(QFileDialog.getOpenFileUrl()[0])) # 选取视频文件def predict_button_click(self):"""推理按钮:return:"""# 启动线程去调用self.predict_handler_thread.start()def change_slide_bar(self, position):"""进度条移动:param position::return:"""self.video_length = self.input_player.duration() + 0.1self.video_horizontalSlider.setValue(round((position / self.video_length) * 100))self.video_percent_label.setText(str(round((position / self.video_length) * 100, 2)) + '%')@pyqtSlot()def play_pause_button_click(self):"""播放、暂停按钮回调事件:return:"""name = self.sender().objectName()if self.media_source == "":returnif name == "play_pushButton":print("play")self.input_player.play()self.output_player.play()elif name == "pause_pushButton":self.input_player.pause()self.output_player.pause()@pyqtSlot()def open_file_in_browser(self):os.system(f"start explorer {self.out_file_path}")@pyqtSlot()def closeEvent(self, *args, **kwargs):"""重写关闭事件:param args::param kwargs::return:"""print("Close")if __name__ == '__main__':app = QApplication(sys.argv)weight_root = Path.cwd().joinpath("weights")if not weight_root.exists():raise FileNotFoundError("weights not found !!!")weight_file = [item for item in weight_root.iterdir() if item.suffix == ".pt"]weight_root = [str(weight_file[0])] # 权重文件位置out_file_root = Path.cwd().joinpath(r'inference/output')out_file_root.parent.mkdir(exist_ok=True)out_file_root.mkdir(exist_ok=True)real_time_show_predict = True # 是否实时显示推理图片,有可能导致卡顿,软件卡死main_window = MainWindow(weight_root, out_file_root, real_time_show_predict)# 设置窗口图标icon = QIcon()icon.addPixmap(QPixmap("./UI/icon/icon.ico"), QIcon.Normal, QIcon.Off)main_window.setWindowIcon(icon)main_window.show()sys.exit(app.exec_())
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。