基于QT5以及opencv4.0的打开笔记本摄像头系统

1.完成功能

github地址(完整代码)

1.完成界面上可选择的软件触发以及连续采集模式下,在界面上实时显示笔记本摄像头所拍摄的画面
2.可选择保存图像的格式如".jpg"、".bmp"、".png"格式,并可选择将要保存的文件目录
3.在连续采集模式下,会在界面实时显示抓取的每一帧,即像视频一样播放摄像头所拍摄的画面
4.在软件触发模式下,点击一次拍照按钮才会抓取一帧图像,即点击一次拍一张图像显示在界面

2.思路

1.开辟一个线程专门用来抓取摄像头捕获的帧率

专门写一个camerathread类,使其继承QThread,重写其run()函数,run()函数内容:

void CameraThread::run() {
    cv::VideoCapture m_Capture(0);
    while(!mIsStop) {
        switch(mWorkMode) {
        case CONTINUE_MODE: // 连续采集 -------------------------------------
            mMutex.lock();
            m_Capture >> mFrame;
            mGrabFps ++;
            mMutex.unlock();
            emit GrabFrame(mFrame, mGrabFps);
            break;

        case SOFTWARE_MODE: // 软件触发 --------------------------------------
            mMutex.lock();
            if(PAUSING_NUM == mCount) {
                mWaitcondtion.wait(&mMutex);
            }
            mCount --;
            mStatus = THREAD_ISRUNING;
            m_Capture >> mFrame;
            mStatus = THREAD_ISIDLE;
            mMutex.unlock();
            emit GrabFrame(mFrame, mGrabFps);
            break;

        default:
            break;
        }
    }
}

如上面所示,每抓取一帧即发送一个信号(emit GrabFrame(mFrame, mGrabFps)?,此信号接收者为MainWindow类,该信号对应的槽函数为

/// 接收抓图线程抓到的帧并显示
void MainWindow::RecvFrame(cv::Mat mat, int grabfps) {
    switch(mat.type()) {
    case CV_8UC1:
        mImage = QImage(mat.cols, mat.rows, QImage::Format_Indexed8);
        // Set the color table (used to translate colour indexes to qRgb values)
        mImage.setColorCount(256);
        for(int i = 0; i < 256; i++)  {
            mImage.setColor(i, qRgb(i, i, i));
        }
        break;
    case CV_8UC3:
        cv::cvtColor(mat, mat, CV_BGR2RGB);
        mImage = QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        break;
    case CV_8UC4:
        // Create QImage with same dimensions as input Mat
        mImage = QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        break;
    default:
        break;
    }

    QSize size = ui->label->size();
    QImage image = mImage.scaled(size, Qt::IgnoreAspectRatio);
    ui->label->setPixmap(QPixmap::fromImage(image));
    mDisplayFps ++;
    mReadFps = grabfps;
}

由于是opencv抓取的图像,所以应转为对应的QImage格式,如上所示
该信号以及槽函数不在一个线程内,所以connect()函数应改变其第五个参数,如下

CameraThread *mCameraThread;

mCameraThread = new CameraThread();
mCameraThread->start();
connect(mCameraThread, SIGNAL(GrabFrame(cv::Mat, int)), this, 
       SLOT(RecvFrame(cv::Mat, int)), Qt::DirectConnection);

3.代码

时间有限,代码就不一一讲解,下面贴上mainwindow.h和mainwindow.cpp中的代码, 完整代码可直接gitclone本人github上的代码获取观看

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>
#include <QWaitCondition>
#include <QMutex>
#include <QLabel>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/core/mat.hpp>
#include <opencv2/dnn.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core/types_c.h>
#include <opencv2/imgproc/imgproc_c.h>
#include <opencv2/videoio.hpp>

namespace Ui {
class MainWindow;
}

/// 工作模式 连续采集/软件触发
enum {
    CONTINUE_MODE,
    SOFTWARE_MODE
};

/// 软件触发信号数字
enum {
    PAUSING_NUM,
    RUNING_NUM
};

/// 拍照模式 手动/自动
enum {
    MANUAL_MODE,
    AUTO_MODE
};

/// 抓图线程抓帧传输是否完成
enum {
    THREAD_ISIDLE,
    THREAD_ISRUNING
};

class CameraThread : public QThread
{
    Q_OBJECT

public:
    explicit CameraThread(int count = 0, int workmode = CONTINUE_MODE, bool isstop = false, int status = 0);
    ~CameraThread();
    void run();
    void Stop();
    void Pause();
    void Start();

signals:
    /// 抓到图像传送给ui界面显示
    void GrabFrame(cv::Mat frame, int grabfps);

private slots:
    void RecvWorkMode(int workmode);
    void ResetFpsSlot();

private:
    cv::Mat mFrame;
    bool mIsStop;
    int mWorkMode;
    int mCount;
    int mStatus;
    int mGrabFps;
    QWaitCondition mWaitcondtion;
    QMutex mMutex;
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
    void closeEvent(QCloseEvent *event);

private slots:
    /// 接收抓图线程抓到的帧并显示
    void RecvFrame(cv::Mat mat, int grabfps);
    /// 触发模式选择
    void on_radioButtonContinue_clicked(bool checked);
    void on_radioButtonSoftware_clicked(bool checked);
    /// 软件触发时点击拍照按钮
    void on_pushButtonTakepic_clicked();
    /// 保存图像到指定路径
    void on_pushButtonSave_clicked();
    /// 选择保存图像的地址
    void on_pushButtonChoosePath_clicked();
    /// 图像保存格式
    void on_radioButtonJPG_clicked(bool checked);
    void on_radioButtonBMP_clicked(bool checked);
    void on_radioButtonPNG_clicked(bool checked);
    /// Fps
    void UpDateFps();

signals:
    void SetWorkMode(int workmode);
    void ResetGrabFps();

private:
    Ui::MainWindow *ui;
    CameraThread *mCameraThread;
    QString mPath;
    QImage mImage;
    QString mImageSaveFormat;
    QLabel *mLabelFps;
    int mReadFps;
    int mDisplayFps;

};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QFileDialog>
#include <QDateTime>
#include <QTimer>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow) {
    ui->setupUi(this);
    setWindowTitle(tr("基于Opencv与QT5的打开笔记本摄像头显示"));
    mImageSaveFormat = QString(".jpg");
    ui->lineEdit->setEnabled(false);
    ui->scrollAreaSoftware->setEnabled(false);
    ui->scrollAreaSoftware->setStyleSheet("color:gray");
    mLabelFps = new QLabel(this);
    mLabelFps->setAlignment(Qt::AlignHCenter);
    ui->statusBar->addWidget(mLabelFps);
    QTimer *timer = new QTimer(this);
    timer->setInterval(1000);
    connect(timer, SIGNAL(timeout()), this, SLOT(UpDateFps()));
    timer->start();

    mCameraThread = new CameraThread();
    mCameraThread->start();
    connect(mCameraThread, SIGNAL(GrabFrame(cv::Mat, int)), this, SLOT(RecvFrame(cv::Mat, int)), Qt::DirectConnection);
    connect(this, SIGNAL(SetWorkMode(int)), mCameraThread, SLOT(RecvWorkMode(int)), Qt::DirectConnection);
    connect(this, SIGNAL(ResetGrabFps()), mCameraThread, SLOT(ResetFpsSlot()), Qt::DirectConnection);
}

MainWindow::~MainWindow() {
    delete ui;
}

void MainWindow::closeEvent(QCloseEvent *event) {
    mCameraThread->Stop();
    delete mCameraThread;
}

/// 接收抓图线程抓到的帧并显示
void MainWindow::RecvFrame(cv::Mat mat, int grabfps) {
    switch(mat.type()) {
    case CV_8UC1:
        mImage = QImage(mat.cols, mat.rows, QImage::Format_Indexed8);
        // Set the color table (used to translate colour indexes to qRgb values)
        mImage.setColorCount(256);
        for(int i = 0; i < 256; i++)  {
            mImage.setColor(i, qRgb(i, i, i));
        }
        break;
    case CV_8UC3:
        cv::cvtColor(mat, mat, CV_BGR2RGB);
        mImage = QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        break;
    case CV_8UC4:
        // Create QImage with same dimensions as input Mat
        mImage = QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        break;
    default:
        break;
    }

    QSize size = ui->label->size();
    QImage image = mImage.scaled(size, Qt::IgnoreAspectRatio);
    ui->label->setPixmap(QPixmap::fromImage(image));
    mDisplayFps ++;
    mReadFps = grabfps;
}

/// 连续采集模式
void MainWindow::on_radioButtonContinue_clicked(bool checked) {
    if(checked) {
        ui->scrollAreaSoftware->setEnabled(false);
        ui->scrollAreaSoftware->setStyleSheet("color:gray");
        ui->pushButtonSave->setEnabled(true);
        ui->pushButtonSave->setStyleSheet("color:rgb(46, 52, 54)");
        emit SetWorkMode(CONTINUE_MODE);
    }
}

/// 软件触发模式
void MainWindow::on_radioButtonSoftware_clicked(bool checked) {
    if(checked) {
        ui->scrollAreaSoftware->setEnabled(true);
        ui->scrollAreaSoftware->setStyleSheet("color:rgb(46, 52, 54)");
        ui->pushButtonSave->setEnabled(false);
        ui->pushButtonSave->setStyleSheet("color:gray");
        emit SetWorkMode(SOFTWARE_MODE);
    }
}

/// 软件触发时点击拍照按钮
void MainWindow::on_pushButtonTakepic_clicked() {
    mCameraThread->Start();
}

/// 保存图像到指定路径
void MainWindow::on_pushButtonSave_clicked() {
    QDateTime datetime = QDateTime::currentDateTime();
    QString time = datetime.toString("yyyy_MM_dd_hh_mm_ss_zzz");
    QString path = mPath + "/" + time + mImageSaveFormat;
    if(!mImage.save(path)) {
        QMessageBox::warning(nullptr, tr("保存错误"), tr("保存图像失败"));
        return ;
    }
    QMessageBox::information(nullptr, tr("成功"), tr("保存图像成功"));
}

/// 选择保存图像的地址
void MainWindow::on_pushButtonChoosePath_clicked() {
    mPath = QFileDialog::getExistingDirectory(this, tr("请选择保存路径"), tr("./"));
    ui->lineEdit->clear();
    ui->lineEdit->setText(mPath);
}

/// JPG格式
void MainWindow::on_radioButtonJPG_clicked(bool checked) {
    if(checked) {
        mImageSaveFormat = QString(".jpg");
    }
}

/// BMP格式
void MainWindow::on_radioButtonBMP_clicked(bool checked) {
    if(checked) {
        mImageSaveFormat = QString(".bmp");
    }
}

/// PNG格式
void MainWindow::on_radioButtonPNG_clicked(bool checked) {
    if(checked) {
        mImageSaveFormat = QString(".png");
    }
}

/// FPS
void MainWindow::UpDateFps() {
    QString readfps = QString::number(mReadFps, 10);
    QString displayfps = QString::number(mDisplayFps, 10);
    mLabelFps->setText(tr("Grab fps : %1  Display fps : %2").arg(readfps).arg(displayfps));
    mReadFps = 0;
    mDisplayFps = 0;
    emit ResetGrabFps();
}

CameraThread::CameraThread(int count, int workmode, bool isstop, int status):
    mCount(count),
    mWorkMode(workmode),
    mIsStop(isstop),
    mStatus(status) {
    mGrabFps = 0;
}

CameraThread::~CameraThread() {

}

void CameraThread::run() {
    cv::VideoCapture m_Capture(0);
    while(!mIsStop) {
        switch(mWorkMode) {
        case CONTINUE_MODE: // 连续采集 -------------------------------------
            mMutex.lock();
            m_Capture >> mFrame;
            mGrabFps ++;
            mMutex.unlock();
            emit GrabFrame(mFrame, mGrabFps);
            break;

        case SOFTWARE_MODE: // 软件触发 --------------------------------------
            mMutex.lock();
            if(PAUSING_NUM == mCount) {
                mWaitcondtion.wait(&mMutex);
            }
            mCount --;
            mStatus = THREAD_ISRUNING;
            m_Capture >> mFrame;
            mStatus = THREAD_ISIDLE;
            mMutex.unlock();
            emit GrabFrame(mFrame, mGrabFps);
            break;

        default:
            break;
        }
    }
}

/// 终止线程
void CameraThread::Stop() {
    if(SOFTWARE_MODE == mWorkMode) {
        mWaitcondtion.wakeAll();
        mCount = PAUSING_NUM;
    }
    mIsStop = true;
    quit();
    wait();
}

void CameraThread::Pause() {

}

/// 点击拍照按钮启动软件触发
void CameraThread::Start() {
    if(THREAD_ISIDLE == mStatus) {
        mCount = RUNING_NUM;
        mWaitcondtion.wakeAll();
    }
}

/// 抓图线程接收工作模式信号
void CameraThread::RecvWorkMode(int workmode) {
    mStatus = THREAD_ISIDLE;
    mCount = PAUSING_NUM;
    if(SOFTWARE_MODE == mWorkMode && CONTINUE_MODE == workmode) {
        mWaitcondtion.wakeAll();
    }
    mWorkMode = workmode;
}

/// 将抓取帧率清零
void CameraThread::ResetFpsSlot() {
    mGrabFps = 0;
}

4.运行结果展示

在界面最下方为相机的抓取fps以及实现显示的fps, (fps即每秒中图片的刷新速度)

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值