【pyqt5】【多线程】【matplotlib】解决子线程上运行的matplotlib无法在主线程上的UI界面上绘制图形的问题

问题描述

在使用PyQt5为一个项目写UI界面的时候,我试图把matplotlib绘制的图像展示在UI界面的窗口中,但matplotlib是运行在一个子线程中的,这导致它出现了如下警告:UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fail.并且我无法使用matplotlib.backends.backend_qt5agg 下的 FigureCanvasQTAgg直接把图像绘制在UI窗口中,经过我测试如果matplotlib运行在主线程中的话就不会出现该问题。

解决方法

我用了一个笨办法,那就是使用IO.BytesIO()把matplotlib绘制的图像以png或者jpeg格式的二进制流保存在内存中,然后用PIL.Image.open()打开为图片,然后把这张图片经过处理后传递给窗口显示。

buf = io.BytesIO()
fig.savefig(buf, format="png", dpi=100)
buf.seek(0)
img = Image.open(buf)

下面说说图片处理过程:我使用的是QLabel来展示图片,这就需要图片数据类型类型是PyQt5.QtGui.QImage。经常使用下面的代码来展示:

image = QImage(img.data, img.shape[1], img.shape[0], QImage.Format_RGB888)
label.setPixmap(QPixmap.fromImage(image))

其中的img必须是numpy.ndarray类型的,但目前我们获得的img是PIL.PngImagePlugin.PngImageFile类型的。我们可以使用img = numpy.asarray(img)来进行转换,这样就可以使用上面的代码进行展示了。

img = Image.open(buf)
img = np.asarray(img)
image = QImage(img.data, img.shape[1], img.shape[0], QImage.Format_RGB888)
label.setPixmap(QPixmap.fromImage(image))

奇怪的是不知道为什么,通过这样的方法展示出来的图片却总是损坏的,如下图。
损坏的图片

通过打印查看转换为numpy.ndarray类型后的图片数组发现里面大部分数据都是255,但是将这张图片再转换回PIL类型的数据展示或者使用opencv显示却都没问题,这一度让我束手无策。

直到我发现PIL.PngImagePlugin.PngImageFile类型的图片可以使用PIL.ImageQt直接转换为QImage类型进行展示,通过如下代码:

image = ImageQt.ImageQt(img1)
label.setPixmap(QPixmap.fromImage(image))

ok,到这里我的问题就解决啦!最终在UI界面得到了如下效果。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/m0_57110410/article/details/129233582