Using PIL and NumPy to convert an image to Lab array, modify the values and then convert back
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.shaper,g,b = img.transpose( 2,0,1 ) # 3 10 5print "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 againprint "rgb.shape:", rgb.shapeassert (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()
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]])>>> aarray([[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>>> barray([[ 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 numpysrcArray = numpy.asarray(src)/255# Convert array from RGB into LabsrcArray = color.rgb2lab(srcArray)# Convert array back into Labend = color.lab2rgb(srcArray)*255end = end.astype(numpy.uint8)