Frage

Ich habe versucht, meinen eigenen Faltungsoperator zu machen, anstatt das eingebaute mit Java geliefert zu verwenden. Ich habe den eingebauten Faltungsoperator auf dieses Bild angewendetVerknüpfung

Mit dem eingebauten Faltungsoperator mit Gaußschen Filter habe ich dieses Bild erhalten.Verknüpfung

Jetzt führe ich das gleiche Bild mit meinem Code aus

public static int convolve(BufferedImage a,int x,int y){
 int red=0,green=0,blue=0;
      float[] matrix = { 
 0.1710991401561097f, 0.2196956447338621f, 0.1710991401561097f, 
 0.2196956447338621f, 0.28209479177387814f, 0.2196956447338621f, 
 0.1710991401561097f, 0.2196956447338621f, 0.1710991401561097f, 
 };
      for(int i = x;i<x+3;i++){
          for(int j = y;j<y+3;j++){
              int color = a.getRGB(i,j);
              red += Math.round(((color >> 16) & 0xff)*matrix[(i-x)*3+j-y]);
              green += Math.round(((color >> 8) & 0xff)*matrix[(i-x)*3+j-y]);
              blue += Math.round(((color >> 0) & 0xff)*matrix[(i-x)*3+j-y]);

          }
      }

    return (a.getRGB(x, y)&0xFF000000) | (red << 16) | (green << 8) | (blue);
}

Und das Ergebnis, das ich erzielte, ist das.Verknüpfung

Auch wie optimiere ich den Code, den ich geschrieben habe? Der eingebaute Faltungsbetreiber dauert 1 ~ 2 Sekunden, während mein Code auch dann 5 bis 7 Sekunden dauert!

Ich habe mein Quellbild beim Hochladen versehentlich gedreht. Also bitte ignoriere das.

War es hilfreich?

Lösung

Zunächst wandeln Sie Ihr Ergebnis von Float zu Int in jedem Zyklus der Schleife unnötig (und fälschlicherweise). Dein red, green und blue Sollte vom Typ Float sein und sollten erst nach der Faltung wieder zur Ganzzahl gegossen werden (wenn sie zurück zu RGB konvertiert werden):

  float red=0.0f, green = 0.0f, blue = 0.0f
  for(int i = x;i<x+3;i++){
      for(int j = y;j<y+3;j++){
          int color = a.getRGB(i,j);
          red += ((color >> 16) & 0xff)*matrix[(i-x)*3+j-y];
          green += ((color >> 8) & 0xff)*matrix[(i-x)*3+j-y];
          blue += ((color >> 0) & 0xff)*matrix[(i-x)*3+j-y];

      }
  }

return (a.getRGB(x, y)&0xFF000000) | (((int)red) << 16) | (((int)green) << 8) | ((int)blue);

Die Blutung der Farben in Ihrem Ergebnis wird verursacht, weil Ihre Koeffizienten in matrix sind falsch:

0.1710991401561097f + 0.2196956447338621f + 0.1710991401561097f + 
0.2196956447338621f + 0.28209479177387814f + 0.2196956447338621f +
0.1710991401561097f + 0.2196956447338621f + 0.1710991401561097f =

1.8452741

Die Summe der Koeffizienten in einer verwischenden Faltungsmatrix sollte 1,0 betragen. Wenn Sie diese Matrix auf ein Bild anwenden, erhalten Sie möglicherweise Farben, die über 255 sind. Wenn dies passiert, "bluten" in den nächsten Kanal (blau bis grün usw.). Ein völlig grünes Bild mit dieser Matrix würde zu:

 green = 255 * 1.8452741 ~= 471 = 0x01D7;
 rgb = 0xFF01D700;

Das ist ein weniger intensives Grün mit einem Hauch von Rot.

Sie können dies beheben, indem Sie die Koeffizienten durch teilen 1.8452741, aber du willst das sicherstellen:

 (int)(255.0f * (sum of coefficients)) = 255

Wenn nicht, müssen Sie eine Überprüfung hinzufügen, die die Größe der Kanäle auf 255 beschränkt, und lassen Sie sie sich nicht umwickeln. Z.B:

if (red > 255.0f)
   red = 255.0f;

In Bezug auf Effizienz/Optimierung:
Es könnte sein, dass der Geschwindigkeitsunterschied durch dieses unnötige Casting und Mathematik erklärt werden kann, aber ein wahrscheinlicherer Kandidat ist die Art und Weise, wie Sie auf das Bild zugreifen. Ich bin mit BufferedImage und Raster nicht vertraut genug, um Sie auf die effizienteste Weise zu beraten, um auf den zugrunde liegenden Bildpuffer zuzugreifen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top