Qt+多线程实现单幅图像高斯、灰度、边缘处理,调用opencv库导入图片

【QT】多线程+OpenCV的demo

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

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

ui界面如下
在这里插入图片描述

Mythread.h

#pragma once
#include "qobject.h"
#include<QObject>
#include<QRunnable>
#include<QThread>
#include<opencv2/opencv.hpp>
#include<iostream>
#include<QPixmap>

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<QPainter>
#include<QPixmap>
#include<QAction>
#include<QPainter>
#include<QLabel>
#include<QPushButton>
#include<QDebug>
#include<opencv2/opencv.hpp>
#pragma execution_character_set("utf-8")
#include<QFileDialog>
#include<QMessageBox>
#include<QPixmap>
#include<QImage>
#include<QElapsedTimer>

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 <QtWidgets/QMainWindow>
#include "ui_demo_qt_cv_thread.h"
#include<opencv2/opencv.hpp>
#include<iostream>

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<QDebug>
#include<opencv2/opencv.hpp>
#include<QPixmap>
#include<QLabel>
#pragma execution_character_set("utf-8")
#include<QImage>
#include<QMessageBox>
#include "Mythread.h"
#include<QThread>
#include<QThreadPool>
#include<QFileDialog>

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();
	}
}

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

通过调试信息可以看到
在这里插入图片描述

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值