5

我发现了非常相似的主题:如何将 opencv cv::Mat 转换为 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的复制。当我简单地返回临时图像时,我遇到了段错误。

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

4

3 回答 3

4

推出自己的解决方案可能是最容易的。下面是从灰色到 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));

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

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

另外,请查看我的其他答案,其中涉及如何将 OpenCV 与 Qt 集成。

于 2012-06-13T15:22:50.583 回答
4

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

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

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

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

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

于 2012-06-13T16:08:30.610 回答
1

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

请参阅如何在 Qt 中输出此 24 位图像

于 2012-06-13T15:51:19.863 回答