通常来说Linux下可以通过V4L2接口及ioctl相关函数直接在底层调用摄像头设备,进行摄像头控制及图像预览和捕获,相对复杂。
QT5.0新增QMultimedia模块提供了更为方便的编程支持,模块涵盖了视,音频及摄像头功能,提供了QML类型和C++类用以处理多媒体内容。
环境: QT5.9.0 Qt Creator Ubuntu 16.04.6 LTS Linux-4.15.0-133-generic
1.创建Qt Widgets Application工程,并添加QT +=multimedia,QT+=multimediawidgets项
2双击mainwindow.ui启动qt designer可视化布局界面
首先在布局左侧放置一个Horizental Layout控件,修改对象名为ImageView,用于图像预览显示;再在右侧放一个Vertical Layout 控件,依次在其中放置一个label和4个Push Button,修改label的对象名为ImageCapture,用于显示捕获的图像,修改按钮的显示名称及对象名分别为buttonCapture, buttonOpen,buttonSave, buttonQuit,添加一个ComboBox存放摄像头列表,拖动控件到合适的布局,如图
3. mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QCamera>
#include <QCameraViewfinder>
#include <QCameraImageCapture>
#include <QFileDialog>
namespace Ui {
class MainWindow;
}
class QCamera;
class QCameraViewfinder;
class QCameraImageCapture;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void openCamera(QString description=QString());
void enumCamera();
void bindRecoder(QCamera *camera);
private slots:
void captureImage();
void displayImage(int, QImage);
void saveImage();
void openCamera_on_clicked();
private:
Ui::MainWindow *ui;
QCamera *camera; //摄像头对象
QCameraViewfinder *viewfinder; //摄像头取景器
QCameraImageCapture *imageCapture; //截图对象
};
#endif // MAINWINDOW_
4. mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QCameraInfo>
#include <QUrl>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// camera=new QCamera(this);
viewfinder = new QCameraViewfinder(this);
ui->ImageView->addWidget(viewfinder);
ui->ImageCapture->setScaledContents(true);
connect(ui->buttonSave,SIGNAL(clicked()),this,SLOT(saveImage()));
connect(ui->buttonQuit,SIGNAL(clicked()),qApp,SLOT(quit()));
connect(ui->buttonOpen,SIGNAL(clicked()),this,SLOT(openCamera_on_clicked()));
enumCamera();
}
MainWindow::~MainWindow()
{
if(camera != NULL)
camera->stop();
delete ui;
}
void MainWindow::openCamera_on_clicked()
{
openCamera();
// openCamera(ui->comboBox->currentText());
}
void MainWindow::openCamera(QString description)
{
if(description.isEmpty())
{
QCameraInfo info = QCameraInfo::defaultCamera();
camera=new QCamera(info, this);
}else
{
QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
foreach(const QCameraInfo &cameraInfo, cameras)
{
if(cameraInfo.description() == description)
{
camera = new QCamera(cameraInfo,this);
break;
}
}
}
//camera->setCaptureMode(QCamera::CaptureVideo);
camera->setViewfinder(viewfinder);
imageCapture = new QCameraImageCapture(camera);
connect( camera, static_cast<void(QCamera::*)(QCamera::Error)>(&QCamera::error),
[=](QCamera::Error value){ qDebug()<<value;});
connect(imageCapture,SIGNAL(imageCaptured(int,QImage)),this,SLOT(displayImage(int,QImage)));
connect(ui->buttonCapture,SIGNAL(clicked()),this,SLOT(captureImage()));
camera->start();
}
void MainWindow::captureImage()
{
if(!camera)
return;
ui->statusBar->showMessage(tr("capturing..."),1000);
imageCapture->capture();
}
void MainWindow::displayImage(int id,QImage image)
{
qDebug()<<"hello->"<<id;
ui->ImageCapture->setPixmap((QPixmap::fromImage(image)));
ui->statusBar->showMessage(tr("capture OK!"),5000);
}
void MainWindow::enumCamera()
{
QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
foreach(const QCameraInfo &cameraInfo, cameras)
{
qDebug()<<"camera:"<<cameraInfo.description();
ui->comboBox->addItem(cameraInfo.description());
}
}
void MainWindow::saveImage()
{
QString fileName=QFileDialog::getSaveFileName(this,tr("save file"),QDir::homePath(),tr("jpegfile(*.jpg)"));
if(fileName.isEmpty()){
ui->statusBar->showMessage(tr("save cancel"), 5000);
return;
}
const QPixmap* pixmap=ui->ImageCapture->pixmap();
if(pixmap){
pixmap->save(fileName);
ui->statusBar->showMessage(tr("save OK"),5000);
}
}
5.编译运行
QCamera类封装了很多底层操作,为了进一步了解Linux下的摄像头的调用机制,我们可以试验下V4L2和ioctl操作摄像头机理。
6.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <error.h>
#include <string.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include<sys/ioctl.h>
int fd;
const char *input_dev = "/dev/video0";
//const char *input_dev = "/dev/vboxusb/002";
const char *qctrl_name = NULL;
int qctrl_value = 0;
struct v4l2_capability cap;
struct v4l2_queryctrl qctrl;
static void print_qctrl(struct v4l2_queryctrl *qctrl)
{
struct v4l2_control ctrl;
ctrl.id = qctrl->id;
if (ioctl(fd, VIDIOC_G_CTRL, &ctrl) < 0)
{
perror("get ctrl failed");
ctrl.value = -999;
}
printf("%-14s : id=%08x, type=%d, minimum=%d, maximum=%d
"
" value = %d, step=%d, default_value=%d
",
qctrl->name, qctrl->id, qctrl->type, qctrl->minimum, qctrl->maximum,
ctrl.value, qctrl->step, qctrl->default_value);
}
static void print_menu(struct v4l2_querymenu *menu)
{
printf(" %d : %s
", menu->index, menu->name);
}
static int set_qctrl(struct v4l2_queryctrl *qctrl)
{
struct v4l2_control ctrl;
printf("set %s = %d
", qctrl_name, qctrl_value);
ctrl.id = qctrl->id;
ctrl.value = qctrl_value;
return ioctl(fd, VIDIOC_S_CTRL, &ctrl);
}
static void deal_qctrl(struct v4l2_queryctrl *qctrl)
{
print_qctrl(qctrl);
if (qctrl_name && !strcmp(qctrl_name, (const char *)qctrl->name))
set_qctrl(qctrl);
}
static void qctrl_get(int id)
{
qctrl.id = id;
if (ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0)
{
deal_qctrl(&qctrl);
if (qctrl.type == V4L2_CTRL_TYPE_MENU)
{
int idx;
struct v4l2_querymenu menu;
for (idx = qctrl.minimum; idx <= qctrl.maximum; idx++)
{
menu.id = qctrl.id;
menu.index = idx;
if (ioctl(fd, VIDIOC_QUERYMENU, &menu)==0)
{
print_menu(&menu);
}
}
}
}
}
int main(int argc, char **argv)
{
int ret, i;
if (argc == 3)
{
qctrl_name = argv[1];
qctrl_value = atoi(argv[2]);
}
fd = open(input_dev, O_RDWR);
if (fd < 0)
{
perror("open video failed");
return -1;
}
printf("open video '%s' success
", input_dev);
ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if (ret < 0)
{
perror("ioctl querycap");
return -1;
}
if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0)
{
printf("video device donot support capture
");
return -1;
}
for (i = V4L2_CID_BASE; i < V4L2_CID_LASTP1; i++)
{
qctrl_get(i);
}
for (i = V4L2_CID_PRIVATE_BASE; i < V4L2_CID_PRIVATE_BASE+25; i++)
{
qctrl_get(i);
}
printf("close video
");
close(fd);
}