OpenCV能夠處理圖像、視頻、深度圖像等各種類型的視覺數(shù)據(jù),在某些情況下,盡管OpenCV可以顯示窗口,但PyQt5可能更適合用于創(chuàng)建復(fù)雜的交互式應(yīng)用程序,而自帶GPU的H618就成為了這些圖像顯示的最佳載體。
這里分享一個代碼,功能是使用圖像處理庫opencv從攝像頭獲取數(shù)據(jù),縮放后從pyqt5的窗口中顯示出來。
安裝opencv
sudo pip3 install opencv-python
創(chuàng)建一個pyqt5窗口
1. 用Qt Designer畫個窗口
這里我在電腦上使用designer軟件,創(chuàng)建一個Main Window類型窗體。從左邊組件欄中拖出一個label放到窗口中間。
點(diǎn)一下放在窗口中的label,在軟件右下角的屬性編輯器里可以設(shè)置很多東西,這里就不細(xì)介紹了。這里我是設(shè)置了QFrame啟用了邊框,QLabel中的texte屬性控制顯示的文本,QLabel中的alignment屬性控制文本對齊方式。
然后保存為.ui結(jié)尾的文件
2. 將designer繪制的ui文件轉(zhuǎn)化為py文件
python3 -m PyQt5.uic.pyuic ui_main.ui -o ui_main.py
3. 編寫main.py程序,調(diào)用剛剛畫的窗口進(jìn)行顯示
先把剛剛的ui_main.py以及一些qt庫給import進(jìn)來
from ui_main import Ui_MainWindow
import PyQt5
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
# 修正qt的plugin路徑,因?yàn)槟承┏绦颍╟v2)會將其改到其他路徑
import os
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = os.path.dirname(PyQt5.__file__)
放入一點(diǎn)輔助代碼,一個是為了實(shí)現(xiàn)從遠(yuǎn)程命令行運(yùn)行qt程序顯示到桌面上,一個是為了在命令行下可以按ctrl+c快捷鍵來強(qiáng)制退出qt程序
#【可選代碼】允許遠(yuǎn)程運(yùn)行
import os
os.environ["DISPLAY"] = ":0.0"
#【建議代碼】允許終端通過ctrl+c中斷窗口,方便調(diào)試
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
timer = QtCore.QTimer()
timer.start(100) # You may change this if you wish.
timer.timeout.connect(lambda: None) # Let the interpreter run each 100 ms
定義窗口類,重寫窗口的一些觸發(fā)事件。這里我修改了鼠標(biāo)點(diǎn)擊后會被自動調(diào)用的mousePressEvent和窗口繪制時會被調(diào)用的paintEvent
class WINDOW(QtWidgets.QMainWindow):
def mousePressEvent(self, event):
# 被左鍵點(diǎn)擊后退出本程序
if event.button() == Qt.LeftButton:
self.close()
exit(-1)
def paintEvent(self,event):
# 修改label的大小和位置
new_width = int(window.width()/10*8)
new_height = int(window.height()/10*8)
lab_x = int((window.width() - new_width) / 2)
lab_y = int((window.height() - new_height) / 2)
ui.label.setGeometry( lab_x, lab_y, new_width, new_height)
加上調(diào)用函數(shù)進(jìn)行顯示的部分,這個顯示pyqt5窗口的基本程序就完成了
# 初始化窗口
import sys
app = QtWidgets.QApplication(sys.argv)
window = WINDOW()
ui = Ui_MainWindow()
ui.setupUi(window)
window.showFullScreen() #全屏顯示
# window.show() #按繪制時的尺寸顯示
sys.exit(app.exec_())
在核桃派lcd屏上的效果展示
opencv怎么讀取攝像頭
調(diào)用頭文件,opencv的頭文件只需要這一個
import cv2
打開攝像頭,其中傳入的參數(shù)1是攝像頭編號,一般是從0開始往后排
cap = cv2.VideoCapture(1)
從攝像頭讀取一幀圖像,ret是讀取狀態(tài),frame是圖像數(shù)據(jù)
ret, frame = cap.read()
怎么把opencv的圖像數(shù)據(jù)顯示到qt的label
cap.read函數(shù)讀到的是bgr格式的,需要先轉(zhuǎn)為rgb格式
rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
將圖像轉(zhuǎn)為Qt中用來表示圖像的QImage
h, w, ch = rgbImage.shape
qtImage = QImage(rgbImage.data, h, w, ch*w, QtGui.QImage.Format_RGB888)
label的setPixmap方法可以圖像數(shù)據(jù)覆蓋label
label.setPixmap(QPixmap.fromImage(qtImage))
線程,信號與槽
我們這里使用qt自帶的多線程功能,他的使用很簡單,只需要創(chuàng)建一個類并繼承自QThread, 然后將要運(yùn)行的東西寫到類里的run方法下面。實(shí)例化一個對象后,調(diào)用start方法即可創(chuàng)建新線程
class Work(QThread):
def run(self):
pass
work = Work()
work.start()
直接在線程內(nèi)調(diào)用函數(shù)去修改qt窗口的內(nèi)容,不能滿足線程安全。
我們需要創(chuàng)建一個信號,把修改qt窗口的語句寫到一個槽內(nèi),連接他們,在想修改窗口時發(fā)出信號,讓qt內(nèi)部去調(diào)度,防止跟其他qt內(nèi)部的線程發(fā)生沖突。
因?yàn)槲覀冞@個線程類繼承自QThread,所以可以在類內(nèi)定義信號。只需要實(shí)例化一個pyqtSignal對象即可,調(diào)用時括號內(nèi)的參數(shù)決定了槽函數(shù)必須有什么類型的參數(shù),以及發(fā)送信號時需要傳入什么參數(shù)。
```
signal_update_label = pyqtSignal( QPixmap)
槽函數(shù)就是隨便定義一個函數(shù),只要函數(shù)參數(shù)跟信號一樣就行。
```
label:QLabel
def sloat_update_label( self, pixmap:QPixmap):
self.label.setPixmap(pixmap)
連接信號與槽,使用connect方法即可
self.signal_update_label.connect(self.sloat_update_label)
使用emit方法即可發(fā)送信號,qt內(nèi)部會進(jìn)行調(diào)度,將所有連接到本信號的函數(shù)都調(diào)出來運(yùn)行,并將參數(shù)傳給他們。這是qt實(shí)現(xiàn)線程安全的重要機(jī)制。
self.signal_update_label.emit(QPixmap.fromImage(qtImage))
最終代碼文章來源:http://www.zghlxwxcb.cn/news/detail-790294.html
import cv2
from ui_main import Ui_MainWindow
import PyQt5
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
# 修正qt的plugin路徑,因?yàn)槟承┏绦颍╟v2)會將其改到其他路徑
import os
os.environ['QT_QPA_PLATFORM_PLUGIN_PATH'] = os.path.dirname(PyQt5.__file__)
#【可選代碼】允許Thonny遠(yuǎn)程運(yùn)行
import os
os.environ["DISPLAY"] = ":0.0"
#【建議代碼】允許終端通過ctrl+c中斷窗口,方便調(diào)試
import signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
timer = QTimer()
timer.start(100) # You may change this if you wish.
timer.timeout.connect(lambda: None) # Let the interpreter run each 100 ms
# 線程類
class Work(QThread):
signal_update_label = pyqtSignal(QPixmap)
label:QLabel
def sloat_update_label( self, pixmap:QPixmap):
self.label.setPixmap(pixmap)
def run(self):
print("label.width()=", self.label.width())
print("label.height()=", self.label.height())
self.signal_update_label.connect(self.sloat_update_label)
cap = cv2.VideoCapture(1)
while True:
ret, frame = cap.read()
if ret:
# 顏色轉(zhuǎn)換
rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# 按比例縮放
h, w, ch = rgbImage.shape
aspect_ratio = w / h
new_width = self.label.width()
new_height = int(new_width / aspect_ratio)
if new_height > self.label.height():
new_height = self.label.height()
new_width = int(new_height * aspect_ratio)
rgbImage = cv2.resize(rgbImage, (new_width, new_height))
# 顯示到label
bytesPerLine = ch * new_width
self.signal_update_label.emit(QPixmap.fromImage(QImage(rgbImage.data, new_width, new_height, bytesPerLine, QImage.Format_RGB888)))
else :
print("cap read error")
return
class WINDOW(QMainWindow):
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.close()
def paintEvent(self,event):
new_width = int(window.width()/10*8)
new_height = int(window.height()/10*8)
lab_x = int((window.width() - new_width) / 2)
lab_y = int((window.height() - new_height) / 2)
ui.label.setGeometry( lab_x, lab_y, new_width, new_height)
import sys
app = QApplication(sys.argv)
window = WINDOW()
ui = Ui_MainWindow()
ui.setupUi(window)
window.showFullScreen() #全屏顯示
# window.show() #按繪制時的尺寸顯示
# 創(chuàng)建讀取攝像頭并顯示的線程
work = Work()
work.label = ui.label
work.start()
sys.exit(app.exec_())
文章來源地址http://www.zghlxwxcb.cn/news/detail-790294.html
到了這里,關(guān)于可視可交互!在全志H618上用OpenCV讀取圖像顯示到PyQt5窗口上的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!