thomas thomas - 7 months ago 123
C++ Question

How does OpenCV imread convert between 16 bit and 8 bit

I'm currently dealing with depth images retrieved from a kinect sensor that have been saved as 16 bit grayscale PNG's. At the moment I'm just loading these images using the

function with the
flag and everything works fine. The reason why I'm doing this is because some OpenCV functions rely on the input being 8 bit.

Here is the problem: The next step is to use the depth frames captured by the sensor, which come as 16 bit, directly. I though it would be sufficient to scale and convert the values using
covertTo(dst, CV_8U, 1.0/256.0)
but for some reason the resulting image looks very different from the ones loaded as 8 bit? So, how does OpenCV convert the image when loaded as 8 bit.

Here is the image I used for a test and here is some code that shows the problem:

int main(int argc, char *argv[]){

Mat depth8 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
Mat depth16 = imread(argv[1], CV_LOAD_IMAGE_ANYDEPTH);

depth16.convertTo(depth16, CV_8U, 1.0/256.0);

Mat diff;
absdiff(depth8, depth16, diff);

//imshow("depth8", depth8*255.0/16.0);
//imshow("depth16", depth16*255.0/16.0);
imshow("diff", diff > 0);

return 0;

The output of the code can be found here.

I case you wonder why the test image is so dark, it is because the maximum value for 16 bit is so much larger than the values produced by kinect (up to around 4000).

Another thing: The image loaded as 8 bit seems to be much better than the converted one. If you comment in the two lines you can see what I mean.

So again: How is OpenCV doing its conversion?

Thanks in advance.

  1. the imread function will eventually call imread_(...) in highgui/src/loadsave.cpp.

  2. the correct decoder will be determined in imread_ function and a matrix mat was initialized according to the second parameter in imread().

  3. mat is passed to the readData() method of the decoder. In this case, a png decoder is invoked.

  4. Depending on the depth of mat, png_set_strip_16 in the png decoder (highgui/src/grfmt_png.cpp) might be called.

  5. png_set_strip_16() makes libpng to call png_do_chop() eventually. (It simply discard the low byte. see pngrtran.c in libpng)