QImage与OpenCV的cv::Mat数据转换

在Qt中使用OpenCV,经常是用QImage与OpenCV的mat进行数据转换,最终显示都是转成QImage或QPixmap的数据,本篇介绍QImage与cv::Mat的数据转换。

1.QImage读取图片转换成cv::Mat
首先通过QImage加载图片image.load(":/image/t2.jpg");
然后通过QImageToMat函数转成cv::Mat

cv::Mat QImageToMatDialog::QImageToMat(const QImage &image)
{
    cv::Mat mat;
    switch(image.format())
    {
    case QImage::Format_Grayscale8: // 灰度图,每个像素点1个字节(8位)
        // Mat构造:行数,列数,存储结构,数据,step每行多少字节
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        break;
    case QImage::Format_ARGB32: // uint32存储0xAARRGGBB,pc一般小端存储低位在前,所以字节顺序就成了BGRA
    case QImage::Format_RGB32: // Alpha为FF
//    case QImage::Format_ARGB32_Premultiplied:
//        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
//        break;
    case QImage::Format_ARGB32_Premultiplied:
    {
        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
        std::vector<cv::Mat>channels;
        split(mat, channels);
        channels.pop_back();
        cv::merge(channels, mat);
        return mat;
    }
    case QImage::Format_RGB888: // RR,GG,BB字节顺序存储
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        return mat.clone();
        break;
    case QImage::Format_RGBA64: // uint64存储,顺序和Format_ARGB32相反,RGBA
        mat = cv::Mat(image.height(), image.width(), CV_16UC4, (void*)image.constBits(), image.bytesPerLine());
        // opencv需要转为BGRA的字节顺序
        cv::cvtColor(mat, mat, cv::COLOR_RGBA2BGRA);
        break;

    case QImage::Format_Mono:
    case QImage::Format_MonoLSB:
    {
        QImage rgbImage = image.convertToFormat(QImage::Format_Grayscale8);
        return cv::Mat(rgbImage.height(), rgbImage.width(), CV_8UC1, (void*)rgbImage.bits(), rgbImage.bytesPerLine()).clone();
    }

    case QImage::Format_Indexed8:
    {
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        return mat.clone();
    }
    default:
        return mat;

    }
    return mat;
}

通过cv::imwrite函数保存图片,即
cv::Mat mat = QImageToMat(image);
cv::imwrite("./mat_t2.jpg", mat);

void QImageToMatDialog::slotQImageToMat()
{
    QImage image;
    bool isLoad = image.load(":/image/t2.jpg");
    if(isLoad)
    {
        QPixmap pixOrg = QPixmap::fromImage(image);
        pixOrg = pixOrg.scaled(400, 300);
        ui->label->setPixmap(pixOrg);

        cv::Mat mat = QImageToMat(image);
        cv::imwrite("./mat_t2.jpg", mat);//保存到本地

        ui->label_1->setPixmap(pixOrg);

    }

}

2..opencv读取图片转成QImage
cv::Mat mat = cv::imread("./t3.jpg");
通过QImage matToQImage(const cv::Mat &mat)函数转成QImage数据

QImage QImageToMatDialog::matToQImage(const cv::Mat &mat)
{
    QImage image;
    switch(mat.type())
    {
    case CV_8UC1:
        // QImage构造:数据,宽度,高度,每行多少字节,存储结构
        image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8);
        break;
    case CV_8UC3:
        image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        image = image.rgbSwapped(); // BRG转为RGB
        // Qt5.14增加了Format_BGR888
        // image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.cols * 3, QImage::Format_BGR888);
        break;
    case CV_8UC4:
        image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        break;
    case CV_16UC4:
        image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGBA64);
        image = image.rgbSwapped(); // BRG转为RGB
        break;
    default:
        break;
    }
    return image;
}

使用:


void QImageToMatDialog::slotMatToQImage()
{
    cv::Mat mat = cv::imread("./t3.jpg");

    QImage image = matToQImage(mat);
    QPixmap pix2 = QPixmap::fromImage(image);
    pix2 = pix2.scaled(400, 300);
    ui->label_2->setPixmap(pix2);
}

完整代码

#ifndef QIMAGETOMATDIALOG_H
#define QIMAGETOMATDIALOG_H

#include <QDialog>
#include "opencv2/opencv.hpp"

using namespace cv;

QT_BEGIN_NAMESPACE
namespace Ui { class QImageToMatDialog; }
QT_END_NAMESPACE

class QImageToMatDialog : public QDialog
{
    Q_OBJECT

public:
    QImageToMatDialog(QWidget *parent = nullptr);
    ~QImageToMatDialog();
    void initView();

    cv::Mat QImageToMat(const QImage &image);
    QImage matToQImage(const cv::Mat& mat);

public slots:
    void slotQImageToMat();
    void slotMatToQImage();

private:
    Ui::QImageToMatDialog *ui;
};
#endif // QIMAGETOMATDIALOG_H
#include "qimagetomatdialog.h"
#include "ui_qimagetomatdialog.h"
#include <QDebug>
#include <QImage>
#include <QPixmap>


QImageToMatDialog::QImageToMatDialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::QImageToMatDialog)
{
    ui->setupUi(this);
    initView();
}

QImageToMatDialog::~QImageToMatDialog()
{
    delete ui;
}

void QImageToMatDialog::initView()
{
    connect(ui->btnQImageToMat, SIGNAL(clicked()), this, SLOT(slotQImageToMat()));
    connect(ui->btnMatToQImage, SIGNAL(clicked()), this, SLOT(slotMatToQImage()));
}

cv::Mat QImageToMatDialog::QImageToMat(const QImage &image)
{
    cv::Mat mat;
    switch(image.format())
    {
    case QImage::Format_Grayscale8: // 灰度图,每个像素点1个字节(8位)
        // Mat构造:行数,列数,存储结构,数据,step每行多少字节
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        break;
    case QImage::Format_ARGB32: // uint32存储0xAARRGGBB,pc一般小端存储低位在前,所以字节顺序就成了BGRA
    case QImage::Format_RGB32: // Alpha为FF
//    case QImage::Format_ARGB32_Premultiplied:
//        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
//        break;
    case QImage::Format_ARGB32_Premultiplied:
    {
        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
        std::vector<cv::Mat>channels;
        split(mat, channels);
        channels.pop_back();
        cv::merge(channels, mat);
        return mat;
    }
    case QImage::Format_RGB888: // RR,GG,BB字节顺序存储
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        return mat.clone();
        break;
    case QImage::Format_RGBA64: // uint64存储,顺序和Format_ARGB32相反,RGBA
        mat = cv::Mat(image.height(), image.width(), CV_16UC4, (void*)image.constBits(), image.bytesPerLine());
        // opencv需要转为BGRA的字节顺序
        cv::cvtColor(mat, mat, cv::COLOR_RGBA2BGRA);
        break;

    case QImage::Format_Mono:
    case QImage::Format_MonoLSB:
    {
        QImage rgbImage = image.convertToFormat(QImage::Format_Grayscale8);
        return cv::Mat(rgbImage.height(), rgbImage.width(), CV_8UC1, (void*)rgbImage.bits(), rgbImage.bytesPerLine()).clone();
    }

    case QImage::Format_Indexed8:
    {
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        return mat.clone();
    }
    default:
        return mat;

    }
    return mat;
}

QImage QImageToMatDialog::matToQImage(const cv::Mat &mat)
{
    QImage image;
    switch(mat.type())
    {
    case CV_8UC1:
        // QImage构造:数据,宽度,高度,每行多少字节,存储结构
        image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8);
        break;
    case CV_8UC3:
        image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        image = image.rgbSwapped(); // BRG转为RGB
        // Qt5.14增加了Format_BGR888
        // image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.cols * 3, QImage::Format_BGR888);
        break;
    case CV_8UC4:
        image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        break;
    case CV_16UC4:
        image = QImage((const unsigned char*)mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGBA64);
        image = image.rgbSwapped(); // BRG转为RGB
        break;
    default:
        break;
    }
    return image;
}



void QImageToMatDialog::slotQImageToMat()
{
    QImage image;
    bool isLoad = image.load(":/image/t2.jpg");
    if(isLoad)
    {
        QPixmap pixOrg = QPixmap::fromImage(image);
        pixOrg = pixOrg.scaled(400, 300);
        ui->label->setPixmap(pixOrg);

        cv::Mat mat = QImageToMat(image);
        cv::imwrite("./mat_t2.jpg", mat);

        ui->label_1->setPixmap(pixOrg);

    }

}

void QImageToMatDialog::slotMatToQImage()
{
    cv::Mat mat = cv::imread("./t3.jpg");

    QImage image = matToQImage(mat);
    QPixmap pix2 = QPixmap::fromImage(image);
    pix2 = pix2.scaled(400, 300);
    ui->label_2->setPixmap(pix2);
}

参考:

https://www.cnblogs.com/ybqjymy/p/13595616.html         
https://blog.csdn.net/amnesiagreen/article/details/10735
https://blog.csdn.net/liyuanbhu/article/details/46659725

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值