25
votes

I have an unsigned char* buffer containing data of a jpeg image. I would like to display that image using c++ and opencv. If i do:

Mat img(Size(640, 480), CV_8UC3, data);
namedWindow("image", 1);
imShow("image", img);

I get a noisy mess of pixels.

I suppose it's because the data is jpeg (with a header). Because this works:

Mat imgbuf(Size(640, 480), CV_8UC3, data);
Mat img = imdecode(imgbuf, CV_LOAD_IMAGE_COLOR);

BUT I cannot use the imdecode function as it is from highgui.h which is based upon GTK 2, and in my project I use GTK 3.

So, how can I display the buffer data? Is there a way to decode the jpeg image other than imdecode in opencv, if that's the problem. I don't really want to have to rebuild opencv with Qt...

Any other suggestions?

(Using Linux)

2
Can't you use libjpeg for decoding and be done with it ? What is the problem with that ? - mmgp
@mmgp I will try libjpeg, just thought I could do the same thing without including another library. - Matekk
opencv won't load jpeg image if you don't have libjpeg, so there is no other library being included. - mmgp
Wow what you are doing is really not okay. In your Mat imgbuf(...) line you read in data in 640x480x3 fields. Since jpegs are compressed, the jpeg will indeed fit in there with ease. So the rest of the spots are then filled in with random data from memory, that's very, very bad. After that you load in the Mat, that includes the JPEG and a bunch of random memory data, and decode it. Instead, first put your unsigned char buffer in a vector or mat exactly the size of your buffer and THEN feed it in imdecode. - TimZaman

2 Answers

53
votes

I have seen many responses to this question around on the net saying that you should call libjpeg directly and bypass OpenCV's imread() routine.

This is NOT necessary! You can use imdecode() to decode a raw image buffer from memory. The way to do it is NOT intuitive, and isn't documented enough to help people trying to do this for the first time.

If you have a pointer/size for your raw file data (fread() directly from the .jpg, .png, .tif, files, etc...

int    nSize = ...       // Size of buffer
uchar* pcBuffer = ...    // Raw buffer data


// Create a Size(1, nSize) Mat object of 8-bit, single-byte elements
Mat rawData( 1, nSize, CV_8UC1, (void*)pcBuffer );

Mat decodedImage  =  imdecode( rawData /*, flags */ );
if ( decodedImage.data == NULL )   
{
    // Error reading raw image data
}

That's IT!

Hope this helps someone in the future.

4
votes

I have decompressed the JPEG image using libjpeg using the standard procedure described in the libjpeg API documentation under 'Decompression details'.

After having decompressed the data you can use it to construct the cv::Mat. Mind you, the decompressed image is in RGB format, whereas openCV uses a BGR format so a cvtColor() operation with format CV_RGB2BGR is needed.