Java-Code?
Wie sieht die Methode Punktspiegelung und horizonalspieglung aus?
Implementieren Sie die Operation punktSpiegeln, die alle Punkte am Mittelpunkt des Bildes spiegelt.
Implementieren Sie in SWBild die Operation horizontalSpiegeln, die das Bild an der horizontalen Achse spiegelt.Für die Lösung zu dieser Operation ist kein zusätzliches Array-Objekt zugelassen, sie muss also „in place“ erfolgen
/**
* SWBild ist eine Klasse, die Graustufenbilder repraesentiert und
* manipuliert. Die Implementierung erfolgt durch ein einfaches
* Bildformat: Die Bildpunkte werden in einem zweidimensionalen
* Array von 'short'-Werten gehalten. Jeder Feldeintrag kann einen
* Wert zwischen 0 und 255 annehmen. Andere Werte sind unzulaessig.
* Der Wertebereich [0..255] repraesentiert den Graustufenbereich:
* 0 fuer Schwarz, 255 fuer Weiss und dazwischenliegende Werte fuer
* die Grauabstufungen.
*
* Beispielmethode 'dunkler': Ein geladenes Bild kann um
* ein gegebenes 'delta' abgedunkelt werden.
*
*/
class SWBild
{
private int anzahlPiksel=0;
// die Bilddaten dieses Bildes
private short[][] _bilddaten;
// die Breite dieses Bildes
private int _breite;
// die Hoehe dieses Bildes
private int _hoehe;
// Leinwand zur Anzeige
private Leinwand _leinwand;
/**
* Initialisiert ein Bild mit einer Bilddatei. Der Benutzer kann interaktiv mit
* Hilfe eines Dateidialogs die zu ladende Datei auswaehlen.
*/
public SWBild()
{
_bilddaten = BildEinleser.liesBilddaten();
if (_bilddaten != null)
{
aktualisiereBildgroesse(_bilddaten);
erzeugeLeinwand();
}
}
/**
* Initialisiert ein Bild mit einer Bilddatei. Der Dateiname kann als absoluter
* oder relativer Pfad uebergeben werden.
*
* @param bilddateiName
* der Name der Bilddatei
*/
public SWBild(String bilddateiName)
{
_bilddaten = BildEinleser.liesBilddaten(bilddateiName);
aktualisiereBildgroesse(_bilddaten);
erzeugeLeinwand();
}
/**
* Erzeuge bei diesem Bild einen Spot mit Radius r, Mittelpunkt x0,y0 und
* Beleuchtungsintensitaet i. Ausserhalb von r nimmt die Ausleuchtung linear ab.
* Wie im wirklichen Leben...
*
* @param xo
* x-Koordinate des Mittelpunktes
* @param yo
* y-Koordinate des Mittelpunktes
* @param r
* Radius
* @param i
* Beleuchtungsintesitaet
*/
public void spot(int x0, int y0, int r, short i)
}
1 Antwort
Naja, du nimmst dir das Array und tauschst jeweils das erste mit dem letzten Element, dann das zweite mit dem vorletzen und so weiter, bis du in der Mitte des Arrays ankommst.
Ich würde der Einfachheit halber eine Methode schreiben, die einfach ein Array spiegeln kann und die dann in die beiden gefragten Methoden einbauen.
Die Methode horizontalSpiegeln ist etwas verwirrend, weil wenn man das Bild an der horizontalen Achse spiegelt, werden oben und unten vertauscht, was ich eher als "vertikal Spiegeln" ansehen würde.
Ja, sehr gut 👍. Du machst es etwas anders als erwartet, aber das Ergebnis stimmt.
Bei dem Namen punktSpiegeln ist dir das S verloren gegangen, mach das noch rein, bevor du die Aufgabe zurückschickst.
Bei horizontalSpiegeln hätte ich immer die ganze Zeile getauscht und nicht jeden Pixel einzeln:
public void horizontalSpiegeln() {
for (int y = 0; y < _hoehe / 2; y++) {
var tempZeile = _bilddaten[y];
_bilddaten[y] = _bilddaten[_hoehe - y - 1];
_bilddaten[_hoehe - y - 1] = tempZeile;
}
zeichneBild();
}
allerdings wäre "tempZeile" dann ein Array und Arrays sind ja nicht erlaubt (auch wenn ich glaube, dass der Lehrer damit meinte, dass man das Ergebnis nicht in ein neues Array speichern soll, und nicht dass gar keine Arrays erlaubt sind)
Wie kann ich diese Methode schreiben, verstehe ich nicht:
Implementieren Sie die Operation weichzeichnen. Das Weichzeichnen wird erreicht, in- dem der Mittelwert der acht umgebenden Bildpunkte des jeweils betrachteten Bildpunkts errechnet wird und dieser Mittelwert dann den neuen Wert dieses Bildpunktes bildet. Achten Sie auf Randbedingungen!
Warum wäre eine „in place“-Lösung hier problematisch?
Hab ich unter den originalen Kommentar geschrieben. Wenn du die Antwort nicht siehst, musst du auf "Weitere Kommentare zur Antwort anzeigen" klicken.
Wie kann ich die Methode spot schreiben?
Implementieren Sie die Operation spot, die ein Scheinwerferlicht projiziert. Am einfachsten ist ein Scheinwerferlicht, das exakt von oben auf unser Bild scheint und einen runden Kegel wirft. Sie können aber auch eine andere Lichtkegelform wählen.
/**
* Erzeuge bei diesem Bild einen Spot mit Radius r, Mittelpunkt x0,y0 und
* Beleuchtungsintensitaet i. Ausserhalb von r nimmt die Ausleuchtung linear ab.
* Wie im wirklichen Leben...
*
* @param xo
* x-Koordinate des Mittelpunktes
* @param yo
* y-Koordinate des Mittelpunktes
* @param r
* Radius
* @param i
* Beleuchtungsintesitaet
*/
public void spot(int x0, int y0, int r, short i)
{
Hui, jetzt wird's etwas komplizierter. Da nicht nur die Pixel innerhalb des Spots beleuchtet werden sollen, sondern es außerhalb des Spots linear abnimmt (mit welchem Faktor?) würde ich jeden Pixel durchgehen und den Abstand zum Mittelpunkt des Spots berechnen (Satz des Pythagoras. Die Funktion für die Wurzel findest du unter Math.sqrt(). Die Betragsfunktion ist Math.abs()).
Wenn der Abstand kleiner/gleich r ist, dann wird i dazuaddiert, ansonsten wird je nach Abstand etwas weniger als i dazuaddiert.
schwer zu vertstehen. Können Sie vielleicht den Code mit Erklärung schreiben? Ich komme mit dieser Aufgabe nicht zurecht.
Ich probiere es mal. Ob das Ergebnis stimmt, kann ich nicht sagen, weil ich meine Tests einfach mit einem kleinen Array mache und kein Bild daraus zeichnen lasse.
public void spot(int x0, int y0, int r, short i)
{
// Jeden Pixel durchgehen
for (int y = 0; y<_hoehe; y++) {
for (int x = 0; x<_breite; x++) {
/*
* h = horizontaler Abstand
* v = vertikaler Abstand
* Abstand = Wurzel(h²+v²)
*/
double h = Math.abs(x-x0);
double v = Math.abs(y-y0);
double abstand = Math.sqrt((h*h)+(v*v));
// Berechnen, wie viel heller der Pixel gemacht werden soll
int gain;
// Gucken, ob der Pixel im Spot ist
if (abstand <= r) {
gain = i;
} else {
// Ansonsten einen linearen Gradienten berechnen
// Ich nehme jetzt einfach mal eine Helligkeit von 5 pro Pixel Abstand zum Spotrand
gain = (int)((-5.0 * (abstand-r))+i);
// Wenn der Pixel so weit weg ist, dass ein negatives Ergebnis rauskommt, soll er natürlich nicht verändert werden
gain = Math.max(gain, 0);
}
// auf den Pixel anwenden
_bilddaten[y][x] += gain;
}
}
zeichneBild();
}
Wie kann ich diese Methode schreiben, verstehe ich nicht:
Implementieren Sie die Operation weichzeichnen. Das Weichzeichnen wird erreicht, in- dem der Mittelwert der acht umgebenden Bildpunkte des jeweils betrachteten Bildpunkts errechnet wird und dieser Mittelwert dann den neuen Wert dieses Bildpunktes bildet. Achten Sie auf Randbedingungen!
Warum wäre eine „in place“-Lösung hier problematisch?
Bei der Aufgabe musst du wie eben zwei Schleifen machen, damit du jeden Pixel durchgehst (diesmal über die gesamte Höhe und Breite) und in den Schleifen nochmal zwei Schleifen, mit denen du jeweils von -1 bis +1 Pixel gehst und den Mittelwert der Pixel bildest. An den Rändern und Ecken musst du aufpassen, dass du nur Pixel abfragst, die auch existieren. Wenn du ganz oben links bist, kannst du natürlich nicht den Pixel links daneben abfragen.
Und in-Place geht natürlich nicht, weil wenn du einen Pixel weichzeichnest, können die umliegenden Pixel nicht mehr auf den Originalwert zugreifen und kriegen ein falsches Ergebnis.
public void weichzeichnen()
{
int a=0;
short[][] _kopie = new short[_hoehe][_breite];
for (int y=1;y<_hoehe-1;y++)
{
for (int x=1;x<_breite-1;x++)
{
a=(_bilddaten[y+1][x+1]+_bilddaten[y-1][x-1]+_bilddaten[y+1][x-1]+_bilddaten[y-1][x+1]+_bilddaten[y][x+1]+_bilddaten[y][x-1]+_bilddaten[y+1][x]+_bilddaten[y-1][x])/8;
_kopie[y][x]=(short)a;
}
}
_bilddaten=_kopie;
zeichneBild();
}
Wie gesagt, ich würde eher noch zwei zusätzliche Schleifen einbauen, die jeweils von -1 bis +1 gehen. Da kannst du dann auch einstellen, dass sie am Rand z.B. nur von 0 bis 1 oder -1 bis 0 gehen sollen und dann halt zählen, wie viele Pixel summiert wurden.
public void weichzeichnen()
{
short[][] _kopie = new short[_hoehe][_breite];
for (int y = 0; y < _hoehe; y++)
{
for (int x = 0; x < _breite; x++)
{
int sum = 0; // Summe der Pixelwerte
int count = 0; // Anzahl der Pixelwerte (normalerweise 8, am Rand 5, in den Ecken 3)
// Delta-Y Schleife von -1 bis +1 (Am Rand nur ab/bis 0)
for (int dy = (y>0?-1:0); dy <= (y<_hoehe-1?1:0); dy++) {
// Delta-X Schleife von -1 bis +1 (Am Rand nur ab/bis 0)
for (int dx = (x>0?-1:0); dx <= (x<_breite-1?1:0); dx++) {
// Eigenen Pixelwert ignorieren
if (dy != 0 || dx != 0) {
sum += _bilddaten[y + dy][x + dx];
count++;
}
}
}
_kopie[y][x] = (short) (sum/count);
}
}
_bilddaten = _kopie;
zeichneBild();
}
Woher wissen Sie, dass am Rand 5, in den Ecken 3 ist?
Ich kann kein Bild einfügen, um das zu verdeutlichen. In der Mitte des Bildes hast du halt 8 Pixel um jeden Pixel rum (3 Zeilen mal 3 Spalten minus den mittleren Pixel). Am Rand fehlt eine Zeile/Spalte, wodurch es nur noch 2*3-1 Pixel sind und in einer Ecke fehlt eine Zeile und eine Spalte. Also 2*2-1 Pixel. Und dann gibt es theoretisch noch Sonderfälle, wenn das Bild nur einen Pixel hoch oder breit ist.