Obsah
Co je to histogram?Vytvoření tabulky histogramu
Povolení a zákaz plnění histogramu
Získání hodnot z histogramu
Vynulování hodnot v tabulce histogramu a získání nastavených parametrů histogramu
Pokračování
Seznam funkcí OpenGL Imaging Subsetu zmíněných v této části
Nové funkce OpenGL Imaging Subsetu popsané v této části
Demonstrační příklady
Zkomprimovaný článek s přílohami
Co je to histogram?
Pojem histogram si nejlépe vysvětlíme na monochromatickém obrázku, tj. na obrázku, který obsahuje pouze stupně šedi. Rozšíření na plnobarevné obrázky ve formátu RGB je vcelku jednoduché a bude popsáno o několik odstavců níž.
Histogram H je vektor (v programovacích jazycích většinou implementovaný jako pole nebo lineární seznam) absolutních četností jednotlivých jasových hodnot zastoupených v rastrovém obrazu. Hodnota H(i) histogramu H určuje, kolik pixelů v obrazu má jasovou hodnotu i. Pokud nesly pixely původního rastrového obrazu pouze jasovou složku (luminance), je histogram tohoto obrazu jednorozměrný vektor. V případě, že pixely obsahují hodnoty barvových složek RGB (ale i HSV, HLS apod.), je histogram n-rozměrný vektor, kde n je počet barvových složek.
Pokud budeme uvažovat pouze jednorozměrný histogram, který je vytvořen nad monochromatickým rastrovým obrazem, platí vztah:
kde m je počet sloupců a n je počet řádků v obrazu.
Histogram je však pouze statistickou veličinou, která charakterizuje pravděpodobnost výskytu i-té jasové složky v rastrovém obrazu. Ostatní charakteristiky obrazu, například informace o plošném rozložení barev, nejsou v histogramu zahrnuty. Proto mohou mít dva naprosto rozdílné obrazy stejné histogramy.
Při zpracování obrazu se také používá takzvaný kumulativní histogram, který lze z normálního histogramu vypočítat podle vztahu:
Každá p-tá položka v kumulativním histogramu má hodnotu rovnou součtu hodnot všech položek normálního histogramu, které mají index menší nebo roven p.
V OpenGL Imaging Subsetu však lze počítat pouze normální histogram, což ovšem nevadí, protože výpočetní náročnost pro získání kumulativního histogramu není tak velká jako výpočetní náročnost získání histogramu normálního. Při výpočtu normálního histogramu se totiž musí získat a započítat hodnota každého pixelu, což je, obzvláště u obrazů s vysokým rozlišením, poměrně náročné. Proto se v některých případech histogram počítá pouze z vybraných pixelů, které jsou uspořádány například do pravidelné mřížky – viz digitální fotoaparáty při automatickém nastavování kontrastu a jasu (zde se také počítá histogram).
Pokud je práce s histogramem povolena (viz část Povolení a zakázání plnění histogramu) a je také vytvořena tabulka histogramu, jsou všechny barvové složky R, G, B a A vhodně zkonvertovány, aby představovaly index do tabulky histogramu. Konverze se provádí tak, že se barvové složky, které jsou vnitřně reprezentovány jako číslo v pohyblivé řádové čárce, ořežou na rozsah hodnot 0.0–1.0, poté se vynásobí počtem položek tabulky histogramu a následně zaokrouhlí na nejbližší celé číslo.
Výsledkem těchto operací jsou čtyři obecně různé indexy do tabulky histogramu (tyto tabulky jsou ve skutečnosti také čtyři, pro každou barvovou složku je alokována jedna tabulka). Hodnota v položce tabulky zadané vypočteným indexem se zvýší o jedničku. Pokud by se překročila maximální hodnota, kterou lze v buňce uschovat, stane se její hodnota nedefinovanou, což se sice nepovažuje za chybu, ale může to zkomplikovat další práci s histogramem.
Vytvoření tabulky histogramu
Před prvním použitím histogramu je zapotřebí v paměti grafického akcelerátoru alokovat místo pro jeho tabulku. Tabulka histogramu se vytvoří pomocí funkce:
void glHistogram( GLenum target, GLsizei width, GLenum internalFormat, GLboolean sink );
Význam jednotlivých argumentů funkce glHistogram():
- Argument target musí být vždy nastaven na hodnotuGL_HISTOGRAM.
- V argumentu width je uložen počet vytvářených položek v tabulce histogramu. Maximální počet položek je závislý na implementaci OpenGL, minimálně však musí dosahovat hodnoty třiceti dvou položek. Počet položek musí být vždy mocninou dvou.
- Argumentem InternalFormat se specifikuje formát, v jakém jsou uloženy jednotlivé položky v tabulce histogramu. Tento argument může obsahovat konstanty:
GL_ALPHA,
GL_ALPHA4,
GL_ALPHA8,
GL_ALPHA12,
GL_ALPHA16,
GL_LUMINANCE,
GL_LUMINANCE4,
GL_LUMINANCE8,
GL_LUMINANCE12,
GL_LUMINANCE16,
GL_LUMINANCE_ALPHA,
GL_LUMINANCE4_ALPHA4,
GL_LUMINANCE6_ALPHA2,
GL_LUMINANCE8_ALPHA8,
GL_LUMINANCE12_ALPHA4,
GL_LUMINANCE12_ALPHA12,
GL_LUMINANCE16_ALPHA16,
GL_R3_G3_B2,
GL_RGB,
GL_RGB4,
GL_RGB5,
GL_RGB8,
GL_RGB10,
GL_RGB12,
GL_RGB16,
GL_RGBA,
GL_RGBA2,
GL_RGBA4,
GL_RGB5_A1,
GL_RGBA8,
GL_RGB10_A2,
GL_RGBA12 nebo
GL_RGBA16. - Pokud je argument sink nastavený na hodnotu GL_TRUE, budou se zapisované pixely podílet pouze na tvorbě histogramu a nebudou se tedy dále zpracovávat ani vykreslovat. Pokud je naopak tento argument nastavený na hodnotu GL_FALSE, pokračují pixely do dalšího zpracování.
Povolení a zákaz plnění histogramu
I když je tabulka histogramu vytvořena, nemusí být povolen zápis do této tabulky. Povolení se provede pomocí funkce:
void glEnable( GL_HISTOGRAM );
Opětovný zákaz zápisu do tabulky histogramu lze provést pomocí funkce:
void glDisable( GL_HISTOGRAM );
Získání hodnot z histogramu
Hodnoty, které jsou v tabulce histogramu uloženy, lze kdykoli přečíst do předem alokovaného pole pomocí funkce glGetHistogram(). Formát dat je stejný jako formát používaný v případě čtení či zápisu rastrových dat pixmapy pomocí funkcí glReadPixels() a glDrawPixels(), tj. jedná se buď o pole položek stejného významu (například formát histogramu
GL_RED), nebo je za sebou uložena sekvence více různých položek (jedná se například o formát histogramu GL_RGBA).
Pro získání tabulky histogramu se používá funkce:
void glGetHistogram( GLenum target, GLboolean reset, GLenum format, GLenum type, GLvoid *values );
Význam jednotlivých argumentů funkce glGetHistogram():
- Argument target musí být vždy nastaven na hodnotu GL_HISTOGRAM.
- Argument reset může nabývat pouze dvou hodnot: GL_TRUE nebo GL_FALSE. Pokud je nastavena hodnota GL_TRUE, jsou informace z tabulky histogramu ihned po jejím přečtení vynulovány. Pokud je však hodnota nastavena na GL_FALSE, tabulka histogramu se jejím přečtením nezmění.
- V argumentu format lze specifikovat, která tabulka či tabulky histogramu se mají přečíst. Možné hodnoty jsou:
GL_RED – histogram červené barvové složky
GL_GREEN – histogram zelené barvové složky
GL_BLUE – histogram modré barvové složky
GL_ALPHA – histogram alfa složky
GL_RGB – společný histogram barvových složek R, G a B uložený v tomto pořadí
GL_BGR – společný histogram barvových složek R, G a B uložený v opačném pořadí
GL_RGBA – společný histogram barvových složek R, G, B společně s průhledností A
GL_LUMINANCE – histogram luminance, tj. světlosti pixelů
GL_LUMINANCE_ALPHA – společný histogram luminance a průhledností A - V argumentu type je uveden datový typ barvových složek. V případě, že se interní formát histogramu neshoduje se zadaným typem, je provedena automatická konverze. Tento argument může nabývat stejných hodnot jako u funkce glReadPixels(), tj.
GL_UNSIGNED_BYTE,
GL_BYTE,
GL_BITMAP (povoleno, i když nedává smysl),
GL_UNSIGNED_SHORT,
GL_SHORT,
GL_UNSIGNED_INT,
GL_INT,
GL_FLOAT,
GL_UNSIGNED_BYTE3_3_2,
GL_UNSIGNED_BYTE2_3_3_REV,
GL_UNSIGNED_SHORT5_6_5,
GL_UNSIGNED_SHORT5_6_5_REV,
GL_UNSIGNED_SHORT4_4_4_4,
GL_UNSIGNED_SHORT4_4_4_4_REV,
GL_UNSIGNED_SHORT5_5_5_1,
GL_UNSIGNED_SHORT1_5_5_5_REV,
GL_UNSIGNED_INT8_8_8_8,
GL_UNSIGNED_INT8_8_8_8_REV,
GL_UNSIGNED_INT10_10_10_2 nebo
GL_UNSIGNED_INT2_10_10_10_REV - V argumentu values se předává ukazatel na oblast paměti, do které se histogram uloží.
Vynulování hodnot v tabulce histogramu a získání nastavených parametrů histogramu
Před vykreslením scény může být žádoucí vynulování všech hodnot uložených v tabulce histogramu (není to však podmínkou, někdy potřebujeme pro statistické výpočty data v histogramu kumulovat přes více snímků). Vynulování se může provést dvěma způsoby:
První způsob spočívá v přečtení hodnot z histogramu pomocí funkce glGetHistogram() a s nastaveným argumentem reset na hodnotu GL_TRUE. Tento způsob však představuje značné zdržení, protože se musí přenášet data z paměti grafického akcelerátoru do operační paměti počítače.
Druhý způsob spočívá ve volání funkce glResetHistogram(). Tato funkce vynuluje všechny tabulky histogramu, přičemž se žádné zbytečné přenosy dat neprovádí. Funkce volaná pro vymazání histogramu má tvar:
void glResetHistogram( GLenum target );
Argument target musí být nastaven na hodnotu GL_HISTOGRAM, podobně jako u dalších funkcí, které pracují s histogramem.
Získání nastavených parametrů histogramu lze provést pomocí jedné z následujících funkcí, které se liší pouze typem výsledku:
void glGetHistogramParameterfv( GLenum target, GLenum pname, GLfloat *params ); void glGetHistogramParameteriv( GLenum target, GLenum pname, GLint *params );
Pokračování
V příštím pokračování tohoto seriálu si popíšeme funkce, které se používají pro získání dalších statistických informací o rastrových obrazech. Jedná se o tabulky minim a maxim v obraze – takzvané minmax tabulky.
Seznam funkcí OpenGL Imaging Subsetu zmíněných v této části
glEnable()glDisable()
glReadPixels()
glDrawPixels()
Nové funkce OpenGL Imaging Subsetu popsané v této části
glHistogram()glGetHistogram()
glResetHistogram()
glGetHistogramParameterfv()
glGetHistogramParameteriv()
Demonstrační příklady
Při spuštění prvního demonstračního příkladu se načte rastrový obrázek ze souboru „lena.txt“. Tento obrázek se posléze zobrazí pomocí funkce glDrawPixels(). Po vykreslení rastrového obrázku se z paměti grafického akcelerátoru přečte a následně vykreslí i jeho histogram, který je vytvořen pro každou barvovou složku zvlášť.
Zdrojový kód prvního demonstračního příkladu je dostupný zde, HTML verze se zvýrazněním syntaxe zde.
Obrázek 1: Screenshot prvního příkladu s histogramem pro všechny barvové složky
Druhý demonstrační příklad se v mnohém podobá příkladu prvnímu. Jediný rozdíl spočívá v tom, že se histogram nezobrazuje zvlášť pro každou barvovou složku, ale pouze pro světlosti vykreslovaných pixelů. Tento typ histogramu je použitelný například pro kalibraci kontrastu a jasu.
Zdrojový kód druhého demonstračního příkladu je dostupný zde, HTML verze se zvýrazněním syntaxe zde.
Obrázek 2: Screenshot druhého příkladu s histogramem pro světlost pixelů
Pro spuštění demonstračních příkladů je nutné mít stažený i původní obrázek Leny, který pro jistotu opět přikládám i do zkomprimované verze článku, i když je totožný s obrázky uvedenými v předchozích částech tohoto seriálu.
Zkomprimovaný článek s přílohami
Zkomprimovaná verze tohoto článku spolu s demonstračními příklady a obrázky je umístěna zde.