I have the following piece of code:
public List<Tuple<double, double, double>> GetNormalizedPixels(Bitmap image)
{
System.Drawing.Imaging.BitmapData data = image.LockBits(
new Rectangle(0, 0, image.Width, image.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
image.PixelFormat);
int pixelSize = Image.GetPixelFormatSize(image.PixelFormat) / 8;
var result = new List<Tuple<double, double, double>>();
unsafe
{
for (int y = 0; y < data.Height; ++y)
{
byte* row = (byte*)data.Scan0 + (y * data.Stride);
for (int x = 0; x < data.Width; ++x)
{
Color c = Color.FromArgb(
row[x * pixelSize + 3],
row[x * pixelSize + 2],
row[x * pixelSize + 1],
row[x * pixelSize]);
// (*)
result.Add(Tuple.Create(
1.0 * c.R / 255,
1.0 * c.G / 255,
1.0 * c.B / 255);
}
}
}
image.UnlockBits(data);
return result;
}
The key fragment (*) is this:
result.Add(Tuple.Create(
1.0 * c.R / 255,
1.0 * c.G / 255,
1.0 * c.B / 255);
which adds a pixel with its components scaled to range [0, 1]
to be further used in classification tasks with different classifiers. Some of them require the attributes to be normalized like this, others don't care - hence this function.
However, what should I do when I'd like to classify pixels in a different colour space than RGB
, like L*a*b*
? While values of all coordinates in RGB
colour space fall into range [0,256)
in L*a*b*
colour space a*
and b*
are said to be unbounded.
So when changing the fragment (*) to:
Lab lab = c.ToLab();
result.Add(Tuple.Create(
1.0 * lab.L / 100,
1.0 * lab.A / ?,
1.0 * lab.B / ?);
(ToLab
is an extension method, implemented using appropriate algorithms from here)
what should I put for the question marks?
CIELAB or CIE L*a*b* is a device-independent, 3D color space that enables accurate measurement and comparison of all perceivable colors using three color values. In this color space, numerical differences between values roughly correspond to the amount of change humans see between colors.
Any color space based on such a 24-bit RGB model is thus limited to a range of 256×256×256 ≈ 16.7 million colors.
L* axis (lightness) ranges from 0 to 100. a* and b* (color attributes) axis range from -128 to +127.
Hue and chroma can be visualized and quantified by using the a*b*-plane of the CIELAB color space. A saturated (or brilliant) color is represented by a color point that is far away from the lightness axis. The color point of a pale (or dull, or pastel) color, a color of low saturation, is close to the L*-axis.
In practice the number of all possible RGB
colours is finite, so the L*a*b*
space is bounded. It is easy to find the ranges of coordinates with the following simple program:
Color c;
double maxL = double.MinValue;
double maxA = double.MinValue;
double maxB = double.MinValue;
double minL = double.MaxValue;
double minA = double.MaxValue;
double minB = double.MaxValue;
for (int r = 0; r < 256; ++r)
for (int g = 0; g < 256; ++g)
for (int b = 0; b < 256; ++b)
{
c = Color.FromArgb(r, g, b);
Lab lab = c.ToLab();
maxL = Math.Max(maxL, lab.L);
maxA = Math.Max(maxA, lab.A);
maxB = Math.Max(maxB, lab.B);
minL = Math.Min(minL, lab.L);
minA = Math.Min(minA, lab.A);
minB = Math.Min(minB, lab.B);
}
Console.WriteLine("maxL = " + maxL + ", maxA = " + maxA + ", maxB = " + maxB);
Console.WriteLine("minL = " + minL + ", minA = " + minA + ", minB = " + minB);
or a similar one using any other language.
So, CIELAB
space coordinate ranges are as follows:
L in [0, 100]
A in [-86.185, 98.254]
B in [-107.863, 94.482]
and the answer is:
Lab lab = c.ToLab();
result.Add(Tuple.Create(
1.0 * lab.L / 100,
1.0 * (lab.A + 86.185) / 184.439,
1.0 * (lab.B + 107.863) / 202.345);
Normally, the following values work because it is the standard output of common color conversion algorithms:
L* axis (lightness) ranges from 0 to 100
a* and b* (color attributes) axis range from -128 to +127
More information can be found here.
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