1

I want to create a color spectrum of constant perceived luminance.

This is my attempt so far (here's the codesandbox):

enter image description here

The code

  • goes through 8-bit RGB values of increasing hue and constant (and irrelevant) lightness,
  • transforms the triples to the corresponding linear values (un-"gamma", code for that taken from here),
  • calculates the luminance by forming the scalar product with the sRGB luminance values,
  • normalized the color by dividing by the luma and finally
  • convert back to 8-bit RGB (re-"gamma").

As I annotated in the image, the second stripe from the bottom has a rather bright blue if you ask me though. Now that could be because

  • my screen is off of sRGB (although my phone agrees),
  • my eyeballs are off the human average,
  • sRGB luminance values don't reflect luminance perception to begin with

I think it's more likely I've made some mistake or haven't understood something here.

I tweaked the sRGB luminance values slightly to get the bottom stripe that is on the verge of being what I would expect (perhaps still a bit bright that blue though).

So my question:

  • What do you guys see on your screens, subjectively? Which of the bottom two stripes do you think is closer to perceived constant brightness?
  • Presuming I'm not the only one, what's wrong here?
John
  • 6,693
  • 3
  • 51
  • 90
  • Other question's probably gonna get deleted, so I'll comment here. Regarding mining, it's definitely an interesting idea. I remember that thepiratebay used to do something like that a few years ago to supplement ad income. I don't know how that worked out, but I'm curious to know. It might have scaling issues too. Client-side in-browser miners are incredibly inefficient for the amount of energy they spend. – Snow Sep 14 '20 at 19:01

2 Answers2

4

RGB colourspaces are not perceptually uniform spaces. Generating a perceptually uniform hue stripe requires using a perceptually uniform colourspace or colour appearance model such as ICtCp or CAM16.

With Colour, it could be achieved as follows:

import colour
import numpy as np


def colour_stripe(S=1, samples=360):
    H = np.linspace(0, 1, samples)

    HSV = colour.utilities.tstack([H, np.ones(samples) * S, np.ones(samples)])
    RGB = colour.HSV_to_RGB(HSV)
 
    return RGB[np.newaxis, ...]


RGB = np.resize(colour_stripe(), [36, 360, 3])

colour.plotting.plot_image(colour.cctf_encoding(RGB * 0.5));

CAM16 = colour.convert(RGB, 'RGB', 'CAM16')
CAM16_UL = colour.CAM16_Specification(
    np.full(CAM16.J.shape, 0.5), CAM16.C, CAM16.h)

RGB_PU = colour.convert(CAM16_UL, 'CAM16', 'RGB')

colour.plotting.plot_image(colour.cctf_encoding(RGB_PU));

RGB RGB PU

Keep in mind that the assumptions here are sRGB display calibration and viewing conditions.

Kel Solaar
  • 3,660
  • 1
  • 23
  • 29
  • Well, my question was regarding constant perceived brightness, not uniform hue stripes. Still, that library is some interesting resource I didn't know about. – John Aug 01 '20 at 12:38
  • 1
    This is exactly what is happening, lightness is made constant here: `np.full(CAM16.J.shape, 0.5)`, you could apply that to any image, not just the hue stripe. – Kel Solaar Aug 01 '20 at 20:09
  • You're right, the lower stripe is indeed appearing to have constant lightness. I would still like to understand why it's not enough to normalize by sRGB luminance values (and what those are for, if not that). Also, do you have good links to hose CAM16/CIECAM thingies? I couldn't find anything particularly accessible by googling. I did find an alternative way of achieving this through resources from the chroma.js guy using a color space called HCL or HLC, but I don't know why it works or what the relationship to CAM16 might be. – John Aug 02 '20 at 09:51
  • 2
    Colour Appearance Models by Mark D. Fairchild is the defacto book to possess on that topic. As far as links go, the simplest one to get a good grasp is looking at this : https://en.wikipedia.org/wiki/Color_difference#Tolerance and especially the MacAdam Ellipses showing how hue and chroma are not uniform in CIE xyY. RGB is built directly on top of CIE xyY and CIE XYZ, and thus inherits their flaws. With that in mind and roughly the CIE created CIE L*a*b* and L*u*v*, it was also discovered that colour appearance was dependent on the surround, and thus CAMs were designed. – Kel Solaar Aug 02 '20 at 20:34
1

It depends on what you want "perceived luminance" to model. When you consider the Helmholtz-Kohlrausch effect, NOT modeled by CAM02, you should see that you need to decide on a model or a range of colour appearance effects you would like your model to fit.

https://en.wikipedia.org/wiki/Helmholtz%E2%80%93Kohlrausch_effect

Simon Thum
  • 576
  • 4
  • 15