1.完成界面上可选择的软件触发以及连续采集模式下,在界面上实时显示笔记本摄像头所拍摄的画面
2.可选择保存图像的格式如".jpg"、".bmp"、".png"格式,并可选择将要保存的文件目录
3.在连续采集模式下,会在界面实时显示抓取的每一帧,即像视频一样播放摄像头所拍摄的画面
4.在软件触发模式下,点击一次拍照按钮才会抓取一帧图像,即点击一次拍一张图像显示在界面
专门写一个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);
时间有限,代码就不一一讲解,下面贴上mainwindow.h和mainwindow.cpp中的代码, 完整代码可直接gitclone本人github上的代码获取观看
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
#include
#include
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;
}