What is the CieLuv value of Black? - colors

The Wikipedia page about CieL*u*v* color space describes the conversion function from a color expressed in the XYZ color space.
For black, expressed as (R=0, G=0, B=0) in the RGB color space, and (X=0, Y=0, Z=0) in the XYZ color space, which values should we use to represent it in CieLuv?
The formula uses a division, 4x/(x+15y+3z), whose result is undefined for black.
Should we use (L=0, u=0, v=0), or are there more subtleties?

In fact black is not represented in uv.
So in Luv black can be represented by L = 0 and u = v = undefined.

Well there's a difference between theoretical black" (all zeros) and "practical black" which is 1/1000 the lightness of white.
See "Charles Poynton. Digital Video and HD. Morgan Kaufmann, second
edition edition, 2012.", page 248.
So in practice it's not exactly zero.
Or maybe imagine just grays: They all have u* = v* = 0, only L* is different.
So when you approach black, it should be clear what it looks like.

Related

How to tell if a color is imaginary/impossible?

Short version
How can I tell if a color (e.g. XYZ) is impossible? (Wikipedia: Imposible color)
For example, this color is impossible:
XYZ: (15.96, 84.04, 0)
xyY: (0.1595, 0.8404, 0.8404)
Lab: (93, -196, 161) (D65 whitepoint)
It's impossible because it lies outside of the chromacity diagram:
How can I know that?
Incorrect code
The goal is for someone to fill in the function:
Boolean IsImaginaryColor(Single X, Single Y, Single Z)
{
//...TODO: Get someone to answer the question.
}
Right now we know that if any of the components of a corresponding LMS color are negative, then the color is imaginary.
That is a necessary, but not sufficient, condition for a color to be real. You can have all three components of LMS be positive, but it still be an imaginary color.
Boolean IsImaginaryColor(Single X, Single Y, Single Z)
{
//If any component of LMS color is negative,
//then the color is definitely imaginary.
LMSColor lms = XYZtoLMS(X, Y, Z);
if ((lms.L < 0) or (lms.M < 0) or (lms.S < 0))
return true;
//The color may still be imaginary,
//but i don't know how to solve that problem
//So as a first approximation i'll say it's real
return false;
}
LMSColor XYZtoLMS(Single X, Single Y, Single Z)
{
//perform Matrix multiplication:
//
// LMS = M * XYZ
//
// Where M is the M_CAT02 transformation matrix from CIECAM02
//
// 0.7328, 0.4296, -0.1624
// -0.7036, 1.6975, 0.0061
// 0.0030, 0.0136, 0.9834
LMSColor result;
result.L = 0.7328*X + 0.4296*Y + -0.1624*Z
result.M = -0.7036*X + 1.6975*Y + 0.0061*Z
result.S = 0.0030*X + 0.0136*Y + 0.9834*Z
}
In the xy color plane, this gives a good first-approximation (and nice visual indication) of impossible colors:
But the calculation still gives colors outside the chromacity diagram *(technically they're outside the "spectral locus"). So obviously only checking for negative components in LMS is incomplete.
Long Version
I am rendering a color picker. For example:
to pick an Lab color
you pick an ab color
for a given L plane
This is similar to what you can already do in Photoshop:
So in this case I've picked the color:
Lab: (72, -58, 119)
That color (assuming the D65 whitepoint) corresponds to the XYZ color:
Lab: (72, -58, 119)
XYZ: (25.22, 43.66, 0.36)
You can tell if a real color is outside the sRGB color gamut if one of its components is either:
less than 0
greater than 255
This XYZ color lies outside of the sRGB color space because one of it's components is negative:
XYZ: (25.22, 43.66, 0.36)
Lab: (72, -58, 119) (D65)
RGB: (106.1, 199.6, -234.7) (sRGB)
Photoshop already knows if a color is outside the sRGB color gamut, and will display a gumut warning:
But I'd like to go one step further
I can already know if a color is outside the sRGB color gamut.
But now i want to know if a color is imaginary, so i can continue to show the gamut, but hide completely impossible colors. A conceptual mockup might be:
Warning: I have no idea which of those colors actually are impossible. This is only the idea of the concept.
So what I need to know is if a color is impossible.
Background Theory - What is an example of an impossible color?
The Wikipedia page on Impossible colors notes that while the primaries for the sRGB color space all lie inside the spectral locus - and so are all real colors:
The ProPhotoRGB color space does use some primaries that are impossible:
The ProPhoto RGB color space uses imaginary green and blue primaries to obtain a larger gamut (space inside the triangle) than would be possible with three real primaries. However, some real colors are still irreproducible.
So now I have a concrete example of an impossible color: the green primary of the ProPhoto RGB color space:
| Color | CIE x | CIE y |
|-------|--------|--------|
| red | 0.7347 | 0.2653 |
| green | 0.1596 | 0.8404 | <--- this one
| blue | 0.0366 | 0.0001 |
| white | 0.3457 | 0.3585 |
This impossible color, given different color spaces, is:
xyY: (0.1596, 0.8404, 0.8404)
XYZ: (15.96, 84.04, 0)
LMS: (47.80, 131.43, 1.19)
Lab: (93.4679, -195.9973, 161.1515)
LCHab: (93.4679, 253.7415, 140.5725)
How can I tell that this color is impossible?
Given an XYZ color, how can I tell that it is impossible? E.g.:
XYZ: 15.96, 84.04, 0
Bonus Chatter
It's important to note the difference between
colors existing outside some gamut
and imaginary colors
A quick single-image primer would be:
Gamut: a color may not be displayable on your monitor, or printer, or phone, but it is still a real color - you could get a combination of Electromagnetic Waves of various wavelengths and intensities to generate the color
Imaginary: No combination of EM waves, of any intensities, of any wavelengths, can generate that response in the Long, Medium, and Short human cones
I already know how to tell if a color exists outside a particular color gamut.
I want to know if a color also exists outside the spectral locus.
In other words: i want to know if it is imaginary.
Bruce Lindbloom has a nice graphic that raises the issues of colors outside the Lab color space when you arbitrary choose to arbitrarily limit the a and b component values to +- 128:
Bonus Reading
https://physics.stackexchange.com/q/94375/
Determine that a Luv Color is non-imaginary
https://physics.stackexchange.com/questions/420614
This is a duplicate of the answer I gave here: Determine that a Luv Color is non-imaginary which relate to https://stackoverflow.com/a/48396021/931625
I think the safe way is to compute the XYZ volume boundaries and check if you are within or outside.

Given the RGB components of a color, how can I decide if it is perceived as gray by humans?

One simple way is to say that when the RGB components are equal, they form a gray color.
However, this is not the whole story, because if they only have a slight difference, they will still look gray.
Assuming the viewer has a healthy vision of color, how can I decide if the given values would be perceived as gray (presumably with an adjustable threshold level for "grayness")?
A relatively straightforward method would be to convert RGB value to HSV color space and use threshold on the saturation component, e.g. "if saturation < 0.05 then 'almost grey', else not grey".
Saturation is actually the "grayness/colorfulness" by definition.
This method is much more accurate than using differences between R, G and B channels (since human eye perceives saturation differently on light and dark colors). On the other hand, converting RGB to HSV is computationally intensive. It is up to you to decide what is of more value - precise answer (grey/not grey) or performance.
If you need an even more precise method, you may use L*a*b* color space and compute chroma as sqrt(a*a + b*b) (see here), and then apply thresholding to this value. However, this would be even more computationally intensive.
You can also combine multiple methods:
Calculate simple differences between R, G, B components. If the color can be identified as definitely desaturated (e.g. max(abs(R-G), abs(R-B), abs(G-B)) <= 5) or definitely saturated (e.g. max(abs(R-G), abs(R-B), abs(G-B)) > 100), then stop.
Otherwise, convert to L*a*b*, compute chroma as sqrt(a*a + b*b) and use thresholding on this value.
r = 160;
g = 179;
b = 151;
tolerance = 20;
if (Math.abs(r-g) < 20 && Math.abs(r-b) < 20) {
#then perceived as gray
}

How to get colors with the same perceived brightness?

Is there a tool / program / color system that enables you to get colors of the same luminance (perceived brightness)?
Say I pick a color (determine RGB values) and the program gives me all the colors around the color wheel with the same luminance but different hues?
I haven't seen such tool yet, all I came across were three different algorithms for color luminance:
(0.2126*R) + (0.7152*G) + (0.0722*B)
(0.299*R + 0.587*G + 0.114*B)
sqrt( 0.241*R^2 + 0.691*G^2 + 0.068*B^2 )
Just to be clear, I'm talking about color luminance / perceived brightness or whatever you want to call it - the attribute that encounters that we perceive red hue brighter than blue for example. (So 255,0,0 has higher luminance value than 0,0,255.)
P.S.: Does anyone know which algorithm is used to determine color luminence on this website: http://www.workwithcolor.com/hsl-color-picker-01.htm
It looks like they used none of the posted algorithms.
In the HSL color picker you linked to, it looks like they are using the 3rd Lightness equation given here, and then making it a percentage. So the equation is:
L = (100 * 0.5 * (max(r,g,b) + min(r,g,b))) / 255
Edit: Actually, I just realized that they have an L value and a Lum value shown on that color picker. The equation above applies to the L value, but I don't know how they are arriving at the Lum value. It doesn't seem to follow any of the standard equations.

Given an RGB value, how do I create a tint (or shade)?

Given an RGB value, like 168, 0, 255, how do I create tints (make it lighter) and shades (make it darker) of the color?
Among several options for shading and tinting:
For shades, multiply each component by 1/4, 1/2, 3/4, etc., of its
previous value. The smaller the factor, the darker the shade.
For tints, calculate (255 - previous value), multiply that by 1/4,
1/2, 3/4, etc. (the greater the factor, the lighter the tint), and add that to the previous value (assuming each.component is a 8-bit integer).
Note that color manipulations (such as tints and other shading) should be done in linear RGB. However, RGB colors specified in documents or encoded in images and video are not likely to be in linear RGB, in which case a so-called inverse transfer function needs to be applied to each of the RGB color's components. This function varies with the RGB color space. For example, in the sRGB color space (which can be assumed if the RGB color space is unknown), this function is roughly equivalent to raising each sRGB color component (ranging from 0 through 1) to a power of 2.2. (Note that "linear RGB" is not an RGB color space.)
See also Violet Giraffe's comment about "gamma correction".
Some definitions
A shade is produced by "darkening" a hue or "adding black"
A tint is produced by "ligthening" a hue or "adding white"
Creating a tint or a shade
Depending on your Color Model, there are different methods to create a darker (shaded) or lighter (tinted) color:
RGB:
To shade:
newR = currentR * (1 - shade_factor)
newG = currentG * (1 - shade_factor)
newB = currentB * (1 - shade_factor)
To tint:
newR = currentR + (255 - currentR) * tint_factor
newG = currentG + (255 - currentG) * tint_factor
newB = currentB + (255 - currentB) * tint_factor
More generally, the color resulting in layering a color RGB(currentR,currentG,currentB) with a color RGBA(aR,aG,aB,alpha) is:
newR = currentR + (aR - currentR) * alpha
newG = currentG + (aG - currentG) * alpha
newB = currentB + (aB - currentB) * alpha
where (aR,aG,aB) = black = (0,0,0) for shading, and (aR,aG,aB) = white = (255,255,255) for tinting
HSV or HSB:
To shade: lower the Value / Brightness or increase the Saturation
To tint: lower the Saturation or increase the Value / Brightness
HSL:
To shade: lower the Lightness
To tint: increase the Lightness
There exists formulas to convert from one color model to another. As per your initial question, if you are in RGB and want to use the HSV model to shade for example, you can just convert to HSV, do the shading and convert back to RGB. Formula to convert are not trivial but can be found on the internet. Depending on your language, it might also be available as a core function :
RGB to HSV color in javascript?
Convert RGB value to HSV
Comparing the models
RGB has the advantage of being really simple to implement, but:
you can only shade or tint your color relatively
you have no idea if your color is already tinted or shaded
HSV or HSB is kind of complex because you need to play with two parameters to get what you want (Saturation & Value / Brightness)
HSL is the best from my point of view:
supported by CSS3 (for webapp)
simple and accurate:
50% means an unaltered Hue
>50% means the Hue is lighter (tint)
<50% means the Hue is darker (shade)
given a color you can determine if it is already tinted or shaded
you can tint or shade a color relatively or absolutely (by just replacing the Lightness part)
If you want to learn more about this subject: Wiki: Colors Model
For more information on what those models are: Wikipedia: HSL and HSV
I'm currently experimenting with canvas and pixels... I'm finding this logic works out for me better.
Use this to calculate the grey-ness ( luma ? )
but with both the existing value and the new 'tint' value
calculate the difference ( I found I did not need to multiply )
add to offset the 'tint' value
var grey = (r + g + b) / 3;
var grey2 = (new_r + new_g + new_b) / 3;
var dr = grey - grey2 * 1;
var dg = grey - grey2 * 1
var db = grey - grey2 * 1;
tint_r = new_r + dr;
tint_g = new_g + dg;
tint_b = new_b _ db;
or something like that...

Built in colormaps in Matlab

I want a lighter version of the "cyan" color, using the function colormap('cyan'). How do you do this?
Check out the function BRIGHTEN:
X = spiral(8);
image(X)
colormap(winter), colorbar
brighten(0.6)
Another trick is to right click on the colorbar and select Interactive Colormap Shift, this allows to shift the color-to-data mapping using mouse dragging.
Pure cyan is represented by the RGB triple [0 1 1]. To make it lighter, just increase the red component (ex: [0.5 1 1]), thus moving it closer to pure white ([1 1 1]). If you want to make a colormap that spans from pure cyan through lighter shades of cyan all the way to pure white, you can do the following:
nValues = 128; %# The number of unique values in the colormap
map = [linspace(0,1,nValues)' ones(nValues,2)]; %'# 128-by-3 colormap
Now you can set the colormap to the one made above using the COLORMAP function:
colormap(map);
For more discussion of colors in MATLAB, check out this link.
For me colormap('cyan') fails because cyan is undefined.
However, you can create your own colors easily. If cyan is equivalent to [0,1,1] a lighter color would be [0,1,1] + [.1,0,0] = [.1,1,1] or rather just increase the R in RGB to increase the luminosity.

Resources