如何在Qt Creator的Python Qt Quick应用中通过OpenCV向QML MediaPlayer推流
实现方案
核心思路:不使用MediaPlayer组件接收自定义帧数据,直接将OpenCV处理后的帧转为Qt支持的图像格式,通过属性绑定同步到QML端渲染,性能更高,更适配安防监控多路流的扩展需求。
1. 修改后端main.py代码
你需要在原有MainWindow类中新增视频采集逻辑、图像转换逻辑和供QML绑定的帧属性:
import sys import os import datetime import cv2 from pathlib import Path from PyQt5.QtCore import QObject, QTimer, pyqtSignal, pyqtProperty from PyQt5.QtGui import QImage from PyQt5.QtQml import QQmlApplicationEngine from PyQt5.QtGui import QGuiApplication class MainWindow(QObject): # 帧更新信号 frameChanged = pyqtSignal(QImage) def __init__(self): QObject.__init__(self) # 原有时间更新逻辑保留 self.timer = QTimer() self.timer.timeout.connect(lambda: self.setTime()) self.timer.start(1000) # 新增OpenCV视频采集逻辑 self.capture = cv2.VideoCapture(0) # 填0为本地摄像头,填RTSP地址即可拉取监控流 self._cv_frame = QImage() # 视频帧采集定时器,30fps对应33ms间隔,可根据实际帧率调整 self.frame_timer = QTimer() self.frame_timer.timeout.connect(self.updateFrame) self.frame_timer.start(33) # 新增帧属性供QML绑定 @pyqtProperty(QImage, notify=frameChanged) def cvFrame(self): return self._cv_frame # 新增帧采集转换逻辑 def updateFrame(self): ret, frame = self.capture.read() if not ret: return # OpenCV默认BGR格式,需转为RGB frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # 转QImage height, width, channel = frame_rgb.shape bytes_per_line = channel * width q_image = QImage(frame_rgb.data, width, height, bytes_per_line, QImage.Format_RGB888) # 更新属性并发射信号 if self._cv_frame != q_image: self._cv_frame = q_image self.frameChanged.emit(self._cv_frame) # 原有时间逻辑保留 def setTime(self): now = datetime.datetime.now() formatDate = now.strftime("Time: %H:%M:%S %p of %Y/%m/%d") self.printTime.emit(formatDate) # 原有printTime信号定义,若之前代码已存在可忽略 printTime = pyqtSignal(str) if __name__ == "__main__": app = QGuiApplication(sys.argv) engine = QQmlApplicationEngine() main = MainWindow() engine.rootContext().setContextProperty("backend", main) engine.load(os.fspath(Path(__file__).resolve().parent / "qml/main.qml")) if not engine.rootObjects(): sys.exit(-1) sys.exit(app.exec_())
2. 修改QML端代码
将原有MediaPlayer+VideoOutput的组合替换为Image组件,绑定后端暴露的cvFrame属性即可:
Image { id: cvFrameDisplay anchors.fill: parent source: backend.cvFrame fillMode: Image.PreserveAspectFit // 按需调整填充模式 } // 原有时间显示的Connections逻辑保留 Connections{ target: backend function onPrintTime(time){ labelDate.text = time } }
扩展多路流说明
后续需要接入多路监控流时,可单独封装一个CVStreamWorker类继承QObject,每个流实例化一个该类的对象,分别注册到QML上下文或者注册为QML可实例化类型,每个对象对应一个QML端的Image组件即可,无需修改现有核心逻辑。
注意:如果需要对帧进行AI检测、叠加OSD信息等操作,直接在updateFrame方法中拿到OpenCV的frame对象处理后再转QImage即可,无需额外改适配逻辑。
内容的提问来源于stack exchange,提问作者Cizhu
相关产品推荐
相关产品推荐

