安裝套件
WebCam的影像擷取, 使用 opencv 就可以很簡單的取得影像, 請先安裝如下套件
Windows: pip install PyQt5 opencv-python
Linux : sudo apt-get install python3-opencv python3-pyqt5 qt5-default qttools5-dev-tools
權限
WebCam的驅動代號為 /dev/video0~X, 其擁有者:群組為 root:video
所以必需先下執如下指令, 將你的帳號歸入video群組, 如此才能開啟web cam
usermod -a -G video ${USER}
坑洞
1. 請注意樹莓派的 wifi ip 是否正確, pi4 raspbin有bug, 有時會跑掉 2. 注意是否將帳號加入 video群組, 否則無法開啟 web cam 3. Python 變更照片品質時, 以 '.jpg' 傳送 4. C#接收端, 需轉換成 .jpg, 不能用 .png 5. fps 是告知播放器一秒要放映幾張的意思, 比如30fps, 是告知播放器一秒要放映30張. 但如果檔案裏並沒有這麼多張, 播放器還是拼命抓取, 就會造成影片快速播放的現像. 所以fps是要以實際sdcard存放的時間為主, 樹莓派每秒約7張
主程式 MahalVideo.py
#!/usr/bin/python3 import sys from PyQt5.QtGui import QPixmap, QImage from PyQt5.QtWidgets import QMainWindow, QApplication from Camera import Camera from ui.ui_mainwindow import * class MainWindow(QMainWindow,Ui_MainWindow): def __init__(self, parent=None): super().__init__(parent) self.setupUi(self) self.CamThread=Camera() self.CamThread.callback.connect(self.refreshWindow) self.CamThread.start() self.bytesPerLine = 3 * 1920 self.btnExit.clicked.connect(self.btnExit_click) def refreshWindow(self, img): w=self.img.width() h=self.img.height() qimg = QImage(img.data, 1920, 1080, self.bytesPerLine, QImage.Format_RGB888).rgbSwapped().scaled(w, h, transformMode=QtCore.Qt.SmoothTransformation) self.img.setPixmap(QPixmap.fromImage(qimg)) def btnExit_click(self): app.closeAllWindows() if __name__ == "__main__": app = QApplication(sys.argv) mainwindow = MainWindow() #mainwindow.show() mainwindow.showFullScreen() #mainwindow.showMaximized() app.exec()
Camera.py
from PyQt5.QtCore import QThread, pyqtSignal import cv2 import time class Camera(QThread): callback = pyqtSignal(object) # 自定義訊號, Qt的文件中有說明, 必需為類別變數 def __init__(self, parent=None): super().__init__(parent) self.runFlag = True def __del__(self): self.runFlag = False cv2.destroyAllWindows() self.wait() def run(self): cam = cv2.VideoCapture(0) cam.set(cv2.CAP_PROP_FRAME_WIDTH, 1920) cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080) while self.runFlag: try: ret, img = cam.read() if ret: self.callback.emit(img) #cv2.imshow('frame', img) #time.sleep(0.01) QThread.msleep(40) except Exception as e: print(str(e))
ui_mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>MainWindow</class> <widget class="QMainWindow" name="MainWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>600</height> </rect> </property> <property name="windowTitle"> <string>MainWindow</string> </property> <widget class="QWidget" name="centralwidget"> <layout class="QVBoxLayout" name="verticalLayout"> <property name="spacing"> <number>1</number> </property> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> <item> <widget class="QLabel" name="img"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text"> <string/> </property> </widget> </item> <item> <widget class="QFrame" name="frame"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="minimumSize"> <size> <width>0</width> <height>80</height> </size> </property> <property name="frameShape"> <enum>QFrame::Panel</enum> </property> <property name="frameShadow"> <enum>QFrame::Sunken</enum> </property> <layout class="QHBoxLayout" name="horizontalLayout"> <property name="spacing"> <number>2</number> </property> <property name="leftMargin"> <number>0</number> </property> <property name="topMargin"> <number>0</number> </property> <property name="rightMargin"> <number>0</number> </property> <property name="bottomMargin"> <number>0</number> </property> <item> <widget class="QFrame" name="frame_2"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="frameShape"> <enum>QFrame::StyledPanel</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> </widget> </item> <item> <widget class="QPushButton" name="btnSetting"> <property name="sizePolicy"> <sizepolicy hsizetype="Minimum" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text"> <string>設定</string> </property> </widget> </item> <item> <widget class="QPushButton" name="btnRecord"> <property name="sizePolicy"> <sizepolicy hsizetype="Minimum" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text"> <string>錄影</string> </property> </widget> </item> <item> <widget class="QPushButton" name="btnExit"> <property name="sizePolicy"> <sizepolicy hsizetype="Minimum" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="text"> <string>離開</string> </property> </widget> </item> <item> <widget class="QFrame" name="frame_3"> <property name="sizePolicy"> <sizepolicy hsizetype="Preferred" vsizetype="Expanding"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> <property name="frameShape"> <enum>QFrame::StyledPanel</enum> </property> <property name="frameShadow"> <enum>QFrame::Raised</enum> </property> </widget> </item> </layout> </widget> </item> </layout> </widget> </widget> <resources/> <connections/> </ui>