Reputation: 40909
I have an 8-bit .gif
image that I'm able to read into a Numpy array of dtype uint8
. However, when I try to convert the dtype to a larger type of integer, such as uint32
and uint64
, for use in OpenCV, I get weird errors.
I'm using Google Colab and am running Python 3.6.
I downloaded this 8-bit color gif image:
!wget https://www.cosy.sbg.ac.at/~pmeerw/Watermarking/lena_color.gif
And here's my code below where I try to convert the image to each of [ np.uint8, np.uint16, np.uint32, np.uint64 ]
and then draw a rectangle.
import numpy as np
import cv2
import matplotlib
print(np.__version__) # 1.19.5
print(cv2.__version__) # 4.1.2
print(matplotlib.__version__) # 3.2.2
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
img_orig = mpimg.imread('lena_color.gif')
print('img_orig dtype: %s' % img_orig.dtype) # img_orig dtype: uint8
# Coordinates for rectangle to be drawn.
TL = (100, 100)
BR = (400, 400)
# Convert to different integer dtypes.
dtypes = [ np.uint8, np.uint16, np.uint32, np.uint64 ]
for dtype in dtypes:
print('Changing type to %s' % (dtype.__name__))
img = img_orig.astype(dtype)
try:
cv2.rectangle(img, TL, BR, (0, 0, 255), 2)
_ = plt.imshow(img)
_ = plt.show()
except Exception as ex:
print(ex)
I get the following results:
Changing type to uint8
Changing type to uint16
Changing type to uint32
an integer is required (got type tuple)
Changing type to uint64
Specific questions:
Why do I get an exception when I change the dtype to uint32
?
I drew the rectangle with blue (0, 0, 255)
. Why is the rectangle coming out as kind of white-purple?
Why does the rectangle not appear when the dtype is uint64
?
Upvotes: 0
Views: 3853
Reputation: 5805
There are a couple of things that are happening here. First, you are using OpenCV
and matplotlib
. These are different imaging libraries that are not 100% compatible among themselves. OpenCV
uses BGR
color channel ordering while matplotlib
uses RGB
. If you process the image using a function from OpenCV
(such as cv2.rectangle
) expect to operate on reversed channels, if you loaded or are showing the image with matplotlib
.
Now, for your first question. Image types are normally encoded using 8 unsigned bits per channel. That is 8 x 3
bits for a BGR
(or RGB
) image, although you can also have 8 x 1
bits for greyscale images, or 8 x 4 bits for a BGRA
(the last channel being the Alpha channel - the transparency channel. Every type outside of those cases could be unsupported for a set of functions. In the case of OpenCV
, cv2.rectangle
does not support arrays of the type uint32
nor uint64
. In fact, I get an exception using BOTH formats.
Now, the rectangle. You draw the rectangle using OpenCV
and show it using matplotlib
, so expect the color you set on the rectangle function to not match what you see on the screen. This image file, in particular, is a .gif
with an extra transparency channel, making it a RGBA
(4 channels) image. You are setting the color with three parameters, however, cv2.rectangle
only appears to be affecting the alpha channel, setting it to 255
. The solution is to convert the RGBA
image to an RGB
image using cv2.cvtColor
:
# Include this line just before drawing the rectangle:
# Conversion from RGBA to RGB:
img = cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
So you will see the correct result on screen:
Advices:
If you are going to use multiple imaging libraries be aware of their differences and possible compatibility issues
Operate and show BGR
or RGB
images only, other types are usually mid-operation temporal results
If processing .gif
s, check out how many channels they are using. Images (at least as OpenCV
requires them) are represented as numpy
arrays. You can check the dimensions of a numpy
array using shape
Like this:
(height, width, channels) = img.shape
print((height, width, channels))
For the Lena image, this returns:
(512, 512, 4)
Upvotes: 1
Reputation: 54698
Your image has an alpha channel. That means each pixel has 4 components (R,G,B,A), not just three. You should print the image arrays to see what they contain. When you specify (0,0,255), it defaults to 0 for the alpha. That means you're seeing the background show through. The rectangle will be whatever color the background window was at that point. If you specify (0,0,255,255), you will see the blue you expect.
Also note that it really serves no purpose to change the datatype of the numpy arrays. The components are taken as values from 0 to 255, regardless of the datatype of the components.
Upvotes: 1