Punktfilter
Der einfachste Filter, den es gibt, schaut sich jeden Bildpunkt einzeln an, rechnet eine neue Zahl aus und schreibt sie ins Ergebnis. Was rundherum liegt, interessiert ihn nicht. Solche Filter heißen Punktoperatoren – und überraschend viel von dem, was eine Kamera-App anbietet, gehört dazu.
Heller und dunkler
Heller heißt: zu jedem Wert etwas dazuzählen. Eines musst du dabei bedenken – es gibt keine Helligkeit über 255.
Ein Filter liefert ein neues Gitter, er ändert das alte nicht.
int[][] neu = new int[pGrau.length][pGrau[0].length];
Diese Zeile steht am Anfang fast jedes Filters. Sie legt ein Gitter derselben Größe an – gefüllt mit Nullen, die gleich überschrieben werden. Nur so kannst du das Original hinterher noch danebenstellen.
In heller wird nach oben abgeschnitten, nach unten aber nicht. Trotzdem sieht
das linke Bild richtig aus.
a) Warum stürzt dunkler(grau, 60) nicht ab, obwohl dabei negative Werte
entstehen?
b) Wo genau werden diese negativen Werte abgefangen? Sieh in Leinwand.java nach.
c) Warum ist es trotzdem besser, im Filter selbst zu begrenzen?
Auflösung
a) und b) Die Klasse Leinwand hat eine private Methode begrenzt, die jeden
Wert vor dem Zeichnen auf 0 bis 255 zurechtstutzt. Ein Wert von −40 wird dort
zu 0.
c) Weil das nur beim Zeichnen hilft. Sobald du zwei Filter hintereinander anwendest, rechnet der zweite mit den unbegrenzten Werten weiter – und −40 ist etwas anderes als 0. Auf der Seite Filter als Klassen steckst du Filter zu Ketten zusammen; spätestens dort fällt das auf.
Aufgabe 1: Invertieren und Schwellenwert
Schreibe zwei weitere Punktfilter.
a) invertiert – aus hell wird dunkel und umgekehrt. Ein Wert von 0 wird
zu 255, ein Wert von 200 wird zu 55.
b) schwelle – jeder Bildpunkt wird entweder ganz schwarz oder ganz weiß,
je nachdem, ob er über oder unter einer Grenze liegt. Das Ergebnis hat nur
noch zwei Farben.
Sage vorher: Welche Grenze braucht schwelle, damit von dem Foto ungefähr
die Umrisse der LED übrig bleiben? Du hast auf der vorigen Seite ausgerechnet,
dass die mittlere Helligkeit bei 115 liegt.
Tipp 1: Der Bauplan
Beide Filter haben denselben Rumpf wie heller. Es ändert sich nur die eine
Zeile, in der gerechnet wird:
int[][] neu = new int[pGrau.length][pGrau[0].length];
for (int zeile = 0; zeile < pGrau.length; zeile++) {
for (int spalte = 0; spalte < pGrau[zeile].length; spalte++) {
neu[zeile][spalte] = /* hier */;
}
}
return neu;
Tipp 2: Die beiden Vorschriften
Invertieren: Du suchst eine Rechnung, die 0 auf 255 schickt und 255 auf 0. Probiere sie mit beiden Werten durch, bevor du sie hinschreibst.
Schwellenwert: Hier wird nicht gerechnet, sondern entschieden. Ein if mit
einem else genügt.
Aufgabe 2: Kontrast
Heller machen verschiebt alle Werte. Kontrast dagegen zieht sie auseinander: Was über der Mitte liegt, wird heller, was darunter liegt, wird dunkler.
Die Vorschrift lautet
neu = 128 + (alt - 128) * faktor
a) Rechne von Hand nach, was aus den Werten 40, 128 und 220 bei faktor = 2
wird. Welche davon musst du begrenzen?
b) Schreibe die Methode kontrast(int[][] pGrau, int pFaktor) und probiere die
Faktoren 2, 3 und 4 aus.
c) Was passiert bei faktor = 0? Sage es vorher, dann probiere es.
Tipp: Begrenzen an zwei Enden
Anders als bei heller läuft der Wert hier nach beiden Seiten aus dem
Bereich heraus. Zwei if-Abfragen nacheinander sind völlig in Ordnung:
if (wert < 0) { wert = 0; }
if (wert > 255) { wert = 255; }
Zum Weiterdenken
schwelle ist der Filter, mit dem Scanner-Apps arbeiten, bevor sie Text
erkennen. Eine feste Grenze funktioniert dabei schlecht: Auf einem Foto mit
Schatten ist dieselbe Grenze in der einen Bildhälfte zu hoch und in der anderen
zu niedrig.
Wie könnte ein Schwellenwert aussehen, der sich an die Umgebung anpasst? Skizziere die Idee in Worten – programmieren kannst du sie, sobald du die Seite Weichzeichnen durchhast.