CV2 not displaying colors when converting to uint8

Viewed 1008

I have a python list that contains the RGBA data of a PNG image represented as int32, which was sent over from a Java socket server.

A sample output of this data as a numpy array without any conversions:

[[-12763847 -12763847 -12763847 ...  -5590160 -12039396 -12434915]
 [-12763847 -12763847 -12763847 ...  -6643102 -12828909 -12830184]
 [-12763847 -12763847 -12763847 ...  -8419763 -13487094 -12435167]]

CV2, of course, accepts uint8 as the data type (displaying as int32 shows a black screen), so I convert my list to a numpy array with dtype = np.uint8 with the following:

image_data = np.array(data_list, dtype = np.uint8)

A sample output of this:

[[ 57  57  57 ... 112  28  29]
 [ 57  57  57 ...  98  19  24]
 [ 57  57  57 ...  77  10  33]]

However, when I display the image using

cv2.imshow("Image", image_data)

I get a window showing the image, but in grayscale; it lacks colors.

How do I prevent the colors from being ignored?

2 Answers

For outputting color image with cv2 you need to image to be of shape (x,y,3), the last axis being the colors.

As your data is int32 representation of RGBA, I assume each number actually hold 4 different numbers, where the first 2 bytes are the uint8 of red, the second green, third blue and last alpha: (0000 0001, 0000 0010, 0000 0100,0000 1000) in this example r is 1, g is 2, b is 4 and alpha is 8.
You will need to extract this 8 bytes into the separate colors.

In addition, keep in mind that cv2 color space is BGR and not RGB, so you will have to switch channels after converting.

Hopefully this will help you see how to extract the Red, Green and Blue channels from the 32-bit values. I started off with the first row of your array.

im=np.array([-12763847,-12763847,-12763847,-5590160,-12039396,-12434915],dtype=np.int32)

R = ((im & 0xff).astype(np.uint8)
# array([ 57,  57,  57, 112,  28,  29], dtype=uint8)

G = ((im>>8) & 0xff).astype(np.uint8)
# array([ 61,  61,  61, 179,  75,  66], dtype=uint8)

B = ((im>>16) & 0xff).astype(np.uint8)
# array([ 61,  61,  61, 170,  72,  66], dtype=uint8)

If those values look correct, you should be able to merge them into a colour image with:

img = cv2.merge((B,G,R))

bearing in mind that OpenCV uses BGR channel ordering rather than the more conventional RGB.


The ordering of the bytes in your 32-bit number may be different from what I am guessing above. The easiest way to test is to put a red card in front of your camera, and see what comes through, then a green card, then a blue one. The four channels (R,G,B,A) should be given by the following but which is which may be a matter for experiment:

(im    ) & 0xff
(im>>8 ) & 0xff
(im>>16) & 0xff
(im>>24) & 0xff
Related