【问题标题】:cv::Mat to QImage conversioncv::Mat 到 QImage 的转换
【发布时间】:2012-06-16 10:42:41
【问题描述】:

我找到了非常相似的主题:how to convert an opencv cv::Mat to qimage,但它并没有解决我的问题。

我有将 cv::Mat 转换为 QImage 的函数

QImage cvMatToQImg(cv::Mat& mat)
{
    cv::Mat rgb;
    if(mat.channels()==1)
    {
        cv::cvtColor(mat,rgb,CV_GRAY2BGR);
        cv::cvtColor(rgb,rgb,CV_BGR2BGRA);
        QImage temp = QImage((unsigned char*)(rgb.data), rgb.cols, 
                              rgb.rows,QImage::Format_ARGB32 );

        QImage returnImage = temp.copy();
        return returnImage;
}

它对我有用,但我想让它更有效率。 第一:为什么要更改 2 个 cvtColor 函数:

cv::cvtColor(mat,rgb,CV_GRAY2BGRA)

失败

QImage returnImage = temp.copy() 

有段错误。

那么如何消除QImage的复制。当我简单地返回临时图像时,我遇到了段错误。

那里可以进行任何其他优化吗?这是非常常用的功能,所以我想尽可能快。

【问题讨论】:

  • 你没有指定mat的图片格式,还是24bit灰度图吗?
  • 我主要使用 8 位灰度。但功能处理的案例越多越好。
  • 无需复制。 QImage 是共享指针。 Segfauld 不是由于不复制,而是似乎是由于不正确的对齐。 QImage 有类似的构造函数,每行指定额外的字节 - 使用它。 P.S:通过谷歌搜索找到:code.google.com/p/qt-opencv-multithreaded/source/browse/trunk/…

标签: qt opencv


【解决方案1】:

您对该问题的解决方案效率不高,特别是它的效率低于我在您链接到的另一个问题上发布的代码。

您的问题是您必须从灰度转换为彩色或 RGBA。一旦您需要此对话,自然就需要数据副本。

我的解决方案同时进行灰度和颜色之间的转换,以及 cv::Mat 和 QImage 之间的转换。这就是为什么它是您可以获得的最高效的。

在您的解决方案中,您首先尝试转换,然后想要直接围绕 OpenCV 数据构建 QImage 以节省第二个副本。但是,您指向的数据是临时的。一旦你离开这个函数,cv::Mat 就会释放它的相关内存,这就是为什么它在 QImage 中也不再有效的原因。您可以事先手动增加 cv::Mat 的引用计数器,但这为之后的内存泄漏打开了大门。

最后,你尝试用肮脏的解决方案来解决问题,以干净的方式更好地解决。

【讨论】:

    【解决方案2】:

    推出自己的解决方案可能是最简单的。下面是从灰色到 RGBA 格式的当前 OpenCV 实现:

    template<typename _Tp>
    struct Gray2RGB
    {
        typedef _Tp channel_type;
    
        Gray2RGB(int _dstcn) : dstcn(_dstcn) {}
        void operator()(const _Tp* src, _Tp* dst, int n) const
        {
            if( dstcn == 3 )
                for( int i = 0; i < n; i++, dst += 3 )
                {
                    dst[0] = dst[1] = dst[2] = src[i];
                }
            else
            {
                _Tp alpha = ColorChannel<_Tp>::max();
                for( int i = 0; i < n; i++, dst += 4 )
                {
                    dst[0] = dst[1] = dst[2] = src[i];
                    dst[3] = alpha;
                }
            }
        }
    
        int dstcn;
    };
    

    这里是实际的cvtColor 调用发生的地方:

        case CV_GRAY2BGR: case CV_GRAY2BGRA:
            if( dcn <= 0 ) dcn = 3;
            CV_Assert( scn == 1 && (dcn == 3 || dcn == 4));
            _dst.create(sz, CV_MAKETYPE(depth, dcn));
            dst = _dst.getMat();
    
            if( depth == CV_8U )
                CvtColorLoop(src, dst, Gray2RGB<uchar>(dcn));
    

    此代码包含在imgproc 库中的color.cpp 文件中。

    如您所见,由于您没有在cvtColor 调用中设置dstCn 参数,因此它默认为dcn = 3。要直接从灰色到 BGRA,请将 dstCn 设置为 4。由于 OpenCV 的默认颜色顺序是 BGR,您仍然需要交换颜色通道才能使其看起来正确(假设您从 OpenCV 函数获取图像数据) .因此,可能值得按照上面的示例实现您自己的转换器,或者使用ypnos 答案here

    另外,看看我的另一个 answer 涉及如何将 OpenCV 与 Qt 集成。

    【讨论】:

      【解决方案3】:

      问题在于 cv::Mat 和 QImage 数据不一定是连续的。 opencv 中的新数据行从 32 位边界开始(不确定 QImage - 我认为它取决于系统)所以你不能复制内存块,除非你的行恰好是 4 字节的倍数

      How to output this 24 bit image in Qt

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-12
        相关资源
        最近更新 更多