Hlavní navigace

OpenGL Imaging Subset (8)

20. 4. 2004
Doba čtení: 8 minut

Sdílet

V dnešním pokračování seriálu o OpenGL Imaging Subsetu si ukážeme práci s histogramem. Pomocí histogramu je možné zjistit zajímavé statistické informace o vykreslovaném obraze. Tyto informace je možné dále použít například pro úpravy obrazu.

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:

\sum_{i=1}^{max}H(i)=m.n

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:

H_k(p)=\sum_{i=0}^{p}H(i)

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_HIS­TOGRAM.
  • 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_AL­PHA,
    GL_LUMINANCE4_AL­PHA4,
    GL_LUMINANCE6_AL­PHA2,
    GL_LUMINANCE8_AL­PHA8,
    GL_LUMINANCE12_AL­PHA4,
    GL_LUMINANCE12_AL­PHA12,
    GL_LUMINANCE16_AL­PHA16,
    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_AL­PHA – 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_SHOR­T,
    GL_SHORT,
    GL_UNSIGNED_INT,
    GL_INT,
    GL_FLOAT,
    GL_UNSIGNED_BY­TE3_3_2,
    GL_UNSIGNED_BY­TE2_3_3_REV,
    GL_UNSIGNED_SHOR­T5_6_5,
    GL_UNSIGNED_SHOR­T5_6_5_REV,
    GL_UNSIGNED_SHOR­T4_4_4_4,
    GL_UNSIGNED_SHOR­T4_4_4_4_REV,
    GL_UNSIGNED_SHOR­T5_5_5_1,
    GL_UNSIGNED_SHOR­T1_5_5_5_REV,
    GL_UNSIGNED_IN­T8_8_8_8,
    GL_UNSIGNED_IN­T8_8_8_8_REV,
    GL_UNSIGNED_IN­T10_10_10_2 nebo
    GL_UNSIGNED_IN­T2_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()
glGetHistogram­Parameterfv()
glGetHistogram­Parameteriv()
 

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.

Screenshot prvního příkladu s histogramem pro všechny barvové složky
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.

Screenshot druhého příkladu s histogramem pro světlost pixelů
Obrázek 2: Screenshot druhého příkladu s histogramem pro světlost pixelů

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, 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.

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.