用QT5的QCamera实现USB摄像头之截图保存功能

通常来说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);
}

原文地址:https://www.cnblogs.com/7star/p/14408246.html