Well, I'm working with image processing to identify the color variation of an image and to be able to plot that data in a histogram. For this, I use images of skin spots in the RGB color space. The code below I can get the colors of each pixel and convert to HSV using color.rgb2lab. But as I want to convert to L*a*b*, because it is closer to human vision, in the python library there is no conversion to L*a*b*. With this, through the separated pixels of RGB, how do I transform these pixels into LAB colors?
import numpy as np
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.pyplot as plt
import colorsys
from PIL import Image
# (1) Import the file to be analyzed!
img_file = Image.open("IMD006.png")
img = img_file.load()
# (2) Get image width & height in pixels
[xs, ys] = img_file.size
max_intensity = 100
hues = {}
# (3) Examine each pixel in the image file
for x in xrange(0, xs):
for y in xrange(0, ys):
# (4) Get the RGB color of the pixel
[r, g, b] = img[x, y]
# (5) Normalize pixel color values
r /= 255.0
g /= 255.0
b /= 255.0
# (6) Convert RGB color to HSV
[h, s, v] = colorsys.rgb_to_hsv(r, g, b)
# (7) Marginalize s; count how many pixels have matching (h, v)
if h not in hues:
hues[h] = {}
if v not in hues[h]:
hues[h][v] = 1
else:
if hues[h][v] < max_intensity:
hues[h][v] += 1
Linear RGB to XYZ For example, if your values are in the range [0, 255], you must first divide each by 255.0. The output XYZ values are in the nominal range [0.0, 1.0]. The XYZ values will be relative to the same reference white as the RGB system.
Each 8 bit RGB component can have 256 possible values, ranging from 0 to 255. For example, three values like (250, 165, 0), meaning (Red=250, Green=165, Blue=0) to denote one Orange pixel. Photo editor programs have an EyeDropper tool to show the 3 RGB color components for any image pixel.
lab = rgb2lab( RGB ) converts sRGB values to CIE 1976 L*a*b* values. lab = rgb2lab( RGB , Name,Value ) specifies additional conversion options, such as the color space of the RGB image, using one or more name-value pair arguments.
You can do it with PIL/Pillow using the built-in Colour Management System and building a transform like this:
#!/usr/local/bin/python3
import numpy as np
from PIL import Image, ImageCms
# Open image and discard alpha channel which makes wheel round rather than square
im = Image.open('colorwheel.png').convert('RGB')
# Convert to Lab colourspace
srgb_p = ImageCms.createProfile("sRGB")
lab_p = ImageCms.createProfile("LAB")
rgb2lab = ImageCms.buildTransformFromOpenProfiles(srgb_p, lab_p, "RGB", "LAB")
Lab = ImageCms.applyTransform(im, rgb2lab)
And Lab
is now your image in Lab colourspace. If you carry on and add the following lines to the end of the above code, you can split the Lab image into its constituent channels and save them each as greyscale images for checking.
# Split into constituent channels so we can save 3 separate greyscales
L, a, b = Lab.split()
L.save('L.png')
a.save('a.png')
b.save('b.png')
So, if you start with this image:
you will get this as the L
channel:
this as the a
channel:
and this the b
channel:
Being non-scientific for a moment, the a
channel should be negative/low where the image is green and should be high/positive where the image is magenta so it looks correct. And the b
channel should be negative/low where the image is blue and high/positive where it is yellow, so that looks pretty good to me! As regards the L
channel, the RGB to greyscale formula is (off the top of my head) something like:
L = 0.2*R + 0.7*G + 0.1*B
So you would expect the L
channel to be much brighter where the image is green, and darkest where it is blue.
Alternatively, you can do it with the scikit-image module, maybe even more simply like this:
import numpy as np
from skimage import color, io
# Open image and make Numpy arrays 'rgb' and 'Lab'
rgb = io.imread('image.png')
Lab = color.rgb2lab(rgb)
I am not 100% sure of the scaling, but I suspect the L
channel is a float in range 0..100, and that a
and b
are also floats in range -128..+128, though I may be wrong!
With my colour wheel image above I got the following minima/maxima for each channel:
Lab[:,:,0].min() # L min
32.29567256501352
Lab[:,:,0].max() # L max
97.13950703971322
Lab[:,:,1].min() # a min
-86.18302974439501
Lab[:,:,1].max() # a max
98.23305386311316
Lab[:,:,2].min() # b min
-107.85730020669489
Lab[:,:,2].max() # b max
94.47812227647823
from colormath.color_objects import sRGBColor, LabColor
from colormath.color_conversions import convert_color
def rgb_to_cielab(a):
"""
a is a pixel with RGB coloring
"""
a1,a2,a3 = a/255
color1_rgb = sRGBColor(a1, a2, a3);
color1_lab = convert_color(color1_rgb, LabColor);
return color1_lab
rgb_to_cielab(np.array([255,0,255]))
Output: LabColor(lab_l=60.32364943499053,lab_a=98.23532017664644,lab_b=-60.83501679458592)
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