import cv2 import numpy as np from OpenGL.GL import * from OpenGL.GLU import * from PyQt5.QtCore import QTimer from PyQt5.QtWidgets import QApplication, QOpenGLWidget class VideoDisplayer(QOpenGLWidget): def __init__(self, frame_getter=None): super().__init__() self.frame_getter = frame_getter # 初始化帧获取函数 self.texture = None # 纹理变量初始化为 None self.is_update = False def initializeGL(self): glClearColor(0.0, 0.0, 0.0, 1.0) # 设置清除颜色为黑色 self.texture = glGenTextures(1) # 生成纹理对象 def resizeGL(self, w, h): glViewport(0, 0, w, h) # 设置 OpenGL 视口大小 glMatrixMode(GL_PROJECTION) # 设置当前矩阵为投影矩阵 glLoadIdentity() # 重置当前矩阵为单位矩阵 gluOrtho2D(0, w, h, 0) # 设置正交投影,匹配窗口宽度和高度 glMatrixMode(GL_MODELVIEW) # 设置当前矩阵为模型视图矩阵 glLoadIdentity() # 重置当前矩阵为单位矩阵 def paintGL(self): frame = self.frame_getter() # 获取一帧图像 if frame is None: return frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 转换颜色通道顺序为 RGB height, width, _ = frame.shape # 获取图像高度、宽度 # 创建 OpenGL 纹理 glBindTexture(GL_TEXTURE_2D, self.texture) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, frame.data) # 清除颜色缓冲区和深度缓冲区 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) glLoadIdentity() # 绘制纹理 glEnable(GL_TEXTURE_2D) glBegin(GL_QUADS) glTexCoord2f(0.0, 0.0); glVertex2f(0, 0) glTexCoord2f(1.0, 0.0); glVertex2f(self.width(), 0) glTexCoord2f(1.0, 1.0); glVertex2f(self.width(), self.height()) glTexCoord2f(0.0, 1.0); glVertex2f(0, self.height()) glEnd() glDisable(GL_TEXTURE_2D) if self.is_update: self.update() def set_frame_generator(self, frame_getter): self.frame_getter = frame_getter # 设置新的帧获取函数 def start(self): self.is_update = True self.update() def pause(self): self.is_update = False def resume(self): self.is_update = True self.update() def close(self): self.is_update = False if __name__ == '__main__': cap = cv2.VideoCapture(0) # 打开默认摄像头 def get_frame(): ret, frame = cap.read() # 读取摄像头帧 if ret: return frame app = QApplication([]) # 创建 PyQt 应用程序对象 widget = VideoDisplayer(get_frame) # 创建 VideoDisplayer 实例,传入帧获取函数 widget.resize(640, 480) # 设置窗口初始大小 widget.show() # 显示窗口 widget.start() # 开始显示视频流 app.exec_() # 进入 PyQt 主循环