Cv :: Convert Mat to QImage

I found a very similar topic: how to convert opencv cv :: Mat to qimage , but this does not solve my problem.

I have a function to convert cv :: Mat to 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; } 

And it works for me, but I want to make it more efficient. First: why change 2 cvtColor functions with:

 cv::cvtColor(mat,rgb,CV_GRAY2BGRA) 

does not work

 QImage returnImage = temp.copy() 

with segfault.

Then how to eliminate copying QImage. When I just return the temp image, I get segfault.

Can any other optimizations be made there? This feature is used very often, so I want to do it as quickly as possible.

+4
source share
3 answers

Your solution to the problem is inefficient, in particular, it is less efficient than the code that I posted on another issue that you are referring to.

Your problem is that you need to convert from shades of gray to color or RGBA. As soon as you need this conversation, naturally, you need a copy of the data.

My solution is doing the conversion between grayscale and color, as well as between cv :: Mat and QImage at the same time. That is why it is most effective you can get.

In your solution, you will first try to convert, and then want to build a QImage based on OpenCV data to save a second copy. But the data you point to is temporary. As soon as you leave the function, cv :: Mat will free the memory associated with it, and therefore it is also invalid in QImage. You can manually increase the cv :: Mat reference counter manually, but after that the door will open for a memory leak.

In the end, you are trying to solve a dirty solution to a problem that will be solved in a clean way.

+4
source

It might be easiest to roll your own solution. Below is the current OpenCV implementation for moving from gray to RGBA:

 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; }; 

This is where the actual cvtColor call comes in:

  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)); 

This code is contained in the color.cpp file in the imgproc library.

As you can see, since you are not setting the dstCn parameter in your cvtColor calls, it defaults to dcn = 3 . To switch from gray to BGRA, set dstCn to 4. Since the default color order of OpenCV is BGR, you still need to change the color channels so that it looks right (provided that you get image data from the OpenCV function), Thus it may be appropriate to implement your own converter, perhaps by following the example above or using ypnos answer here .

Also, look at my other answer that describes how to integrate OpenCV with Qt.

+3
source

The problem is that the cv :: Mat and QImage data need not be contiguous. New lines of data in opencv start with a 32-bit boundary (not sure about QImage - I think it depends on the system), so you cannot copy the memeory block unless your lines are an exact multiple of 4 bytes

See How to output this 24-bit image in Qt

+1
source

All Articles