Informatik

Weichzeichnen

Alle bisherigen Filter haben einen Bildpunkt angesehen und daraus einen neuen gemacht. Weichzeichnen geht anders: Der neue Wert entsteht aus dem Bildpunkt und seinen acht Nachbarn. Solche Filter heißen Nachbarschaftsoperatoren, und mit ihnen fängt die eigentliche Bildverarbeitung an – Weichzeichnen, Schärfen, Rauschunterdrückung, Kantensuche funktionieren alle nach diesem Muster.

Neun Werte, ein Durchschnitt

 ┌────┬────┬────┐
 │ 90 │ 95 │ 98 │     Der neue Wert in der Mitte ist
 ├────┼────┼────┤     der Durchschnitt aller neun:
 │ 88 │ 40 │ 97 │
 ├────┼────┼────┤     (90+95+98+88+40+97+91+94+99) / 9 = 88
 │ 91 │ 94 │ 99 │
 └────┴────┴────┘

Aus der 40 – einem einzelnen dunklen Ausreißer – wird eine 88. Genau das macht Weichzeichnen: Es zieht jeden Wert zu seiner Umgebung hin.

Dieser Filter braucht spürbar länger als die bisherigen – für jeden der 6912 Bildpunkte werden neun Werte geholt. Dreimal hintereinander angewandt, wie im rechten Bild, sind das über 180 000 Zugriffe. Ein paar Zehntelsekunden sind also normal.

Der Rand

Sieh dir das mittlere Bild genau an: Es hat einen schwarzen Rahmen. Die Schleifen beginnen bei 1 und enden bei hoehe - 1, der äußerste Ring bleibt also auf 0.

Jeder Nachbarschaftsfilter hat ein Randproblem. Der Bildpunkt oben links hat keinen Nachbarn über sich und keinen links von sich. Es gibt drei übliche Antworten darauf:

  1. Den Rand auslassen – wie hier. Ehrlich, aber man sieht es.
  2. Den Rand kopieren – die ursprünglichen Werte unverändert übernehmen.
  3. Nach außen fortsetzen – für fehlende Nachbarn den nächstgelegenen gültigen Wert nehmen.

Keine davon ist die richtige. Man muss sich entscheiden und wissen, wofür.

Aufgabe 1: Den Rand behandeln

a) Ändere weich so, dass der Rand unverändert übernommen wird (Antwort 2). Der schwarze Rahmen verschwindet damit.

b) Was ist am Ergebnis von a) unschön, wenn du den Filter dreimal hintereinander anwendest? Sieh genau hin und erkläre es.

c) Setze Antwort 3 um: Schreibe eine Methode wertBei(int[][] pGrau, int pZeile, int pSpalte), die einen Index außerhalb des Bildes auf den nächsten gültigen zurechtstutzt, und benutze sie in den Schleifen. Die Schleifen dürfen dann wieder über das ganze Bild laufen.

Tipp zu a)

Bevor die eigentlichen Schleifen beginnen, kopierst du das Original einmal vollständig nach neu. Danach überschreibst du nur noch die Mitte.

Tipp zu c)

wertBei ist kurz und macht die Schleifen einfacher:

int wertBei(int[][] pGrau, int pZeile, int pSpalte) {
    if (pZeile < 0) { pZeile = 0; }
    // … drei weitere Fälle
    return pGrau[pZeile][pSpalte];
}

In der Schleife steht dann summe = summe + wertBei(pGrau, zeile + dz, spalte + ds);.

Eine mögliche Lösung. Erfrage das Passwort bei deiner Lehrkraft oder sieh auf der Seite Lösungspasswörter nach.

Warum es ohne Kopie schiefgeht

Ein naheliegender Gedanke: Wozu ein zweites Gitter? Man könnte den neuen Wert doch direkt ins alte schreiben und Speicher sparen.

Im folgenden Bereich steht genau das: weichOhneKopie schreibt jeden neuen Wert sofort ins übergebene Gitter zurück, ein zweites gibt es nicht.

Sage vorher, was dabei herauskommt. Dann starte das Programm.

Auflösung

Das Bild wird viel stärker weichgezeichnet, als ein einziger Durchgang es könnte – und zwar ungleichmäßig: Die linke und die obere Kante der LED bleiben schärfer als die rechte und die untere, an der alles verschmiert.

Der Grund: Wenn die Schleife bei Zeile 5, Spalte 5 ankommt, sind die Nachbarn oben und links schon überschrieben. Der Filter rechnet also teils mit Originalwerten, teils mit eigenen Zwischenergebnissen. Und die Zwischenergebnisse enthalten wieder Zwischenergebnisse – der Effekt schaukelt sich über das Bild hinweg auf, in der Richtung, in der die Schleife läuft.

Ein Nachbarschaftsfilter braucht das unveränderte Original. Lesen und Schreiben müssen in verschiedenen Gittern stattfinden.

Das ist kein Sonderfall des Weichzeichnens, sondern die Regel bei jedem Verfahren, das seine Nachbarn ansieht – auch beim Spiel des Lebens oder bei einer Wärmeausbreitungssimulation.

Und noch eine Falle steckt darin: pGrau ist eine Referenz. Die Methode bekommt nicht eine Kopie des Bildes, sondern den Verweis darauf. Wer hineinschreibt, verändert das Gitter, mit dem main weiterarbeitet – auch dann, wenn dort noch das Original erwartet wird. Warum das so ist, steht auf der Seite Wert und Referenz.

Aufgabe 2: Schärfen

Schärfen ist das Gegenteil von Weichzeichnen – und lässt sich aus ihm bauen. Die Idee: Ziehe vom Original ab, was das Weichzeichnen ihm weggenommen hätte, und lege es noch einmal obendrauf.

scharf = original + (original - weich)

a) Rechne von Hand nach: Was passiert an einer Stelle, an der das Bild ohnehin gleichmäßig ist, an der also original und weich denselben Wert haben?

b) Schreibe scharf(int[][] pGrau) und probiere es aus.

c) Probiere original + (original - weich) * 2. Ab wann sieht es nicht mehr schärfer aus, sondern kaputt? Beschreibe, was du siehst.

Eine mögliche Lösung. Erfrage das Passwort bei deiner Lehrkraft oder sieh auf der Seite Lösungspasswörter nach.
Weichzeichnen

Teilbare URL erstellen

Abschnitte auswählen