Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PIL Image Convert from RGB to YCbCr Results in 4 Channels Instead of 3 and Behaves Like RGB

Well, the title is pretty self explanatory. I have an image file that I want to separate into Y, Cb and Cr respectively. After opening the file, convert it from RGB (which is the default mode when opening an image file) into YCbCr and then turn it into an array using numpy.array(), it resulted in a 2D array with 4 channels, which is not I expected as according to the documentation in http://www.nmt.edu/tcc/help/pubs/pil/pil.pdf

Here is what I do in the interpreter:

ImageFile = Image.open('filePath', 'r')
ImageFile = ImageFile.convert('YCbCr')
ImageFileYCbCr = numpy.array(ImageFile)
ImageFileYCbCr

resulted in

array([[[103, 140, 133,  95],
    [140, 133,  91, 141],
    [132,  88, 141, 131],
    ..., 
    [129,  65, 146, 129],
    [ 64, 146, 130,  65],
    [146, 129,  64, 147]],

   [[129,  64, 147, 129],
    [ 62, 149, 130,  62],
    [149, 130,  62, 149],
    ..., 

And when I separate it into its channels

ImageFileY = copy.deepcopy(ImageFileYCbCr) # to make a separate copy as array is immutable
ImageFileY[:,:,1] *= 0
ImageFileY[:,:,2] *= 0
ImageFileY[:,:,3] *= 0
ImageFileYOnly = Image.fromarray(ImageFileY)
ImageFileYOnly.show()

It resulted in a red color channel as if it is an RGB. Ho can I get the Y, Cb, Cr values respectively?

EDIT: Numpy version 1.3, Python 2.6 Linux Backtrack 5

like image 718
絢瀬絵里 Avatar asked Jul 07 '14 12:07

絢瀬絵里


People also ask

Why RGB is converted to YCbCr?

Image and Video consumes a lot of data. One of the reasons is because they are represented in the RGB format. However, is not worth to store or transmit information in this color space representaion, once it has a large bandwidth. Thus all the pixels should be converted to YCbCr to accomplish that.


2 Answers

https://mail.python.org/pipermail/image-sig/2010-October/006526.html

It's an old bug with Numpy. To correct it

>>> import numpy
>>> import Image as im
>>> image = im.open('bush640x360.png')
>>> ycbcr = image.convert('YCbCr')

>>> B = numpy.ndarray((image.size[1], image.size[0], 3), 'u1', ycbcr.tostring())
>>> print B.shape
(360, 640, 3)
>>> im.fromarray(B[:,:,0], "L").show()
like image 79
絢瀬絵里 Avatar answered Oct 12 '22 03:10

絢瀬絵里


FYI, for future people coming from Google:

This seems to work now.

For reference, I have Pillow 6.1.0 and numpy 1.17.0. Doing

img = np.array(Image.open(p).convert('YCbCr'))

gives the same as

img = Image.open(p).convert('YCbCr')
img = np.ndarray((img.size[1], img.size[0], 3), 'u1', img.tobytes())

and is not the same as RGB.

like image 23
fabian789 Avatar answered Oct 12 '22 01:10

fabian789