Vorlesung Informatik 2 - Teil A: Java Kurs

8.6 Lookup-Table Filter

Das Prinzip habe wir schon im letzten Semester bei den  GIF und PNG Dateien gesehen.

Der Filter hat eine Tabelle (lookup-Table, LUT), die so lang ist wie es unterschiedliche Werte pro Farbkanal geben kann. Bei 8 Bilt Farbtiefe pro Farbe sind das 256 Werte.

Für jeden original-Farbwert steht in der Tabelle ein neuer Farbwert.

In Java wird dieser Filter durch die Klasse LookupOp realisiert. Das folgende Beispiel erzeugt einen Filter, der ein Farbpositiv in ein Negativ umwandelt oder umgekehrt:

   short[] tabelle = new short [256];
   for(int i=0;i<tabelle.length;i++) tabelle[i]=(short)(255-i);
   LookupTable lut = new ShortLookupTable(0,tabelle);
   LookupOp op = new LookupOp(lut, null);  // der 2. Parameter kann auf ein RenderingHints Objekt zeigen

Die Klasse LookupOp ist von BufferedImageOp abgeleitet und hat eine Methode filter(bild1.getRaster(), bild2.getRaster()) zum Umwandeln der Bilder.

Die Lookup-Tabelle kann auch ein mehrstufiges Array sein, also ein Array welches so viele Arrays hält wie das Bild Farbkomponenten hat. Damit kann man für jede Farbe eine eigene Tabelle haben.

short[] rot = new short[256];
short[] gruen = new short[256];
short[] blau = new short[256];

for (short i = 0; i < 256; i++) {
    rot[i] = blau[i] = 255 - i;
    gruen[i] = i;
}

short[][] lut = new short[][] { rot, gruen, blau  };

LookupTable lookupTable = new ShortLookupTable(0, lut);

Ein interessanter Effekt mit einer LUT ist die Reduktion der Farben, die folgenden  Programmzeilen erzeugen eine Reduktion auf nur vier Farbwerte pro Farbkanal:

   short[] tabelle= new short[256];
   int DELTA=64;
   for(int i=DELTA-1;i<tabelle.length;i+=DELTA) {		 
      for(int j=0;j<DELTA;j++) tabelle[i-j]=(short)(i-DELTA/2);
   }

Dabei entsteht ein Rotoscoping-Effekt - probieren Sie es aus.

Lookup-Tables  schieben Farben so im Farbraum so umher, dass ein bestimmter Look erzielt wird. Sie nehmen Einfluss auf  Helligkeit, Kontrast, Luminanz, Chrominanz und die Farben. Sie werden auch häufig als Farbpalette bezeichnet.

In Programmen zur Farbkorrektur (LightRoom, Photoshop, DaVinci Resolve, Final Cut, ...) sind Lookup-Tables eine Möglichkeit, um die Farbstimmung anzupassen.

Farbpaletten werden nicht nur in Film und Fotografie eingesetzt. Wichtige andere Anwendungsgebiete sind z.B.:

  • Medizin: mit geeigneten Farbpaletten werden z.B. in der Pathologie in Abstrichen oder Gewebeuntersuchungen, Röntgenaufnahmen, Doppler-Sonarbilde, Tomografische Aufnahmen
  • Astronomie: die Bilder von Teleskopen werden meist mit geeigneten Farbpaletten aufgebessert. Oft sind die Bilder ja keine Aufnahmen im Spektrum des sichtbaren Lichts sondern im UV, Infrarot, Röntgen oder anderen Spektren aufgenommen.
  • Wettervorhersage:  die Radarbilder zur Regenvorhersage oder die Wolkenbilder von Wettersatelliten sind ebenfalls farblich angepasst

Im Netzt findet man viele Lookup-Tabellen, ein große Sammlung ist diese:

http://soliton.vm.bytemark.co.uk/pub/cpt-city/

Die Farbpaletten werden dort in verschiedenen Formaten angeboten (CSS, Gimp, Gnuplot, SVG, PaintShop, ...)

Zusätzlich gibt es einen Markt von Professionellet Farbpaletten für Fotografie und Cinematografie, z.B. lutify.me/

Als praktisches Beispiel bauen wir die folgenden Lookup-Tabellen aus GitHub in unser Java Programm ein:

https://github.com/quokka79/DavLUT

Die Dateien mit den Farbtabellen sind in einem Rohformat mit 256 Farbwerten je Kanal. Auf jeder Zeile der Datei befinden sich 3 ganze Zahlen mit dem neuen Wert für Rot, Grün und Blau.

Folgende kleine Hilfsmethode erzeugt ein LookupOp-Objekt aus einer solchen Datei:

	private LookupOp file2LUT(File datei) throws FileNotFoundException {		
			short[] r = new short[256], g = new short[256], b = new short[256];
			Scanner scanner = new Scanner(datei);			
			for(int index=0;index<256;index++) {
				r[index] = scanner.nextShort();
				g[index] = scanner.nextShort();
				b[index] = scanner.nextShort();
			}
			scanner.close();
			short[][] lut = {r,g,b};
			return new LookupOp(new ShortLookupTable(0,lut), null);		
	}

Wenn wir die Dateien aus der GitHub Quelle in eine Verzeichnis LUT in unserem Projekt kopieren, erzeugt folgende Methode eine Map mit Lookup-Op Objekten:

 	private void readLutTabellen() {
try {
URI uri = this.getClass().getResource("/LUT").toURI();
File[] lutDateien = new File(uri).listFiles();
for(File datei:lutDateien) {
if(datei.isFile() && datei.canRead()) {
LookupOp lut = file2LUT(datei);
String name = datei.getName().substring(0, datei.getName().lastIndexOf('.'));
lutTables.put(name,lut);
}
}
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}

In den Übungen bauen wir uns damit ein Menü mit einer Reihe von Effekten.

Lehrvideo (YouTube)