1 前言
本章将是Qt 媒体应用的最后一章节了,讲完本章,Qt媒体库的学习将到此为止!本章将学习Qt如何使用摄像头进行拍照和摄像等相关操作,下面先介绍以下有关Qt 摄像头的概述。
2 效果图
3 摄像头控制概述
Qt多媒体模块为摄像头控制提供了几个类,可以用于获取摄像头设备信息,通过摄像头进行拍照和录像。
1、摄像头设备信息类QCameraInfo。
QCameraInfo 用于获取系统的摄像头设备信息,有两个静态函数获取摄像头设备:
- QList<QCameraInfo> availableCameras(), 返回 QCameraInfo 类的列表,表示系统可用的
摄像头设备列表; - QCameraInfo defaultCamera(), 返回系统缺省的摄像头设备信息。
QCameraInfo 有几个函数表示摄像头信息:
- QString description(), 返回摄像头设备描述;
- QString deviceName(), 返回摄像头设备名称;
- QCamera::Position position(), 返回摄像头的位置,如手机设备上一般有两个摄像头,前
置摄像头位置类型为QCamera::FrontFace, 后置摄像头位置类型为QCamera::BackFace,
未指定位置的是QCamera::UnspecifiedPosition。
2、 摄像头控制类QCamera
QCamera 是用于控制摄像头的类,创建 QCamera 对象时需传递一个 QCameraInfo 对象作为参数,QCamera 主要的功能函数包括以下几个。
- setViewfinder() ,为摄像头指定一个QVideoWidget或QGraphicsVideoItem对象作为取景器,
用于摄像头图像预览。 - QCameraExposure *exposure(), 返回用于曝光控制的对象。
- QCameraFocus *focus(), 返回用于聚焦控制的对象。
- setCaptureMode(QCamera::CaptureModes mode), 用于设置摄像头处于不同的工作模式,
QCamera::CaptureModes 枚举类型的取值有:
QCamera::CaptureViewfinder,取景器模式;
QCamera::CaptureStillImage,抓取静态图片模式; .
QCamera::CaptureVideo,视频录制模式。 - bool isCaptureModeSupported(CaptureModes mode) ,判断摄像头是否支持某种抓取模式。
3、 静态图片抓取类QCameralmageCapture
QCameralmageCapture 用于控制摄像头进行静态图片的抓取。
4、视频和音频录制类QMediaRecorder。
QMediaRecorder 通过摄像头和音频输入设备进行录像。
注意: 使用Qt多媒体模块的摄像头相关类无法在Windows平台上进行视频录制,只能进行静态图片抓取但是在Linux平台上可以实现静态图片抓取和视频录制。
Qt多媒体模块的功能实现是依赖于平台的。在Windows平台上,Qt 多媒体模块依赖于两个
插件,一个是使用Microsoft DirectShow API的插件,DirectShow API在Windows 98引入,在Windows XP以后就逐渐过时了;另一个是Windows Media Foundation ( WMF)架构的插件,WMF插件在Windows Vista引入,用于替代DirectShow API。
Qt中的WMF插件目前无法提供摄像头支持,对摄像头的有限支持是由DirectShow插件提供
的,目前只能显示取景器和抓取静态图片,其他大部分功能不支持。所以,目前在Windows平台上,Qt的摄像头控制不支持视频录制功能,也不支持底层的视频功能,如使用QVideoProbe监测视频帧。
对于这些限制的原文介绍可以参考Qt官方文档上 Qt Multimedia on Windows 的解释,如图:
所以,本节的实例程序,在window系统中进行拍照,不进行录像处理,下图所示是程序运行时界面。.
工具栏上几个按钮的功能一目了然,摄像头参数 里显示摄像头的参数,以及录制视频的一些设置。窗口工作区左侧的 摄像头预览框 里显示摄像头的实时图像预览,右侧 抓取图片
框里显示抓取的静态图片。
4 实例设计与初始化
实例中的主窗口是基于 QWidget 的类 Camera ,界面由 UI设计器 设计。
在窗口左侧 摄像头预览 框里放置一个 QWidget 组件,并提升为 QCameraViewfinder ,这是从 QVideoWidget 继承的类,专门用于摄像头预览显示。在窗口右侧 抓取图片 框里放置一个QLabel组件,用于显示抓取的图片。
主窗口类 Camera 的定义如下:
class Camera : public QWidget
{
Q_OBJECT
public:
Camera(QWidget *parent = nullptr);
~Camera();
private slots:
//QCamera的槽函数
void onCameraStateChanged(QCamera::State state);
void onCameraCaptureModeChanged(QCamera::CaptureModes mode);
//QCameraImageCapture的槽函数
void onImageReadyForCapture(bool ready);
void onImageCaptured(int id, const QImage &preview);
void onImageSaved(int id, const QString &fileName);
// QMediaRecorder 的槽函数
void onVideoStateChanged(QMediaRecorder::State state);
void onVideoDurationChanged(qint64 duration);
//ui 设计器自动关联槽函数
void on_actStartCamera_clicked();
void on_actStopCamera_clicked();
void on_actCapture_clicked();
void on_actVideoRecord_clicked();
void on_actVideoStop_clicked();
private:
void iniCamera();//初始化
void iniImageCapture(); //初始化静态抓图
void iniVideoRecorder(); //初始化视频录制
private:
Ui::Camera *ui;
QCamera * curCamera=Q_NULLPTR; //拍照
QCameraImageCapture * imageCapture = Q_NULLPTR; //抓图
QMediaRecorder *mediaRecorder = Q_NULLPTR; //录像
};
这里定义了QCamera、QCameralmageCapture 和QmediaRecorder 3个类型的私有变量。定义了3个私有函数,分别用于3个对象的创建和初始化。
定义了多个槽函数,分别与3个对象的相应信号关联。
下面是 Camera 的构造函数的代码:
Camera::Camera(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Camera)
{
ui->setupUi(this);
QList<QCameraInfo> cameras = QCameraInfo::availableCameras() ;
if (cameras.size()>0){
ui->actStartCamera->setEnabled(true);
ui->actStopCamera->setDisabled(true);
iniCamera(); //初始化摄像头
iniImageCapture() ;//初始化静态抓图
iniVideoRecorder() ;//初始化视频录制
curCamera->start() ;
}
else
{
ui->actStartCamera->setDisabled(true);
ui->actStopCamera->setDisabled(true);
ui->actCapture->setDisabled(true);
ui->actVideoRecord->setDisabled(true);
ui->actVideoStop->setDisabled(true);
}
}
构造函数首先使用QCameraInfo的静态函数 availableCameras()获取摄像头列表cameras,如果存在摄像头设备,就依次调用3个初始化函数进行初始化,然后打开摄像头。否则失能所有的按钮触发。
5 QCamera对象创建与控制
iniCamera() 函数进行QCamera 对象的创建与初始化,在 Camera 的构造函数里调用,下面是 iniCamera() 函数的代码:
void Camera::iniCamera()
{
// 创建QCamera对象
QCameraInfo curCameraInfo=QCameraInfo::defaultCamera(); //获取缺省 摄像头
ui->comboCamera->addItem(curCameraInfo.description());
ui->comboCamera->setCurrentIndex (0) ;
curCamera=new QCamera (curCameraInfo, this); //创建摄像头对象
curCamera->setViewfinder(ui->viewFinder); //设置 预览框
curCamera->setCaptureMode(QCamera::CaptureViewfinder) ;
//判断摄像头是否支持抓图、录制视频
ui->checkStillImage->setChecked(curCamera->isCaptureModeSupported (QCamera::CaptureStillImage)) ; //抓图
ui ->checkVideo->setChecked (curCamera->isCaptureModeSupported (QCamera::CaptureVideo)) ;//视频录制
connect (curCamera, SIGNAL (stateChanged (QCamera: :State)),this, SLOT (onCameraStateChanged(QCamera::State)));
//Windows平台上不支持captureModeChanged()信号
connect (curCamera, SIGNAL(captureModeChanged(QCamera::CaptureModes)), this, SLOT (onCameraCaptureModeChanged(QCamera::CaptureModes))) ;
}
这里用 QCameralnfo::defaultCamera() 获取缺省的摄像头设备,然后用于创建 QCamera 对象实例curCamera。
QCamera::setViewfinder() 函数用于设置取景框预览组件。
QCamera::setCaptureMode() 函数设置摄像头的抓取模式。
然后查询 curCamera 是否支持抓图、支持录像,并更新界面上的复选框的状态。
为curCamera的两个信号分别设置了关联的槽函数。stateChanged()在摄像头状态变化时发射,**captureModeChanged()则在摄像头抓取模式变化时发射,不过在Windows 平台上不会发射captureModeChanged()**信号。这两个槽函数的代码如下:
void Camera::onCameraStateChanged(QCamera::State state)
{
switch (state){
case QCamera:: UnloadedState:
ui->LabCameraState->setText ("摄像头state: UnloadedState") ;
break;
case QCamera:: LoadedState:
ui->LabCameraState->setText ("摄像头state: LoadedState") ;
break;
case QCamera::ActiveState:
ui->LabCameraState->setText ("摄像头state: ActiveState") ;
}
ui ->actStartCamera->setEnabled (state!=QCamera::ActiveState);
ui ->actStopCamera->setEnabled (state==QCamera::ActiveState);
}
void Camera::onCameraCaptureModeChanged(QCamera::CaptureModes mode)
{
if (mode==QCamera::CaptureStillImage)
ui->LabCameraMode->setText ("抓取模式: StillImage") ;
else if (mode==QCamera::CaptureVideo)
ui->LabCameraMode->setText ("抓取模式: Video") ;
else
ui->LabCameraMode->setText ("抓取模式: Viewfinder") ;
}
窗口工具栏上的 开启摄像头 和 关闭摄像头 两个按钮控制摄像头的开启和关闭,其关联按钮点击的槽函数代码如下:
void Camera::on_actStartCamera_clicked()
{
//开启摄像头
curCamera->start();
}
void Camera::on_actStopCamera_clicked()
{
//关闭摄像头
curCamera->stop();
}
开启和关闭摄像头时,QCamera对象会发射stateChanged()信号。开启摄像头之后,摄像头状态为QCamera::ActiveState,关闭之后状态会变成QCamera::LoadedState。
6 QCameralmageCapture抓取静态图片
QCameralmageCapture 类对象 imageCapture 用于通过摄像头抓取静态图片,iniImageCapture()函数用于创建 imageCapture 并进行初始化设置,Camera 构造函数调用此函数。iniImageCapture() 函数的代码如下:
void Camera::iniImageCapture()
{
//创建QCameraImageCapture对象
imageCapture = new QCameraImageCapture(curCamera, this) ;
imageCapture->setBufferFormat(QVideoFrame::Format_Jpeg); //缓冲区格式
imageCapture->setCaptureDestination (QCameraImageCapture::CaptureToFile); //保存目标
connect (imageCapture, SIGNAL (readyForCaptureChanged (bool)),this, SLOT (onImageReadyForCapture (bool) ) ) ;
connect (imageCapture, SIGNAL (imageCaptured(int, const QImage &)) , this, SLOT (onImageCaptured(int, const QImage &))) ;
connect (imageCapture, SIGNAL (imageSaved(int, const QString &)) , this, SLOT (onImageSaved(int, const QString &))) ;
}
创建 QCameralmageCapture 对象 imageCapture 时传递QCamera对象curCamera作为输入参数,建立与摄像头设备的关联。
setBufferFormat(QVideoFrame::Format_Jpeg) 设置缓冲区里图片为JPG格式。
setCaptureDestination(QCameraImageCapture::CaptureToFile) 设置抓图存储目标为文件,抓取的图片文件会自动保存到用户目录的图片文件夹里。
为 imageCapture 的3个信号关联了自定义槽函数,这3个槽函数的代码如下:
void Camera::onImageReadyForCapture(bool ready)
{
//可以抓图 了
ui->actCapture->setEnabled(ready) ;
}
void Camera::onImageCaptured(int id, const QImage &preview)
{
//抓取图片后显示
Q_UNUSED(id);
QImage scaledImage = preview.scaled (ui->LabCapturedImage->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
ui->LabCapturedImage->setPixmap(QPixmap::fromImage(scaledImage));
}
void Camera::onImageSaved(int id, const QString &fileName)
{
//文件保存后显示保存的文件名
Q_UNUSED(id) ;
qInfo()<<"onImageSaved ="<<fileName;
ui->editOutputFile->setText(fileName);
}
单击窗口工具栏上的 抓图 按钮可实现抓取静态图片功能,其代码如下:
void Camera::on_actCapture_clicked()
{
//抓图按钮
if (curCamera->captureMode () !=QCamera::CaptureStillImage){
curCamera->setCaptureMode (QCamera::CaptureStillImage) ;
}
imageCapture->capture() ;
}
这里首先将curCamera的抓取模式设置为 QCamera::CaptureStillmage, 然后使用QCameralmageCapture::capture( ) 函数抓图。
7 QMediaRecorder视频录制
QMediaRecorder 类对象 mediaRecorder 用于通过摄像头进行视频录制, iniVideoRecorder()函数创建mediaRecorder并进行初始化设置,Camera 构造函数调用此函数。iniVideoRecorder()函数代码如下:
void Camera::iniVideoRecorder()
{
//创建QMediaRecorder对象
mediaRecorder = new QMediaRecorder(curCamera, this) ;
ui->chkMute->setChecked (mediaRecorder->isMuted() ) ;
connect (mediaRecorder,SIGNAL (stateChanged(QMediaRecorder::State)) , this, SLOT (onVideoStateChanged(QMediaRecorder::State))) ;
connect (mediaRecorder, SIGNAL (durationChanged (qint64)) , this, SLOT(onVideoDurationChanged(qint64)));
}
mediaRecorder 创建时传递QCamera对象 curCamera 作为输入参数。
为 mediaRecorder 的两个信号设置了关联槽函数,两个槽函数的代码如下:
void Camera::on_actVideoRecord_clicked()
{
//开始录像
if ( !mediaRecorder->isAvailable() )
{
QMessageBox::critical (this, "错误",
"不支持视频录制! \n mediaRecorder->isAvailable()==false") ;
return;
}
if (curCamera->captureMode () !=QCamera::CaptureVideo)
curCamera->setCaptureMode (QCamera::CaptureVideo);
QString selectedFile=ui->editOutputFile->text().trimmed();
if (selectedFile. isEmpty())
{
QMessageBox::critical (this, "错误", "请先设置录音输出文件") ;
return;
}
if (QFile::exists(selectedFile) )
if (!QFile::remove(selectedFile) )
{
QMessageBox::critical (this, "错误", "所设置录音输出文件被占用,无法删除") ;
return;
}
mediaRecorder->setOutputLocation (QUrl::fromLocalFile(selectedFile)) ;
mediaRecorder->record() ;
}
void Camera::on_actVideoStop_clicked()
{
//停止录像
mediaRecorder->stop();
}
开始录像之前,还需要将摄像头的抓取状态设置为QCamera::CaptureVideo,然后检查设置的视频输出文件,当文件没问题后用setOutputLocation()函数设置视频录制输出文件。
调用QMediaRecorder的record()函数开始录像,stop()函数停止录像。