Hlavní navigace

OpenGL Imaging Subset (4)

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

Sdílet

V dnešním pokračování seriálu pojednávajícím o OpenGL Imaging Subsetu si řekneme, jakým způsobem je možné pracovat s barvovými paletami. Při zpracování pixelů, které se přenášejí z operační paměti počítače do framebufferu, je totiž možné na několika místech vykreslovacího řetězce použít barvové palety, pomocí nichž lze zásadním způsobem změnit vykreslovaný rastrový obraz. Dále si stručně povíme, jakým způsobem je možné přeložit a spustit demonstrační příklady z tohoto dílu.

Obsah

Umístění barvových palet ve vykreslovacím řetězci
Zadání barvové palety
Specifikace pixmapy pro naplnění barvové palety
Získání nastavené barvové palety
Povolení a zákaz použití barvové palety
Překlad a spuštění demonstračních příkladů
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

Umístění barvových palet ve vykreslovacím řetězci

Při použití OpenGL Imaging Subsetu je možné použít tři barvové palety, které jsou umístěny v různých částech vykreslovacího řetězce. Umístění barvových palet ve vykreslovacím řetězci je zvoleno tak, aby bylo možné po každé složitější operaci s vykreslovanými pixely jednoduše změnit jejich hodnoty. Připomeňme, že vykreslování pixelů uložených v rastrovém obrazci je spuštěno pomocí funkce glDrawPixels().

Na prvním obrázku je zobrazena část vykreslovacího řetězce, v níž se mění hodnoty pixelů, které do vykreslovacího řetězce proudí buď ve formátu RGBA (true color), nebo ve formátu L (pouze Luminance, resp. index do LUT tabulky). Vidíme, že hodnoty pixelů je možné měnit pomocí barvových palet v několika místech:

  1. První barvová paleta je aplikována po vynásobení barvových složek pixelů konstantou scale, přičtení ke konstantě bias a po převodu hodnot pomocí LUT tabulky. Použitím této barvové palety se tak de facto provádí dvojí překódování barev – jedno pomocí LUT tabulky a druhé pomocí barvové palety. Tato první barvová paleta bývá nazývána jednodušeGL_CO­LOR_TABLE.
  2. Druhá barvová paleta je aplikována až po provedení konvolucí, tj. aplikaci konvolučního filtru na přenášený rastrový obraz. Jak konvoluce, tak i další operace lze při vykreslování zakázat (přeskočit), což je na prvním obrázku znázorněno pomocí šedých šipek. Tato druhá barvová paleta se při volání funkcí Imaging Subsetu nazývá GL_POST_CONVO­LUTION_COLOR_TAB­LE.
  3. Třetí a poslední barvová paleta je na přenášené pixely aplikována po provedení transformace barev pomocí barvové transformační matice. Po nalezení nových barev v barvové paletě se mohou hodnoty pixelů podílet na vytváření histogramu a MinMax tabulek (viz další díly). Následně jsou pixely zapsány do framebufferu. Poslední barvová paleta se při volání funkcí Imaging Subsetu nazývá GL_POST_COLOR_MAT­RIX_COLOR_TAB­LE.

Část vykreslovacího řetězce s barvovými paletami
Obrázek 1: Část vykreslovacího řetězce s barvovými paletami

V dalších odstavcích budou popsány funkce, pomocí kterých lze položky barvových palet naplnit, změnit a zpětně přečíst do operační paměti.

Zadání barvové palety

Barvovou paletu lze pro převod pixelů z paletového režimu do režimu true color (RGBA) (nebo i při prostém převodu barev z režimu RGBA do RGBA) zadat pomocí funkce glColorTable() tak, že se „nanečisto“ provedou všechny předem specifikované operace, které se provádějí s pixely při přenosu do vykreslovacího řetězce, a následně se zapamatují výsledné hodnoty barev nově vypočtených pixelů.

V praxi vypadá celá operace následovně:

  1. Do vykreslovacího řetězce se pomocí funkce glColorTable() pošle pixmapa, která má výšku pouze jeden řádek pixelů a jejíž šířka odpovídá výsledné velikosti barvové palety.
  2. Pixely jsou z této pixmapy přečteny do operační paměti počítače stejným způsobem, jako by se volala funkce glDrawPixels(), tj. jsou provedena všechna potřebná dekódování a rozpakování hodnot jednotlivých pixelů.
  3. Hodnota barvy každého pixelu je vynásobena konstantou zadanou pomocí funkce glColorTablePa­rameterf(GL_CO­LOR_TABLE_SCA­LE) a posléze přičtena ke konstantě, která je zadána pomocí funkce glColorTablePa­rameterf(GL_CO­LOR_TABLE_BIAS).
  4. Výsledná barva je následně oříznuta do rozsahu 0.0–1.0.
  5. Barvové složky jsou potom získány z vypočtených hodnot R, G, B a A, a je z nich vytvořena barvová paleta se zadaným interním formátem (viz argument internalFormat popsaný v následujícím odstavci). Velikost barvové palety je nastavena tak, aby měla width položek. Indexy do palety mají hodnoty od 0 do width-1. Platí, že i-tá pozice v barvové paletě odpovídá i-tému pixelu ve zdrojové pixmapě.

Specifikace pixmapy pro naplnění barvové palety

Pro naplnění barvové palety z předem připravené pixmapy je zapotřebí zavolat následující funkci:

void glColorTable(
    GLenum  target,
    GLenum  internalFormat,
    GLsizei width,
    GLenum  format,
    GLenum  type,
    GLvoid  *table
);

Význam jednotlivých argumentů funkce glColorTable():

  • Argument target musí obsahovat jednu z těchto hodnot: GL_COLOR_TABLE, GL_POST_CONVO­LUTION_COLOR_TAB­LE a GL_POST_COLOR_MAT­RIX_COLOR_TAB­LE pro přímou modifikaci barvové palety. Alternativně lze zadat hodnoty GL_PROXY_COLOR_TAB­LE,GL_PROXY_POS­T_CONVOLUTION_CO­LOR_TABLE a GL_PROXY_POST_CO­LOR_MATRIX_CO­LOR_TABLE. V případě posledních tří hodnot se ve skutečnosti žádné výpočty neprovádí (ve vykreslovacím řetězci neproudí data), pouze se zjistí, zda může být zadaný obraz nahrán do příslušné barvové palety.
  • V argumentu internalFormat je uložen interní formát dat barvové palety, tj. formát, do kterého se (nezávisle na vstupním rastrovém obrázku) barevná paleta uloží. Mezi povolené hodnoty, které je možné v tomto argumentu zadat, patří: GL_RGBA, GL_RGB, GL_RED,GL_GRE­EN, GL_BLUE, GL_ALPHA atd. Nejpoužívanější jsou hodnoty GL_RGBA a GL_RGB, pomocí kterých lze vytvořit barevnou paletu s výběrem libovolné barvy.
  • Pomocí argumentu width je možné specifikovat šířku přenášené pixmapy, a tím i určit počet položek v barvové paletě. Maximální šířka (tj. hodnota argumentu width) je závislá na implementaci OpenGL, minimální podporovaná hodnota je však rovna 32 pixelům. Výšku pixmapy není zapotřebí zadávat, protože je vždy nastavena na hodnotu 1.
  • V argumentu format je zadán formát rastrového obrazu, který je funkci předáván. Význam jednotlivých hodnot je stejný jako u funkce glDrawPixels(), povolené hodnoty tohoto argumentu jsou: GL_RGBA, GL_RGB, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA a rozšířené formáty jakoGL_BGR_EXT, GL_BGRA_EXT apod.
  • Argument type má, podobně jako argument předchozí, stejný význam jako u funkce glDrawPixels() – lze pomocí něj specifikovat, jaký formát budou mít jednotlivé barvové složky předávaných pixelů. Povolené hodnoty jsou GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHOR­T,GL_SHORT, GL_UNSIGNED_INT, GL_INT a GL_FLOAT. Všimněte si, že není povolen typ GL_BITMAP, který by při práci s barvovou paletou nedával žádný smysluplný výstup.
  • V argumentu table se předává ukazatel na rastrová data přenášeného obrázku. Při přenosu se provádí datové konverze a případné rozpakování barvových hodnot pixelů podobně jako při vykreslování rastrových bitmap a pixmapy.

Získání nastavené barvové palety

Funkce glGetColorTable() je inverzní k výše popsané funkci glColorTable(), protože je pomocí ní možné získat aktuálně nastavenou barevnou paletu. Barevná paleta je přečtena a uložena do operační paměti ve formě pixmapy. Hlavička funkce glGetColorTable() má podobu:

void glGetColorTable(
    GLenum target,
    GLenum format,
    GLenum type,
    GLvoid *table
);

Význam argumentů této funkce je podobný jako u funkce glColorTable():

  • Argument target musí být nastaven na jednu z hodnot: GL_COLOR_TABLE, GL_POST_CONVO­LUTION_COLOR_TAB­LE neboGL_POST_CO­LOR_MATRIX_CO­LOR_TABLE.
  • Argumentem format je specifikováno, jaký formát budou mít přečtené pixely. Jsou možné tytéž hodnoty jako u funkce glReadPixels(), tj. GL_RGBA, GL_RGB, GL_BGR_EXT, GL_BGRA_EXTapod.
  • V argumentu type je zadán typ barvových složek čtených pixelů. Podobně jako u funkce glReadPixels() je možné použít hodnoty GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHOR­T, GL_SHORT, GL_UNSIGNED_INT, GL_INT aGL_FLOAT.
  • Ukazatel na oblast operační paměti, do které se mají pixely uložit, se předává v argumentu table. Paměť musí být předem alokovaná, jinak může dojít k havárii počítače (nezávisle na OS), protože přenos dat řídí přímo grafická karta!

Všimněte si, že při čtení barvové palety není nutné zadávat počet položek v paletě ani interní formát barvové palety, protože obě vlastnosti jsou uloženy spolu s barvovou paletou v paměti grafického akcelerátoru.

Povolení a zákaz použití barvové palety

Pro povolení použití barvové palety je nutné jednoduše zavolat funkci glEnable() s parametry:

glEnable(GL_COLOR_TABLE);
glEnable(GL_POST_CONVOLUTION_COLOR_TABLE); nebo
glEnable(GL_POST_COLOR_MATRIX_COLOR_TABLE);

Podobně jako povolení barvové palety lze i její zákaz provést velmi jednoduše. Stačí provést jeden z následujících příkazů:

glDisable(GL_COLOR_TABLE);
glDisable(GL_POST_CONVOLUTION_COLOR_TABLE); nebo
glDisable(GL_POST_COLOR_MATRIX_COLOR_TABLE);

Překlad a spuštění demonstračních příkladů

Na mnoha systémech pravděpodobně nepůjdou dnes popsané demonstrační příklady přeložit ani spustit. V těchto příkladech jsou totiž využity funkce Imaging Subsetu, které nemusí být podporovány – bližší informace jsou uvedeny v úvodních částech tohoto seriálu.

Pro překlad je nutné, aby byly k dispozici upravené hlavičkové soubory knihovny OpenGL a aby byl dostupný i příslušný soubor pro linker. Pro spuštění je nutné, aby byla přítomna dynamická knihovna OpenGL s podporou Imaging Subsetu – statická verze se téměř nepoužívá, protože by velikost výsledného spustitelného souboru vzrostla až o několik set kilobytů.

Pravděpodobně nejjednodušším postupem pro testování Imaging Subsetu je instalace knihovny Mesa. Ke knihovně Mesa se dodávají i nové hlavičkové soubory gl.h apod., kterými lze nahradit soubory stávající.

V Unixových systémech jsou překlad a instalace této knihovny velmi jednoduché, stačí použít připravený soubor Makefile. Pro některé systémy, například Solaris, lze stáhnout i přeloženou verzi knihovny spolu s hlavičkovými soubory.

V systémech Microsoft Windows lze použít připravené makefile soubory pro překladač MinGW, ale z mých zkušeností plyne, že se někdy nemusí překlad podařit kvůli špatně nastaveným cestám v souboru makefile.mgw, proto je nutné tento soubor ručně projít a upravit.

Se zdrojovými kódy knihovny Mesa je dodáván i projektový soubor pro Microsoft Visual Studio 6.0. V tomto projektovém souboru je i odkaz na knihovnu GLUT, takže se při otevírání projektu hledají neznámé soubory. Hledání je však možné stornovat a výsledný projekt se přeloží bez problémů. Výsledkem překladu jsou dynamické knihovny glu32.dll, opengl32.dll a osmesa32.dll spolu s verzemi pro linker, které je možné použít pro překlad demonstračních aplikací.

Pokračování

V následující části tohoto seriálu si popíšeme způsob nastavení parametrů, které ovlivňují naplnění barvové palety. Dále budou popsány operace pro zjištění těchto parametrů, změnu barvové palety, načtení barvové palety přímo z framebufferu a změnu části barvové palety.

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

glDrawPixels()
glReadPixels()
glEnable()
glDisable()
 

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

glColorTable()
glGetColorTable()

Demonstrační příklady

V prvním příkladu, který zobrazuje obrázek Leny pomocí funkce glDrawPixels(), je použita barvová paleta pro inverzi jedné barvové složky.

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 2: Screenshot prvního demonstračního příkladu

Ve druhém demonstračním příkladu je barvová paleta použita pro inverzi všech barev – výsledkem je tedy barevný negativ původního obrázku.

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 3: Screenshot druhého demonstračního příkladu

UX DAy - tip 2

Pro spuštění demonstračních příkladů je nutné mít stažený i původní obrázek Leny.

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.