Hlavní navigace

OpenGL Imaging Subset (3)

16. 3. 2004
Doba čtení: 8 minut

Sdílet

V dnešním pokračování seriálu o OpenGL Imaging Subsetu si popíšeme způsob práce s takzvanými Pixel Look-Up Tables, což není nic jiného než tabulky, pomocí nichž je možné měnit hodnotu pixelů během jejich zpracování před zápisem do framebufferu.

Obsah

Pixel Look-Up Tables
Vytvoření LUT tabulek
Význam jednotlivých vyhledávacích tabulek
Získání nastavených parametrů LUT tabulek
Povolení a zákaz používání LUT tabulek
Pokračování
Seznam funkcí zmíněných v této části
Nové funkce popsané v této části
Demonstrační příklady
Zkomprimovaná verze článku

Pixel Look-Up Tables

V předchozím dílu tohoto seriálu jsme si řekli, jakým způsobem se může měnit hodnota pixelů před jejich zápisem do framebufferu. Nyní si blíže popíšeme tabulky, pomocí kterých je možné provést téměř libovolné přemapování hodnot pixelů před dalším zpracováním.

Kromě výpočtů nových hodnot jednotlivých pixelů na základě hodnot původních (což jsou, jak již víme z předchozích dvou dílů, pouze lineární funkce, založené na vynásobení vstupní hodnoty pixelu konstantou scale a sečtení s konstantou bias) je možné hodnoty pixelů měnit na základě vyhledávací tabulky (Look-Up Table, zkráceně LUT). Vyhledávací tabulka pracuje na jednoduchém principu: původní hodnota pixelu je použita jako index do tabulky, v políčku tabulky se potom najde nová hodnota pixelu.

Pomocí LUT lze jednoduše mapovat buď jednotlivé barvové složky (například samostatně měnit hodnoty zelené), alfa složku, nebo je možné provádět konverzi ze zadaných intenzit pixelu na jednotlivé barevné složky. Poslední možnost lze s výhodou použít v případě, že je obrázek uložen v paletovém režimu a pixely v obrázku přímo neobsahují barvu, nýbrž pouze index do palety. V takovém případě lze jednoduše nastavit mapování z intenzit pixelů (OpenGL neví nic o tom, že jde ve skutečnosti o index) na jednotlivé barevné složky, a to dokonce i pro alfa složku, což je výhodné zejména při použití grafických formátů TGA a PNG – bližší informace o těchto formátech jsou uvedeny v XXVII dílu původního seriálu o OpenGL.

Minimální velikostí LUT tabulky, kterou musí splňovat všechny implementace OpenGL, je 32 položek, maximální velikost je implementačně závislá.

Vytvoření LUT tabulek

Parametry LUT tabulek se zadávají pomocí funkcí:

void glPixelMapfv(
    GLenum  mapType,
    GLsizei mapSize,
    const GLfloat *values
);

void glPixelMapuiv(
    GLenum  mapType,
    GLsizei mapSize,
    const GLuint *values;
);

void glPixelMapusv(
    GLenum  mapType,
    GLsizei mapSize,
    const GLushort *values
);

V argumentu mapType se předává symbolické jméno tabulky. Argument mapSize obsahuje velikost tabulky (počet položek), která musí být vždy mocninou dvou, a argument values odkaz (ukazatel) na hodnoty, které se mají do vytvořené tabulky nahrát. Odkazem je většinou ukazatel na Céčkové pole. Všimněte si, že v případě zadávání celočíselných hodnot jsou povoleny pouze kladné hodnoty (datové typy unsigned). Je to z toho důvodu, že interně jsou barvové složky reprezentovány ve formátu pohyblivé řádové čárky a rozsah těchto hodnot je 0.0–1.0.

Význam jednotlivých položek zadaných v argumentech mapType,mapSize a values je shrnut v následujících tabulkách:

Tabulka č. 551
Význam vstupních hodnot pixelů při použití LUT
Typ LUT Význam vstupní hodnoty
GL_PIXEL_MAP_I_TO­_I index barvy
GL_PIXEL_MAP_S_TO­_S hodnota šablony
GL_PIXEL_MAP_I_TO­_R index barvy
GL_PIXEL_MAP_I_TO­_G index barvy
GL_PIXEL_MAP_I_TO­_B index barvy
GL_PIXEL_MAP_I_TO­_A index barvy
GL_PIXEL_MAP_R_TO­_R barvová složka R
GL_PIXEL_MAP_G_TO­_G barvová složka G
GL_PIXEL_MAP_B_TO­_B barvová složka B
GL_PIXEL_MAP_A_TO­_A průhlednost alfa

Při inicializaci grafické knihovny OpenGL má každá vyhledávací tabulka kapacitu pouze pro jednu položku. Inicializační hodnoty těchto položek jsou rovny nule a současně je mapování pomocí LUT zakázáno.

Tabulka č. 552
Význam výstupních hodnot pixelů při použití LUT
Typ LUT Význam výstupní hodnoty
GL_PIXEL_MAP_I_TO­_I index barvy
GL_PIXEL_MAP_S_TO­_S hodnota šablony
GL_PIXEL_MAP_I_TO­_R barvová složka R
GL_PIXEL_MAP_I_TO­_G barvová složka G
GL_PIXEL_MAP_I_TO­_B barvová složka B
GL_PIXEL_MAP_I_TO­_A průhlednost alfa
GL_PIXEL_MAP_R_TO­_R barvová složka R
GL_PIXEL_MAP_G_TO­_G barvová složka G
GL_PIXEL_MAP_B_TO­_B barvová složka B
GL_PIXEL_MAP_A_TO­_A průhlednost alfa

Význam jednotlivých vyhledávacích tabulek

V následujících odstavcích si popíšeme význam jednotlivých vyhledávacích tabulek (LUT), které lze pomocí funkce glPixelMap*() za­dat.

Vyhledávací tabulka zadaná pomocí parametru GL_PIXEL_MAP_I_TO­_I převádí indexy barvy jednotlivých pixelů opět na indexy barvy. Toto mapování lze použít zejména v paletovém režimu, kdy se do barvových bufferů nezapisuje přímo barva pixelů, ale pouze indexy do palety. Pomocí funkce glPixelMap*() a paletového režimu tak vlastně používáme dvojí překódování hodnot pixelů. První překódování zajistí vyhledávací tabulka, druhé překódování barevná paleta.

Vyhledávací tabulka zadaná pomocí parametru GL_PIXEL_MAP_S_TO­_S převádí hodnoty šablony opět na hodnotu šablony. Tato tabulka se používá, na rozdíl od všech ostatních vyhledávacích tabulek, pouze pro práci s pamětí šablony (stencil bufferem). Podle normy jsou hodnoty zapisované do paměti šablony reprezentovány ve formátu s pevnou řádovou čárkou, většinou se však na tyto hodnoty díváme jako na celočíselné (tomu také odpovídají operace prováděné nad pamětí šablony).

LUT tabulky typu GL_PIXEL_MAP_I_TO­_R, GL_PIXEL_MAP_I_TO­_G, GL_PIXEL_MAP_I_TO­_B a GL_PIXEL_MAP_I_TO­_A jsou použity pro převod pixelů, jejichž hodnota při vstupu do zobrazovacího řetězce představuje pouze index do barevné palety. Tento index je pomocí třech tabulek převeden na tři barvové složky R, G, B a pomocí čtvrté tabulky také na hodnotu průhlednosti. Tento typ LUT tabulek je velmi často používaný, zejména při práci s rastrovými obrázky, které jsou uloženy v externích souborech, v nichž je použita barevná paleta.

LUT tabulky typu GL_PIXEL_MAP_R_TO­_R, GL_PIXEL_MAP_G_TO­_G, GL_PIXEL_MAP_B_TO­_B a GL_PIXEL_MAP_A_TO­_A se používají pro převod hodnot v odpovídajících barvových složkách. Smysl barev v pixelu se tak nemění, je možné pouze změnit barevný nádech obrázku, jeho kontrast, světlost apod. Jedním z častých použití tohoto typu tabulek je korekce gama hodnoty nezávisle na operačním systému a monitoru. Stačí pouze předpočítat funkční hodnoty exponenciální funkce, která je zadána gama hodnotou, a tyto hodnoty uložit do LUT tabulek. Je samozřejmě možné použít pro každou barvovou složku jinou funkci.

Získání nastavených parametrů LUT tabulek

V některých případech může být zapotřebí zpětně získat parametry LUT tabulek. Nejjednodušší je dotaz, zda je povoleno mapování hodnot pixelů reprezentujících barvu a šablonu:

glGetBooleanv(
    GL_MAP_COLOR,
    &result
);

glGetBooleanv(
    GL_MAP_STENCIL,
    &result
);

Dále je možné získat velikost alokovaných LUT tabulek. Vrácené číslo je vždy kladnou mocninou hodnoty 2:

glGetIntegerv(
    GL_PIXEL_MAP_I_TO_I_SIZE,
    &result
);

glGetIntegerv(
    GL_PIXEL_MAP_S_TO_S_SIZE,
    &result
);

glGetIntegerv(
    GL_PIXEL_MAP_I_TO_R_SIZE,
    &result
);

glGetIntegerv(
    GL_PIXEL_MAP_I_TO_G_SIZE,
    &result
);

glGetIntegerv(
    GL_PIXEL_MAP_I_TO_B_SIZE,
    &result
);

glGetIntegerv(
    GL_PIXEL_MAP_I_TO_A_SIZE,
    &result
);

glGetIntegerv(
    GL_PIXEL_MAP_R_TO_R_SIZE,
    &result
);

glGetIntegerv(
    GL_PIXEL_MAP_G_TO_G_SIZE,
    &result
);

glGetIntegerv(
    GL_PIXEL_MAP_B_TO_B_SIZE
    &result
);

glGetIntegerv(
    GL_PIXEL_MAP_A_TO_A_SIZE
    &result
);

Maximální alokovatelnou kapacitu pro všechny LUT tabulky lze zjistit pomocí volání funkce:

glGetIntegerv(
    GL_MAX_PIXEL_MAP_TABLE,
    &result
);

Povolení a zákaz používání LUT tabulek

Povolení použití LUT tabulek pro přemapování barevných hodnot pixelů je možné provést pomocí funkce:

glPixelTransferi(
    GL_MAP_COLOR,
    GL_TRUE
);

Zákaz mapování barevných hodnot se provádí pomocí stejné funkce, pouze s odlišnou hodnotou druhého argumentu:

glPixelTransferi(
    GL_MAP_COLOR,
    GL_FALSE
);

Pro povolení LUT tabulky při práci s hodnotami ve stencil bufferu je použito volání:

glPixelTransferi(
    GL_MAP_STENCIL,
    GL_TRUE
);

Zákaz mapování hodnot zapisovaných do stencil bufferu:

glPixelTransferi(
    GL_MAP_STENCIL,
    GL_FALSE
);

Pokračování

V příštím pokračování tohoto seriálu si vysvětlíme práci s barevnou paletou, tj. vytvoření barevné palety, modifikaci položek v barevné paletě a zpětné získání hodnot uložených v barevné paletě.

Seznam funkcí zmíněných v této části

glGetBooleanv()
glGetIntegerv()
glPixelTransferi()
glDrawPixels()
 

Nové funkce popsané v této části

glPixelMapfv()
glPixelMapuiv()
glPixelMapusv()
 

Demonstrační příklady

První demonstrační příklad představuje základ pro další příklady uvedené v této i v následujících částech tohoto seriálu. Po překladu a spuštění tohoto programu se načte známý obrázek Leny (tedy pouze ta nejvíce používaná část, zbytek hledejte na Googlu – The Complete Story of Lenna). Tento obrázek se bez dalšího zpracování zobrazí v okně aplikace. Pro zobrazení se používá již dříve popsaná funkce glDrawPixels(). Obrázek Leny ve formátu TGA si můžete stáhnout zde.

Zdrojový kód prvního demonstračního příkladu je dostupný zde, HTML verze se zvýrazněním syntaxe zde.

Screenshot prvního demonstračního příkladu
Obrázek 1: Screenshot prvního demonstračního příkladu

Druhý demonstrační příklad navazuje na příklad první. Při přenosu pixelů z operační paměti počítače do framebufferu se však provádí změna kontrastu, tj. vynásobení RGB hodnot pixelů nějakou konstantou. Tuto možnost jsme si ukázali v předchozí části tohoto seriálu při popisu funkce glPixelTransfe­ri(). Kontrast lze měnit pomocí myši na zobrazených posuvnících.

Zdrojový kód druhého demonstračního příkladu je dostupný zde, HTML verze se zvýrazněním syntaxe zde.

Screenshot druhého demonstračního příkladu
Obrázek 2: Screenshot druhého demonstračního příkladu

Třetí demonstrační příklad navazuje na příklad první i druhý. Při přenosu pixelů z operační paměti počítače do framebufferu se provádí změna jasu, tj. k RGB hodnotám pixelů se přičte nějaká konstanta. Tuto možnost jsme si taktéž ukázali v předchozí části tohoto seriálu při popisu funkce glPixelTransfe­ri(). Kontrast lze měnit pomocí myši na zobrazených posuvnících.

Zdrojový kód třetího demonstračního příkladu je dostupný zde, HTML verze se zvýrazněním syntaxe zde.

Screenshot třetího demonstračního příkladu
Obrázek 3: Screenshot třetího demonstračního příkladu

Čtvrtý demonstrační příklad ukazuje použití LUT tabulek při překódování barev pixelů, které jsou posílány do vykreslovacího řetězce. Před vykreslením obrázku jsou vytvořeny tři LUT tabulky pro jednotlivé barvy R, G a B. V tabulkách je uložena jednoduchá „kolísavá“ funkce, což se projeví změnou barevného podání celého obrázku.

Zdrojový kód čtvrtého demonstračního příkladu je dostupný zde, HTML verze se zvýrazněním syntaxe zde.

UX DAy - tip 2

Screenshot čtvrtého demonstračního příkladu
Obrázek 4: Screenshot čtvrtého demonstračního příkladu

Zkomprimovaná verze článku

Zkomprimovaná verze tohoto článku spolu s demonstračními příklady a obrázky je umístěna zde.

Byl pro vás článek přínosný?

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.