天天看点

QT和OpenCV混合使用显示图片

在这里先祝各位小伙伴端午节快乐,因工作需要,须使用QT+OpenCV处理显示图片,期间踩了一些坑、总结了一些经验,今天做下记录,希望可以帮助更多小伙伴,开搞!!

一、新建QT工程

需要带窗口工程

QT和OpenCV混合使用显示图片

二、添加路径和库文件

在xxx.pro里面添加支持

QT和OpenCV混合使用显示图片
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中绘制界面

QT和OpenCV混合使用显示图片

四、在头文件中添加引入头文件和函数声明

QT和OpenCV混合使用显示图片
#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、点击打开图片按钮,进入目录选中图片

QT和OpenCV混合使用显示图片
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、效果

QT和OpenCV混合使用显示图片

(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、效果

QT和OpenCV混合使用显示图片

上面两种方法都默认图片格式为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、效果

QT和OpenCV混合使用显示图片

(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混合使用显示图片

好了,到这里你们是不是已经学会了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