Nötr Düzeltme: Grileriniz Gerçekten Gri mi?
Bağımsız gamma üsleri gri tonlara renk verir. Helmlab v19'un nötr düzeltmesi bunu yapısal olarak çözer, COMBVD maliyeti +0.04.
Tasarim sisteminizde bir gri arka plan tanimliyorsunuz. sRGB'de R=G=B=128 — kusursuz bir notr gri. Bunu algisal bir renk uzayina donusturuyorsunuz ve a ile b koordinatlarinin sifir olmasini bekliyorsunuz. Ama degiller. Griyleriniz hafif mavimsi veya sarumsi cikmis. Bu bir hata degil — bu, pipeline mimarisinin matematiksel bir sonucu.
Bu yazida, bagimsiz gamma ustlerinin grilere neden renk kattiklarina, lineer matrisin bu sorunu neden cozemedigini ve Helmlab'in v19'da uyguladigi notr duzeltme (Neutral Correction, NC) yontemini inceliyoruz.
Sorun: Bagimsiz Gammalar ve Renkli Griler
Helmlab'in pipeline'i XYZ uzayindan baslar. Ilk adim, 3x3 bir M1 matrisiyle XYZ'yi ic uzaya donusturmektir. Ikinci adim, bu uc kanala bagimsiz kuvvet fonksiyonlari (gamma) uygulamaktir:
// Pipeline'in ilk asamalari
[u, v, w] = M1 * [X, Y, Z] // 3x3 matris donusumu
[u', v', w'] = [u^g1, v^g2, w^g3] // Bagimsiz gammalar
// v19 parametreleri:
// g1 = 0.395, g2 = 0.421, g3 = 0.434Ucuncu adim, baska bir 3x3 matris (M2) ile son donusumun yapilmasidir:
[L, a_raw, b_raw] = M2 * [u', v', w']Sorun tam burada ortaya cikiyor. Bir gri tonun XYZ karsiliginda X, Y ve Z kanallari birbirine bagli — hepsi Y'nin lineer fonksiyonlari. Ama farkli gamma ustleri uygulayinca:
// Gri ton icin (Y degerine bagli):
u' = (m11*X + m12*Y + m13*Z) ^ 0.395
v' = (m21*X + m22*Y + m23*Z) ^ 0.421
w' = (m31*X + m32*Y + m33*Z) ^ 0.434Uc farkli kuvvet, uc farkli egri olusturur. Bu uclu artik lineer bir sekilde birlestirilemez — cunku Y^0.395, Y^0.421 ve Y^0.434 lineer olarak bagimsiz fonksiyonlardir.
Gorsel: Renkli Gri Kayma Etkisi
Asagidaki gorsel, sorunun pratikteki yansisini gosteriyor. Ust sirada kusursuz notr bir gri gecisi, alt sirada ise bagimsiz gammalar nedeniyle olusan hafif renk kaymasi:
Kayma kucuk gorunebilir, ama UI tasariminda gri tonlar her yerde kullanilir: arka planlar, kenarliklari, boluculer, devre disi durumlar. Bir gri arka planin hafifce maviye kaymasi, ozellikle diger notr arka planlarla yan yana geldiginde goze carpar.
Matematiksel Ispat: M2 Neden Cozemez?
Dogrudan bir soru akla geliyor: M2 matrisini oyle secemez miyiz ki gri tonlar icin a=0 ve b=0 garanti olsun?
Cevap hayir. Ispatini gostermek icin, griyi tanimlamakla baslanir. Gri tonlarda X, Y ve Z kanallari sabit oranlarla Y'ye baglidir (beyaz noktaya bagimli olarak). Dolayisiyla M1 sonrasi uc kanal da Y'nin lineer fonksiyonlari olur:
u = c1 * Y, v = c2 * Y, w = c3 * Y (sabit c1, c2, c3)Gamma uyguladiktan sonra:
u' = c1^g1 * Y^g1
v' = c2^g2 * Y^g2
w' = c3^g3 * Y^g3Simdi M2 matrisi ile a ve b'yi hesapliyoruz. a=0 sartini yazmak icin:
a = m21*c1^g1*Y^g1 + m22*c2^g2*Y^g2 + m23*c3^g3*Y^g3 = 0Bu denklemin tum Y degerleri icin dogru olmasi gerekir (cunku her luminans seviyesinde bir gri ton vardir). Ama g1 ≠ g2 ≠ g3 oldugu icin, Y^g1, Y^g2 ve Y^g3 lineer olarak bagimsiz fonksiyonlardir. Lineer bagimsiziklardan olusan bir toplamin her yerde sifir olmasi icin, her katsayinin sifir olmasi gerekir:
m21 = 0, m22 = 0, m23 = 0Bu ise M2'nin a satirini tamamen sifirlar — yani a ekseni yok olur. Ayni durum b icin de gecerlidir. Baska bir deyisle: bagimsiz gammalari korurken, lineer bir matris ile gri tonlarin notr kalmasini garanti etmek matematiksel olarak imkansizdir.
Uc Cozum Yolu
Bu sorunu cozmek icin uc yaklasimi degerlendirdik:
1. Ortak Gamma (v18)
En basit cozum: uc kanal icin tek bir gamma degeri kullanmak. Bu durumda Y^g tum kanallar icin aynidir ve M2 matrisi kolayca a=0, b=0 saglayabilir.
Bedeli: 21 serbestlik derecesinden (DOF) 17'ye dusus. Uc bagimsiz gamma yerine bir ortak gamma, core pipeline'in ifade gucunu azaltir. COMBVD'de olculebilir kayip.
2. Opponent-First (Rakip-Kanalli)
Gamma oncesi opponent kanallara donusum: once (L, a, b) turu kanallar olustur, sonra gamma uygula. Bu durumda achromatic eksen yapisal olarak korunur.
Bedeli: Ayni DOF kaybi — 21'den 17'ye. Matematik farkli ama sonuc ayni: temel ifade gucu azaliyor.
3. Notr Duzeltme / Neutral Correction (v19)
Pipeline'in sonunda, gri tonlarin kactigi a ve b hatalarini cikar. Uc bagimsiz gamma oldugu gibi kaliyor — DOF kaybi yok.
Bedeli: Bir LUT (look-up table) ekleniyor, ama pipeline'in ifade gucu korunuyor. 72 parametrenin tamami aktif.
Secimimiz v19 NC oldu. Neden? Cunku ortak gamma ve opponent-first yaklasimlarinda kayip somuttu (21→17 DOF), oysa NC'nin maliyeti neredeyse sifir.
v19 NC Yontemi: LUT Cikarimi ve PCHIP Interpolasyon
Notr duzeltme yontemi su sekilde calisir:
Adim 1: Gri Yaniti Hesapla
256 gri Y degeri (luminans) olustur. Bunlarin her birini tam forward pipeline'dan gecir (M1 → gamma → M2 → hue duzeltme → H-K → kubik L → ...). Her biri icin sonuc (L_i, a_i, b_i) degerlerini kaydet.
// 256 gri ton icin pipeline'i calistir
for (let Y = 0; Y < 256; Y++) {
const gray_XYZ = luminanceToXYZ(Y / 255);
const [L, a, b] = fullForward(gray_XYZ);
a_err[Y] = a; // Bu sifir olmali ama degil
b_err[Y] = b; // Bu da sifir olmali ama degil
L_lut[Y] = L;
}Adim 2: PCHIP Interpolasyon Tablosu Olustur
256 noktadan olusan (L, a_err) ve (L, b_err) ciftlerini kullanarak PCHIP (Piecewise Cubic Hermite Interpolating Polynomial) interpolasyonu olustur. PCHIP, spline'dan farkli olarak monotonluk koruyucu — asiri salinimlara yol acmaz.
Adim 3: Pipeline Sonunda Cikar
Her rengin son (L, a, b) ciktisinda:
// Notr duzeltme: pipeline sonunda uygula
T(L, a, b) = (L, a - a_err(L), b - b_err(L))Grilar icin: a = a_err oldugu icin sonuc a = 0. Renkli tonlar icin: hatanin bir kismini cikararak lokal olarak duzeltir — buyuk renk degisikliklerine yol acmaz cunku hata fonksiyonu yavas degisen, puruzsuz bir egridir.
Ters Donusum
Tersine donusum basittir — cikarma yerine toplama:
// Ters notr duzeltme: pipeline tersinin basinda uygula
T_inv(L, a, b) = (L, a + a_err(L), b + b_err(L))Helmlab'in JavaScript implementasyonunda bu, onceden hesaplanmis bir LUT ile lineer interpolasyon kullanilarak yapilir:
import { Helmlab } from 'helmlab';
const hl = new Helmlab();
// Kusursuz gri: sRGB (0.5, 0.5, 0.5)
const gray = hl.fromSRGB(0.5, 0.5, 0.5);
console.log('L:', gray.L.toFixed(6));
console.log('a:', gray.a.toFixed(6)); // ~0.000000
console.log('b:', gray.b.toFixed(6)); // ~0.000000
// Chroma: sqrt(a^2 + b^2)
const C = Math.sqrt(gray.a ** 2 + gray.b ** 2);
console.log('C:', C.toFixed(6)); // < 0.000001Neden Pipeline Sonunda? Hue Cascade Problemi
NC duzeltmesinin pipeline'da nerede uygulandigi kritiktir. Ilk dusunce "M2'den hemen sonra duzeltme yapalim" olabilir. Ama bu ciddi sorunlara yol acar.
M2'den sonra NC uygulamak su anlama gelir:
// YANLIS: M2 sonrasi NC
[L, a_raw, b_raw] = M2 * [u', v', w']
a_corrected = a_raw - a_err(L)
b_corrected = b_raw - b_err(L)
// Simdi hue duzeltme, H-K, dark_L, chroma_scale... devam ediyorSorun: a ve b degerlerini degistirmek hue acisini degistirir. Degisen hue acisi ise sonraki tum asamalari etkiler:
- Hue duzeltme: 4 harmonikli Fourier serisi, hue acisina bagli — farkli hue, farkli duzeltme
- H-K etkisi: Hue'ya bagli lightness kaymasi — farkli hue, farkli L degisimi
- dark_L sikistirma: L degerine bagli — degismis L, farkli sikistirma
- chroma_scale: Hue'ya bagli 4 harmonik — farkli hue, farkli chroma olcekleme
Bu kademeli etkilesim, gri tonlarda kucuktur ama asiri renklerde patlar. Deneysel olarak su durumu gozlemledik:
// Asiri bir renk icin M2-sonrasi NC etkisi:
// NC oncesi L = 0.94
// NC sonrasi L = 7.27 (L degisimi cascade ile patladi)
// L-chroma etkilesimi chroma'yi yokediyor
// Round-trip (Lab → XYZ → Lab) kirildiPipeline sonunda NC uygulamak bu zincirleme etkiyi tamamen onler. Zenginlestirme asamalari (hue duzeltme, H-K, dark_L, chroma_scale) orijinal hue acisini gorur — NC sadece son ciktida ince bir ayar yapar.
Sonuclar: achC < 10⁻⁶, COMBVD Maliyeti +0.04
v19 NC'nin performansi:
Rakamlari yorumlamak gerekirse:
- COMBVD STRESS: 23.18'den 23.22'ye — artis yalnizca 0.04 birim. Bu, 3813 renk cifti ve 64.000+ insan gozlemi uzerinden olculen degerin icinde olusabilecek istatistiksel gürültünün bile altinda.
- Achromatic chroma: 0.34'ten 0.000001'e — yapisal garanti. Bu sayede gri tonlarin Lab uzayinda renk kaymasi fiilen sifir.
- Core DOF: 21 serbestlik derecesi korundu. Uc bagimsiz gamma hala aktif, pipeline ifade gucu azalmadi.
Gri Eksen Testi: Helmlab vs Oklab
NC'nin pratikte ne anlama geldigini gormek icin, birden fazla gri tonu Helmlab ile test edelim:
import { Helmlab } from 'helmlab';
const hl = new Helmlab();
// Farkli luminans seviyelerinde gri tonlar
const grays = [0.1, 0.3, 0.5, 0.7, 0.9];
for (const v of grays) {
const lab = hl.fromSRGB(v, v, v);
const C = Math.sqrt(lab.a ** 2 + lab.b ** 2);
console.log(
`sRGB(${v}, ${v}, ${v}) => ` +
`L=${lab.L.toFixed(4)}, ` +
`a=${lab.a.toFixed(6)}, ` +
`b=${lab.b.toFixed(6)}, ` +
`C=${C.toFixed(6)}`
);
}
// Her satirda C < 0.000001: griler gercekten gri
// Round-trip testi
const original = [0.5, 0.5, 0.5];
const lab = hl.fromSRGB(...original);
const back = hl.toSRGB(lab.L, lab.a, lab.b);
console.log('Round-trip hata:',
Math.max(
Math.abs(back.r - original[0]),
Math.abs(back.g - original[1]),
Math.abs(back.b - original[2])
).toExponential(2)
); // ~1e-6Neden Diger Uzaylar Bunu Yapmiyor?
CIE Lab bu sorunu yasamaz cunku tek bir kuvvet fonksiyonu kullanir: f(t) = t^(1/3). Uc kanal icin ayni fonksiyon, dolayisiyla gri tonlarda a*=0, b*=0 yapisal olarak garanti. Oklab da benzer sekilde, uc kanal icin ayni kup kok fonksiyonunu kullanir.
Ama bu basitligin bedeli var: tek bir kuvvet fonksiyonu, her kanali farkli bir dogrusal olmama ile modelleme yetenegini ortadan kaldirir. Insan gorusunun uc kon tipi (L, M, S) farkli hassasiyetlere ve farkli dogrusal olmama profillerine sahiptir. Bunu modellemek icin bagimsiz gammalar gerekir — ama bagimsiz gammalar gri sorununu getirir.
Helmlab, NC yontemiyle her iki avantaji da birlestiriyor: bagimsiz gammalarin ifade gucu + gri tonlarin yapisal garantisi.
Sonuc
Bagimsiz gamma ustleri, bir renk uzayina onemli ifade gucu kazandirir — insan gorusunun kanal bazli dogrusal olmama profilini modellemek icin gereklidir. Ama bu esneklik, gri tonlarin renk kaymasi riskini beraberinde getirir.
Helmlab v19, bu sorunu pipeline sonunda uygulanan notr duzeltme (NC) ile cozer. 256 noktali bir LUT, PCHIP interpolasyonu ve basit cikarma islemi. Sonuc: achromatic chroma 0.000001'in altina iner, COMBVD maliyeti yalnizca +0.04 birim, uc bagimsiz gamma ve 72 parametrenin tamami korunur.
Grileriniz gercekten gri olmalidir. 10.3 KB'lik bir npm paketiyle bunu garanti edebilirsiniz:
npm install helmlabKaynak kod: GitHub | Paket: npm
Bu yazi, Helmlab serisi 16 blog yazisinin dokuzuncusudur. Bir sonraki yazida: Rigid Rotation — ab duzleminde bedava hue iyilestirmesi.