cv::Mat与QImage的互相转换

OpenCV 的 cv::Mat 和 Qt 的 QImage 的转换很简单,网上也很多参考,这里只是记录一下。

转换的时候除了要关注构造参数中的图像宽高、存储精度、通道数和通道顺序外,大小端也需要注意。如 QImage::Format_ARGB32 是用 32 位整形存储一个像素,虽然写的是 ARGB 顺序,但是由于存储大小端的关系,PC 一般小端存储,所以字节顺序成了 BGRA。

要注意的一点,直接通过数据指针构造 QImage 是复用的原来的内存,要注意释放顺序,也可以 copy() 拷贝一份,但又增加了一点开销。直接通过数据指针构造 cv::Mat 也是不会拷贝数据的,需要调用 clone() 或者 copyTo() 进行深拷贝。

(2023-03-09 补充)QImage 每行的字节宽度,一般会有四字节对齐的约定,通过 bytesPerLine() 获取每行实际字节宽度。cv::Mat 的 step 属性实测没有字节对齐,如果字节宽度不是四的倍数构造出来的 QImage 是否会有问题待验证,但是一旦修改 QImage 内容就会自动重新对齐了。

(2023-03-09 补充)带透明通道的图在 cvtColor 转换时,要带上透明通道如: cv::COLOR_RGBA2BGRA

QImage::Format枚举参考:https://doc.qt.io/qt-5/qimage.html#Format-enum
Qt的枚举体现了通道顺序和一个像素点的位宽
如:Format_ARGB32一个32位整形存储ARGB值
Format_RGB888相当于三个8位整形存储RGB值
Qt5.14增加了Format_BGR888,和opencv转换更方便了

cv的枚举体现位宽和通道数,而通道顺序是固定的
如:CV_8UC1
U表示存储类型
U无符号整形、S有符号整形、F单精度浮点型
8U就是每个通道由8位的无符号整形表示,unsigned char
C表示通道,多通道时排列顺序为BGR
C1-灰度图片,单通道
C3-BGR图像,3通道
C4-BGRA图像,4通道
BGR转换成RGB调用cv::cvtColor(cv::Mat src, cv::Mat dst, cv::COLOR_BGR2RGB)

QImage转cv::Mat

cv::Mat QImage2cvMat(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_RGB888: // RR,GG,BB字节顺序存储
        mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
        // opencv需要转为BGR的字节顺序
        cv::cvtColor(mat, mat, cv::COLOR_RGB2BGR);
        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;
    }
    return mat;
}

cv::Mat转QImage

QImage cvMat2QImage(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;
    }
    return image;
}

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龚建波

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值