semmixkolor i percepcja

Kąt barwy (hue) na RGB

Kąt barwy H to współrzędna wspólna dla HSV i HLS. Zamiana kąta na RGB to pierwszy krok przekształcenia obu modeli z powrotem do RGB. Najpierw liczy się czystą barwę o danym odcieniu, a dopiero potem dokłada nasycenie i jasność.

Koło barw jako sześciokąt

W HSV i HLS koło barw jest w rzeczywistości sześciokątem: co 60° jest jeden wierzchołek sześcianu RGB. Między wierzchołkami jedna składowa rośnie albo maleje liniowo, a pozostałe są stałe:

HRGBCo się zmienia
0°..60°1rośnie 0 → 10czerwień → żółć
60°..120°maleje 1 → 010żółć → zieleń
120°..180°01rośnie 0 → 1zieleń → cyjan
180°..240°0maleje 1 → 01cyjan → błękit
240°..300°rośnie 0 → 101błękit → magenta
300°..360°10maleje 1 → 0magenta → czerwień

Wzór bez warunków

Całą tabelę da się zapisać trzema wzorami z wartością bezwzględną. Niech h = H / 60°, a clamp obcina wynik do 0..1 (zob. funkcje pomocnicze):

P_R = clamp(|h - 3| - 1) P_G = clamp(2 - |h - 2|) P_B = clamp(2 - |h - 4|)

Dla H = 15°: h = 0,25, więc P = (clamp(1,75), clamp(0,25), clamp(-1,75)) = (1; 0,25; 0), czyli RGB (255, 64, 0).

HRGB czystej barwy
0°255, 0, 0
30°255, 128, 0
60°255, 255, 0
90°128, 255, 0
120°0, 255, 0
180°0, 255, 255
200°0, 170, 255
240°0, 0, 255
300°255, 0, 255
330°255, 0, 128

Dodanie nasycenia i jasności

Mając czystą barwę P, dowolną barwę HSV albo HSL dostaje się jednym wzorem:

HSV: RGB = V · (1 - S + S · P) HSL: C = (1 - |2L - 1|) · S RGB = L + C · (P - 0,5)

Dla HSV (15°, 80%, 78,4%):

RGB = 0,7843 · (0,2 + 0,8 · (1; 0,25; 0)) = 0,7843 · (1; 0,4; 0,2) = (0,7843; 0,3137; 0,1569) → (200, 80, 40)

Dla HSL (15°, L 47,1%, S 66,7%): C = 0,9412 · 0,6667 = 0,6275, a RGB = 0,4706 + 0,6275 · (0,5; -0,25; -0,5) = (0,7843; 0,3137; 0,1569). Ten sam kolor.

Kod

const clamp = (x) => Math.min(1, Math.max(0, x));

// czysta barwa dla kąta h w stopniach
function hueToRgb(h) {
  const t = (((h % 360) + 360) % 360) / 60;
  return {
    r: clamp(Math.abs(t - 3) - 1),
    g: clamp(2 - Math.abs(t - 2)),
    b: clamp(2 - Math.abs(t - 4)),
  };
}

function hsvToRgb(h, s, v) {
  const p = hueToRgb(h);
  const f = (c) => v * (1 - s + s * c);
  return { r: f(p.r), g: f(p.g), b: f(p.b) };
}

Odwrotne przekształcenie, z RGB na kąt barwy, opisuje strona RGB na kąt barwy.