【OpenCV】 代码实现:Mat 转为 Qt5 QImage

本文介绍了一种在Qt5.11.1和OpenCV3.4.2环境下将OpenCV的Mat对象转换为Qt QImage的方法。针对不同类型的图像数据(如灰度图、RGB三通道图和RGBA四通道图),提供了详细的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在Qt 5.11.1 + OpenCV 3.4.2 + macOS 10.13.6 环境下通过运行。 

QImage ChildWin::cvMat2QImage(const cv::Mat& mat)
{
    // 8-bits unsigned, NO. OF CHANNELS = 1
    if(mat.type() == CV_8UC1)
    {
        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
        // Set the color table (used to translate colour indexes to qRgb values)
        image.setColorCount(256);
        for(int i = 0; i < 256; i++)
        {
            image.setColor(i, qRgb(i, i, i));
        }
        // Copy input Mat
        uchar *pSrc = mat.data;
        for(int row = 0; row < mat.rows; row ++)
        {
            uchar *pDest = image.scanLine(row);
            memcpy(pDest, pSrc, mat.cols);
            pSrc += mat.step;
        }
        return image;
    }
    // 8-bits unsigned, NO. OF CHANNELS = 3
    else if(mat.type() == CV_8UC3)
    {
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    }
    else if(mat.type() == CV_8UC4)
    {
        // Copy input Mat
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        return image.copy();
    }
    else
    {
        return QImage();
    }
}

 

<think>我们正在处理一个关于OpenCV的cv::Mat转换QtQImage的问题。根据要求,我们需要使用中文回答,并且注意LaTeX格式(行内公式用$...$,独立公式用$$...$$)。同时,我们需要在回答末尾生成相关问题。 首先,我们需要了解转换的关键点: 1. 颜色空间转换OpenCV默认使用BGR颜色顺序,而Qt使用RGB。因此,在转换时通常需要交换红蓝通道。 2. 数据格式:cv::Mat的数据布局需要与QImage兼容。QImage支持多种格式,如Format_RGB888, Format_ARGB32等。 3. 深度和通道:根据源cv::Mat的通道数和深度(如8位、16位等)选择正确的QImage格式。 常见的转换方法有两种: 方法一:使用cv::cvtColor进行颜色转换,然后创建QImage。这种方法适用于需要颜色空间转换的情况。 方法二:直接创建QImage,并在构造时指定格式,同时手动交换红蓝通道(如果必要)。 下面我们给出一个典型的转换函数(针对8位3通道BGR图像): ```cpp #include <opencv2/opencv.hpp> #include <QImage> QImage cvMatToQImage(const cv::Mat &inMat) { switch (inMat.type()) { // 8位3通道 case CV_8UC3: { // 创建QImage,数据由cv::Mat提供,注意QImage不会复制数据,因此cv::Mat的生命期需长于QImage QImage image(inMat.data, inMat.cols, inMat.rows, static_cast<int>(inMat.step), QImage::Format_RGB888); // OpenCV是BGR,Qt需要RGB,因此交换红蓝通道 return image.rgbSwapped(); } // 8位1通道(灰度图) case CV_8UC1: { // 灰度图可以直接用Format_Grayscale8(需要Qt5.5以上),或者转换为RGB三通道 QImage image(inMat.data, inMat.cols, inMat.rows, static_cast<int>(inMat.step), QImage::Format_Grayscale8); return image; } // 其他格式可以继续添加 default: qWarning() << "cvMatToQImage() - cv::Mat image type not handled:" << inMat.type(); break; } return QImage(); } ``` 注意:上述代码中,我们使用了`rgbSwapped()`来交换红蓝通道。对于灰度图像,我们直接使用Format_Grayscale8格式(需要Qt5.5及以上版本)。如果使用的是较旧的Qt版本,可以将灰度图像转换为三通道(RGB)图像。 另外,需要注意的是,QImage对象不会复制数据,而是直接使用cv::Mat的数据缓冲区。因此,要确保在QImage使用期间,cv::Mat对象不会被销毁或修改。如果需要在QImage使用后仍保留图像数据,应该使用`copy()`函数来创建深拷贝。 如果需要深拷贝,可以这样: ```cpp QImage image_copy = cvMatToQImage(inMat).copy(); ``` 对于32位浮点图像等,需要先进行类型转换(例如转换为8位)再进行转换。 此外,如果图像是ARGB格式(带有Alpha通道),则需要注意处理四通道的情况。 下面是一个处理4通道图像(例如带透明度的BGRA)的例子: ```cpp case CV_8UC4: { // OpenCV的4通道是BGRA,而Qt的Format_ARGB32是ARGB,所以需要重新排列通道 cv::Mat argbMat; cv::cvtColor(inMat, argbMat, cv::COLOR_BGRA2RGBA); // 将BGRA转换为RGBA(注意:RGBA在内存中的布局与Format_ARGB32不同) // 但是QImage的Format_ARGB32_Premultiplied或Format_ARGB32是BGRA布局?实际上,Format_ARGB32是存储为0xAARRGGBB,但内存布局是BGRA? // 实际上,QImage的Format_ARGB32在内存中的布局是:BGRA(小端序),即第一个字节是B,第二个是G,第三个是R,第四个是A。 // 而OpenCV的BGRA图像在内存中的布局也是:B,G,R,A。所以实际上可以直接使用Format_ARGB32,但要注意字节序。 // 因此,我们可以直接构造QImage,然后调整通道顺序?或者使用cvtColor转换到RGBA,然后使用Format_RGBA8888(Qt5.2以上支持)? // 在Qt5.2以上,可以使用Format_RGBA8888,这样就是RGBA顺序,那么我们就需要将BGRA转换为RGBA。 // 这里我们使用Format_ARGB32,但注意ARGB32的存储格式是0xAARRGGBB,所以需要重新排列通道顺序,但内存布局并不是简单的排列。 // 实际上,更简单的方法是:使用Format_ARGB32,然后交换红蓝通道?但是这样并不能正确得到ARGB格式。 // 推荐:使用Format_RGBA8888(Qt5.2以上)并且将BGRA转换为RGBA(即交换红蓝通道) cv::cvtColor(inMat, argbMat, cv::COLOR_BGRA2RGBA); return QImage(argbMat.data, argbMat.cols, argbMat.rows, static_cast<int>(argbMat.step), QImage::Format_RGBA8888); } ``` 但是,请注意,不同版本的Qt支持的图像格式可能不同,因此需要根据实际情况调整。 另外,我们也可以使用另一种方法,即直接使用`memcpy`并重新排列通道,但这样效率较低。 总结:转换的关键在于匹配颜色通道顺序和图像格式。 最后,我们生成相关问题: §§相关问题§§ 1. 如何将QImage转换回cv::Mat? 2. 在转换过程中如何处理深拷贝和浅拷贝的问题? 3. 如何处理16位深度图像(如CV_16UC1)的转换? 4. 在Qt中显示OpenCV图像时,如何保证图像不出现失真或颜色错误?</think>### OpenCV cv::Mat Qt QImage 方法 在计算机视觉应用中,OpenCV 的 `cv::Mat` 与 Qt 的 `QImage` 转换是常见需求。以下是核心转换方法及注意事项: #### 1. **基础转换方法(8位3通道BGR图像)** ```cpp #include <opencv2/opencv.hpp> #include <QImage> QImage matToQImage(const cv::Mat& mat) { if (mat.type() == CV_8UC3) { // 创建临时图像并转换BGR->RGB cv::Mat rgbMat; cv::cvtColor(mat, rgbMat, cv::COLOR_BGR2RGB); // 创建QImage(不复制数据) return QImage( rgbMat.data, rgbMat.cols, rgbMat.rows, rgbMat.step, QImage::Format_RGB888 ); } return QImage(); // 返回空图像 } ``` #### 2. **关键注意事项** - **颜色空间转换**:OpenCV 默认使用 $BGR$ 顺序,Qt 使用 $RGB$,必须通过 `cv::cvtColor()` 转换[^1]。 - **内存管理**: - 默认创建**浅拷贝**(共享数据),需确保原 `cv::Mat` 生命周期覆盖 `QImage` 使用期 - 深拷贝方法: ```cpp QImage deepCopy = matToQImage(mat).copy(); ``` - **格式兼容性**: | `cv::Mat` 类型 | Qt 图像格式 | 处理方式 | |----------------------|--------------------------|------------------------------| | `CV_8UC3` (BGR) | `QImage::Format_RGB888` | 需BGR→RGB转换 | | `CV_8UC1` (灰度) | `QImage::Format_Grayscale8` | 直接转换 (Qt5.5+) | | `CV_8UC4` (BGRA) | `QImage::Format_ARGB32` | 需通道重组或RGBA8888转换 | | `CV_16UC1` (16位灰度)| 无直接支持 | 需缩放至8位或自定义处理 | #### 3. **多格式扩展实现** ```cpp QImage matToQImageEx(const cv::Mat& mat) { switch (mat.type()) { case CV_8UC3: { cv::Mat rgb; cv::cvtColor(mat, rgb, cv::COLOR_BGR2RGB); return QImage(rgb.data, rgb.cols, rgb.rows, rgb.step, QImage::Format_RGB888); } case CV_8UC1: return QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8); case CV_8UC4: { cv::Mat rgba; cv::cvtColor(mat, rgba, cv::COLOR_BGRA2RGBA); return QImage(rgba.data, rgba.cols, rgba.rows, rgba.step, QImage::Format_RGBA8888); } default: // 处理非常规格式 (如转换为8UC3) cv::Mat tmp; mat.convertTo(tmp, CV_8UC3, 255.0); return matToQImageEx(tmp); } } ``` #### 4. **转换原理** 转换核心是数据指针传递: $$ \text{QImage} \leftarrow \text{(data\_ptr, width, height, bytes\_per\_line, format)} $$ 其中 `bytes_per_line` 对应 `cv::Mat::step`,需确保内存对齐一致[^2]。 #### 5. **典型应用场景** ```cpp // 在Qt Widget中显示OpenCV图像 void showImage(const cv::Mat& mat) { QImage qimg = matToQImage(mat); QPixmap pix = QPixmap::fromImage(qimg); label->setPixmap(pix.scaled(label->size(), Qt::KeepAspectRatio)); } ``` > **警告**:若原始 `cv::Mat` 在 `QImage` 使用前被释放,会导致野指针访问。对异步操作或长期保存的图像,务必使用深拷贝。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值