版權聲明:本文為博主原創文章,轉載 請注明出處:https://blog.csdn.net/sc2079/article/details/90454379
- 寫在前面
本科畢業設計終於告一段落了。特寫博客記錄做畢業設計(路面裂紋識別)期間的踩過的坑和收獲。希望對你有用。
目前有:
1.Tensorflow&CNN:裂紋分類
2.Tensorflow&CNN:驗證集預測與模型評價
3.PyQt5多個GUI界面設計
本篇講GUI界面的設計。設計目標:實現用戶對路面裂紋快速檢測與識別,有三個界面:主界面、裂紋快速識別界面、圖像處理測試界面。
- 環境配置安裝
運行環境:Python3.6、Spyder、Qt Designer
依賴的模塊:PyQt5、mysql等
值得注意的是:我安裝PyQt5模塊時,按照網上方法,如下:
pip install PyQt5
pip install PyQt5-tools
卻發現找到Qt Designer的應用程序,(其實是有的,在C盤的某個角落,可以用everything小工具可以找到)。
於是乎,我就直接使用了PyQt5運行環境合集,內含Qt Designer(主要用來設計界面以及UI文件轉換成PY)。
下載地址如下:
- 開始工作
1. 界面設計
打開Qt Designer:

可以參照網上或書籍上關於Qt Designer的資料,簡單設計三個界面,如下:



Qt Designer設計的文件后綴為.ui,需要將其轉換為.py文件。打開剛才下載的PyQt5合集中的WinPython Command Prompt,輸入:
pyuic5 -o D:\WinPyQt5.9-32bit-3.5.3.1\test\XX.py D:\WinPyQt5.9-32bit-3.5.3.1\test\XX.ui
即可得到界面的Python文件。
2. 界面功能實現
2.1 主界面
主界面功能比較簡單,主要是用戶對功能的選擇以及對該系統的了解。
from PyQt5.QtWidgets import QMainWindow,QMessageBox,QApplication
from main_gui import Ui_MainWindow
import sys
import time
from PyQt5.QtGui import QPixmap
class MainWindow(QMainWindow):
def __init__(self,parent = None):
super(MainWindow,self).__init__(parent=parent)#調用父類的init
global ui
ui = Ui_MainWindow()
ui.setupUi(self)
def about_us(self):
msgBox = QMessageBox(QMessageBox.NoIcon, '關於','XX的本科畢業設計')
msgBox.setIconPixmap(QPixmap(".//icon//me3.jpg"))
msgBox.exec()
def function_exp(self):
msgBox = QMessageBox(QMessageBox.NoIcon, '功能說明','')
msgBox.exec()
def operate_exp(self):
msgBox = QMessageBox(QMessageBox.NoIcon, '操作說明','')
msgBox.exec()
def jump_to_1(self):
pass
def jump_to_2(self):
pass
def closeEvent(self, event):
reply = QMessageBox.question(self, '提醒',
"確定退出?", QMessageBox.Yes |
QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
if __name__ == '__main__':
app = 0
app = QApplication(sys.argv)
myMainWindow = MainWindow()#自定義的類例化
myMainWindow.show()
time.sleep(10)
sys.exit(app.exec_())
而對於轉換的主界面的py代碼(注意:本文將轉換成的.py文件命名為xx_gui.py,而其對應的.py文件命名為xx_win.py),找到如下語句:
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
修改為:
self.retranslateUi(MainWindow)
self.crack_info.triggered.connect(MainWindow.jump_to_1)
self.img_processing.triggered.connect(MainWindow.jump_to_2)
self.function_exp.triggered.connect(MainWindow.function_exp)
self.operate_exp.triggered.connect(MainWindow.operate_exp)
self.about_us.triggered.connect(MainWindow.about_us)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
這樣,主界面功能就實現了。
2.2 裂紋快速識別界面
現已經利用CNN以及圖像處理技術實現了對裂紋的識別與檢測。這里主要是怎么將結果顯示在界面上。這里參照了博客使用PyQt5創建帶文件對話框和文本對話框的ui窗口程序。
from PyQt5.QtWidgets import (QMainWindow,QApplication,QFileDialog)
from PyQt5 import QtCore
from crack_detect_gui import Ui_MainWindow2
from prediction import prediction
import sys
import threading
import time
from img_processing import img_processing
import numpy as np
from mysql_save import save_mysql
class MainWindow2(QMainWindow):
_signal=QtCore.pyqtSignal(str)#自定義信號
def __init__(self,parent = None):
super(MainWindow2,self).__init__(parent=parent)#調用父類的init
self.img_opened = False
self.imgs_opened = False
global ui
ui = Ui_MainWindow2()
ui.setupUi(self)
self.mainWindow2=ui.MainWindow2
ui.output_info.clear()
ui.file_name.clear()
self._signal.connect(self.print_info)
def back(self):
pass
def reset(self,parent = None):
pass
def open_file(self):
self.img_name = QFileDialog.getOpenFileName(self,"打開","","圖片(*.jpg;*.png)")
ui.file_name.setPlainText(self.img_name[0])
self.img_opened = True
def open_files(self):
self.imgs_name = QFileDialog.getOpenFileNames(self,"打開","","多個圖片(*.jpg;*.png)")
imgs_name=''
for img_name in self.imgs_name[0]:
imgs_name=imgs_name+img_name+'\n'
ui.file_name.setPlainText(imgs_name)
self.imgs_opened = True
def print_info(self,pri_str):
ui.output_info.appendPlainText(pri_str)
ui.output_info.show()
def output_info_thread(myMainWindow):
t1=time.time()
Opened = False
while(True):
if myMainWindow.img_opened==True:
imgs_path = myMainWindow.img_name[0].replace("/","//")
break
elif myMainWindow.imgs_opened==True:
imgs_path=[]
for path in myMainWindow.imgs_name[0]:
imgs_path.append(path.replace("/","//"))
break
Opened = True
myMainWindow._signal.emit("當前線程:%s" %threading.current_thread().name)
timeArray = time.localtime(t1)
now=time.strftime("%Y_%m_%d", timeArray)
try:
if(Opened):
s1 = "正在進行裂紋識別評估"
myMainWindow._signal.emit(s1)
kinds=prediction(imgs_path)
s2='裂紋圖片 裂紋類型 裂紋長度 裂紋面積 裂紋最大寬度 裂紋最小寬度 裂紋平均寬度'
myMainWindow._signal.emit(s2)
data= np.empty(shape=[0, 8])
for i in range(len(kinds)):
if len(kinds)==1:
name=imgs_path[::-1].split('//', 1)[0][::-1]
else:
name=imgs_path[i][::-1].split('//', 1)[0][::-1]
if kinds[i]=='無裂紋':
crack_info=[imgs_path[i],kinds[i],'','','','']
elif len(kinds)==1:
crack_info=img_processing(imgs_path,kinds[i])
else:
crack_info=img_processing(imgs_path[i],kinds[i])
s=name+' '+crack_info[0]+' '*5+crack_info[1]+' '*7+crack_info[2]+\
' '*11+crack_info[3]+' '*12+crack_info[4]+' '*12+crack_info[5]
myMainWindow._signal.emit(s)
new_crack_info=[name,crack_info[0],crack_info[1],crack_info[2],
crack_info[3],crack_info[4],crack_info[5],now]
data=np.append(data, [new_crack_info], axis = 0)
t2=time.time()
database='crack_info'
try:
save_mysql(database,data)
myMainWindow._signal.emit('數據已存入'+database+'數據庫中')
except:
myMainWindow._signal.emit('數據存儲失敗,請檢查數據庫是否打開!')
time_comsume=round(t2-t1,2)
myMainWindow._signal.emit('共耗時: '+str(time_comsume)+' s')
myMainWindow._signal.emit("****************處理完畢****************")
except BaseException as e1:
print(e1)
except EnvironmentError as e2:
print(e2)
except (OSError,WindowsError,
MemoryError,NameError,
UnboundLocalError,ReferenceError,
RuntimeError,NotImplementedError,
UnicodeDecodeError,UnicodeEncodeError,
UnicodeError,UnicodeTranslateError,
RuntimeWarning,UserWarning) as e3:
print(e3)
if __name__ == '__main__':
app = 0
if not QApplication.instance():
app = QApplication(sys.argv)
else:
app = QApplication.instance()
myMainWindow = MainWindow2()#自定義的類例化
myMainWindow.show()
t1 = threading.Thread(target = output_info_thread, args = (myMainWindow,))
t1.start()
time.sleep(10)
sys.exit(app.exec_())
同理,將該界面的XX_gui.py修改為:
self.retranslateUi(MainWindow2)
self.pushButton.clicked.connect(MainWindow2.open_file)
self.pushButton_2.clicked.connect(MainWindow2.open_files)
self.pushButton_3.clicked.connect(MainWindow2.reset)
self.pushButton_4.clicked.connect(MainWindow2.back)
QtCore.QMetaObject.connectSlotsByName(MainWindow2)
self.MainWindow2=MainWindow2
mainWindow2=self.MainWindow2
2.3 圖像處理測試界面
import sys
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QFileDialog,QWidget
#from img_pro_gui_code import Ui_Dialog
from img_pro_gui import Ui_Dialog
from img_processing_plot import img_processing
#from main_win import MainWindow
class Picture(QWidget):
def __init__(self):
super(Picture,self).__init__()#調用父類的init
global ui
ui = Ui_Dialog()
ui.setupUi(self)
self.imgs_data=ui.imgs_data
self.dialog=ui.dialog
def reset(self):
pass
def back(self):
pass
def open_file(self):
imgName, imgType = QFileDialog.getOpenFileName(self, "打開圖片", "", "*.jpg;;*.png;;All Files(*)")
self.path=imgName
img_path=self.path.replace("/","//")
imgs=img_processing(img_path)
for i in range(len(imgs)):
jpg = QtGui.QPixmap(imgs[i]).scaled(self.imgs_data[i].width(),
self.imgs_data[i].height())
self.imgs_data[i].setPixmap(jpg)
if __name__ == "__main__":
app=0
app = QtWidgets.QApplication(sys.argv)
my = Picture()
my.show()
sys.exit(app.exec_())
值得一提的是,這里的多圖片顯示功能,我是先將圖像處理測試程序中產生的圖片保存到本地再使用QPixmap方法導入並顯示。
同理,該界面所對應的XX_gui.py文件中改寫為:
self.retranslateUi(Dialog)
self.choose.clicked.connect(Dialog.open_file)
self.clear.clicked.connect(Dialog.reset)
self.back.clicked.connect(Dialog.back)
QtCore.QMetaObject.connectSlotsByName(Dialog)
self.imgs_data=[self.img_source,self.img_blur,self.img_canny,self.img_cut,
self.img_close,self.img_open,self.img_domain,self.img_skeleton]
imgs_data=self.imgs_data
self.dialog=Dialog
dialog=self.dialog
3. 界面跳轉與重置
3.1主界面與裂紋快速識別界面
主界面跳轉界面1修改為:
def jump_to_1(self):
#myMainWindow.hide() #如果沒有這一句,關閉子界面后就會關閉程序
self.ui_1=MainWindow2()
self.ui_1.show()
crack_detect(self.ui_1)
裂紋快速識別界面上返回功能是直接關閉當前界面,重置功能是將界面數據清零並再次啟動多線程。
def back(self):
self.mainWindow2.close()
def reset(self,parent = None):
self.img_opened = False
self.imgs_opened = False
ui.output_info.clear()
ui.file_name.clear()
t1 = threading.Thread(target = output_info_thread, args = (myMainWindow,))
t1.start()
3.2主界面與圖像處理測試界面
主界面跳轉界面2修改為:
def jump_to_2(self):
#myMainWindow.hide() #如果沒有這一句,關閉子界面后就會關閉程序
self.ui_2=Picture()
self.ui_2.show()
圖像處理測試界面上返回功能的實現同上,重置功能是將界面數據清零。
def reset(self):
for label in self.imgs_data:
label.clear()
def back(self):
self.dialog.close()
- 結果展示
在命令行運行主界面程序,結果如下(以Gif展示):
- 寫在最后
由於時間有限且初次設計GUI界面(經驗不足),界面比較丑,請見諒。若有問題,歡迎留言。