Implementierung eines Glasfilters für Bilder
Dies ist Übung 3.1.39. aus dem Buch Informatik Ein interdisziplinärer Ansatz von Sedgewick & Wayne:
Schreiben Sie ein Programm, das den Namen einer Bilddatei als Befehlszeilenargument verwendet und einen Glasfilter anwendet: Setzen Sie jedes Pixel p auf die Farbe eines zufälligen benachbarten Pixels (dessen Pixelkoordinaten sich beide um höchstens 5 von den Koordinaten von p unterscheiden).
Hier ist mein Programm:
import java.awt.Color;
public class test
{
public static int[] chooseRandomNeighbor(int i, int j)
{
int[] chosenNeighbor = new int[2];
double r = Math.random();
if (r < 1.0/8.0)
{
chosenNeighbor[0] = i-1;
chosenNeighbor[1] = j-1;
}
else if (r < 2.0/8.0)
{
chosenNeighbor[0] = i-1;
chosenNeighbor[1] = j;
}
else if (r < 3.0/8.0)
{
chosenNeighbor[0] = i-1;
chosenNeighbor[1] = j+1;
}
else if (r < 4.0/8.0)
{
chosenNeighbor[0] = i;
chosenNeighbor[1] = j+1;
}
else if (r < 5.0/8.0)
{
chosenNeighbor[0] = i+1;
chosenNeighbor[1] = j+1;
}
else if (r < 6.0/8.0)
{
chosenNeighbor[0] = i+1;
chosenNeighbor[1] = j;
}
else if (r < 7.0/8.0)
{
chosenNeighbor[0] = i+1;
chosenNeighbor[1] = j-1;
}
else if (r < 8.0/8.0)
{
chosenNeighbor[0] = i;
chosenNeighbor[1] = j-1;
}
return chosenNeighbor;
}
public static Picture filter(Picture picture)
{
int width = picture.width();
int height = picture.height();
Picture filteredPicture = new Picture(width,height);
// the following four for-loops make the dead frame
for (int row = 0; row < height; row++)
{
Color color = picture.get(0,row);
filteredPicture.set(0,row,color);
}
for (int row = 0; row < height; row++)
{
Color color = picture.get(width-1,row);
filteredPicture.set(width-1,row,color);
}
for (int col = 0; col < width; col++)
{
Color color = picture.get(col,0);
filteredPicture.set(col,0,color);
}
for (int col = 0; col < width; col++)
{
Color color = picture.get(col,height-1);
filteredPicture.set(col,height-1,color);
}
// the real filtering takes place here
for (int col = 1; col < width-1; col++)
{
for (int row = 1; row < height-1; row++)
{
int[] chosenNeighbor = chooseRandomNeighbor(row,col);
Color color = picture.get(chosenNeighbor[1],chosenNeighbor[0]);
filteredPicture.set(col,row,color);
}
}
return filteredPicture;
}
public static void main(String[] args)
{
Picture picture = new Picture(args[0]);
Picture filteredPicture = filter(filter(filter(filter(picture))));
filteredPicture.show();
}
}
Picture ist eine einfache API, die von den Autoren des Buches geschrieben wurde. Ich habe mein Programm überprüft und es funktioniert. Hier ist eine Instanz davon:
Input (Bild von James McAvoy aus Wikipedia , der im Film Glass gespielt hat ):
Ausgabe:
Gibt es eine Möglichkeit, mein Programm zu verbessern?
Danke für Ihre Aufmerksamkeit.
Antworten
Interessante Übung und nette Umsetzung, einige Vorschläge auf meiner Seite:
- Die Methode
chooseRandomNeighborwird nur von verwendetfilterund kann daher auf festgelegt werdenprivate - Der Name
filterist zu allgemein für eine Methode, ein besserer Name könnte seinapplyGlassFilter - In Java beginnt der Name einer Klasse mit einem Großbuchstaben
Optimierung
zufälliges benachbartes Pixel (dessen Pixelkoordinaten sich beide um höchstens 5 von den p-Koordinaten unterscheiden).
Die Methode chooseRandomNeighborwählt einen benachbarten zufälligen Nachbarn aus (der sich um höchstens 1 unterscheidet) und wird dann viermal aufgerufen. Das bedeutet, dass 4 vollständige Bilder im Speicher erstellt werden. Wäre es nicht besser, direkt einen Nachbarn mit maximaler Entfernung 5 auszuwählen?
Dazu muss die Methode chooseRandomNeighbordie Breite oder Höhe akzeptieren:
int neighborColIndex = chooseRandomNeighbor(col,width);
int neighborRowIndex = chooseRandomNeighbor(row,height);
Und das wird chooseRandomNeighborüberarbeitet:
private static int chooseRandomNeighbor(int index, int max) {
// Random delta between -5 and +5
int randomDelta = (int) ((Math.random() * (10)) - 5);
// Add delta to index without overflowing the limit
int neighborIndex = (index + randomDelta) % max;
// If index is negative return 0
return neighborIndex < 0 ? 0 : neighborIndex;
}
Jetzt kann die Methode filternur noch einmal aufgerufen werden und nur das neue Bild wird im Speicher erstellt.
Randnotiz : Sie werden immer besser, machen Sie weiter so!
Code überarbeitet
public class Test {
public static Picture applyGlassFilter(Picture inputPicture) {
int width = inputPicture.width();
int height = inputPicture.height();
Picture outputPicture = new Picture(width, height);
for (int col = 0; col < width; col++) {
for (int row = 0; row < height; row++) {
int neighborColIndex = chooseRandomNeighbor(col,width);
int neighborRowIndex = chooseRandomNeighbor(row,height);
Color c = inputPicture.get(neighborColIndex,neighborRowIndex);
outputPicture.set(col, row, c);
}
}
return outputPicture;
}
private static int chooseRandomNeighbor(int index, int max) {
// Random delta between -5 and +5
int randomDelta = (int) ((Math.random() * (10)) - 5);
// Add delta to index without overflowing the limit
int neighborIndex = (index + randomDelta) % max;
// If index is negative return 0
return neighborIndex < 0 ? 0 : neighborIndex;
}
public static void main(String[] args) {
Picture inputPicture = new Picture(args[0]);
Picture outputPicture = applyGlassFilter(inputPicture);
outputPicture.show();
}
}