Qt QImage 与 OpenCV 的 Mat 类型的相互转化(改进)

Qt QImage 与 OpenCV 的 Mat 类型的相互转化(2)

在我的以前的一篇博客中其实已经介绍过转化方法。
https://blog.csdn.net/liyuanbhu/article/details/46662115

但是那篇博客里的代码不够完善。主要是转化后的图像与转化前的图像是否共享内存数据比较的乱。有些情况是共享内存的,有些情况又没有共享内存。代码的说明里也没有交代清楚。给使用我这个代码的人可能会造成困扰。所以就又写了篇博客。把代码进一步完善。

这一版的代码可以控制是否共享内存,对于 RGB24 格式的图像,也可以控制是否交换 R 与 B 的位置。通过这两点改进,可以在某些应用场景下大大的提高代码的运行速度。

下面是代码:

/****************************************************************************
** file: convert.h
** brief: cv::Mat 与 QImage 之间的转换函数。在 Qt 程序中使用 OpenCV 时有用。
** Copyright (C) LiYuan
** Author: LiYuan
** E-Mail: 18069211#qq(.)com
** Version 2.0.1
** Last modified: 2019.01.11
** Modified By: LiYuan
****************************************************************************/


#ifndef QT_OPENCV_CONVERT_H
#define QT_OPENCV_CONVERT_H

#include <QtCore/QDebug>
#include <QtGui/QImage>
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/opencv.hpp"
/**
 * @brief 将 OpenCV 的 cv::Mat 类型图像转换为 QImage 类型
 * @param mat 待转换的图像,支持 CV_8UC1、CV_8UC3、CV_8UC4 三种OpenCV 的数据类型
 * @param clone true 表示与 Mat 不共享内存,更改生成的 mat 不会影响原始图像,false 则会与 mat 共享内存
 * @param rb_swap 只针对 CV_8UC3 格式,如果 true 则会调换 R 与 B RGB->BGR,如果共享内存的话原始图像也会发生变化
 * @return 转换后的 QImage 图像
*/
QImage cvMat2QImage(const cv::Mat& mat, bool clone = true, bool rb_swap = true);

/**
 * @brief 将 QImage 的类型图像转换为 cv::Mat 类型
 * @param image 待转换的图像,支持 Format_Indexed8/Format_Grayscale、24 位彩色、32 位彩色格式,
 * @param clone true 表示与 QImage 不共享内存,更改生成的 mat 不会影响原始图像,false 则会与 QImage 共享内存
 * @param rg_swap 只针对 RGB888 格式,如果 true 则会调换 R 与 B RGB->BGR,如果共享内存的话原始图像也会发生变化
 * @return 转换后的 cv::Mat 图像
*/
cv::Mat QImage2cvMat(QImage &image, bool clone = false, bool rb_swap = true);

#endif


/****************************************************************************
** file: convert.cpp
** brief: cv::Mat 与 QImage 之间的转换函数。在 Qt 程序中使用 OpenCV 时有用。
** Copyright (C) LiYuan
** Author: LiYuan
** E-Mail: 18069211#qq(.)com
** Version 2.0.1
** Last modified: 2019.01.11
** Modified By: LiYuan
****************************************************************************/

#include "convert.h"

QImage cvMat2QImage(const cv::Mat& mat, bool clone, bool rb_swap)
{
    const uchar *pSrc = (const uchar*)mat.data;
    // 8-bits unsigned, NO. OF CHANNELS = 1
    if(mat.type() == CV_8UC1)
    {
        //QImage image(mat.cols, mat.rows, QImage::Format_Grayscale8);
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8);
        if(clone) return image.copy();
        return image;
    }
    // 8-bits unsigned, NO. OF CHANNELS = 3
    else if(mat.type() == CV_8UC3)
    {
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        if(clone)
        {
            if(rb_swap) return image.rgbSwapped();
            return image.copy();
        }
        else
        {
            if(rb_swap)
            {
                cv::cvtColor(mat, mat, CV_BGR2RGB);
            }
            return image;
        }

    }
    else if(mat.type() == CV_8UC4)
    {
        qDebug() << "CV_8UC4";
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        if(clone) return image.copy();
        return image;
    }
    else
    {
        qDebug() << "ERROR: Mat could not be converted to QImage.";
        return QImage();
    }
}

cv::Mat QImage2cvMat(QImage &image, bool clone, bool rb_swap)
{
    cv::Mat mat;
    //qDebug() << image.format();
    switch(image.format())
    {
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32_Premultiplied:
        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void *)image.constBits(), image.bytesPerLine());
        if(clone)  mat = mat.clone();
        break;
    case QImage::Format_RGB888:
        mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void *)image.constBits(), image.bytesPerLine());
        if(clone)  mat = mat.clone();
        if(rb_swap) cv::cvtColor(mat, mat, CV_BGR2RGB);
        break;
    case QImage::Format_Indexed8:
    case QImage::Format_Grayscale8:
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void *)image.bits(), image.bytesPerLine());
        if(clone)  mat = mat.clone();
        break;
    }
    return mat;
}

欢迎大家使用。也欢迎反馈使用中遇到的问题。

猜你喜欢

转载自blog.csdn.net/liyuanbhu/article/details/86307283