úloha 094: Tone-mapping HDR obrázku

Úkolem je implementovat některý netriviální algoritmus převodu HDR obrázku do méně dynamického formátu (LDR, 8 bitů na kanál). Požijte některou z globálních metod transformace jasu nebo obtížnější lokální přístup.

Screenshot

Základ

Základem poslouží projekt 094tonemapping z repository grcis. Je připravena WinForm aplikace, ve které implementujete vlastní metodu ToneMapping.ToneMap() převádějící vstupní HDR obrázek do LDR formátu. Je možné předávat další potřebné parametry přes textové pole formuláře.
Výsledek se automaticky zobrazí na obrazovce a je možné ho uložit na disk ve formátu PNG.

Pilotní aplikace dále obsahuje několik užitečných funkcí:

  • Levé tlačítko myši slouží k prozkoumání příslušného pixelu obrázku - do titulku formuláře se vypíší hodnoty pixelu ve vstupním HDR souboru i v LDR výsledku
  • Parametr 'sub=K' způsobí naškálování vstupního HDR obrazu na menší velikost, K je celočíselný faktor zmenšení
  • Vpravo pod obrázkem se nachází 'track-bar' pro nastavení expozice. Ukazují se v něm mezní hodnoty nalezené v HDR vstupu (vše v logaritmické škále o základě 2) a jakékoli posunutí způsobí překreslení obrázku prostou expozicí, s příp. nastaveným parametrem před-kompenzace gamma.
  • Stisk tlačítka 'Tone-map' se vyvolá Váš vlastní převodní algoritmus. Pro pohodlnost je vykonáván ve zvláštním výpočetním vlákně a lze ho v případě potřeby zastavit tlačítkem 'Stop' (Váš algoritmus to však musí podporovat, viz níže).
  • Stiskem tlačítka 'Save image' můžeme uložit výsledný LDR obrázek v PNG formátu. Ať se jedná o automatický rendering (prostá expozice, změnou v track-baru) nebo spočítaný tone-mapping..

Technicky

ToneMapping.ToneMap() je funkce, do které musíte implementovat Váš konverzní algoritmus, HDR vstup dostanete v parametru, LDR výsledek je v návratové hodnotě funkce. Parametr Bitmap result může obsahovat již dříve použitou instanci třídy Bitmap, pokud vyhovují rozměry i formát, může být efektivnější tento objekt recyklovat místo alokace úplně nové instance (viz pilotní implementace).
Obvyklý parametr string param slouží k přenosu libovolných dalších potřebných informací. V pilotní implementaci si všimněte pohodlné extrakce hodnot pomocí Util.ParseKeyValueList() a mnohých variant Util.TryParse(). Framework aplikace předpokládá použití parametrů gamma a sub, můžete si přidat další..
Pro možnost předčasného zastavení výpočtu je potřeba občas (např. jednou v každé vodorovné řádce obrazu) testovat globální proměnnou Form1.cont - pokud se její hodnota změní na false, znamená to, že si uživatel přeje výpočet přerušit, co nejdříve tedy funkci ukončete, přepočítávání nemusí být hotové..

Inicializace parametrů: Pro pohodlné ladění i pro odevzdání vhodného nastavení modifikujte inicializační proceduru InitParams(). Ta se zavolá vždy na začátku při inicializaci formuláře.
Do posledního parametru out string name napište své celé jméno (stejně jako do komentáře na první řádce zdrojového souboru). Usnadníte tím příp. automatické vyhodnocování výsledků.

Rychlý přístup do bufferu obrázku

Projekt 094tonemapping používá intenzivně rychlejšího přístupu do paměťových bufferů rastrových obrázků. Prohlédněte si kód pro práci s vestavěným rastrovým objektem Bitmap (je zde ukázán pouze výstup/zápis, vstup by byl analogický):

...
BitmapData dataOut = result.LockBits( new Rectangle( 0, 0, width, height ), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb );
unsafe
{
  byte* optr;
  int dO = Image.GetPixelFormatSize( PixelFormat.Format24bppRgb ) / 8;    // BGR

  for ( int y = 0; y < height; y++ )
  {
    optr = (byte*)dataOut.Scan0 + y * dataOut.Stride;

    for ( int x = 0; x < width; x++, optr += dO )
    {
      ...
      optr[ 0 ] = blue;
      optr[ 1 ] = green;
      optr[ 2 ] = red;
    }
  }
}
result.UnlockBits( dataOut );
...

Druhá ukázka je rychlá práce s objektem FloatImage, ve kterém jsou všechna data obecného K-kanálového rastrového obrazu uložena v jednom dlouhém poli float[] Data. Rychlé čtení vstupního HDR obrázku pixel po pixelu:

...
fixed ( float* id = input.Data )
{
  float* iptr;

  for ( int y = 0; y < height; y++ )
  {
    iptr = id + input.Scan0 + y * input.Stride;

    for ( int x = 0; x < width; x++, iptr += input.Channels )
    {
      float R = iptr[ 0 ];
      float G = iptr[ 1 ];
      float B = iptr[ 2 ];
      ...
    }
  }
}
...
Shrnutí vlastností ("properties") třídy FloatImage užitečných pro rychlý přístup k datům:
  • float[] Data - vlastní pole pixelů. Pozor - v managovaném prostředí není zaručeno, že se během výpočtu adresa nezmění, proto musíme používat konstrukci fixed ( float* ptr = img.Data )
  • int Channels - počet kanálů obrazu - kolik následujících hodnot float tvoří jeden pixel
  • int Scan0 - první index pixelu obrázku (levý horní pixel obrazu [0,0])
  • int Stride - délka jedné vodorovné řádky obrazu (počet float hodnot) - o tolik indexů se musíme posunout, chceme-li se přesunout k dolnímu sousedu aktuálního pixelu

Co odevzdat

Jako řešení úlohy posílejte mailem modifikovaný zdrojový soubor ToneMapping.cs.

Termín

Odevzdat do: 18. 11. 2018

Body

Základ: 6 bodů + bonus (až 8 bodů).

Projekt

Visual Studio projekt: 094tonemapping.

Zdrojový soubor

Modifikujte a odevzdejte soubor: ToneMapping.cs
Přes parametr funkce InitParams() vraťte své celé jméno!

Vstupní data

Jakýkoli HDR obrázek rozumného rozlišení byste měli být schopni zpracovat. Pro testování použijte např. obrázky vystavené na této stránce.


Copyright (C) 2016-2018 J.Pelikán, last change: 2019-05-09 17:52:59 +0200 (Thu, 09 May 2019)