【QT】多线程+OpenCV的demo

结合最近学的知识自己做了个小demo。可以实现对输入的图片进行图像处理,高斯模糊、灰度处理以及边缘检测,三种处理同时进行。

思路:借助OpenCv库,用Mat读取图片并输出展示在界面上,多线程进行图像处理。这里采用线程池的方法。

ui界面如下

Mythread.h

#pragma once

#include "qobject.h"

#include

#include

#include

#include

#include

#include

using namespace std;

using namespace cv;

//高斯模糊

class Gaussuianintroduce :public QObject, public QRunnable

{

Q_OBJECT

public:

Gaussuianintroduce();

~Gaussuianintroduce();

void run();

void recvmat(Mat mat);

signals:

void finish(Mat mat);

private:

Mat m_mat;

Mat mat_Gussian;

};

//灰度处理

class Grayintroduce :public QObject, public QRunnable

{

Q_OBJECT

public:

Grayintroduce();

~Grayintroduce();

void run();

void recvmat(Mat mat);

signals:

void finish(Mat mat);

private:

Mat m_mat2;

Mat mat_Gray;

};

//边缘检测

class Cannyintroduce :public QObject, public QRunnable

{

Q_OBJECT

public:

Cannyintroduce();

~Cannyintroduce();

void run();

void recvmat(Mat mat);

signals:

void finish(Mat mat);

private:

Mat m_mat3;

Mat mat_Canny;

};

Mythread.cpp

#include "Mythread.h"

#include

#include

#include

#include

#include

#include

#include

#include

#pragma execution_character_set("utf-8")

#include

#include

#include

#include

#include

using namespace cv;

using namespace std;

Gaussuianintroduce::Gaussuianintroduce()

{

setAutoDelete(true);

}

Gaussuianintroduce::~Gaussuianintroduce()

{

}

//高斯模糊

void Gaussuianintroduce::run()

{

qDebug() << "高斯模糊处理的线程地址:" << QThread::currentThread();

QElapsedTimer time;

time.start();

GaussianBlur(m_mat, mat_Gussian, Size(29, 29), 0, 0);

int milsec = time.elapsed();

qDebug() << "高斯模糊处理用时" << milsec << "毫秒";

//发送完成的信号 将信号中的图片传给主线程

emit finish(mat_Gussian);

}

void Gaussuianintroduce::recvmat(Mat mat)

{

m_mat = mat;

}

Grayintroduce::Grayintroduce()

{

setAutoDelete(true);

}

Grayintroduce::~Grayintroduce()

{

}

//灰度处理

void Grayintroduce::run()

{

qDebug() << "灰度处理的线程地址:" << QThread::currentThread();

QElapsedTimer time;

time.start();

cvtColor(m_mat2, mat_Gray, COLOR_BGR2GRAY);

int milsec = time.elapsed();

qDebug() << "灰度处理用时" << milsec << "毫秒";

//发送完成的信号 将信号中的图片传给主线程

emit finish(mat_Gray);

}

void Grayintroduce::recvmat(Mat mat)

{

m_mat2 = mat;

}

Cannyintroduce::Cannyintroduce()

{

setAutoDelete(true);

}

Cannyintroduce::~Cannyintroduce()

{

}

//灰度处理

void Cannyintroduce::run()

{

qDebug() << "边缘检测的线程地址:" << QThread::currentThread();//返回一个指向管理当前执行线程的QThread的指针

//QElapsedTimer主要用来测量一个操作耗时多久

QElapsedTimer time;//定义一个对象

time.start();//开始计时

//相关操作

Canny(m_mat3, mat_Canny, 150, 100, 3);

//输出结果

int milsec = time.elapsed();

qDebug() << "灰度处理用时" << milsec << "毫秒";

//发送完成的信号 将信号中的图片传给主线程

emit finish(mat_Canny);

}

void Cannyintroduce::recvmat(Mat mat)

{

m_mat3 = mat;

}

demo_qt_cv_thread.h

#pragma once

#include

#include "ui_demo_qt_cv_thread.h"

#include

#include

using namespace std;

using namespace cv;

class demo_qt_cv_thread : public QMainWindow

{

Q_OBJECT

public:

demo_qt_cv_thread(QWidget *parent = Q_NULLPTR);

QImage MatToImage(Mat &mat);

signals:

void starting(Mat mat);

private:

Ui::demo_qt_cv_threadClass *ui;

Mat image;

};

demo_qt_cv_thread.cpp

#include "demo_qt_cv_thread.h"

#include

#include

#include

#include

#pragma execution_character_set("utf-8")

#include

#include

#include "Mythread.h"

#include

#include

#include

using namespace std;

using namespace cv;

demo_qt_cv_thread::demo_qt_cv_thread(QWidget *parent)

: QMainWindow(parent)

{

ui->setupUi(this);

this->setWindowTitle("多线程图像处理");

this->setWindowIcon(QPixmap(":/res/b2.jpg"));

connect(ui->pushButton_2, &QPushButton::clicked, [=]() {

ui->label->clear();

ui->label_2->clear();

ui->label_3->clear();

ui->label_4->clear();

//调用窗口打开图片文件

//文件对话框 QFileDialog

QString filename = QFileDialog::getOpenFileName(this,

tr("open image"), ".", tr("Image file(*.png *.jpg *.bmp)")

);

//第二个参数是弹窗的标题

//第三个参数是最初显示的目录

//第三个是筛选条件 即过滤器 Image Files(*.png *.jpg *.bmp)中给出的模式匹配的文件

//将QString 转换为String 这样opencv才可读取图片

image = imread(filename.toLocal8Bit().data());

//image = imread("E:/Code/opencvcode/demo_qt_cv_thread/res/b2.jpg");

qDebug() << image.data;

if (image.empty())

{

QMessageBox::information(this, tr("提示"), tr("未成功载入图片"), QMessageBox::Ok);

}

//绘图

QPixmap pix;

pix = QPixmap::fromImage(MatToImage(image).scaled(ui->label->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));

ui->label->setPixmap(pix);

});

//创建任务类对象

Gaussuianintroduce *th1 = new Gaussuianintroduce;

Grayintroduce *th2 = new Grayintroduce;

Cannyintroduce *th3 = new Cannyintroduce;

//主线程和子线程数据交互

connect(this, &demo_qt_cv_thread::starting, th1, &Gaussuianintroduce::recvmat);

connect(this, &demo_qt_cv_thread::starting, th2, &Grayintroduce::recvmat);

connect(this, &demo_qt_cv_thread::starting, th3, &Cannyintroduce::recvmat);

connect(ui->pushButton, &QPushButton::clicked, [=]() {

ui->label_2->clear();

ui->label_3->clear();

ui->label_4->clear();

//放入线程池 启动子线程

QThreadPool::globalInstance()->start(th1);

QThreadPool::globalInstance()->start(th2);

QThreadPool::globalInstance()->start(th3);

emit starting(image);

});

//利用label绘图显示

connect(th1, &Gaussuianintroduce::finish, [=](Mat mat_Gussian) {

QPixmap pix2;

pix2 = QPixmap::fromImage(MatToImage(mat_Gussian).scaled(ui->label_2->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));

ui->label_2->setPixmap(pix2);

});

connect(th2, &Grayintroduce::finish, [=](Mat mat_Gray) {

QPixmap pix3;

pix3 = QPixmap::fromImage(MatToImage(mat_Gray).scaled(ui->label_3->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));

ui->label_3->setPixmap(pix3);

});

connect(th3, &Cannyintroduce::finish, [=](Mat mat_Canny) {

QPixmap pix4;

pix4 = QPixmap::fromImage(MatToImage(mat_Canny).scaled(ui->label_4->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));

ui->label_4->setPixmap(pix4);

});

destroyAllWindows();

}

//图片转化

QImage demo_qt_cv_thread::MatToImage(Mat &mat)

{

//输入图像为三通道

if (mat.type() == CV_8UC3)

{

//复制输入的mat数据

const uchar* pSrc = (const uchar*)mat.data;

//创建与输入Mat尺寸相同的QImage

QImage image(pSrc, mat.cols, mat.rows,(mat.cols)*3, QImage::Format_RGB888);

//将RGB转换为BGR

return image.rgbSwapped();

}

//输入图像为单通道

else if (mat.type() == CV_8UC1)

{

QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);

//设置颜色表(用于将颜色索引转换为qRgb值)

image.setColorCount(256);//灰度级数256

for (int i = 0; i < 256; i++)

{

image.setColor(i, qRgb(i, i, i));

}

//复制输入

uchar *pSrc = mat.data;

for (int row = 0; row < mat.rows; row++)

{

uchar *pDest = image.scanLine(row);//对图像的一行进行扫描,获取本行中个像素的内存地址

//复制src的内存的前num个字节内容给dest

memcpy(pDest, pSrc, mat.cols);

pSrc += mat.step;

}

return image;

}

//输入图像为四通道

else if (mat.type() == CV_8UC4)

{

qDebug() << "CV_8UC4";

// Copy input Mat

const uchar *pSrc = (const uchar*)mat.data;

// Create QImage with same dimensions as input Mat

QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);

return image.copy();

}

else

{

qDebug() << "ERROR:Mat could not be converted to QImage";

return QImage();

}

}

运行效果如下: 点击输入图片按钮,弹出一个文件夹,可选取自己想处理的图片 这里我选择了一张狗头的表清包 点击开始处理按钮,成功实现同时输出三种处理图像

通过调试信息可以看到

推荐阅读

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。