Das Bild als Gitter
Halte dein Handy nah genug an ein Foto, und irgendwann siehst du keine Kabel und keine LED mehr, sondern Kästchen. Genau so liegt ein Bild im Speicher: als Tabelle aus Zahlen, Zeile für Zeile.
Das Foto zum ersten Mal
Das Objekt foto liefert dir das Bild als Graustufen – eine Zahl je
Bildpunkt, 0 ist schwarz, 255 ist weiß.
| Schreibweise | Bedeutung |
|---|---|
int[][] grau |
ein zweidimensionales Feld – ein Feld von Feldern |
grau[3][10] |
der Bildpunkt in Zeile 3, Spalte 10 |
grau.length |
die Anzahl der Zeilen, hier 72 |
grau[0].length |
die Anzahl der Spalten in Zeile 0, hier 96 |
Zuerst die Zeile, dann die Spalte. Wer das vertauscht, greift bei einem 96 × 72 großen Bild irgendwann außerhalb zu und bekommt einen Laufzeitfehler.
Und: Zeile 0 ist oben. Die Zeilennummern wachsen nach unten, anders als die y-Achse auf der Bühne.
grau
Spalte 0 1 2 … 95
Zeile 0 ┌────┬────┬────┬───┬────┐
│ 64 │ 66 │ 71 │ … │ 76 │ ← grau[0] ist ein int[] der Länge 96
Zeile 1 ├────┼────┼────┼───┼────┤
│ 64 │ 69 │ 70 │ … │ 76 │
… ├────┼────┼────┼───┼────┤
Zeile 71 │101 │100 │100 │ … │ 25 │
└────┴────┴────┴───┴────┘
Jeden Bildpunkt einmal anfassen
Fast jeder Filter in diesem Projekt sieht innen gleich aus: zwei ineinandergeschachtelte Schleifen, außen die Zeilen, innen die Spalten.
for (int zeile = 0; zeile < grau.length; zeile++) {
for (int spalte = 0; spalte < grau[zeile].length; spalte++) {
// hier steht grau[zeile][spalte] zur Verfügung
}
}
Schreibe innen grau[zeile].length und nicht grau[0].length. Bei einem
Foto sind alle Zeilen gleich lang, aber die Gewohnheit trägt später, wenn sie
es nicht mehr sind.
Aufgabe 1: Wie hell ist das Bild?
Ergänze die Methode durchschnitt. Sie soll die mittlere Helligkeit aller
Bildpunkte liefern.
Sage vorher: Das Foto zeigt eine überstrahlte LED vor einem dunklen Hintergrund. Liegt der Durchschnitt eher bei 60, bei 128 oder bei 200?
Tipp 1: Was brauchst du?
Zwei Dinge: die Summe aller Werte und die Anzahl der Bildpunkte. Die
Summe sammelst du in einer Variablen, die vor den Schleifen angelegt wird. Die
Anzahl musst du nicht mitzählen – sie ist pGrau.length * pGrau[0].length.
Tipp 2: Das Gerüst
int summe = 0;
for (int zeile = 0; zeile < pGrau.length; zeile++) {
for (int spalte = 0; spalte < pGrau[zeile].length; spalte++) {
summe = summe + pGrau[zeile][spalte];
}
}
return summe / ???;
Aufgabe 2: Wo ist der hellste Punkt?
Suche den Bildpunkt mit dem größten Wert und gib seine Zeile und seine Spalte aus. Markiere ihn anschließend: Setze im Gitter ein Kreuz aus schwarzen Punkten (Wert 0) um ihn herum und zeige das Bild noch einmal.
Anders als bei Aufgabe 1 genügt eine Zahl als Ergebnis nicht – du brauchst zwei. Überlege dir, wie du beide aus einer Methode herausbekommst.
Tipp 1: Zwei Ergebnisse
Drei Wege gibt es:
- Zwei Attribute der Klasse, die die Methode setzt.
- Ein
int[]mit zwei Feldern als Rückgabewert. - Gar keine Methode – die Suche steht direkt in
main.
Für eine erste Lösung ist der dritte Weg völlig in Ordnung.
Tipp 2: Die Suche
Es ist dieselbe Suche wie beim Maximum eines eindimensionalen Feldes, nur mit einer Schleife mehr. Merke dir nicht nur den Wert, sondern auch, wo er stand:
int besterWert = pGrau[0][0];
int besteZeile = 0;
int besteSpalte = 0;
// … in den Schleifen: ist pGrau[zeile][spalte] größer, alle drei aktualisieren
Zum Weiterdenken
Das Foto ist 96 × 72 Bildpunkte groß und liegt als int[][] im Speicher.
a) Wie viele Zahlen sind das? Wie viel Speicher braucht das Gitter, wenn ein
int vier Byte belegt?
b) Ein Foto aus einer Handykamera hat 4032 × 3024 Bildpunkte, und zwar in drei Farbkanälen. Wie viel wären es dann?
c) Eine JPEG-Datei dieses Fotos ist keine 5 Megabyte groß. Wie kann das sein?