引言
學習多線程最典型的問題就是如何在多個線程之間傳遞消息與寫作,PyQT5的線程支持在不同線程之間傳遞信號觸發(fā)事件,實現(xiàn)多個線程之間的協(xié)助,完成諸如生產(chǎn)者-消費者這樣經(jīng)典的多線程協(xié)作。本文將通過QThread與信號槽機制構(gòu)建一個生產(chǎn)者-消費者模型,演示多個線程之間的協(xié)作。
應用程序概述
這里演示了一個從圖像采集(用本地圖像數(shù)據(jù)集替代)到圖像分析處理(簡單二值化+形態(tài)學處理)、到主界面更新的應用程序。主界面是UI線程、圖像采集跟圖像分析分別在兩個不同的工作線程中,通過信號與槽機制協(xié)作工作,相互配合實現(xiàn)圖像采集到分析到結(jié)果更新到界面線程。
多線程協(xié)作信號觸發(fā)示意圖
代碼實現(xiàn)
這樣實現(xiàn)了三個類
ImageFetchThread // 圖像采集 ImageAnalysisThread // 圖像分析 ContentPanel // 界面顯示與更新
這三個類的代碼分別,模擬圖像采集線程
1classImageFetchThread(QtCore.QThread): 2fire_stats_signal=QtCore.pyqtSignal(dict) 3 4def__init__(self,images_dir): 5super(ImageFetchThread,self).__init__() 6self.images_dir=images_dir 7self.read_next=True 8 9defrequest_image(self): 10self.read_next=True 11 12defrun(self): 13iflen(self.images_dir)==0: 14return 15files=os.listdir(self.images_dir) 16idx=0 17whileTrue: 18ifidx==len(files): 19break 20ifself.read_nextisTrue: 21print("graboneimage...") 22image=cv.imread(os.path.join(self.images_dir,files[idx])) 23gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY) 24idx+=1 25self.read_next=False 26self.fire_stats_signal.emit({"im_data":gray}) 27self.fire_stats_signal.emit({"done":"done"}) 28return
處理圖像線程
1classImageAnalysisThread(QtCore.QThread): 2request_image_signal=QtCore.pyqtSignal() 3update_result_signal=QtCore.pyqtSignal(dict) 4 5def__init__(self): 6super(ImageAnalysisThread,self).__init__() 7self.image_data=None 8self.stop=False 9 10defprocess_im(self,results): 11self.image_data=results.get("im_data") 12ifresults.get("done")isnotNone: 13self.stop=True 14 15defrun(self): 16whileTrue: 17ifself.stopisTrue: 18break 19ifself.image_dataisNone: 20continue 21print("startedtoprocessoneimage...") 22#ret,binary=cv.threshold(self.image_data,0,255,cv.THRESH_BINARY|cv.THRESH_OTSU) 23binary=cv.adaptiveThreshold(self.image_data,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C, 24cv.THRESH_BINARY_INV,25,10) 25se=cv.getStructuringElement(cv.MORPH_RECT,(7,7)) 26resutl=cv.morphologyEx(binary,cv.MORPH_DILATE,se) 27self.request_image_signal.emit() 28self.update_result_signal.emit({"im_data":resutl}) 29self.image_data=None 30self.update_result_signal.emit({"done":"done"}) 31return
界面線程
1classContentPanel(QtWidgets.QWidget): 2def__init__(self,parent=None): 3super().__init__(parent) 4fileBtn=QtWidgets.QPushButton("目錄...") 5self.image_files_dir=QtWidgets.QLineEdit() 6self.image_files_dir.setMinimumWidth(100) 7self.image_files_dir.setEnabled(False) 8self.processBtn=QtWidgets.QPushButton("開始處理") 9hbox_layout=QtWidgets.QHBoxLayout() 10hbox_layout.addWidget(fileBtn) 11hbox_layout.addWidget(self.image_files_dir) 12hbox_layout.addWidget(self.processBtn) 13panel1=QtWidgets.QGroupBox("目錄選擇") 14panel1.setLayout(hbox_layout) 15 16#圖像標簽 17self.imgLabel=QtWidgets.QLabel() 18self.imgLabel.setMinimumSize(800,600) 19self.imgLabel.setStyleSheet("background-color:black;color:deeppink") 20self.imgLabel.setAlignment(QtCore.Qt.AlignCenter) 21 22#添加到布局管理器中 23vbox_layout=QtWidgets.QVBoxLayout() 24vbox_layout.addWidget(panel1) 25vbox_layout.addWidget(self.imgLabel) 26vbox_layout.addStretch(1) 27 28#面板容器 29self.setLayout(vbox_layout) 30 31#setuplistener 32fileBtn.clicked.connect(self.on_select_image_dir) 33self.processBtn.clicked.connect(self.on_process) 34 35self.fetch_thread=None 36self.analysis_thread=None 37 38defon_select_image_dir(self): 39img_dir=QtWidgets.QFileDialog.getExistingDirectory(self,"圖像文件夾",".") 40self.image_files_dir.setText(img_dir)
演示部分
-
多線程
+關(guān)注
關(guān)注
0文章
278瀏覽量
19956 -
應用程序
+關(guān)注
關(guān)注
37文章
3268瀏覽量
57705 -
OpenCV
+關(guān)注
關(guān)注
31文章
635瀏覽量
41350 -
圖像分析
+關(guān)注
關(guān)注
0文章
82瀏覽量
18679 -
pyqt5
+關(guān)注
關(guān)注
0文章
25瀏覽量
3402
原文標題:PyQT5+OpenCV多線程協(xié)作演示
文章出處:【微信號:CVSCHOOL,微信公眾號:OpenCV學堂】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論