引言
学习多线程最典型的问题就是如何在多个线程之间传递消息与写作,pyqt5的线程支持在不同线程之间传递信号触发事件,实现多个线程之间的协助,完成诸如生产者-消费者这样经典的多线程协作。本文将通过qthread与信号槽机制构建一个生产者-消费者模型,演示多个线程之间的协作。
应用程序概述
这里演示了一个从图像采集(用本地图像数据集替代)到图像分析处理(简单二值化+形态学处理)、到主界面更新的应用程序。主界面是ui线程、图像采集跟图像分析分别在两个不同的工作线程中,通过信号与槽机制协作工作,相互配合实现图像采集到分析到结果更新到界面线程。
多线程协作信号触发示意图
代码实现
这样实现了三个类
imagefetchthread // 图像采集imageanalysisthread // 图像分析contentpanel // 界面显示与更新
这三个类的代码分别,模拟图像采集线程
1class imagefetchthread(qtcore.qthread): 2 fire_stats_signal = qtcore.pyqtsignal(dict) 3 4 def __init__(self, images_dir): 5 super(imagefetchthread, self).__init__() 6 self.images_dir = images_dir 7 self.read_next = true 8 9 def request_image(self):10 self.read_next = true1112 def run(self):13 if len(self.images_dir) == 0:14 return15 files = os.listdir(self.images_dir)16 idx = 017 while true:18 if idx == len(files):19 break20 if self.read_next is true:21 print(grab one image...)22 image = cv.imread(os.path.join(self.images_dir, files[idx]))23 gray = cv.cvtcolor(image, cv.color_bgr2gray)24 idx += 125 self.read_next = false26 self.fire_stats_signal.emit({im_data: gray})27 self.fire_stats_signal.emit({done: done})28 return
处理图像线程
1class imageanalysisthread(qtcore.qthread): 2 request_image_signal = qtcore.pyqtsignal() 3 update_result_signal = qtcore.pyqtsignal(dict) 4 5 def __init__(self): 6 super(imageanalysisthread, self).__init__() 7 self.image_data = none 8 self.stop = false 910 def process_im(self, results):11 self.image_data = results.get(im_data)12 if results.get(done) is not none:13 self.stop = true1415 def run(self):16 while true:17 if self.stop is true:18 break19 if self.image_data is none:20 continue21 print(started to process one image...)22 # ret, binary = cv.threshold(self.image_data, 0, 255, cv.thresh_binary | cv.thresh_otsu)23 binary = cv.adaptivethreshold(self.image_data, 255, cv.adaptive_thresh_gaussian_c,24 cv.thresh_binary_inv, 25, 10)25 se = cv.getstructuringelement(cv.morph_rect, (7, 7))26 resutl = cv.morphologyex(binary, cv.morph_dilate, se)27 self.request_image_signal.emit()28 self.update_result_signal.emit({im_data: resutl})29 self.image_data = none30 self.update_result_signal.emit({done: done})31 return
界面线程
1class contentpanel(qtwidgets.qwidget): 2 def __init__(self, parent=none): 3 super().__init__(parent) 4 filebtn = qtwidgets.qpushbutton(目录...) 5 self.image_files_dir= qtwidgets.qlineedit() 6 self.image_files_dir.setminimumwidth(100) 7 self.image_files_dir.setenabled(false) 8 self.processbtn = qtwidgets.qpushbutton(开始处理) 9 hbox_layout = qtwidgets.qhboxlayout()10 hbox_layout.addwidget(filebtn)11 hbox_layout.addwidget(self.image_files_dir)12 hbox_layout.addwidget(self.processbtn)13 panel1 = qtwidgets.qgroupbox(目录选择)14 panel1.setlayout(hbox_layout)1516 # 图像标签17 self.imglabel = qtwidgets.qlabel()18 self.imglabel.setminimumsize(800, 600)19 self.imglabel.setstylesheet(background-color:black; color: deeppink)20 self.imglabel.setalignment(qtcore.qt.aligncenter)2122 # 添加到布局管理器中23 vbox_layout = qtwidgets.qvboxlayout()24 vbox_layout.addwidget(panel1)25 vbox_layout.addwidget(self.imglabel)26 vbox_layout.addstretch(1)2728 # 面板容器29 self.setlayout(vbox_layout)3031 # setup listener32 filebtn.clicked.connect(self.on_select_image_dir)33 self.processbtn.clicked.connect(self.on_process)3435 self.fetch_thread = none36 self.analysis_thread = none3738 def on_select_image_dir(self):39 img_dir = qtwidgets.qfiledialog.getexistingdirectory(self, 图像文件夹, .)40 self.image_files_dir.settext(img_dir)
演示部分
PLC能取代运动控制器吗?
关于半导体FAB厂的技术100个问题汇总
惠普打造的移动网络经常出现故障遭到了俄罗斯移动运营商的起诉
UHF频段无线收发信机前端设计
国产AIoT SoC芯片龙头初现 MCU变革已来
PyQT5+OpenCV多线程协作演示
魅族科技宣布将于4月23日在珠海举办新品发布会
触摸式报警器
单双张检测超声波传感器的功能特点
采用全数字中频技术的DSA1030A频谱分析仪的设计
天宫二号是干什么的 五个问题让您快速了解
安谋科技吴雄昂:核芯动力XPU,定义全新的融合计算架构
三星Galaxy Note10发布会正式召开, 8GB+256GB版本售价6599元
3月15日直播预告|Vector-CSM测量技术产品方案介绍
如何在全生命周期中满足不断提高流量需求
LED嵌入式绷带可通过蓝光来治愈慢性创面
在选择板对板连接器时可从这几个方面入手
五招帮你排除解决投影机偏色故障
芯片制程技术从3nm走向了2nm
pcb电路板制有什么方法和技巧