Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using PIL and NumPy to convert an image to Lab array, modify the values and then convert back

I am trying to convert a PIL image into an array using NumPy. I then want to convert that array into Lab values, modify the values and then convert the array back in to an image and save the image. I have the following code:

import Image, color, numpy

# Open the image file
src = Image.open("face-him.jpg")

# Attempt to ensure image is RGB
src = src.convert(mode="RGB")

# Create array of image using numpy
srcArray = numpy.asarray(src)

# Convert array from RGB into Lab
srcArray = color.rgb2lab(srcArray)

# Modify array here

# Convert array back into Lab
end = color.lab2rgb(srcArray)

# Create image from array
final = Image.fromarray(end, "RGB")

# Save
final.save("out.jpg")

This code is dependent on PIL, NumPy and color. color can be found in the SciPy trunk here. I downloaded the color.py file along with certain colordata .txt files. I modified the color.py so that it can run independently from the SciPy source and it all seems to work fine - values in the array are changed when I run conversions.

My problem is that when I run the above code which simply converts an image to Lab, then back to RGB and saves it I get the following image back:

alt text

What is going wrong? Is it the fact I am using the functions from color.py?

For reference:
Source Image - face-him.jpg
All source files required to test - colour-test.zip

like image 497
betamax Avatar asked Jul 12 '10 12:07

betamax


People also ask

How do I load an image into a NumPy array?

imread() function is used to load the image and It also reads the given image (PIL image) in the NumPy array format. Then we need to convert the image color from BGR to RGB. imwrite() is used to save the image in the file.

Why do we convert image to NumPy array?

Converting an image to an array is an important task to train a machine learning model based on the features of an image. We mainly use the NumPy library in Python to work with arrays so we can also use it to convert images to an array. Other than NumPy, we can also use the Keras library in Python for the same task.

Which function is used to read and image from a file into an array?

Read an image from a file into an array. Use plt. imread() method.

What is the meaning of image in PIL convert (' L ')?

The Image module provides a class with the same name which is used to represent a PIL image. The module also provides a number of factory functions, including functions to load images from files, and to create new images. Image. convert() Returns a converted copy of this image.


2 Answers

Without having tried it, scaling errors are common in converting colors:
RGB is bytes 0 .. 255, e.g. yellow [255,255,0], whereas rgb2xyz() etc. work on triples of floats, yellow [1.,1.,0].
(color.py has no range checks: lab2rgb( rgb2lab([255,255,0]) ) is junk.)

In IPython, %run main.py, then print corners of srcArray and end ?

Added 13July: for the record / for google, here are NumPy idioms to pack, unpack and convert RGB image arrays:

    # unpack image array, 10 x 5 x 3 -> r g b --
img = np.arange( 10*5*3 ).reshape(( 10,5,3 ))
print "img.shape:", img.shape
r,g,b = img.transpose( 2,0,1 )  # 3 10 5
print "r.shape:", r.shape

    # pack 10 x 5 r g b -> 10 x 5 x 3 again --
rgb = np.array(( r, g, b )).transpose( 1,2,0 )  # 10 5 3 again
print "rgb.shape:", rgb.shape
assert (rgb == img).all()

    # rgb 0 .. 255 <-> float 0 .. 1 --
imgfloat = img.astype(np.float32) / 255.
img8 = (imgfloat * 255).round().astype(np.uint8)  
assert (img == img8).all()
like image 159
denis Avatar answered Sep 25 '22 01:09

denis


As Denis pointed out, there are no range checks in lab2rgb or rgb2lab, and rgb2lab appears to expect values in the range [0,1].

>>> a = numpy.array([[1,2,3],[4,5,6],[7,8,9]])
>>> a
array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])
>>> color.lab2rgb(color.rgb2lab(a))
array([[ -1.74361805e-01,   1.39592186e-03,   1.24595808e-01],
       [  1.18478213e+00,   1.15700655e+00,   1.13767806e+00],
       [  2.62956273e+00,   2.38687422e+00,   2.21535897e+00]])
>>> from __future__ import division
>>> b = a/10
>>> b
array([[ 0.1,  0.2,  0.3],
       [ 0.4,  0.5,  0.6],
       [ 0.7,  0.8,  0.9]])
>>> color.lab2rgb(color.rgb2lab(a))
array([[ 0.1,  0.2,  0.3],
       [ 0.4,  0.5,  0.6],
       [ 0.7,  0.8,  0.9]])

In color.py, the xyz2lab and lab2xyz functions are doing some math that I can't deduce at a glance (I'm not that familiar with numpy or image transforms).

Edit (this code fixes the problem):

PIL gives you numbers [0,255], try scaling those down to [0,1] before passing to the rgb2lab function and back up when coming out. e.g.:

#from __future__ import division # (if required)
[...]
# Create array of image using numpy
srcArray = numpy.asarray(src)/255

# Convert array from RGB into Lab
srcArray = color.rgb2lab(srcArray)

# Convert array back into Lab
end = color.lab2rgb(srcArray)*255
end = end.astype(numpy.uint8)
like image 22
Nick T Avatar answered Sep 25 '22 01:09

Nick T