zoukankan      html  css  js  c++  java
  • 用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);
    }

  • 相关阅读:
    JDBC
    uml 和 unified process
    关于N9手机第三种交互方式的思考和再设计
    [jQuery插件] jQuery Color Animations颜色动画插件
    Azul发布开源工具jHiccup,为Java提供运行时响应时间分析
    行内元素verticalalign:middle在html5和xhtml1.0及以下版本中的表现差异
    使用maven进行scala项目的构建
    计划FM为人人网提供首个开源Ruby SDK
    Chrome扩展:Run Selected HTML
    Team Foundation Service更新:改善了导航和项目状态速查功能
  • 原文地址:https://www.cnblogs.com/7star/p/14408246.html
Copyright © 2011-2022 走看看