-
Notifications
You must be signed in to change notification settings - Fork 0
Description
when the source white point and the destination white point are different, the source white point can be clipped after the colorspace conversion has been applied (e.g. (258, 250, 250) becomes (255, 250, 250)).
One possible approach to fix this is with a chromatic adaptation to the clipped white point in order to preserve "perceptual accuracy".
NB: this is true under the assumption that the game is full screen and no other OS UI elements with full D65 white point are present on screen.
NB: this is true if there are a lot of bright elements on screen which triggers human eye chromatic adaptation
To avoid clipping and chromatic adaptation, you can apply a compression on the XYZ coordinates XYZ' = k * XYZ where k is chosen so that XYZ' is inside the destination colorspace (e.g. sRGB).
this way chromaticity coordinates Yxy are preserved at the expense of the luminance which is lower:
x = X / (X + Y + Z)
x' = kX / (kX + kY + kZ) = kX / k(X + Y + Z) = X / (X + Y + Z)
y = Y / (X + Y + Z)
y' = kY / (kX + kY + kZ) = kY / k(X + Y + Z) = Y / (X + Y + Z)
Y' = k * Y
NB: If k << 1 the resulting image can be pretty dark
NB: scaling XYZ is equivalent to scaling linear RGB (i.e. RGB with EOTF applied) values because
(R,G,B) ∈ [0,1] implies (kR,kG,kB) ∈ [0,1] for 0 <= k <= 1
and
XYZ' = M * (k * RGB_lin) = k * (M * RGB_lin) = k * XYZ
RGB_lin = [M] * XYZ_w
where M is the XYZ -> RGB matrix of the destination colorspace and XYZ_w are the XYZ coordinates of the white point of the starting colorspace
k = min(1, 1 / RGB_lin[0], 1 / 1 / RGB_lin[1], 1 / 1 / RGB_lin[2])