用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\n"
"\t\t value = %d, step=%d, default_value=%d\n",
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("\t %d : %s\n", menu->index, menu->name);
}
static int set_qctrl(struct v4l2_queryctrl *qctrl)
{
struct v4l2_control ctrl;

printf("set %s = %d\n", 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\n", 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\n");
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\n");
close(fd);
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM