Open Fil opened 3 years ago
I've tried to implement it in this notebook — not 100% sure I got it correctly.
The implementation looks good to me. Maybe a
and b
can be halved in the notebook so the a/b plot doesn't look as clipped? I found these approximate ranges for colors in the sRGB gamut: l ∈ [0, 1]
, a ∈ [-0.233, 0.276]
, b ∈ [-0.311, 0.198]
. (sRGB white actually has an annoying L = 0.99998
:P)
I'm sorry I'm not sure I understand. Halving a and b would result in diverging from the original proposal, thus making our implementation incompatible? I agree that it would be nice to fix the computation to L=1 but that too should be done upstream?
Oops, sorry — I was a bit cryptic. I meant halving the interval for a
and b
on the a/b plot in the notebook, not a change in the implementation. The plot has a
and b
running in the interval [-0.5, 0.5]
, which makes the plot show more colors that are outside of the sRGB gamut:
With a
and b
in [-0.25, 0.25]
the plot looks smoother, as fewer colors end up being clamped:
I agree that it would be nice to fix the computation to L=1 but that too should be done upstream?
In some discussion related to the original post, Jacob Rus mentions maybe rounding off the matrices to fewer digits... in my experiments, fewer digits in Oklab's M1 multiplied with the sRGB to XYZ matrix lands it much closer to 1, but it seems more and more implementations are cropping up and choosing to use the original values.
Thanks for the clarification and the references. I've updated the notebook accordingly.
OKLCH could be even more interesting as it simplifies color manipulation and makes it more consistent for a human eye.
https://github.com/d3/d3-color/assets/5985064/da71bacc-6dbe-4d20-9e9c-753987e60b15
@danburzo @Fil About the White point that differs from L=1.0
I think that the issue here is the simplified matrix that Björn gave in his blog. If you look at the math expression, to go from Oklab to LMS we need to invert M2, so we have:
inv(M2)=[ 0.99999999845, 0.39633779217, 0.21580375806, 1.00000000888, -0.10556134232, -0.06385417477, 1.00000005467, -0.08948418209, -1.29148553786]
But in the code you have the simplified formula:
const l = L + 0.3963377774 a + 0.2158037573 b; const m = L - 0.1055613458 a - 0.0638541728 b; const s_ = L - 0.0894841775 a - 1.2914855480 b;
that uses rounded values. For better accuracy I suggest you to use unrounded values directly from the inverted matrix.
Cheers, Leonardo
PS: Attached my implementation of the srgb ab plane when L is changing. When L=0 or L=1 I get a single point (RGB 0,0,0 and RGB 255,255,255).
https://bottosson.github.io/posts/oklab/
Here's a list of the design choices behind oklab: