☞ ░ 前往老猿Python博文目錄 ░
一、引言
在Python-OpenCV中顯示圖像時調用的是一個單獨的窗口,有時我們需要將這些圖像顯示在PyQt的圖形化界面上,這樣就可以將整個圖像顯示與PyQt圖形化界面進行整合。但OpenCV格式的圖像和PyQt格式的圖像並不同,這就需要進行轉換。
二、背景知識
- Python-OpenCV的圖像是BGR格式的,而PyQt圖像格式是RGB格式的,二者需要轉換;
- 為了快速轉換,圖像必須基於內存進行操作;
- PyQt的QImage類可以從內存數組構建;
- OpenCV可以讀取視頻圖像,使用waitKey可以實現休眠特定時長而不影響系統消息處理。
關於PyQt和OpenCV之間的圖像轉換請參考《Python-OpenCV中圖像顏色空間轉換》。
三、案例
下面的案例讀取一個視頻文件的圖像進行顯示,如果再疊加一個音頻播放的功能,就實現了一個視頻播放器。
3.1、設計圖形化界面
該圖形界面非常簡單,包含了一個僅有“ShowImg”的菜單和對應工具欄,一個名為ImgDisp的標簽對象用於顯示圖像(藍色標記部分)。使用PyUIC生成的界面對象代碼如下:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(625, 430)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.ImgDisp = QtWidgets.QLabel(self.centralwidget)
self.ImgDisp.setGeometry(QtCore.QRect(0, 0, 54, 12))
self.ImgDisp.setObjectName("ImgDisp")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 625, 17))
self.menubar.setObjectName("menubar")
self.menushowImg = QtWidgets.QMenu(self.menubar)
self.menushowImg.setObjectName("menushowImg")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.toolBar = QtWidgets.QToolBar(MainWindow)
self.toolBar.setObjectName("toolBar")
MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)
self.actionshowImg = QtWidgets.QAction(MainWindow)
self.actionshowImg.setObjectName("actionshowImg")
self.menushowImg.addAction(self.actionshowImg)
self.menubar.addAction(self.menushowImg.menuAction())
self.toolBar.addAction(self.actionshowImg)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.ImgDisp.setText(_translate("MainWindow", "."))
self.menushowImg.setTitle(_translate("MainWindow", "menu"))
self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar"))
self.actionshowImg.setText(_translate("MainWindow", "showImg"))
3.2、主程序
import cv2,sys
from PyQt5 import QtGui,QtWidgets,QtCore
import mainWin
def cvImgtoQtImg(cvImg): #定義opencv圖像轉PyQt圖像的函數
QtImgBuf = cv2.cvtColor(cvImg, cv2.COLOR_BGR2BGRA)
QtImg = QtGui.QImage(QtImgBuf.data, QtImgBuf.shape[1], QtImgBuf.shape[0], QtGui.QImage.Format_RGB32)
return QtImg
class mainwin(QtWidgets.QMainWindow,mainWin.Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.bClose = False
self.actionshowImg.triggered.connect(self.playVideoFile) #建立菜單點擊的信號與方法playVideoFile連接
def playVideoFile(self): #播放影片
cap = cv2.VideoCapture(r'f:\video\mydream.mp4') #打開影片
fps = 24
if not cap.isOpened():
print("Cannot open Video File")
exit()
while not self.bClose:
ret, frame = cap.read() #逐幀讀取影片
if not ret:
if frame is None:
print("The video has end.")
else:
print("Read video error!")
break
QtImg = cvImgtoQtImg(frame) #將幀數據轉換為PyQt圖像格式
self.ImgDisp.setPixmap(QtGui.QPixmap.fromImage(QtImg)) #在ImgDisp顯示圖像
size = QtImg.size()
self.ImgDisp.resize(size)#根據幀大小調整標簽大小
self.ImgDisp.show() #刷新界面
cv2.waitKey(int(1000/fps)) #休眠一會,確保每秒播放fps幀
# 完成所有操作后,釋放捕獲器
cap.release()
if __name__=='__main__':
app = QtWidgets.QApplication(sys.argv)
w = mainwin()
w.show()
sys.exit(app.exec_())
注意:
本文的實現方法存在不足,相關完善方案請見《OpenCV-Python圖像轉換為PyQt圖像的變形及花屏問題研究》。
3.3、運行程序
初始界面
點擊showImg,開始播放視頻:
關於PyQt的使用請參考付費專欄《使用PyQt開發圖形界面Python應用》,專欄文件目錄《使用PyQt開發圖形界面Python應用專欄目錄》。
也可以參考免費專欄《PyQt入門知識》,專欄文件目錄《使用PyQt進行Python圖形界面程序開發文章目錄》。
關於老猿的付費專欄
老猿的付費專欄《使用PyQt開發圖形界面Python應用》專門介紹基於Python的PyQt圖形界面開發基礎教程,付費專欄《moviepy音視頻開發專欄》詳細介紹moviepy音視頻剪輯合成處理的類相關方法及使用相關方法進行相關剪輯合成場景的處理,兩個專欄加起來只需要19.9元,都適合有一定Python基礎但無相關專利知識的小白讀者學習。這2個收費專欄都有對應免費專欄,只是收費專欄的文章介紹更具體、內容更深入、案例更多。
收費專欄文章目錄:《moviepy音視頻開發專欄文章目錄》、《使用PyQt開發圖形界面Python應用專欄目錄》。
對於缺乏Python基礎的同仁,可以通過老猿的免費專欄《專欄:Python基礎教程目錄》從零開始學習Python。
如果有興趣也願意支持老猿的讀者,歡迎購買付費專欄。