2016-09-25 4 views
1

Ich muss Gaussian Blur in Java für 3x3, 5x5 und 7x7 Matrix implementieren. Können Sie mich korrigieren, wenn ich falsch:Java: Implementierung von Gaußscher Unschärfe

  1. Ich habe eine Matrix (M) 3x3 (Mittelwert M (0, 0)):

    1 2 1 
    2 4 2 
    1 2 1 
    
  2. ich ein Pixel nehmen (P) aus dem angezeigten Bild und für jedes nächste pixel:

    s = M(-1, -1) * P(-1, -1) + M(-1, 0) * P(-1, 0) + ... + M(1, 1) * P(1, 1) 
    
  3. an dann Division es Gesamtwert der Matrix:

    P'(i, j) = s/M(-1, -1) + M(-1, 0) + ... + M(1, 1) 
    

Das ist alles, was mein Programm tut. Ich lasse extreme Pixel unverändert.

Mein Programm:

for(int i = 1; i < height - 1; i++){ 
    for(int j = 1; j < width - 1; j++){ 
     int sum = 0, l = 0; 
     for(int m = -1; m <= 1; m++){ 
      for(int n = -1; n <= 1; n++){ 
       try{ 
        System.out.print(l + " "); 
        sum += mask3[l++] * Byte.toUnsignedInt((byte) source[(i + m) * height + j + n]); 
       } catch(ArrayIndexOutOfBoundsException e){ 
        int ii = (i + m) * height, jj = j + n; 
        System.out.println("Pixels[" + ii + "][" + jj + "] " + i + ", " + j); 
        System.exit(0); 
       } 
      } 
      System.out.println(); 
     } 
     System.out.println(); 
     output[i * width + j] = sum/maskSum[0]; 
    } 
} 

ich source von einem BufferedImage wie folgt aus:

int[] source = image.getRGB(0, 0, width, height, null, 0, width); 

So für dieses Bild: Picture before

Ergebnis ist folgendes: Picture after

Können Sie mich beschreiben, Was ist falsch an meinem Programm?

+2

Welche Art ist Ihr 'source' und' output', können wir sehen ein Erklärung für sie? Weil Sie in byte.toUnsignedInt ((byte) source [(i + m) * height + j + n]) eine Umwandlung in Byte vornehmen und ich kann nicht glauben, dass Ihr Farbbild ein Pixel in ein einzelnes Byte paßt . Jede Abschneidung erlaubt Ihnen einen Wert von maximal 255, der - wenn er in einen RGB-Farbraum mit drei Bytes/Sample konvertiert wird - erklären würde, warum Ihr Ergebnis blau ist (d. H. Die R- und G-Komponenten fehlen). –

+0

'int [] source = image.getRGB (0, 0, width, height, null, 0, width);' 'output' ist eine Kopie von' source', also muss ich 3 mal filtern? Für R und G? Wie kann ich es tun? – Wiszen

+1

Der beste Weg, um individuelle r, g und b Werte zu erhalten, ist die Verwendung eines (ColorModel) [https://docs.oracle.com/javase/7/docs/api/java/awt/image/ColorModel.html] Wenn Sie wissen, wie die Daten gespeichert sind, können Sie die 4 Bytes aus dem int-Wert für das Pixel extrahieren. r = rgbVal & 0xff, g = (rgbVal >> 8) & 0xff etc. –

Antwort

1

Zunächst ist Ihre Formel zur Berechnung des Index im Quell-Array falsch. Die Bilddaten werden in dem Array eine Pixelreihe nach der anderen gespeichert. Daher ist der Index x und y wird berechnet wie folgt angegeben:

index = x + y * width 

Darüber hinaus sind die Farbkanäle in verschiedenen Bits des int gespeichert sind, können nicht einfach tun, die Berechnungen mit der ganzen int, da diese Kanäle andere Kanäle beeinflussen können.

Die folgende Lösung sollte funktionieren (auch wenn es nur die Pixel an den Grenzen transparent Blätter):

public static BufferedImage blur(BufferedImage image, int[] filter, int filterWidth) { 
    if (filter.length % filterWidth != 0) { 
     throw new IllegalArgumentException("filter contains a incomplete row"); 
    } 

    final int width = image.getWidth(); 
    final int height = image.getHeight(); 
    final int sum = IntStream.of(filter).sum(); 

    int[] input = image.getRGB(0, 0, width, height, null, 0, width); 

    int[] output = new int[input.length]; 

    final int pixelIndexOffset = width - filterWidth; 
    final int centerOffsetX = filterWidth/2; 
    final int centerOffsetY = filter.length/filterWidth/2; 

    // apply filter 
    for (int h = height - filter.length/filterWidth + 1, w = width - filterWidth + 1, y = 0; y < h; y++) { 
     for (int x = 0; x < w; x++) { 
      int r = 0; 
      int g = 0; 
      int b = 0; 
      for (int filterIndex = 0, pixelIndex = y * width + x; 
        filterIndex < filter.length; 
        pixelIndex += pixelIndexOffset) { 
       for (int fx = 0; fx < filterWidth; fx++, pixelIndex++, filterIndex++) { 
        int col = input[pixelIndex]; 
        int factor = filter[filterIndex]; 

        // sum up color channels seperately 
        r += ((col >>> 16) & 0xFF) * factor; 
        g += ((col >>> 8) & 0xFF) * factor; 
        b += (col & 0xFF) * factor; 
       } 
      } 
      r /= sum; 
      g /= sum; 
      b /= sum; 
      // combine channels with full opacity 
      output[x + centerOffsetX + (y + centerOffsetY) * width] = (r << 16) | (g << 8) | b | 0xFF000000; 
     } 
    } 

    BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); 
    result.setRGB(0, 0, width, height, output, 0, width); 
    return result; 
} 
int[] filter = {1, 2, 1, 2, 4, 2, 1, 2, 1}; 
int filterWidth = 3; 
BufferedImage blurred = blur(img, filter, filterWidth); 
+0

Vielen Dank! Diese Arbeit ist so gut :) – Wiszen