Przekształcenie HSI i RGB
HSI liczy odcień geometrycznie, więc i powrót do RGB wygląda inaczej niż w HSV i HSL: zamiast sześciu sektorów po 60° są trzy po 120°, a w środku pojawia się cosinus. Opis modelu jest na stronie modele HLS i HSI.
RGB na HSI
Wzór na H z atan2 daje ten sam wynik co klasyczna postać z arccos (zob. RGB na kąt barwy), a jest prostszy w kodzie.
HSI na RGB
Koło dzieli się na trzy sektory. W każdym jedna składowa jest najmniejsza i równa I · (1 - S):
Przykład w obie strony
RGB (200, 80, 40), #c85028:
Wyniki spoza zakresu
W HSV i HSL każda trójka wartości z zakresu daje poprawne RGB. W HSI tak nie jest: przestrzeń HSI z I i S w pełnym zakresie 0..1 jest większa niż sześcian RGB. Przykład:
R = 1,8 nie istnieje w RGB. Czysta czerwień ma w HSI tylko I = 1/3, więc pełnego nasycenia nie da się połączyć z większą intensywnością. Wynik trzeba obciąć do 0..1 (co zmienia barwę) albo zmniejszyć S. Przy edycji obrazu w HSI warto to sprawdzać po każdej zmianie.
Kod
const DEG = Math.PI / 180;
function rgbToHsi(r, g, b) {
const i = (r + g + b) / 3;
const s = i === 0 ? 0 : 1 - Math.min(r, g, b) / i;
let h = Math.atan2(Math.sqrt(3) * (g - b), 2 * r - g - b) / DEG;
if (h < 0) h += 360;
return { h: s === 0 ? 0 : h, s, i };
}
function hsiToRgb(h, s, i) {
h = ((h % 360) + 360) % 360;
const sector = Math.floor(h / 120); // 0: RG, 1: GB, 2: BR
const hh = (h - 120 * sector) * DEG;
const low = i * (1 - s);
const high = i * (1 + (s * Math.cos(hh)) / Math.cos(60 * DEG - hh));
const mid = 3 * i - (low + high);
if (sector === 0) return { r: high, g: mid, b: low };
if (sector === 1) return { r: low, g: high, b: mid };
return { r: mid, g: low, b: high };
}