我发现了一个非常类似的主题: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的复制。当我简单地返回临时图像时,我会遇到段错误。
那里可以做任何其他优化吗?它经常被使用,所以我希望尽可能快地使用它。
答案 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的精确倍数