cv :: Mat to QImage转换

时间:2012-06-13 13:06:25

标签: qt opencv

我发现了一个非常类似的主题: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() 

使用segfault。

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

那里可以做任何其他优化吗?它经常被使用,所以我希望尽可能快地使用它。

3 个答案:

答案 0 :(得分: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));

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

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

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

答案 1 :(得分:4)

您解决问题的方法效率不高,尤其是我在您链接到的其他问题上发布的代码效率较低。

您的问题是您必须从灰度转换为彩色或RGBA。只要您需要此对话,就需要自然地复制数据。

我的解决方案在灰度和颜色之间进行转换,同时在cv :: Mat和QImage之间进行转换。这就是为什么它是最有效的原因。

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

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

答案 2 :(得分:1)

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

请参阅How to output this 24 bit image in Qt