I have been looking this conversion for a while. What are the ways of converting RGB image to YUV image and accessing Y, U and V channels using Python on Linux? (using opencv, skimage, or etc...)
Update: I used opencv
img_yuv = cv2.cvtColor(image, cv2.COLOR_BGR2YUV)
y, u, v = cv2.split(img_yuv)
cv2.imshow('y', y)
cv2.imshow('u', u)
cv2.imshow('v', v)
cv2.waitKey(0)
and got this result but they are all seems gray. Couldn't get an result represented like on the wikipedia page
Am I doing something wrong?
The relation between data rate and sampling (A:B:C) is defined by the ratio between Y to U and V channel. To convert from RGB to YUV or back, it is simplest to use RGB888 and YUV444. For YUV411, YUV422 and YUV420, the bytes need to be converted to YUV444 first.
YUV color-spaces are a more efficient coding and reduce the bandwidth more than RGB capture can. Most video cards, therefore, render directly using YUV or luminance/chrominance images. The most important component for YUV capture is always the luminance, or Y component.
In YUV, 'Y' represents the brightness, or 'luma' value, and 'UV' represents the color, or 'chroma' values. In contrast, the values of the RGB encoding scheme represent the intensities of red, green and blue channels in each pixel. Each unique Y, U and V value comprises 8 bits, or one byte, of data.
YUV also saves transmission bandwidth compared to RGB, because the chroma channels (B-Y and R-Y) carry only half the resolution of the luma. YUV is not compressed RGB; rather, Y, B-Y and R-Y are the mathematical equivalent of RGB. See color space conversion and YUV/RGB conversion formulas.
NB: The YUV <-> RGB conversions in OpenCV versions prior to 3.2.0 are buggy! For one, in many cases the order of U and V channels was swapped. As far as I can tell, 2.x is still broken as of 2.4.13.2 release.
The reason they appear grayscale is that in split
ting the 3-channel YUV image you created three 1-channel images. Since the data structures that contain the pixels do not store any information about what the values represent, imshow
treats any 1-channel image as grayscale for display. Similarly, it would treat any 3-channel image as BGR.
What you see in the Wikipedia example is a false color rendering of the chrominance channels. In order to achieve this, you need to either apply a pre-defined colormap or use a custom look-up table (LUT). This will map the U and V values to appropriate BGR values which can then be displayed.
As it turns out, the colormaps used for the Wikipedia example are rather simple.
Simple progression between green and blue:
colormap_u = np.array([[[i,255-i,0] for i in range(256)]],dtype=np.uint8)
Simple progression between green and red:
colormap_v = np.array([[[0,255-i,i] for i in range(256)]],dtype=np.uint8)
Now, we can put it all together, to recreate the example:
import cv2
import numpy as np
def make_lut_u():
return np.array([[[i,255-i,0] for i in range(256)]],dtype=np.uint8)
def make_lut_v():
return np.array([[[0,255-i,i] for i in range(256)]],dtype=np.uint8)
img = cv2.imread('shed.png')
img_yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV)
y, u, v = cv2.split(img_yuv)
lut_u, lut_v = make_lut_u(), make_lut_v()
# Convert back to BGR so we can apply the LUT and stack the images
y = cv2.cvtColor(y, cv2.COLOR_GRAY2BGR)
u = cv2.cvtColor(u, cv2.COLOR_GRAY2BGR)
v = cv2.cvtColor(v, cv2.COLOR_GRAY2BGR)
u_mapped = cv2.LUT(u, lut_u)
v_mapped = cv2.LUT(v, lut_v)
result = np.vstack([img, y, u_mapped, v_mapped])
cv2.imwrite('shed_combo.png', result)
Result:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With