在正式开始之前,得说几句感想,在最初学python的时候,对于多线程多进程,只有一个概念以及知道大概怎么用,但是什么情况下使用多线程,什么情况下使用多进程,我对这个概念还不是很清晰,正好前一个月左右做了个项目,在这个项目中,我使用了多线程来在界面上显示视频,今天想了想,还是写上这个,用于以后自己看或者给其他有兴趣的朋友看。

使用的技术:python + pyqt + opencv

在使用pyqt的过程中,我们经常就会遇到一种情况,当我们在界面上要显示视频的时候,会出现卡死的情况,要解决这个问题,就得用到多线程的技术,利用分出去的线程来处理后台发过来的图像数据,然后线程将这个图像进行显示。

首先,在Pyqt中,我们如何利用designed来设计整个软件的模样,如何让这个软件的界面好看,这个不属于我们这篇文章的讨论内容,我们值讨论如何让界面正常的显示视频并且不会卡顿。

为了解决这个问题,我们可以得了解pyqt的信号机制这些,这些也不属于我这篇文章讨论的内容,有不明白的可以自行了解,在这个问题中,我们要解决这个问题,得构建一个类,这个类继承pyqt中的QThread,代码如下:

'''this code is designed by nike hu'''
class imageThread(QThread):
    showImage = pyqtSignal(object) # 这里可以不要,这里是定义信号的
    def __init__(self, image): # 在调用这个类的时候传入image这个参数
        super().__init__()
        self.image = image

    def run(self): # 在使用这个类的时候直接调用这个接口就行
        # self.showImage.emit(image_color)
        image = self.image
        (imageH, imageW) = image.shape[0:2]
        Qimag = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) # pyqt中正常显示图片需要将opencv中的bgr转化为rgb
        QiM = QImage(Qimag.data, imageW, imageH,
                     imageW * 3, QImage.Format_RGB888) # 这也是将图像显示在界面中的必备步骤,QImage是从PyQt5.QtGui中导入的
        ui.hotImage.setPixmap(QPixmap.fromImage(QiM)) # ui.hotImage是pyqt中的lable控件,这个名字是你在画界面的时候自己定义的

在处理这类问题的时候,我的处理方法一般是把整个界面当成一个主线程,然后我会另外开一个线程来处理后台的数据,我们将这个线程称为子线程1,那么子线程1在处理接收到的每一帧图像数据的时候,我要么在子线程1的基础上另外开一个子线程2来处理图像的线程,子线程2将图像显示完就自己结束自己,或者我在主线程上开两个线程,一个子线程1,一个子线程2,子线程2是一个while循环,子线程1负责处理后台数据,然后通过全局变量的方式,子线程2来读取子线程1处理的图像数据,经过我的实验,最后界面是不再存在卡顿的现象。由于我的那个涉及到显示视频的是一个完整的项目,要将里面的代码拆分出来显示,不好拆分,所以就不再贴代码了,思路我已经提供了。对了,注意视频流图像读取的速度以及界面显示图像的速度,如果是毫无间隙的进行操作,也可能会出现卡顿现象,这时候,使用time.sleep(0.01)让这个线程休息0.01s或者再稍微长一点的时间,那么就可以避免这个问题的产生。

总结一下:多线程适用这种i/o延时高的操作,如果后台涉及到大量的数据运算的情况,那么就必须得利用多进程了,我有空会写一篇来处理人脸识别中导致的视频显示的效果帧数太低的情况。

2020 4.14