1、功能概述
PyQt5多媒体模块为摄像头操作提供了几个类,可以用于获取摄像头设备信息,通过摄像头进行拍照和录像。
Qt多媒体模块的功能实现是依赖于平台的。在Windows平台上,Qt多媒体模块依赖于两个插件:一个是使用Microsoft DirectShow API的插件,DirectShow在Windows 98引入,在Windows XP以后就逐渐过时了;另一个是Windows Media Foundation(WMF)的插件,WMF插件在Windows Vista引入,用于替代DirectShow。
Qt中的WMF插件目前无法提供摄像头支持,对摄像头的有限支持是由DirectShow插件提供的,目前只能显示取景器和抓取静态图片,其他大部分功能不支持。所以,目前在Windows平台上,Qt的摄像头控制不支持视频录制功能,也不支持底层的视频功能,例如使用QVideoProbe探测视频帧。
PyQt5的多媒体模块在Windows平台上也无法实现摄像头录像功能。
2、主要类与函数
++++++++++++++++++++++++++++
QCameraInfo:摄像头设备信息类
availableCameras():返回QCameraInfo类型的列表,表示系统可用的摄像头。
defaultCamera():返回一个QCameraInfo对象,是系统默认的摄像头设备信息。
description():返回摄像头设备描述。
deviceName():返回摄像头设备名称。
position():返回值是枚举类型QCamera.Position,表示摄像头的位置。
例如手机一般有两个摄像头,前置摄像头位置类型为QCamera.FrontFace,后置摄像头位置类型为QCamera.BackFace,未指定位置的是QCamera.UnspecifiedPosition。
++++++++++++++++++++++++++++
QCamera:操作摄像头的类,创建QCamera对象时需传递一个QCameraInfo对象作为参数。
setViewfinder(viewfinder):为摄像头指定一个QVideoWidget或QGraphicsVideoItem对象viewfinder作为取景器,用于摄像头图像预览。一般使用一个QCameraViewfinder类对象用于摄像头预览,其父类是QVideoWidget。
setCaptureMode(mode):用于设置摄像头工作模式,参数mode是枚举类型QCamera. CaptureModes,有以下几种取值:
QCamera.CaptureViewfinder(取景器模式,摄像头仅用于预览);
QCamera.CaptureStillImage(抓取静态图片模式);
QCamera.CaptureVideo(视频录制模式)。
isCaptureModeSupported(mode),判断摄像头是否支持某种工作模式,参数mode是枚举类型QCamera.CaptureModes。
searchAndLock():拍照之前执行,用于在快门半按下时锁定摄像头的曝光、白平衡等参数
unlock():拍照后执行,用于解除锁定。
++++++++++++++++++++++++++++
QCameraImageCapture:控制摄像头进行静态图片的抓取
setEncodingSettings(settings):设置拍照图片的编码,settings是QImageEncoderSettings类型,设置内容包括编码方案、分辨率、图片质量等。
setBufferFormat(format):设置拍照缓冲区的图片的格式,参数format是枚举类型QVideoFrame.PixelFormat,有几十种取值,这里用QVideoFrame.Format_Jpeg,也就是使用JPEG格式。
setCaptureDestination(destination):用于设置所拍摄图片的保存方式,destination是枚举类型QCameraImageCapture.CaptureDestination,有以下两种取值:
QCameraImageCapture.CaptureToBuffer(拍摄的图片保存在缓冲区里,会发射信号
imageCaptured(),在此信号的槽函数里可以提取缓冲区中的图片); - QCameraImageCapture.CaptureToFile(拍摄的图片自动保存文件到用户目录的“图片”
文件夹里,保存图片后会发射imageSaved()信号)。 如果设置为CaptureToBuffer,就只会发射imageCaptured()信号,图片出现在缓冲区,不会自动保存为文件,也不会发射imageCaptured()信号;而如果设置为CaptureToFile,两个信号都会被发射。
QCameraImageCapture的3个信号及关联的槽函数的作用如下。
readyForCaptureChanged(ready):信号在摄像头是否可以拍照的状态变化时发射,bool型参数ready正好用于控制拍照按钮的使能状态。
imageCaptured(imageID, preview)在图像被抓取到缓冲区后发射,imageID是图像的编号,每次拍照时自动累加,preview是QImage类型,是拍摄的图片。在关联的槽函数里,将此图片的内容显示到界面上的QLabel组件LabImage上。
imageSaved(imageID, fileName)信号在图片保存为文件后发射,fileName是自动保存的文件名称。在关联的槽函数里显示了imageID和文件名fileName。
++++++++++++++++++++++++++++
QMediaRecorder:通过摄像头和音频输入设备进行视频录制
3、代码实现
这个窗口工作区的左侧是摄像头预览显示,是一个QCameraViewfinder组件,右侧是拍摄照片的显示,是一个QLabel组件。两个GroupBox组件之间使用了分割布局。
from PyQt5.QtGui import QImage,QPixmap
from PyQt5.QtMultimedia import (QCameraInfo,QCameraImageCapture,
QImageEncoderSettings,QMultimedia,QVideoFrame,QSound,QCamera)
from ui_MainWindow import Ui_MainWindow
class QmyMainWindow(QMainWindow):
def __init__(self, parent = None):
super().__init__(parent) #调用父类构造函数,创建窗体
self.ui = Ui_MainWindow() #创建UI对象
self.ui.setupUi(self) #构造UI界面
self.__LabCameraState = QLabel("摄像头state:")
self.__LabCameraState.setMinimumWidth(150)
self.ui.statusBar.addWidget(self.__LabCameraState)
self.__LabImageID = QLabel("图片文件ID:")
self.__LabImageID.setMinimumWidth(100)
self.ui.statusBar.addWidget(self.__LabImageID)
self.__LabImageFile = QLabel("") #保存的图片文件名
self.ui.statusBar.addPermanentWidget(self.__LabImageFile)
self.camera = None #QCamera对象
cameras = QCameraInfo.availableCameras() #list[QCameraInfo]
if len(cameras)>0:
self.__iniCamera() #初始化摄像头
self.__iniImageCapture() #初始化静态画图
self.camera.start()
## ==============自定义功能函数========================
def __iniCamera(self): ##创建 QCamera对象
camInfo=QCameraInfo.defaultCamera() #获取缺省摄像头,QCameraInfo
self.ui.comboCamera.addItem(camInfo.description()) #摄像头描述
self.ui.comboCamera.setCurrentIndex(0)
self.camera=QCamera(camInfo) #创建摄像头对象
self.camera.setViewfinder(self.ui.viewFinder) #设置取景框预览
## camera.setCaptureMode(QCamera.CaptureViewfinder) #预览
self.camera.setCaptureMode(QCamera.CaptureStillImage) #设置为抓图
## camera.setCaptureMode(QCamera.CaptureVideo)
mode=QCamera.CaptureStillImage
supported=self.camera.isCaptureModeSupported(mode)
self.ui.checkStillImage.setChecked(supported) #支持拍照
supported=self.camera.isCaptureModeSupported(QCamera.CaptureVideo)
self.ui.checkVideo.setChecked(supported) #支持视频录制
supported=self.camera.exposure().isAvailable()
self.ui.checkExposure.setChecked(supported) #支持曝光补偿
supported=self.camera.focus().isAvailable()
self.ui.checkFocus.setChecked(supported) #支持变焦
self.camera.stateChanged.connect(self.do_cameraStateChanged)
def __iniImageCapture(self): ##创建 QCameraImageCapture对象
self.capturer = QCameraImageCapture(self.camera)
settings=QImageEncoderSettings() #拍照设置
settings.setCodec("image/jpeg") #设置抓图图形编码
settings.setResolution(640, 480) #分辨率
settings.setQuality(QMultimedia.HighQuality) #图片质量
self.capturer.setEncodingSettings(settings)
self.capturer.setBufferFormat(QVideoFrame.Format_Jpeg) #缓冲区格式
if self.ui.chkBoxSaveToFile.isChecked():
dest=QCameraImageCapture.CaptureToFile #保存到文件
else:
dest=QCameraImageCapture.CaptureToBuffer #保存到缓冲区
self.capturer.setCaptureDestination(dest) #保存目标
self.capturer.readyForCaptureChanged.connect(self.do_imageReady)
self.capturer.imageCaptured.connect(self.do_imageCaptured)
self.capturer.imageSaved.connect(self.do_imageSaved)
## ==============event处理函数==========================
## ==========由connectSlotsByName()自动连接的槽函数============
@pyqtSlot(bool) ##设置保存方式
def on_chkBoxSaveToFile_clicked(self,checked):
if checked:
dest=QCameraImageCapture.CaptureToFile #保存到文件
else:
dest=QCameraImageCapture.CaptureToBuffer #保存到缓冲区
self.capturer.setCaptureDestination(dest) #保存目标
@pyqtSlot() ##拍照
def on_actCapture_triggered(self):
QSound.play("shutter.wav") #播放快门音效
self.camera.searchAndLock() #快门半按下时锁定摄像头参数
self.capturer.capture() #拍照
self.camera.unlock() #快门按钮释放时解除锁定
@pyqtSlot() ##打开摄像头
def on_actStartCamera_triggered(self):
self.camera.start()
@pyqtSlot() ##关闭摄像头
def on_actStopCamera_triggered(self):
self.camera.stop()
## =============自定义槽函数===============================
def do_cameraStateChanged(self,state): ##摄像头状态变化
if (state==QCamera.UnloadedState):
self.__LabCameraState.setText("摄像头state: UnloadedState")
elif (state==QCamera.LoadedState):
self.__LabCameraState.setText("摄像头state: LoadedState")
elif (state==QCamera.ActiveState):
self.__LabCameraState.setText("摄像头state: ActiveState")
self.ui.actStartCamera.setEnabled(state!=QCamera.ActiveState)
self.ui.actStopCamera.setEnabled(state==QCamera.ActiveState)
def do_imageReady(self,ready): ##是否可以拍照了
self.ui.actCapture.setEnabled(ready)
def do_imageCaptured(self,imageID,preview): ##图片被抓取到内存
#preview是 QImage
H=self.ui.LabImage.height()
W=self.ui.LabImage.width()
scaledImage = preview.scaled(W,H,
Qt.KeepAspectRatio, Qt.SmoothTransformation)
self.ui.LabImage.setPixmap(QPixmap.fromImage(scaledImage))
self.__LabImageID.setText("图片文件ID:%d"%imageID)
self.__LabImageFile.setText("图片保存为: ")
def do_imageSaved(self,imageID,fileName): ##图片被保存
self.__LabImageID.setText("图片文件ID:%d"%imageID)
self.__LabImageFile.setText("图片保存为: "+fileName)
## ============窗体测试程序 ================================
if __name__ == "__main__": #用于当前窗体测试
app = QApplication(sys.argv) #创建GUI应用程序
form=QmyMainWindow() #创建窗体
form.show()
sys.exit(app.exec_())