Diskrete Faltung (Matrix) Randfälle

bling10

Mitglied
Hallo zusammen :)

Grob gesagt möchte ich Bilder (PGM-Datei) filtern, und zwar so:
Ich habe ein Eingabebild (2d-Array). Auf diese Matrix wird dann eine Kernelmatrix angewendet.
Dabei wird jeder Pixel des Ursprungsbildes durch eine Linearkombination seiner Nachbarschaft und sich selbst ersetzt. Die Einträge der Kernelmatrix stellen dabei die Gewichte dieser Linearkombination dar. Bezeichnen wir A als Ausgangsbild und mit A(i,j) den Pixel in der i-ten Zeile und in der j-ten Spalte, dann ist die diskrete Faltung definiert als: A ∶= B ∗ K. Die neuen Pixelwerte des Ausgangsbildes berechnen sich durch:


A(i, j) = ∑ ∑ B(i + x − a1, j + y − a2) ⋅ K(x, y), Summezeichen: jeweils von x=1 (y=1) nach n


In der Formel oben steht dabei n für die Filtergröße, a1 für die x-Koordinate und a2 für die y-Koordinate des Kernelmittelpunktes.

Hilfreicher Link: hier

Ich hab nun eine Methode linearFilter(Image image, float [][] kernel) wobei Image ein Objekt mit folgenden fertigen Methoden ist: getData() liefert float[][], getHeight(), getWidth, getPixel(height,width), setPixel(float value, int heigth, int width).

so sieht nun meine linearFilter-Methode aus:
Java:
    /**
     * This method implements a linear filter with discrete convolution
     *
     * @param image  the image which should be filtered
     * @param kernel the kernel used for the linear filter
     * @return the filtered image
     */
    public Image linearFilter(Image image, float[][] kernel) {

        Image filtered = image.clone();

        // TODO
        int n = kernel[0].length; // erlaubt, da kernel immer nxn
        int i = 0;
        int j = 0;
        int x = 0;
        int y = 0;
        int a1 = (int) Math.floor(n / 2);
        int a2 = (int) Math.floor(n / 2);

        for (i = 0; i < filtered.getData().length; i++) {
            for (j = 0; j < filtered.getData()[0].length; j++) {
                for (x = 0; x < n; x++) {
                    for (y = 0; y < n; y++) { 
                        filtered.getData()[i][j] = image.getData()[i + x - a1][j + y - a2] * kernel[x][y];
                    }
                }
            }
        }
        return filtered;
    }

So weit so gut. Das GROßE PROBLEM und meine Frage:
Ich soll den Bildrand folgendermaßen Behandeln:
Für Pixelwerte am Rand ist der Kernel eventuell zu groß und greift ins Leere. Dafür wird eine sogenannte Randbehandlungsstrategie benötigt. Die Werte außerhalb des Bildrandes werden dann einfach dem Wert des örtlich nöchsten Nachbarns auf dem Bildrand gleichgesetzt. Betrachten Sie folgende für diesen Spezialfall.
12933


Ich hab verstanden was zu tun ist, aber keine (sinnvolle/ absehbar lösbare) Idee wie ich dies nun umsetzen kann. Ein 2d-Array hat ja keine "-1"-Indizes, wo ich einfach die werte reinpacken kann. Und eine neue Matrix mit zwei dimensionen größer (für 3x3 Kernel, anders wenn dieser 5x5 oder so ist) mit erstellen, wo das bild in der "mitte" ist stell ich mir auch schwierig vor, sodass ich dann den kernel nicht ab [0][0] laufen lassen muss.

Hätte jemand dafür eine idee und stimmt mein Ansatz soweit?
Tausend Dank für jede Antwort!
 

httpdigest

Top Contributor
Einfach als Koordinate `max(0, min(imageWidth-1, x))` (und analog für die y Koordinate) verwenden.
Du kannst also selbstverständlich nicht einfach das Bildarray bei `[i + x - a1][j + y - a2]` lesen, sondern musst die Koordinaten entsprechend beschränken.
 

thecain

Top Contributor
entweder "vergrösserst" du das ursprungsbild und kopierst die Randpixel oder du behandelst die Fälle wenn dein Index negativ oder grösser als das Array wäre.

Oder versteh ich die Frage falsch?
 

bling10

Mitglied
entweder "vergrösserst" du das ursprungsbild und kopierst die Randpixel oder du behandelst die Fälle wenn dein Index negativ oder grösser als das Array wäre.

Oder versteh ich die Frage falsch?
Ja das wäre auch meine Idee aber ich weiß nicht wie ich das umsetzten soll. Der Kernel kann ja auch größer als 3x3 sein und dann müsste man auch einen dementsprechend großen rand bauen oder?
 

httpdigest

Top Contributor
Aber die randfälle sollen auch berechnet werden oder verstehe ich dich falsch?
Das "Clampen" der Indizes sorgt ja gerade dafür, dass die Randfälle immer auf den nähesten gültigen Index gehen und somit auch die Randfälle (darum geht es ja gerade) korrekt berechnet werden...
Wenn du also auf Arrayfeld [-1][-1] zugreifen würdest, sorgt das Clamping dafür, dass du eben auf [0][0] zugreifst.

EDIT: Oder das ganze als Code:
Java:
...
int width = filtered.getData().length;
int height = filtered.getData()[0].length;
for (i = 0; i < width; i++) {
  for (j = 0; j < height; j++) {
    for (x = 0; x < n; x++) {
      for (y = 0; y < n; y++) { 
        int ix = i + x - a1; // <- wie in deinem Code
        int iy = j + y - a2; // <- wie in deinem Code
        int cix = Math.max(0, Math.min(ix, width - 1)); // <- Index auf gültige Positionen beschränken
        int ciy = Math.max(0, Math.min(iy, height - 1)); // <- Index auf gültige Positionen beschränken
        filtered.getData()[i][j] = image.getData()[cix][ciy] * kernel[x][y];
      }
    }
  }
}
 
Zuletzt bearbeitet:

bling10

Mitglied
Das "Clampen" der Indizes sorgt ja gerade dafür, dass die Randfälle immer auf den nähesten gültigen Index gehen und somit auch die Randfälle (darum geht es ja gerade) korrekt berechnet werden...
Wenn du also auf Arrayfeld [-1][-1] zugreifen würdest, sorgt das Clamping dafür, dass du eben auf [0][0] zugreifst.

EDIT: Oder das ganze als Code:
Java:
...
int width = filtered.getData().length;
int height = filtered.getData()[0].length;
for (i = 0; i < width; i++) {
  for (j = 0; j < height; j++) {
    for (x = 0; x < n; x++) {
      for (y = 0; y < n; y++) {
        int ix = i + x - a1; // <- wie in deinem Code
        int iy = j + y - a2; // <- wie in deinem Code
        int cix = Math.max(0, Math.min(ix, width - 1)); // <- Index auf gültige Positionen beschränken
        int ciy = Math.max(0, Math.min(iy, height - 1)); // <- Index auf gültige Positionen beschränken
        filtered.getData()[i][j] = image.getData()[cix][ciy] * kernel[x][y];
      }
    }
  }
}
Danke @httpdigest aber meine Tests dazu laufen leider nicht durch..

Das wären die Tests:
Code:
public class ImageFilterStudentTest {

    Filter filter = new Filter();
    static Image beer;
    static Image cat;
    static Image mandarine;
    static Image cow;
    static float[][] sharpKernel = { { 0, -1, 0 }, { -1, 5, -1 }, { 0, -1, 0 } };
    static float[][] blurKernel = { { 1 * 1 / 16f, 2 * 1 / 16f, 1 * 1 / 16f },
            { 2 * 1 / 16f, 4 * 1 / 16f, 2 * 1 / 16f }, { 1 * 1 / 16f, 2 * 1 / 16f, 1 * 1 / 16f } };

    @Test
    public void testLinearFilterNormal() {
        Image beer_sharp = filter.linearFilter(beer, sharpKernel);
        Image cat_blur = filter.linearFilter(cat, blurKernel);
        assertEquals(26, beer_sharp.getPixel(10, 10), 0f);
        assertEquals(21,beer_sharp.getPixel(56, 34), 0f);
        assertEquals(140,cat_blur.getPixel(77, 77), 0f);
        assertEquals(93,cat_blur.getPixel(33, 11), 0f);
    }

    @Test
    public void testLinearFilterEdge() {
        Image beer_blur = filter.linearFilter(beer, blurKernel);
        Image cat_sharp = filter.linearFilter(cat, sharpKernel);
        assertEquals(25, beer_blur.getPixel(0, 0), 0f);
        assertEquals(24, beer_blur.getPixel(47, 0), 0f);
        assertEquals(54, cat_sharp.getPixel(cat_sharp.getHeight() - 1, cat_sharp.getWidth() - 1), 0f);
        assertEquals(86, cat_sharp.getPixel(0, cat_sharp.getWidth() - 1), 0f);
    }

    @Test
    public void testLinearFilterPicture() throws IOException {
        Path mandarineBlurPath = Paths.get("Mandarine_blur.pgm");
        Image mandarine_blur_solution = new Image(mandarineBlurPath);
        Image mandarine_blur = filter.linearFilter(mandarine, blurKernel);
        assertArrayEquals(mandarine_blur.getData(),mandarine_blur_solution.getData());
    }
}

Und für z.B. den testLinearFilterNormal kommt dieser Failure

12934

LG!
 

httpdigest

Top Contributor
Aha. Es ist offensichtlich unmöglich, ohne den kompletten zu testenden Code, den kompletten Testcode und die Testdaten irgendeinen Fehler zu reproduzieren. Du wirst wohl selber schauen müssen.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
I matrix aufgabe Java Basics - Anfänger-Themen 22
L Zweidimensionaler Array; n x m - Matrix überprüfuen Java Basics - Anfänger-Themen 35
C Matrix mit Array ausgeben Java Basics - Anfänger-Themen 6
idontknow707 Matrix nach z.B. Variable durchsuchen Java Basics - Anfänger-Themen 4
F Adjunkte Matrix erstellen Java Basics - Anfänger-Themen 3
M Matrix Java Basics - Anfänger-Themen 3
F Matrix Multiplikation Java Basics - Anfänger-Themen 3
B Dünn besetzte Matrix Java Basics - Anfänger-Themen 7
Al3xand3r01 Matrix, Nachbarelemente Java Basics - Anfänger-Themen 16
E Rückwärtsmultiplikation einer invertierten matrix Java Basics - Anfänger-Themen 2
U Dreiecks-Matrix mit Array Java Basics - Anfänger-Themen 3
Z Matrix Klasse mit Mehrdimensionalen Array (Addition, Multiplikation, to String) Java Basics - Anfänger-Themen 57
E 2D Array - char durch die Matrix "wandern" lassen Java Basics - Anfänger-Themen 7
M Matrix auf 4 Elemente untersuchen mit offenen Enden Java Basics - Anfänger-Themen 8
M Matrix Elemente vergleichen Java Basics - Anfänger-Themen 11
N Quadratische Matrix inkl Summe Java Basics - Anfänger-Themen 8
J Methoden Moving a n integer matrix Java Basics - Anfänger-Themen 3
D Methoden Matrix Multiplikation Java Basics - Anfänger-Themen 27
O Matrix, Vektor Java Basics - Anfänger-Themen 9
H 2D Array, Symmetrische Matrix Java Basics - Anfänger-Themen 12
S Matrix spaltenweise befüllen Java Basics - Anfänger-Themen 1
T Zufällige Matrix in neue Matrix schreiben Java Basics - Anfänger-Themen 6
C Matrix-Werte werden nicht wie erwartet ausgegeben Java Basics - Anfänger-Themen 7
C Matrix erstellen Spaltensumme, Zeilensumme, Diagonale Java Basics - Anfänger-Themen 1
S Methoden Transponierte Matrix Java Basics - Anfänger-Themen 3
N Vererbung Submatrix mit Verweis auf Matrix erstellen Java Basics - Anfänger-Themen 9
J Matrix erstellen Java Java Basics - Anfänger-Themen 7
B Transponiertes Matrix Java Basics - Anfänger-Themen 12
J Überprüfen, ob eine 2D Matrix ein Baum ist Java Basics - Anfänger-Themen 5
C Matrix transponieren - Hilfe Java Basics - Anfänger-Themen 1
D Ausgabe einer Matrix mit System.out.println Java Basics - Anfänger-Themen 6
T Art 4 Felder Matrix Memory Java Basics - Anfänger-Themen 2
U Ist diese Methode zur Matrix Vektor Multiplikation korrekt ? Java Basics - Anfänger-Themen 5
L Matrix(Array) minimieren... Java Basics - Anfänger-Themen 9
E Matrix mit Vektor multiplizieren Java Basics - Anfänger-Themen 7
S eingegebene Matrix anzeigen Java Basics - Anfänger-Themen 4
J Matrix für Schachbrett Java Basics - Anfänger-Themen 6
G tga Datei lesen und in eine matrix umwandeln Java Basics - Anfänger-Themen 1
G Bilddaten in Matrix umwandeln Java Basics - Anfänger-Themen 1
T Eine String Matrix erstellen die eine boolean Funtion verwendet Java Basics - Anfänger-Themen 10
O Matrix Multiplizieren Java Basics - Anfänger-Themen 4
S LWJGL - Matrix vom Matrixstack laden Java Basics - Anfänger-Themen 3
T Matrix auf Symmetrie überprüfen Java Basics - Anfänger-Themen 6
V Matrix Transponieren Java Basics - Anfänger-Themen 3
V Methoden Matrix als 1D Array mit Werten füllen Java Basics - Anfänger-Themen 12
W Zweidimensionale Arrays als Matrix ausgeben Java Basics - Anfänger-Themen 8
R Matrix-Vektor-Multiplikation Java Basics - Anfänger-Themen 13
O Matrix ordnen Java Basics - Anfänger-Themen 4
M Symmetrische Matrix Java Basics - Anfänger-Themen 2
W Methoden Rang von einer Matrix mit Gauss Java Basics - Anfänger-Themen 0
U Matrix Subtrahieren Java Basics - Anfänger-Themen 12
E Input/Output convert string to two dimensional char and output = matrix Java Basics - Anfänger-Themen 2
A daten vom 1d array in 2d matrix speichern Java Basics - Anfänger-Themen 3
I Matrix überprüfen Java Basics - Anfänger-Themen 8
Z Matrix mit Vektor multiplizieren Java Basics - Anfänger-Themen 13
K Methoden Einlesen einer unbegrenzten Matrix über Konsole Java Basics - Anfänger-Themen 6
O Einlesen einer Matrix von der Console Java Basics - Anfänger-Themen 18
N Matrix/Vektoren Java Basics - Anfänger-Themen 3
N Matrix Java Basics - Anfänger-Themen 14
T Methode, die eine 2 dimensionale Matrix kopiert. Java Basics - Anfänger-Themen 16
J Matrix Java Java Basics - Anfänger-Themen 3
D 2 mehrdimensionale Matrix einlesen Java Basics - Anfänger-Themen 2
A N*N Matrix Determinante berechnen Java Basics - Anfänger-Themen 47
K Quadratische Matrix um 90° drehen Java Basics - Anfänger-Themen 5
C Programm zur Berechnung der Spur einer Matrix Java Basics - Anfänger-Themen 4
B Zeilenumbruch (zweidim. Matrix) Java Basics - Anfänger-Themen 2
O Java Matrix mal Matrix über while Schleife... Java Basics - Anfänger-Themen 10
O Transponieren einer Matrix per While-Schleife Java Basics - Anfänger-Themen 3
M Matrix - Probelm Java Basics - Anfänger-Themen 7
O 2D Matrix befüllen mit geraden Zahlen!? Java Basics - Anfänger-Themen 14
J Java Matrix befüllen Java Basics - Anfänger-Themen 5
M Matrix Matrix Multiplikation Java Basics - Anfänger-Themen 6
F Matrix Java Basics - Anfänger-Themen 11
E Array als Matrix Java Basics - Anfänger-Themen 21
G OOP Parameter Matrix Java Basics - Anfänger-Themen 2
N Matrix Klasse Java Basics - Anfänger-Themen 4
B Maske an eine Matrix anpassen Java Basics - Anfänger-Themen 5
W Matrix übergeben Java Basics - Anfänger-Themen 7
T Matrix transponieren Java Basics - Anfänger-Themen 17
W Eine Methode schreiben, ob eine Matrix eine Diagonalmatrix ist.? Java Basics - Anfänger-Themen 3
M String Datei in Float-Matrix umwandeln Java Basics - Anfänger-Themen 8
D Problem: Werte eine Matrix vergleichen! Java Basics - Anfänger-Themen 5
B Matrix Java Basics - Anfänger-Themen 2
Semox Matrix multiplizieren Java Basics - Anfänger-Themen 4
N Matrix an toString Java Basics - Anfänger-Themen 7
C Diagonale in einem NxN Matrix Java Basics - Anfänger-Themen 6
F Einträgen von Matrix zu sotieren Java Basics - Anfänger-Themen 2
D JUnit auf Matrix anwenden Java Basics - Anfänger-Themen 5
J Spezielle Matrix ausgeben ! Java Basics - Anfänger-Themen 8
S Problem bei Matrix Addition Java Basics - Anfänger-Themen 5
F matrix werte übergeben Java Basics - Anfänger-Themen 5
M Hauptdiagonale Matrix berechnen Java Basics - Anfänger-Themen 6
M Klassenerstellung für Matrix mit Rechenopperationen Java Basics - Anfänger-Themen 42
D Matrix .bat datei erstellen und öffnen Java Basics - Anfänger-Themen 2
J Matrix ausgeben Java Basics - Anfänger-Themen 9
N Matrix Matrix Produkt Java Basics - Anfänger-Themen 7
N prüfe ob etwas in einer Matrix steht... Java Basics - Anfänger-Themen 14
L rechtecke zeichnen anhand von matrix Java Basics - Anfänger-Themen 27
J Matrix aus Datei einlesen mit StreamTokenizer Java Basics - Anfänger-Themen 3
K Transponiere Matrix Java Basics - Anfänger-Themen 4

Ähnliche Java Themen

Neue Themen


Oben