QT+OPENCV简单demo
目录
1 demo功能简介
2 实现过程的难点和要注意的地方
··2.1 制作的UI界面
··2.2 代码实现
··2.3 库的添加
··2.4 自定义函数方法多文件编译
3 代码
4 文件包
1 demo功能简介
制作一个简易的界面软件,人为输入一个路径(如D:\qq.jpg),按下按钮后,通过opencv函数读取图片数据,然后在软件窗口中进行展示
演示效果如下,可以看到,在右边输入路径后,按下按钮即可读取图片并且在窗口中显示
2 实现过程
2.1 制作的UI界面
使用LineEdit来输入路径,使用PushButton来触发读取,在Label中展示图片。
相关的框架与命名如下,左边那个是我自己直接设定好了路径进行加载的,右边是要输入名字之后再进行读取。
2.2 代码实现
lineedit读取数据可以使用
//LineEdit部分
ui->lineEdit_ImagePath_2->text();//lineedit中读取Qstring
ui->lineEdit_ImagePath_2->text().toStdString();//lineedit中读取Qstring并转换为StdString
在Label中显示对应的图片
注意Label中只能显示Qpixmap格式的图片,而我们只能对QImage格式进行像素操作因此我们在展示之前需要将opencv的Mat格式转换为QImage格式
//在label窗口中进行展示QPixmap
ui->label_ShowImage_2->setScaledContents(true);//设定比例
ui->label_ShowImage_2->setPixmap(QSrcPixmap);//Label中只能显示Qpixmap格式
opencv读取照片并转换
注意,opencv用imread读取到的照片是Mat格式的,并且opencv是默认的BGR格式,但是使用QImage的构造函数的话默认是RGB格式的,因此我们需要把Mat从BGR格式转换为RGB格式,因此这里使用了opencv自带的cvtColor函数。
后面的转换函数mat2qimage_ref的本质就是使用qimage构造函数进行转换。然后使用fromImage可以将QImage转换为Pixmap,这样就可以在Label中进行显示了
std::string ImagePath=ui->lineEdit_ImagePath_2->text().toStdString();//读取路径
cv::Mat CVSrcImage=cv::imread(ImagePath,1);
cv::cvtColor(CVSrcImage, CVSrcImage, CV_BGR2RGB);//将opencv的图转换为RGB,这样才方便在QT中展示
QImage QSrcImage;
QSrcImage=StructureLine::mat2qimage_ref(CVSrcImage,QImage::Format_RGB888);
//将Qimage转化为QPixmap格式,方便展示
QPixmap QSrcPixmap = QPixmap::fromImage(QSrcImage,Qt::AutoColor);
2.3 库的添加
使用cvtColor函数要使用imgproc这个文件,如果一开始没有添加的话,要在pro中添加库文件的时候添加进去。如果没有添加的话,编译的时候会显示报错,类似于“找不到XXX,或者XXX不存在这种”。添加的方法在前面的文章“不使用cmake配置qt+opencv环境”里面已经提到了。
2.4 自定义函数方法多文件编译
本demo的文件架构如下所示,其中mat2qtformat自定义的函数方法文件,它用来实现cv::mat到QImage的转换函数
其中mat2qtformat.h的文件代码如下所示,在头文件中添加< QImage >以及< opencv2/opencv.hpp >能够帮助在文件中进行写代码时候的补全,如果这里不进行include相关头文件的话,那么在mat2qtformat.cpp中就必须进行include相关头文件。
mat2qtformat.h
#ifndef MATTOQTFORMAT_H
#define MATTOQTFORMAT_H
#include <QImage>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>
namespace StructureLine {
//##### cv::Mat ---> QImage #####
// Shallow copy
QImage mat2qimage_ref(cv::Mat &m, QImage::Format format);
// Deep copy
QImage mat2qimage_cpy(cv::Mat &m, QImage::Format format);
//##### QImage ---> cv::Mat #####
// Shallow copy
cv::Mat qimage2mat_ref(QImage &img, int format) ;
// Deep copy
//cv::Mat qimage2mat_ref(QImage &img, int format);
//
}
#endif // MATTOQTFORMAT_H
mat2qtformat.cpp
这个文件中不在包含opencv的头文件,因为直接写在了mat2qtformat.h文件中了
#include "mat2qtformat.h"
namespace StructureLine {
//##### cv::Mat ---> QImage #####
// Shallow copy
QImage mat2qimage_ref(cv::Mat &m, QImage::Format format) {
return QImage(m.data, m.cols, m.rows, m.step, format);
}
// Deep copy
QImage mat2qimage_cpy(cv::Mat &m, QImage::Format format) {
return QImage(m.data, m.cols, m.rows, m.step, format).copy();
}
//##### QImage ---> cv::Mat #####
// Shallow copy
cv::Mat qimage2mat_ref(QImage &img, int format) {
return cv::Mat(img.height(), img.width(), format, img.bits(), img.bytesPerLine());
}
// Deep copy
//cv::Mat qimage2mat_ref(QImage &img, int format) {
// return cv::Mat(img.height(), img.width(), format, const_cast<uchar*>(img.bits()), img.bytesPerLine()).clone();
//}
}
3 代码
cvdemo.pro
#-------------------------------------------------
#
# Project created by QtCreator 2019-12-14T11:12:11
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = cvdemo
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp \
mat2qtformat.cpp
HEADERS += \
mainwindow.h \
mat2qtformat.h
FORMS += \
mainwindow.ui
CONFIG +=C++11
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../cvpack/package/opencv/build/x64/vc14/lib/ -lopencv_core2413
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../cvpack/package/opencv/build/x64/vc14/lib/ -lopencv_core2413d
else:unix: LIBS += -L$$PWD/../../cvpack/package/opencv/build/x64/vc14/lib/ -lopencv_core2413
INCLUDEPATH += $$PWD/../../cvpack/package/opencv/build/include
DEPENDPATH += $$PWD/../../cvpack/package/opencv/build/include
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../cvpack/package/opencv/build/x64/vc14/lib/ -lopencv_highgui2413
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../cvpack/package/opencv/build/x64/vc14/lib/ -lopencv_highgui2413d
else:unix: LIBS += -L$$PWD/../../cvpack/package/opencv/build/x64/vc14/lib/ -lopencv_highgui2413
INCLUDEPATH += $$PWD/../../cvpack/package/opencv/build/include
DEPENDPATH += $$PWD/../../cvpack/package/opencv/build/include
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../cvpack/package/opencv/build/x64/vc14/lib/ -lopencv_imgproc2413
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../cvpack/package/opencv/build/x64/vc14/lib/ -lopencv_imgproc2413d
else:unix: LIBS += -L$$PWD/../../cvpack/package/opencv/build/x64/vc14/lib/ -lopencv_imgproc2413
INCLUDEPATH += $$PWD/../../cvpack/package/opencv/build/include
DEPENDPATH += $$PWD/../../cvpack/package/opencv/build/include
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_ReadImagePath_clicked();
void on_pushButton_ReadImagePath_2_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mat2qtformat.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_ReadImagePath_clicked();
void on_pushButton_ReadImagePath_2_clicked();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <string>
#include <opencv2/highgui.hpp>
#include <opencv/cv.h>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <QPixmap>
#include <QImage>
#include <QPainter>
#include <QString>
#include <QLabel>
#include <QMessageBox>
#include <QDebug>
#include "mat2qtformat.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_ReadImagePath_clicked()
{
//这个函数没有使用opencv的函数,单纯使用了qt的函数进行加载
QString filename("D:\\qq.jpg");
QImage* img=new QImage;
if(! ( img->load(filename) ) ) //加载图像
{
QMessageBox::information(this,
tr("打开图像失败"),
tr("打开图像失败!"));
delete img;
return;
}
ui->label_ShowImage->setScaledContents(true);
ui->label_ShowImage->setPixmap(QPixmap::fromImage(*img));
}
void MainWindow::on_pushButton_ReadImagePath_2_clicked()
{
qDebug()<<ui->lineEdit_ImagePath_2->text();//这里的地址只需要写D:\qq.jpg即可,因为下面转换为std::string会直接扩充为D:\\qq.jpg,但是opencv都能读出来
std::string ImagePath=ui->lineEdit_ImagePath_2->text().toStdString();//读取路径
cv::Mat CVSrcImage=cv::imread(ImagePath,1);
cv::cvtColor(CVSrcImage, CVSrcImage, CV_BGR2RGB);//将opencv的图转换为RGB,这样才方便在QT中展示
QImage QSrcImage;
QSrcImage=StructureLine::mat2qimage_ref(CVSrcImage,QImage::Format_RGB888);
//将Qimage转化为QPixmap格式,方便展示
QPixmap QSrcPixmap = QPixmap::fromImage(QSrcImage,Qt::AutoColor);
//在label窗口中进行展示QPixmap
ui->label_ShowImage_2->setScaledContents(true);
ui->label_ShowImage_2->setPixmap(QSrcPixmap);
/*
QImage QSrcImage;
if(QSrcImage.load(ui->lineEdit_ImagePath_2->text(),nullptr)){//如果成功加载
//将Qimage转化为QPixmap格式,方便展示
QPixmap QSrcPixmap = QPixmap::fromImage(QSrcImage,Qt::AutoColor);
//在label窗口中进行展示QPixmap
ui->label_ShowImage_2->setScaledContents(true);
ui->label_ShowImage_2->setPixmap(QSrcPixmap);
}
*/
}
mat2qtformat.cpp
#include "mat2qtformat.h"
namespace StructureLine {
//##### cv::Mat ---> QImage #####
// Shallow copy
QImage mat2qimage_ref(cv::Mat &m, QImage::Format format) {
return QImage(m.data, m.cols, m.rows, m.step, format);
}
// Deep copy
QImage mat2qimage_cpy(cv::Mat &m, QImage::Format format) {
return QImage(m.data, m.cols, m.rows, m.step, format).copy();
}
//##### QImage ---> cv::Mat #####
// Shallow copy
cv::Mat qimage2mat_ref(QImage &img, int format) {
return cv::Mat(img.height(), img.width(), format, img.bits(), img.bytesPerLine());
}
// Deep copy
//cv::Mat qimage2mat_ref(QImage &img, int format) {
// return cv::Mat(img.height(), img.width(), format, const_cast<uchar*>(img.bits()), img.bytesPerLine()).clone();
//}
}
UI框架
文件下载
链接:https://pan.baidu.com/s/1CSdjAoCvfdbSExjOosLzuA
提取码:4bjl
2019-12-16更新
新增加了第二种cvMat转换为Qpixmap的函数,鲁棒性更强,其余文件相同,因此这里不再重复
mainwindow.cpp
将一开始的那种方法给隐藏掉了,使用第二种方法
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <string>
#include <opencv2/highgui.hpp>
#include <opencv/cv.h>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <QPixmap>
#include <QImage>
#include <QPainter>
#include <QString>
#include <QLabel>
#include <QMessageBox>
#include <QDebug>
#include "mat2qtformat.h"
#include "mat2qtformatmethod2.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_ReadImagePath_clicked()
{
//这个函数没有使用opencv的函数,单纯使用了qt的函数进行加载
QString filename("D:\\qq.jpg");
QImage* img=new QImage;
if(! ( img->load(filename) ) ) //加载图像
{
QMessageBox::information(this,
tr("打开图像失败"),
tr("打开图像失败!"));
delete img;
return;
}
ui->label_ShowImage->setScaledContents(true);
ui->label_ShowImage->setPixmap(QPixmap::fromImage(*img));
}
void MainWindow::on_pushButton_ReadImagePath_2_clicked()
{
qDebug()<<ui->lineEdit_ImagePath_2->text();//这里的地址只需要写D:\qq.jpg即可,因为下面转换为std::string会直接扩充为D:\\qq.jpg,但是opencv都能读出来
std::string ImagePath=ui->lineEdit_ImagePath_2->text().toStdString();//读取路径
cv::Mat CVSrcImage=cv::imread(ImagePath,1);
//cv::cvtColor(CVSrcImage, CVSrcImage, CV_BGR2RGB);//将opencv的图转换为RGB,这样才方便在QT中展示
/*
QImage QSrcImage;
QSrcImage=StructureLine::mat2qimage_ref(CVSrcImage,QImage::Format_RGB888);
//将Qimage转化为QPixmap格式,方便展示
QPixmap QSrcPixmap = QPixmap::fromImage(QSrcImage,Qt::AutoColor);
//在label窗口中进行展示QPixmap
ui->label_ShowImage_2->setScaledContents(true);
ui->label_ShowImage_2->setPixmap(QSrcPixmap);
*/
/*
//这一部分是直接使用QT自带的load来读取图片
QImage QSrcImage;
if(QSrcImage.load(ui->lineEdit_ImagePath_2->text(),nullptr)){//如果成功加载
//将Qimage转化为QPixmap格式,方便展示
QPixmap QSrcPixmap = QPixmap::fromImage(QSrcImage,Qt::AutoColor);
//在label窗口中进行展示QPixmap
ui->label_ShowImage_2->setScaledContents(true);
ui->label_ShowImage_2->setPixmap(QSrcPixmap);
}
*/
//使用第二种接口来读取图片
QPixmap QSrcPixmap2=CV2QTFORMAT::cvMatToQPixmap(CVSrcImage);
ui->label_ShowImage_2->setScaledContents(true);
ui->label_ShowImage_2->setPixmap(QSrcPixmap2);
}
mat2qtformatmethod2.h
// 第二种转换函数头文件
#ifndef MAT2QTFORMATMETHOD2_H
#define MAT2QTFORMATMETHOD2_H
#include <QDebug>
#include <QImage>
#include <QPixmap>
#include <QtGlobal>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
// 这是第二种将CV::mat转化为Qimage的函数方法
// 这种方法能够直接识别读入的mat的类型,并且进行相应的转换为Qimage和Qpixmap
// 使用这种方法不需要额外调用cvtColor函数来进行BGR转换为RGB
namespace CV2QTFORMAT {
QImage cvMatToQImage( const cv::Mat &inMat );//cvMat转换为QImage
QPixmap cvMatToQPixmap( const cv::Mat &inMat );//cvMat转换为Qpixmap
}
#endif // MAT2QTFORMATMETHOD2_H
mat2qtformatmethod2.cpp
// 第二种转换函数方法文件
#include "mat2qtformatmethod2.h"
namespace CV2QTFORMAT {
// NOTE: This does not cover all cases - it should be easy to add new ones as required.
QImage cvMatToQImage( const cv::Mat &inMat )
{
switch ( inMat.type() )
{
// 8-bit, 4 channel
case CV_8UC4:
{
QImage image( inMat.data,
inMat.cols, inMat.rows,
static_cast<int>(inMat.step),
QImage::Format_ARGB32 );
return image;
}
// 8-bit, 3 channel
case CV_8UC3:
{
QImage image( inMat.data,
inMat.cols, inMat.rows,
static_cast<int>(inMat.step),
QImage::Format_RGB888 );
return image.rgbSwapped();
}
// 8-bit, 1 channel
case CV_8UC1:
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
QImage image( inMat.data,
inMat.cols, inMat.rows,
static_cast<int>(inMat.step),
QImage::Format_Grayscale8 );
#else
static QVector<QRgb> sColorTable;
// only create our color table the first time
if ( sColorTable.isEmpty() )
{
sColorTable.resize( 256 );
for ( int i = 0; i < 256; ++i )
{
sColorTable[i] = qRgb( i, i, i );
}
}
QImage image( inMat.data,
inMat.cols, inMat.rows,
static_cast<int>(inMat.step),
QImage::Format_Indexed8 );
image.setColorTable( sColorTable );
#endif
return image;
}
default:
qWarning() << "ASM::cvMatToQImage() - cv::Mat image type not handled in switch:" << inMat.type();
break;
}
return QImage();
}
QPixmap cvMatToQPixmap( const cv::Mat &inMat )
{
return QPixmap::fromImage( CV2QTFORMAT::cvMatToQImage( inMat ) );
}
}
更新后文件下载
链接:https://pan.baidu.com/s/1-v-zfueMFYdPrK8KxpVymw
提取码:395j