在这里先祝各位小伙伴端午节快乐,因工作需要,须使用QT+OpenCV处理显示图片,期间踩了一些坑、总结了一些经验,今天做下记录,希望可以帮助更多小伙伴,开搞!!
一、新建QT工程
需要带窗口工程
二、添加路径和库文件
在xxx.pro里面添加支持
INCLUDEPATH += /usr/local/include \
/usr/local/include/opencv \
/usr/local/include/opencv2
LIBS += /usr/local/lib/libopencv_highgui.so \
/usr/local/lib/libopencv_core.so \
/usr/local/lib/libopencv_imgproc.so \
/usr/local/lib/libopencv_imgcodecs.so
三、在UI中绘制界面
四、在头文件中添加引入头文件和函数声明
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QApplication>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <QFileDialog> //打开指定文件
#include <QDebug>
using namespace cv;
using namespace std;
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
QImage MatToQImageThreeAndSignalChannel(cv::Mat& mat, QImage& qimage);
QImage MatToQImageShallowCopy(cv::Mat &mat, QImage::Format format);
QImage MatToQImageDeepCopy(cv::Mat &mat, QImage::Format format);
QImage MatToQImageMultichannel(const cv::Mat &mat);
private slots:
void on_OpenImageButton_clicked();
void on_CloseImageButton_clicked();
private:
Ui::MainWindow *ui;
Mat srcImage, dstImage;
QImage qImage;
QString imageName;
};
#endif // MAINWINDOW_H
五、编写代码显示图片
1、设置一个点击按钮槽函数
private slots:
void on_OpenImageButton_clicked();
2、点击打开图片按钮,进入目录选中图片
imageName = QFileDialog::getOpenFileName(this, tr("打开图片"), ".", tr("所有格式(*.png *.jpg *.jpeg *.bmp)"));
if(imageName.length() <= 0) {
qDebug() << "读取图片错误" << endl;
return;
}
3、使用OpenCV读取图片
srcImage = imread(imageName.toUtf8().data());
4、缩小图片
因为我要显示的图片比较大,显示框显示不完整,需要先缩小(这一部分可选做)。
cv::resize(srcImage, dstImage, Size(), 0.25, 0.25);//缩小四倍
5、格式转换
在QT label中显示图片需要进行OpenCV到QImage的格式转换,下面将介绍四种方法。
(1)、浅拷贝
本人选择的图片默认为RGB三通道。
1、转换函数
QImage MainWindow::MatToQImageShallowCopy(cv::Mat &mat, QImage::Format format) {
return QImage(mat.data, mat.cols, mat.rows, mat.step, format);
}
2、调用
qImage = MatToQImageShallowCopy(dstImage, qImage.Format_RGB888);
3、效果
(2)、深拷贝
1、转换函数
QImage MainWindow::MatToQImageDeepCopy(cv::Mat &mat, QImage::Format format) {
return QImage(mat.data, mat.cols, mat.rows, mat.step, format).copy();
}
2、调用
qImage = MatToQImageDeepCopy(dstImage, qImage.Format_RGB888);
3、效果
上面两种方法都默认图片格式为RGB三通道,那么有没有一种方式可以进行单通道和三通道判断呢?有的,下面将继续介绍。
(3)、单通道和三通道判断
1、转换函数
QImage MainWindow::MatToQImageThreeAndSignalChannel(cv::Mat &mat, QImage &qimage) {
//CV_8UC3 unsigned 型 3通道
//打开的图片是三通道的
if(mat.type() == CV_8UC3) {
qimage = QImage((const unsigned char*)(mat.data),
mat.cols, mat.rows, mat.step,
QImage::Format_RGB888).rgbSwapped();
}
else if(mat.type() == CV_8UC1) {
static QVector<QRgb> sColorTable;
if(sColorTable.isEmpty()) {
for(int i = 0; i < 256; ++i) {
sColorTable.push_back(qRgb(i, i, i)); //如果打开的图片是空的,就自己填充色彩
}
}
qimage = QImage((const unsigned char*)(mat.data),
mat.cols, mat.rows, mat.step,
QImage::Format_Indexed8);
qimage.setColorTable(sColorTable);//转换成qt调色板
}
return qimage;
}
2、调用
调用的时候就不用自己手动的写通道个数了。
qImage = MatToQImageThreeAndSignalChannel(dstImage, qImage);
3、效果
(4)、单通道、三通道、四通道改进
这个方法对以上的三个方法进行了改进,添加了四通道判断功能。
1、转换函数
QImage MainWindow::MatToQImageMultichannel(const cv::Mat &mat) {
QImage image;
switch(mat.type()) {
//8bit,四通道
case CV_8UC4:{
image = QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB32);//step:每一维元素的大小,单位字节
return image;
}
//8bit,三通道
case CV_8UC3:{
image = QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);//step:每一维元素的大小,单位字节
return image;
}
//8bit,单通道
case CV_8UC1: {
static QVector<QRgb> sColorTable;
if(sColorTable.isEmpty()) {
for(int i = 0; i < 256; ++i) {
sColorTable.push_back(qRgb(i, i, i)); //如果打开的图片是空的,就自己填充色彩
}
}
image = QImage((const unsigned char*)(mat.data),
mat.cols, mat.rows, mat.step,
QImage::Format_Indexed8);
image.setColorTable(sColorTable);//转换成qt调色板
}
default:
qDebug("没有支持的图片格式: depth=%d 和 %d channels\n", mat.depth(), mat.channels());
break;
}
return QImage();
}
2、调用
qImage = MatToQImageMultichannel(dstImage);
3、效果
好了,到这里你们是不是已经学会了QT 和 OpenCV混合使用显示图片了呢,下面我将代码贴上。
六、MainWindow代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow){
ui->setupUi(this);
}
MainWindow::~MainWindow(){
delete ui;
}
//方法一:浅拷贝
QImage MainWindow::MatToQImageShallowCopy(cv::Mat &mat, QImage::Format format) {
return QImage(mat.data, mat.cols, mat.rows, mat.step, format);
}
//方法二:深拷贝
QImage MainWindow::MatToQImageDeepCopy(cv::Mat &mat, QImage::Format format) {
return QImage(mat.data, mat.cols, mat.rows, mat.step, format).copy();
}
//方法三:单通道和三通道选择
QImage MainWindow::MatToQImageThreeAndSignalChannel(cv::Mat &mat, QImage &qimage) {
//CV_8UC3 unsigned 型 3通道
//打开的图片是三通道的
if(mat.type() == CV_8UC3) {
qimage = QImage((const unsigned char*)(mat.data),
mat.cols, mat.rows, mat.step,
QImage::Format_RGB888).rgbSwapped();
}
else if(mat.type() == CV_8UC1) {
static QVector<QRgb> sColorTable;
if(sColorTable.isEmpty()) {
for(int i = 0; i < 256; ++i) {
sColorTable.push_back(qRgb(i, i, i)); //如果打开的图片是空的,就自己填充色彩
}
}
qimage = QImage((const unsigned char*)(mat.data),
mat.cols, mat.rows, mat.step,
QImage::Format_Indexed8);
qimage.setColorTable(sColorTable);//转换成qt调色板
}
return qimage;
}
//方法四:多通道和单通道选择
QImage MainWindow::MatToQImageMultichannel(const cv::Mat &mat) {
QImage image;
switch(mat.type()) {
//8bit,四通道
case CV_8UC4:{
image = QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB32);//step:每一维元素的大小,单位字节
return image;
}
//8bit,三通道
case CV_8UC3:{
image = QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);//step:每一维元素的大小,单位字节
return image;
}
//8bit,单通道
case CV_8UC1: {
static QVector<QRgb> sColorTable;
if(sColorTable.isEmpty()) {
for(int i = 0; i < 256; ++i) {
sColorTable.push_back(qRgb(i, i, i)); //如果打开的图片是空的,就自己填充色彩
}
}
image = QImage((const unsigned char*)(mat.data),
mat.cols, mat.rows, mat.step,
QImage::Format_Indexed8);
image.setColorTable(sColorTable);//转换成qt调色板
}
default:
qDebug("没有支持的图片格式: depth=%d 和 %d channels\n", mat.depth(), mat.channels());
break;
}
return QImage();
}
void MainWindow::on_OpenImageButton_clicked(){
imageName = QFileDialog::getOpenFileName(this, tr("打开图片"), ".", tr("所有格式(*.png *.jpg *.jpeg *.bmp)"));
if(imageName.length() <= 0) {
qDebug() << "读取图片错误" << endl;
return;
}
srcImage = imread(imageName.toUtf8().data());
cv::resize(srcImage, dstImage, Size(), 0.25, 0.25);
//方法一 浅拷贝
// qImage = MatToQImageShallowCopy(dstImage, qImage.Format_RGB888);
//方法二 深拷贝
// qImage = MatToQImageDeepCopy(dstImage, qImage.Format_RGB888);
//方法三 单通道和三通道选择
// qImage = MatToQImageThreeAndSignalChannel(dstImage, qImage);
//方法四 多通道和单通道选择改进
qImage = MatToQImageMultichannel(dstImage);
ui->labelShowImage->setPixmap(QPixmap::fromImage(qImage));
}
void MainWindow::on_CloseImageButton_clicked(){
close();
}
感谢大神:
http://www.jeepshoe.net/art/76964.html
https://blog.csdn.net/qq_27901091/article/details/75171378
https://www.cnblogs.com/grandyang/p/5602360.html