Texturesynthesis

Aus DGL Wiki
Wechseln zu: Navigation, Suche

Was ist Texturesynthesis?

Häufig steht man vor dem Problem, dass man zwar in Textursammlung XY eine vom Prinzip eine schöne Textur gefunden hat, diese jedoch aus diversen Gründen nicht sinnvoll nutzbar ist. Ein paar Beispiele:

  • die Textur ist zu klein, würde man die Textur kacheln, sähe man dies sofort
  • die Textur ist ein Foto und daher gar nicht kachelbar
  • die Textur hat einige kleinere Stellen die "doof" aussehen. Beispielsweise größere Schatten in einer Fototextur können merkwürdig aussehen wenn das Licht in der Szene nicht aus der entsprechenden Richtung kommt. Gleiches gilt für besonders auffällige Elemente deren Wiederholung man sofort sehen würde.

Sofern es sich um eine Textur mit nur lokaler Struktur handelt und man etwas Rechenleistung invertiert kann man diese Mängel ohne Verlust an Qualität beheben!

Texturesynthesis ist die Wissenschaft die sich damit beschäftigt die grundlegende Struktur einer Textur weiterzuführen OHNE Wiederholungen zu erzeugen. Der Standardalgorithmus beginnt mit einer Zufallstextur mit RGB-rauschen. Nun wird die Textur Pixel für Pixel durchlaufen und jeweils der Pixel aus der Inputtextur gewählt, dessen lokale Nachbarschaft best-möglich zum aktuellen Pixel passt.

Das ganze klappt nicht bei jeder Textur, erfordert eine Menge Rechenleistung, aber prinzipiell kann man aus einer kleinen Quelltextur beliebig große, kachelbare Texturen zu erzeugen!

Eine Menge Rechenleistung bedeutet folgendes: Angenommen wir haben eine 1024x1024 Inputtextur und wollen daraus eine gleichgroße Outputtextur erzeugen. Für jeden Pixel in der Outputtextur müssen wir die Nachbarschaft jedes Pixels in der Inputtextur anschauen. Also 1024*1024*1024*1024 = 1 Billion Operationen. Natürlich lässt sich das ganze etwas optimieren, indem man beispielsweise eine Baumstruktur einsetzt, trotzdem kann das auf aktueller Hardware durchaus ein paar Stunden dauern.

Beispiele

Info DGL.png Dank freundlicher Genehmigung von cgtextures.com kann ich hier einige Beispiele präsentieren. Die folgenden Beispiel-Texturen unterliegen wie das gesamte Wiki der GNU Free Documentation License 1.2. Dies gilt jedoch ausschließlich für die Texturen in diesem Artikel. Texturen die von cgtextures.com heruntergeladen werden unterliegen nicht dieser Lizenz!

Die Input-Textur ist links zu sehen. In der Masken-Textur rechts sind unerwünschte Bereiche mit schwarz (RGB: 0,0,0) übermalt. Die Textur hatte eine Originalgröße von 1600x1200 und wurden vor Anwendung des Tools auf 683x512 herunter skaliert.
Rock-input.jpg Rock-mask.jpg
Als Output bekommt man diese kachelbare Textur. Sie hat im Original eine Auflösung von 1300x1300.
Rock-output.jpg

Ein weiteres Beispiel mit einer anderen Texturart. Die Schwierigkeit liegt hier darin, dass der Algorithmus nicht weiß was eine Pflanze ist, geschweige denn wie eine Pflanze auszusehen hat. Die Masken Textur wurde etwas aufgehellt, da die Risse in der Erde sehr dunkel sind und sonst möglicherweise ausgeschlossen würden.
Earth-input.jpg Earth-mask.jpg
Die Pflanzen in der Outputtextur sehen leicht abgewetzt oder vertrocknet aus, sind aber noch akzeptabel.
Earth-output.jpg

Das Tool: MRFsynthesis

Es gibt viele verschiedene Tools die sowas können. Ich habe mich für das folgende entschieden. Es gibt aber sicher noch mehr, einfach mal googlen. Das Tool hat den klangvollen Namen "Semi Causal Nonparametric Markov Random Field Texture Synthesis", oder kurz "MRFsynthesis". Es gibt kein Binary, aber der Quellcode ist hier verfügbar:

http://www.texturesynthesis.com/texture.htm

Vermutlich da der Code aus dem Jahr 2002 stammt muss man leider etwas am Quellcode fummeln bis aktuelle Compiler den Code akzeptieren. Sollte aber ziemlich offensichtlich sein, in Option.h musste ich ein using namespace std; hinzufügen und in nr.h zweimal eine ungenutzte Funktion fmin auskommentieren. Ich nutze Fedora 10 Linux mit gcc 4.3.2 und kann daher nichts darüber sagen ob es möglich ist das ganze unter Windows zum laufen zu bringen.

Das Programm ist leider nicht für Mehrkern-CPUs geschrieben, man kann aber einfach für jeden Kern das Programm einmal starten. Man muss sowieso immer etwas an den Parametern spielen, bis man ein sinnvolles Ergebnis erhält. Je nach verwendetem Algorithmus und Größe der Textur kann das ganze durchaus ein paar Stunden dauern.

Als Inputdatei sollte man ein PNG wählen. Zum einen geht so keine Qualität verloren, zum anderen produziert das Programm aus irgendeinem Grund beim speichern von JPG Dateien einen schwarzen Balken am oberen Bildrand. Wenn man Probleme mit Rauschen im Ergebnis hat, kann man die Ausgabeauflösung etwas höher wählen und nachher das Bild herunter skalieren.

Algorithmen

MRFsynthesis implementiert verschiedene Variationen des Algorithmus. Die Unterschiede sind in der beiliegenden Readme beschrieben, verstehen tut man diese vermutlich aber nur nach der Lektüre des Papers, welches ich nicht gelesen habe.

  • nonparaMRF : der Standardalgorithmus?
  • nonparaMRF_fast : eine schnellere Version die einen QuadTree (?) verwendet
  • nonparaMRF_fast_k : eine 2D-Variante von nonparaMRF_fast, was immer das bedeutet...
  • nonparaMRF_gaussian_k : verwendet eine "Gaussian pyramid" als Suchalgorithmus

Es hängt wahrscheinlich von der Quelltextur ab welcher Algorithmus sich am besten eignet. Einfach ausprobieren...

Parameter

Ein Beispielaufruf sieht so aus:

nonparaMRF_fast -n 2 -square -cyclic -x 1300 -y 1300 texinput1.png

Der Parameter -n ist der wichtigste, er gibt den Radius an in dem die Pixel verglichen werden. Möglich sind 1,2,3 und 4. Ein größerer Wert erfordert mehr Rechenleistung. Es hängt aber von der Struktur der Textur ab, ob man auch ein schöneres Ergebnis erhält. Man sollte mal 2 und 3 probieren. Der Parameter -square bewirkt das statt der üblichen 2-norm die Manhattandistanz verwendet wird. Was das heißt sieht man am besten auf dem folgenden Bild:
neighbourhood.png

Der Parameter -cyclic bewirkt das die Textur kachelbar wird. Mit -x und -y gibt man die Größe der Outputtextur an.

Praktisch ist ebenfalls der -m Parameter. Damit kann man "doofe" Stellen in der Inputtextur ausblenden. Einfach die Quelltextur nehmen und mit schwarzer Farbe alles ausradieren was nicht gefällt. Alle Pixel die Farbe RGB 0,0,0 haben werden ignoriert. Sollten sich erwünschte Pixel mit dieser Farbe in der Textur befinden, sollte man vorher die Helligkeit der Masken-Textur erhöhen, z.B. indem man einen dunklen Grauwert aufaddiert. Auf das Ergebnis hat dies keinen Einfluss, da die eigentlichen Farbwerte aus der Inputtextur kommen.

Weitere Parameter sind in der beliegenden Readme beschrieben.

Für das erste Beispiel (siehe oben) habe ich die folgenden Parameter benutzt:

nonparaMRF_fast -n 2 -square -cyclic -x 1300 -y 1300 -m rock_mask.png rock_input.png

Das zweite Beispiel wurde mit folgender Befehlszeile berechnet:

nonparaMRF_fast -n 3 -square -cyclic -x 1300 -y 1300 -m earth_mask.png earth_input.png

Die Rechenzeit betrug auf meinem Intel Core 2 Quad Q9300 jeweils etwa 2-3 Stunden. Allerdings wurde natürlich nur ein Core genutzt und die CPU läuft bei mir zudem auf 2.0 GHz statt 2.5 GHz.

Perspektivenkorrektur

Als Abschluss möchte ich noch erwähnen, dass es mittlerweile auch eine stark verbesserte Implementierung des Lehrstuhls Informatik 8 der RWTH Aachen die unter anderem eine Perspektivenkorrektur einsetzt. Dies ermöglicht es zu einem gewissen Grad auch die globale Struktur zu erhalten bzw. fortzusetzen. Zum Beispiel kann man das Colosseum in Rom virtuell wieder aufbauen. Bilder und ein Video gibts hier. Insbesondere das Bild des Aachener Rathauses ist heftig!