最近在幫導師做一個項目,需求要用Python做一個桌面軟件。如果做正式項目用tk肯定是不行的,所以第一個想到的就是PyQt5
這是我做了兩個月后,才知道,PyQt其實并不是Qt的官方Python支持。官方的Qt for python是PySide2,這兩者在我使用上主要是Signal(信號槽)部分不太一樣,PySide2用的是和C++ Qt相似的語法結構,而PyQt則用了自己的pyqtSignal,其他部分兩家都繼承了C++的接口,區別不是很大。
項目要用到攝像頭視頻監控,一開始我就想到了用QCamera,但怎么都開啟不了(可能是太菜了)后面進度在催,沒辦法用了第二種方案,OpenCV的cv2.Videocapture()。這下好了,給我整的生活不能自理,不知道cv2 Videocapture這個庫到底是怎么實現的,bug一堆不說,運行起來還各種閃退,不穩定。最后不得不用了Capture Thread+ Fetch Thread的方案,即一個線程不停地去抓取攝像頭的數據幀,另一個線程和主線程溝通,才勉強維持穩定(中間還用了一堆Mutex同步線程,頭發都要掉光)。
但后來發現,這樣做資源開銷大的離譜。尤其是當我們項目用到了4K分辨率的攝像頭時,主線程基本卡死不能動了(光一個攝像頭就占用了8核CPU的40%,這還是4GHz x86的CPU啊)項目還要用四個攝像頭,這要跑起來難道得用服務器?
痛定思痛,就算cv2的解決方案維護了兩個月,也只能放棄,轉頭認真研究QCamera。
QCamera是Qt對于攝像設備的一個抽象,所以它首先初始化需要鎖定一個攝像頭。這就需要QCameraInfo類提供系統中可用攝像頭的信息。
const?QList<QCameraInfo> cameras =QCameraInfo::availableCameras();
for (const?QCameraInfo&cameraInfo : cameras)?qDebug()?<< cameraInfo.deviceName();
然后,初始化QCamera。
下面,要給QCamera找一個視頻輸出的區域QCameraViewFinder。QCamera支持QVideoWidget,QGraphicsVideoItem,QAbstractVideoSurface三種接口,感興趣的小伙伴可以去了解一下區別。這三種在QtDesigner里都找不到,沒關系,我們可以在界面里先預留一個QGridLayout,用來動態添加view。
接下來,就是保存圖片了。QCamera需要拍攝圖片,用的是QCameraImageCapture類。這個類初始化用QCamera對象作為參數,然后就可以進行capture操作。但是capture必須寫入硬盤(我也不知道為什么,但是如果需要高性能或者快速拍攝,這個肯定行不通,因為寫入硬盤是非常非常緩慢的,甚至需要界面中添加等待提示,因為我們攝像頭4K拍出來有10MB,保存要十幾秒,這也是我認為Qt做的不夠好的地方,為什么不能加一個capture到QImage的接口)但是好在項目剛好需要保存在本地。
這里有一個細節,因為capture()寫入硬盤和其他線程是異步的,你不能capture()完了立馬cam.stop(),否則會capture失敗。所以我加了個簡單的計數判斷,達到finish計數才stop。這個后面可以再改進。
????到這里QCamera用法基本上就結束了,可以看到Qt5雖然也有不足,但比起cv2.Videocapture還是做的好不少,Cpu占用率也下來了。