Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert RGB image pixels to L*a*b*?

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
like image 657
Tecnologia da Net Avatar asked Oct 11 '18 19:10

Tecnologia da Net


People also ask

How do I convert RGB to XYZ?

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.

How many pixels are in RGB?

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.

How do you convert RGB to LAB color space?

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.


2 Answers

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:

enter image description here

you will get this as the L channel:

enter image description here

this as the a channel:

enter image description here

and this the b channel:

enter image description here

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
like image 84
Mark Setchell Avatar answered Sep 28 '22 10:09

Mark Setchell


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)

like image 43
Kiprono Elijah Koech Avatar answered Sep 28 '22 11:09

Kiprono Elijah Koech