PYQT5多线程加载图片
1.步骤
在PyQt5的多线程中显示图片,可以按以下步骤实现:
- 定义一个继承自QThread的线程类,在其run()方法中加载图片并发射信号。
- 在主线程中创建线程类的实例,连接信号和槽,并启动线程。
- 在槽方法中,接收从线程发射的图像,并更新GUI显示图像。
- 确保主线程中有事件循环,以显示更新的GUI。
2.代码
(发送QImage格式信号)
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtGui import QImage
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
class ImgThread(QThread):
#自定义信号声明
# 使用自定义信号和UI主线程通讯,参数是发送信号时附带参数的数据类型,可以是str、int、list、QImage、object、np.ndarray等
signal = pyqtSignal(QImage)
# 定义一个公共参数path,方便后面主函数的图片地址加载使用
def __init__(self, path):
super(WorkThread, self).__init__()
self.path = path
#run函数是子线程中的操作,线程启动后开始执行(run是官方定义的,不能改成其他的函数名)
def run(self):
img = QImage(self.path)
self.signal.emit(img)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# 绑定按钮点击事件
self.pushButton_2.clicked.connect(self.input_image)
self.pushButton.clicked.connect(self.output_image)
# 导入文件处理函数
def input_image(self):
source = QFileDialog.getOpenFileName(self, '选取视频或图片', "data/", "Pic File(*.mp4 *.mkv *.avi *.flv "
"*.jpg *.png)")
self.centernet_img_path = source[0] # 提取文件路径
jpg = QtGui.QPixmap(self.centernet_img_path).scaled(self.image_in.width(),
self.image_in.height()) # 通过文件路径获取图片文件,并设置图片长宽为label控件的长款
self.image_in.setPixmap(jpg) # 在label控件上显示选择的图片
# 热力图生成并展示
def output_image(self):
print('Start clicked.')
self.img_thread = ImgThread() #实例化一个线程
# 将线程thread的信号signal和UI主线程中的槽函数update_img进行连接
self.img_thread.signal.connect(self.update_img)
# 启动线程,执行线程类中run函数
self.img_thread.start()
#接受通过emit传来的img信息,执行相应操作
def update_img(self, img):
self.img_label.setPixmap(QPixmap.fromImage(img))
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
代码
(发送np.ndarray格式信号)
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtGui import QImage
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
class ImgThread(QThread):
#自定义信号声明
# 使用自定义信号和UI主线程通讯,参数是发送信号时附带参数的数据类型,可以是str、int、list、QImage、object、np.ndarray等
signal = pyqtSignal(np.ndarray)
# 定义一个公共参数path,方便后面主函数的图片地址加载使用
def __init__(self, path):
super(WorkThread, self).__init__()
self.path = path
#run函数是子线程中的操作,线程启动后开始执行(run是官方定义的,不能改成其他的函数名)
def run(self):
data = model(self.path)
self.signal.emit(data)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# 绑定按钮点击事件
self.pushButton_2.clicked.connect(self.input_image)
self.pushButton.clicked.connect(self.output_image)
# 导入文件处理函数
def input_image(self):
source = QFileDialog.getOpenFileName(self, '选取视频或图片', "data/", "Pic File(*.mp4 *.mkv *.avi *.flv "
"*.jpg *.png)")
self.centernet_img_path = source[0] # 提取文件路径
jpg = QtGui.QPixmap(self.centernet_img_path).scaled(self.image_in.width(),
self.image_in.height()) # 通过文件路径获取图片文件,并设置图片长宽为label控件的长款
self.image_in.setPixmap(jpg) # 在label控件上显示选择的图片
# 热力图生成并展示
def output_image(self):
print('Start clicked.')
self.img_thread = ImgThread() #实例化一个线程
# 将线程thread的信号signal和UI主线程中的槽函数update_img进行连接
self.img_thread.signal.connect(self.update_img)
# 启动线程,执行线程类中run函数
self.img_thread.start()
#接受通过emit传来的np.ndarray信息,执行相应操作
def update_img(self, data):
img_src = cv2.cvtColor(data, cv2.COLOR_BGR2RGB)
frame = cv2.resize(img_src, dsize=(int(self.img_label.width()), int(self.img_label.height())), interpolation=cv2.INTER_AREA)
img = QImage(frame.data, frame.shape[1], frame.shape[0], frame.shape[2] * frame.shape[1],
QImage.Format_RGB888)
self.img_label.setPixmap(QPixmap.fromImage(img))
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
3.注意点
- 线程中使用QImage加载图片,并发射信号传递QImage对象。
- 槽方法中接收QImage对象,使用QPixmap显示在label上。
- label需要设置scalContents属性为True,否则图片可能不能完整显示。
- 确保主线程有事件循环,否则GUI不能实时更新显示图片。