編輯UI
編輯UI如下圖所示:
新建視頻播放類Display
定義如下初始化函數
def __init__(self, ui, mainWnd):
self.ui = ui
self.mainWnd = mainWnd
# 默認視頻源為相機
self.ui.radioButtonCam.setChecked(True)
self.isCamera = True
# 信號槽設置
ui.Open.clicked.connect(self.Open)
ui.Close.clicked.connect(self.Close)
ui.radioButtonCam.clicked.connect(self.radioButtonCam)
ui.radioButtonFile.clicked.connect(self.radioButtonFile)
# 創建一個關閉事件並設為未觸發
self.stopEvent = threading.Event()
self.stopEvent.clear()
打開相機
防止UI卡死,需要單獨用一個線程去顯示視頻,可以選中打開相機還是打開本機mp4文件。
def Open(self):
if not self.isCamera:
self.fileName, self.fileType = QFileDialog.getOpenFileName(self.mainWnd, 'Choose file', '', '*.mp4')
self.cap = cv2.VideoCapture(self.fileName)
self.frameRate = self.cap.get(cv2.CAP_PROP_FPS)
else:
# 下面兩種rtsp格式都是支持的
# cap = cv2.VideoCapture("rtsp://admin:Supcon1304@172.20.1.126/main/Channels/1")
self.cap = cv2.VideoCapture("rtsp://admin:Supcon1304@172.20.1.126:554/h264/ch1/main/av_stream")
# 創建視頻顯示線程
th = threading.Thread(target=self.Display)
th.start()
關閉相機
啟動線程可以直接調用start(),但是結束線程並沒有現成的接口可以調用。
添加一個事件用來判斷是否需要關閉相機
def Close():
# 關閉事件設為觸發,關閉視頻播放
stopEvent.set()
顯示視頻畫面
注意:
- OpenCV獲得的圖像幀數據是RGB格式,QImage是BGR格式,所以需要進行格式轉換;
- 每次顯示完成后都去判斷是否點擊了關閉按鈕。
def Display(self):
self.ui.Open.setEnabled(False)
self.ui.Close.setEnabled(True)
while self.cap.isOpened():
success, frame = self.cap.read()
# RGB轉BGR
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
img = QImage(frame.data, frame.shape[1], frame.shape[0], QImage.Format_RGB888)
self.ui.DispalyLabel.setPixmap(QPixmap.fromImage(img))
if self.isCamera:
cv2.waitKey(1)
else:
cv2.waitKey(int(1000 / self.frameRate))
# 判斷關閉事件是否已觸發
if True == self.stopEvent.is_set():
# 關閉事件置為未觸發,清空顯示label
self.stopEvent.clear()
self.ui.DispalyLabel.clear()
self.ui.Close.setEnabled(False)
self.ui.Open.setEnabled(True)
break
完整源代碼
文件VideoDisplay.py
import cv2
import threading
from PyQt5.QtCore import QFile
from PyQt5.QtWidgets import QFileDialog, QMessageBox
from PyQt5.QtGui import QImage, QPixmap
class Display:
def __init__(self, ui, mainWnd):
self.ui = ui
self.mainWnd = mainWnd
# 默認視頻源為相機
self.ui.radioButtonCam.setChecked(True)
self.isCamera = True
# 信號槽設置
ui.Open.clicked.connect(self.Open)
ui.Close.clicked.connect(self.Close)
ui.radioButtonCam.clicked.connect(self.radioButtonCam)
ui.radioButtonFile.clicked.connect(self.radioButtonFile)
# 創建一個關閉事件並設為未觸發
self.stopEvent = threading.Event()
self.stopEvent.clear()
def radioButtonCam(self):
self.isCamera = True
def radioButtonFile(self):
self.isCamera = False
def Open(self):
if not self.isCamera:
self.fileName, self.fileType = QFileDialog.getOpenFileName(self.mainWnd, 'Choose file', '', '*.mp4')
self.cap = cv2.VideoCapture(self.fileName)
self.frameRate = self.cap.get(cv2.CAP_PROP_FPS)
else:
# 下面兩種rtsp格式都是支持的
# cap = cv2.VideoCapture("rtsp://admin:Supcon1304@172.20.1.126/main/Channels/1")
self.cap = cv2.VideoCapture("rtsp://admin:Supcon1304@172.20.1.126:554/h264/ch1/main/av_stream")
# 創建視頻顯示線程
th = threading.Thread(target=self.Display)
th.start()
def Close(self):
# 關閉事件設為觸發,關閉視頻播放
self.stopEvent.set()
def Display(self):
self.ui.Open.setEnabled(False)
self.ui.Close.setEnabled(True)
while self.cap.isOpened():
success, frame = self.cap.read()
# RGB轉BGR
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
img = QImage(frame.data, frame.shape[1], frame.shape[0], QImage.Format_RGB888)
self.ui.DispalyLabel.setPixmap(QPixmap.fromImage(img))
if self.isCamera:
cv2.waitKey(1)
else:
cv2.waitKey(int(1000 / self.frameRate))
# 判斷關閉事件是否已觸發
if True == self.stopEvent.is_set():
# 關閉事件置為未觸發,清空顯示label
self.stopEvent.clear()
self.ui.DispalyLabel.clear()
self.ui.Close.setEnabled(False)
self.ui.Open.setEnabled(True)
break
文件main.py
import sys
import DisplayUI
from PyQt5.QtWidgets import QApplication, QMainWindow
from VideoDisplay import Display
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWnd = QMainWindow()
ui = DisplayUI.Ui_MainWindow()
# 可以理解成將創建的 ui 綁定到新建的 mainWnd 上
ui.setupUi(mainWnd)
display = Display(ui, mainWnd)
mainWnd.show()
sys.exit(app.exec_())
效果圖
