What is the fastest method to convert IplImage IPL_DEPTH_32S to QImage Format_RGB32?
I need to catch pictures from cam and show it on form with frequency 30 frames in second. I tried to use QImage constructor:
QImage qImage((uchar *) image->imageData, image->width, image->height, QImage::Format_RGB32);
but image was corrupted after this. So, how can I do this fast (I think putting pixel by pixel into QImage is not a good decision)?
Before I start, OpenCV uses the BGR format by default. Not RGB! So before creating the QImage
you need to convert your IplImage
to RGB with:
cvtColor(image, image, CV_BGR2RGB);
Then you can:
QImage qImage((uchar*) image->imageData, image->width, image->height, QImage::Format_RGB32);
Note that the constructor above doesn't copy the data as you might be thinking, as the docs states:
The buffer must remain valid throughout the life of the QImage
So if you are having performance issues are not because of the conversion procedure. It is most probably caused by the drawing method you are using (which wasn't shared in the question). To summarize a lot of blah blah blah, you should render the QImage
to an OpenGL texture and let the video card do all the drawing for you.
Your question is a bit misleading because your primary objective is not to find the fastest conversion method, but one that actually works since yours don't.
Another important thing to keep in mind, when you said:
image was corrupted after this
you must know that this is completely vague, and it doesn't help us at all because there is a number of causes for this effect, and without the source code is impossible to tell with certainty what are you doing wrong. Sharing the original and the corrupted image might gives some clues to where the problem is.
That's it for now. Good luck.
IPL_DEPTH_32S
is greyscale with a 32bit pixel - normally used for depth data rather than an actual 'image', if you are packign a colour image into check what the pixel ordering is.
QImage::Format_ARGB32_Premultiplied
is the fastest QImage format because its what the graphics card uses - note that the data order is actually BGRA and the A channel must be at least as large as the pixel, ie 255 if you don't want to use alpha.
There is a RGB2BGRA and BGR2RGBA in cv::cvtColor()
Time ago I found some examples in the internet of how to do that. I improved the examples a bit for how to copy the images in a more easy way. Qt works normally only with char pixels (other image formats are normally called HDR images). I was wondering how you get a video buffer of 32 bit rgb in opencv... I have never seen that !
If you have a color image in opencv you could use this function to allocate memory:
QImage* allocateqtimagefromcv(IplImage* cvimg)
{
//if (cvimg->nChannels==1)
// {
// return new QImage(cvimg->width,cvimg->height,QImage::Format_Indexed8);
// }
if (cvimg)
{
return new QImage(cvimg->width,cvimg->height,QImage::Format_ARGB32);
}
}
to just copy the IplImage to the qt image you could go the easy way and use this function:
void IplImage2QImage(IplImage *iplImg,QImage* qimg)
{
char *data = iplImg->imageData;
int channels = iplImg->nChannels;
int h = iplImg->height;
int w = iplImg->width;
for (int y = 0; y < h; y++, data += iplImg->widthStep)
{
for (int x = 0; x < w; x++)
{
char r, g, b, a = 0;
if (channels == 1)
{
r = data[x * channels];
g = data[x * channels];
b = data[x * channels];
}
else if (channels == 3)
{
r = data[x * channels + 2];
g = data[x * channels + 1];
b = data[x * channels];
}
if (channels == 4)
{
a = data[x * channels + 3];
qimg->setPixel(x, y, qRgba(r, g, b, a));
}
}
}
}
the following function could be a quicker solution:
static QImage IplImage2QImage(const IplImage *iplImage)
{
int height = iplImage->height;
int width = iplImage->width;
if (iplImage->depth == IPL_DEPTH_8U && iplImage->nChannels == 3)
{
const uchar *qImageBuffer =(const uchar*)iplImage->imageData;
QImage img(qImageBuffer, width, height, QImage::Format_RGB888);
return img.rgbSwapped();
}else{
//qWarning() << "Image cannot be converted.";
return QImage();
}
}
hope my function helped. Maybe someone know better ways of doing that :)