• No results found

Souřadný systém textury Java (červeně) a OpenGL (zeleně)

Vlastní hodnoty se počítají dle postupu v teoretické části. Výstupem jsou dvojice hodnot typu double, které se ukládají k datům příslušné textury (viz. následující kapitola).

41

2.7. Uložení textury a souvisejících dat

Proces rekonstrukce je v tuto chvíli hotov, zbývá texturu vhodně uložit, aby bylo jednoduché ji znovu načíst, případně ji exportovat mimo náš program. Pro uložení textury slouží třída TextureData. Vlastní data o obrázku textury jsou uložena v instanci třídy BufferedImage, což je, dalo by se říci, základní třída pro reprezentaci obrázku v jazyku Java. Souřadnice textury jsou ukládány do mapy, kdy klíčem je ID bodu, a data jsou tvořena polem hodnot typu double. Z hlediska výpočtu by mohla tato data stačit, pro potřeby uložení dat na disk a pro zobrazení v interním OpenGL prohlížeči jsou ale potřeba další data.

Pro ukládání dat projektu je použit proces serializace implementovaný přímo v Javě, kdy je možno využít tříd ObjectOutputStream a ObjectInputStream pro velice jednoduché ukládání a načítání kompletních instancí tříd. Podmínkou je, že daná třída musí implementovat rozhraní <Serializable>, to ale nedefinuje žádné metody, pouze říká překladači, že tuto třídu lze ukládat pomocí výše uvedených objektů. Některé třídy Javy ale toto rozhraní neimplementují, je tedy nutné toto omezení nějak obejít. Je to i případ třídy BufferedImage, kdy je nutné data z této třídy převést na jinou reprezentaci a tu uložit. Samozřejmě při načítání se musí použít opačný postup. Pro naše potřeby byla zvolena reprezentace pomocí pole hodnot typu byte. Převod mezi třídou BufferedImage a polem je jednoduchý, existují pro to metody ve třídě ImageIO, převod je tedy pouze otázku přípravy pole a volání vhodné metody třídy ImageIO. Stejně tak zpětné načtení je pouze otázkou vytvoření vstupního proudu a zavolání příslušné metody třídy ImageIO.

Pro zobrazení textury pomocí OpenGL je nutné načíst data do paměti grafické karty.

To znamená převést data ze třídy BufferedImage do reprezentace, které API grafické karty rozumí. Pro tuto operaci je k dispozici třída TextureIO, která umí převést mnoho reprezentací obrázku (jeden z nich je i BufferedImage) na instanci třídy Texture, kterou je již možno přímo načíst do paměti grafické karty. Informace o textuře na grafické kartě není nutné ukládat na disk, protože se musí znovu vytvářet při změně grafického kontextu (typicky nové spuštění aplikace), proto je položka „_texture“ ve třídě TextureData označena jako „transient,“ což říká překladači, aby tuto položku nezahrnoval do výstupního proudu dat při serializaci (uložení na disk).

42 o jednoduchou strukturu, navíc jakákoliv následná modifikace systému ukládání bude záležitostí několika málo oprav kódu, přičemž ve stávajícím systému ukládání ji nalézt v balíčku „cz.tul.data.utils.“ Veřejně dostupné jsou celkem tři metody – uložení dat, jejich načtení a test, jestli je ukládání potřeba. Důležité je také zmínit, že toto ukládání nevytváří výsledný soubor projektu, jedná se pouze o uložení do přechodné složky projektu. Zabalení do souboru projektu se realizuje až na pokyn uživatele a vlastní zabalení řeší jiná třída. Ukládání pomocí PersistenceHandleru je cíleno hlavně na automatické ukládání, samozřejmě je ale také využíván i při ukládání, které inicioval uživatel.

Další klíčovou myšlenkou je, že obalová třída nebude hledat třidy, které má ukládat, naopak samotné třídy se zaregistrují pro ukládání. Pro umožnění tohoto chování je nutné splnit dva předpoklady – dát k dispozici metodu pro registraci a definovat obecné rozhraní pro ukládání / načítání, které musí třída, která se chce registrovat, implementovat. Metoda pro registraci se jmenuje addItem(…). Registrované položky jsou pak ukládány do seznamu, pomocí kterého se k nim pak přistupuje. Rozhraní třídy PersistenceHandler. Poslední výhodou je možnost definice společné části

43

ukládání, což je kontrola existence složky, kde by měla být data a případná náprava (vytvoření složky v případě ukládání, vyhození výjimky v případě načítání).

Pokud tedy budeme chtít, aby se nějaká třída účastnila společného ukládání dat, musíme ji definovat jako potomka třídy Saveable, definovat metody save() a load() (můžeme využít již vytvořené rodičovské části pro kontrolu složky) a zaregistrovat tuto třídu do procesu ukládání ve třídě PersistenceHandler. O ostatní se již nemusíme starat, v případě nutnosti uložení se PersistenceHandler postará u nastavení složky pro ukládání / načítání a zavolání příslušné metody.

2.9. Export texturovaného modelu do VRML

V původním programu byl k dispozici export výsledného modelu do formátu VRML (byly k dispozici i další formáty). Formát VRML podporuje i zobrazení modelu s texturami, bylo tedy přistoupeno k rozšíření exportu o textury. Pouhý drátěný model lze zahrnout do jednoho tvaru (ve VRML se nazývá „Shape“), který bude tvořen jednotlivými polygony. Bohužel každý tvar si může držet pouze jednu texturu, texturovaný model musíme tedy vytvořit pomocí několika tvarů. Na vzhled výsledného modelu to ale nemá vliv (pomineme-li, že model bude texturován).

Textury je nutno k modelu dodat externě pomocí parametru „url,“ který obsahuje název a cestu k textuře. Je tedy nutné připravit export textur. K tomu jsou v jazyku Java metody třídy ImageIO. Umožňují uložit instanci třidy BufferedImage do daného souboru v daném formátu. Jedinou komplikací je nutnost jednoznačné identifikace souboru s texturou na základě jejího názvu. Název je tvořen indexy bodů polygonu, takže například polygon tvořen body s indexy 11,2,3 má stejný název jako 1,12,3. Proto jsou jednotlivé indexy odděleny v názvu souboru tečkou.

Do souboru VRML je nutno také uložit souřadnice textury, ty získáme z objektu textury. Pouze je nutné invertovat souřadnici Y, protože systém VRML používá jiný souřadný systém.

44

3. Testování

Algoritmus rekonstrukce máme nyní plně popsán. Teoretický postup ale není plným ukazatelem kvality vytvořeného algoritmu. Je nutné ho odzkoušet, jednak z hlediska vlastní funkčnosti (jestli vůbec algoritmus funguje) a samozřejmě z hlediska uživatelské přívětivosti. Uživatelskou přívětivostí se myslí například náročnost nastavení před vlastním výpočtem, protože nutnost složitého nastavování může odradit mnoho potencionálních uživatelů. Mnohdy může vést ke zmatení uživatele a možné degeneraci výsledků vlivem nevhodného nastavení. Dalším faktorem je také doba výpočtu. Čím déle bude výpočet trvat, tím spíše se uživatel poohlédne po jiném, rychlejším řešení.

Náš algoritmus vyžaduje pouze dvě nastavení – velikost výstupní textury a použitá interpolační metoda. Velikost textury se vybírá z předem daných hodnot, platí, že čím větší textura, tím kvalitnější výstup. Výběr interpolační metody může být pro neznalého uživatele nepříliš informativní, výchozí volba ale zajistí dostatečně kvalitní výsledky, takže se o tuto volbu uživatel nemusí nutně starat.

Testování se soustředí na dva cíle – vliv velikosti výstupní textury na čas potřebný k provedení výpočtu a vliv volby nejlepší fotografie na kvalitu textury. Pro testování byl použit jednoduchý objekt (krabice od bot). Díky menšímu počtu bodů lze totiž vcelku dobře eliminovat vliv chyb uživatele (hlavně nepřesné vyznačení polohy bodů na fotografii). Program byl samozřejmě odzkoušen i pro složitější modely, naším hlavním cílem je ale porovnání vlivu nastavených parametrů, takže si vystačíme s jednodušším modelem.

45

3.1. Volba nejlepší fotografie

Nevhodná volba fotografie může degradovat kvalitu výstupní textury natolik, že nemusí být vůbec použitelná. Nejhorší případy, kdy je textura zakryta, jsou z velké části eliminovány při vlastním výběru. Zakrytí ale není jediný faktor, který ovlivňuje kvalitu výstupu. Může to být také natočení plochy trojúhelníku vůči kameře, což by měl kompenzovat použitý matematický aparát. To se ukázalo jako pravdivé tvrzení.

Obrázek 15 ukazuje výstupní textury pro jeden trojúhelník při použití různých fotografií.