# Optimierung beim Vergleichen von 2 Bildern



## raimannma (25. Jun 2018)

Hallo,

Ich habe diesen Code hier:

```
private static double getDifferencePercent(BufferedImage img1, BufferedImage img2) {
        int width = img1.getWidth();
        int height = img1.getHeight();
        int width2 = img2.getWidth();
        int height2 = img2.getHeight();
        if (width != width2 || height != height2) {
            throw new IllegalArgumentException(String.format("Images must have the same dimensions: (%d,%d) vs. (%d,%d)", width, height, width2, height2));
        }
        long diff = 0;
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                diff += pixelDiff(img1.getRGB(x, y), img2.getRGB(x, y));
            }
        }
        long maxDiff = 3L * 255 * width * height;
        return 100.0 * diff / maxDiff;
    }
    private static int pixelDiff(int rgb1, int rgb2) {
        int r1 = (rgb1 >> 16) & 0xff;
        int g1 = (rgb1 >>  8) & 0xff;
        int b1 =  rgb1        & 0xff;
        int r2 = (rgb2 >> 16) & 0xff;
        int g2 = (rgb2 >>  8) & 0xff;
        int b2 =  rgb2        & 0xff;
        return Math.abs(r1 - r2) + Math.abs(g1 - g2) + Math.abs(b1 - b2);
    }
```

Und der funktioniert auch so ohne Problem, wenn ich also

```
getDifferencePercent(img1,img2)
```
aufrufe bekomme ich eine Prozentzahl, die mir angibt wie unterschiedlich die Bilder sind.

Allerdings sollte das mehrere Male pro Sekunde aufgerufen werden.

Mein gesamtes Programm habe ich mit VisualVM (Profiler) analysiert.
Und dabei festgestellt, dass genau diese Methode

```
getDifferencePercent()
```
für lange Ladezeiten sorgt.

Deshalb ist meine Frage, ob und wie es möglich ist diesen Code zu optimieren.

Info:
Die Bilder die verglichen werden sind nicht in Farbe sondern nur Grau, vielleicht kann man damit etwas machen.


----------



## Java20134 (25. Jun 2018)

Du kannst definitiv schon einmal die Methode pixelDiff kürzen, wenn es nur Grauwerte sind. Und vielleicht probierst du es einmal mit Streams.


----------



## raimannma (25. Jun 2018)

Danke für die Antwort, aber ich weiß leider nicht wie ich pixelDiff kürzen kann.


----------



## NeuHier6 (25. Jun 2018)

Vielleicht ist es noch interessant zu wissen woher er das hat:
https://www.java-forum.org/thema/hs...plikator-ermitteln.181852/page-2#post-1156599

Gefragt wurde ich natürlich nicht danach.

Und jetzt zu der Frage:


raimannma hat gesagt.:


> Deshalb ist meine Frage, ob und wie es möglich ist diesen Code zu optimieren.


Es ist mögli die Programmiersprache zu wechseln, verstehst du?


----------



## raimannma (25. Jun 2018)

ja, aber was soll das bringen, wenn ich eine andere Programmiersprache benutze??


----------



## NeuHier6 (25. Jun 2018)

Besser als Klauen, ein Plagiat verstehst Du?


----------



## raimannma (25. Jun 2018)

NeuHier6 hat gesagt.:


> Besser als Klauen, ein Plagiat verstehst Du?


Nein verstehe ich nicht.

Also den Code den ich am anfang gepostet habe ist nicht direkt von mir, sondern von hier: http://rosettacode.org/wiki/Percentage_difference_between_images#Java

Aber ich weiß jetzt trotzdem noch nicht wie ich den code optimieren kann?


----------



## Thallius (25. Jun 2018)

Du kannst dir den raw buffer holen mit

Imagebuffer.getRaster().getDataBuffer().getData()

Dann kannst du direkt die Pixel 1:1 vergleichen und sparst dir den ganzen RGB Blödsinn.

Gruß

Claus


----------



## raimannma (25. Jun 2018)

Thallius hat gesagt.:


> Du kannst dir den raw buffer holen mit
> 
> Imagebuffer.getRaster().getDataBuffer().getData()
> 
> ...



Vielen Dank ich werde das mal testen, ob es etwas bringt.


----------



## thecain (25. Jun 2018)

R G und B müssten bei graustufen den selben wert haben. du könntest also 2 vergleiche sparen, bzw bei den raw pixeln werte überspringeb


----------



## mrBrown (26. Jun 2018)

NeuHier6 hat gesagt.:


> Vielleicht ist es noch interessant zu wissen woher er das hat:
> https://www.java-forum.org/thema/hs...plikator-ermitteln.181852/page-2#post-1156599
> 
> Gefragt wurde ich natürlich nicht danach.





NeuHier6 hat gesagt.:


> Besser als Klauen, ein Plagiat verstehst Du?



Du glaubst doch nicht wirklich, dass du er einzige bist, der so einen einfachen Vergleiche zwischen zwei Pixeln hinbekommt? 

Wäre nett, nicht gleich mit so haltlosen Unterstellungen zu kommen...


----------



## raimannma (26. Jun 2018)

thecain hat gesagt.:


> R G und B müssten bei graustufen den selben wert haben. du könntest also 2 vergleiche sparen, bzw bei den raw pixeln werte überspringeb


Soll das bedeuten, dass ich nur die Rotwerte vergleichen müsste?


----------



## Thallius (26. Jun 2018)

Wenn es wirklich nur für GRaustufen gehen muss ja. Frage ist warum du überhaupt einen RGB Buffer bekommst/nimmst wenn es nur ein Graustufenbild ist. Da würde ich eigentlich anfangen zu optimieren. Wenn Du nur ein Graustufenbild einlist hast du 1/3 weniger Daten die du laden und vergleichen musst. Das würde deutlich die Performance steigern.


----------



## mihe7 (26. Jun 2018)

Mal aus Interesse: wozu soll das eigentlich gut sein? Was sind das für Bilder?


----------



## Thallius (26. Jun 2018)

mihe7 hat gesagt.:


> Mal aus Interesse: wozu soll das eigentlich gut sein? Was sind das für Bilder?



Ich würde mal auf Überwachungskamera tippen um festzustellen ob sich was tut oder so.

Gruß

Claus


----------



## NeuHier6 (26. Jun 2018)

mrBrown hat gesagt.:


> Du glaubst doch nicht wirklich,


Glauben ist so eine Sache, ich würd ihn für die zukunft raten, NICHT weiter Sachen abzuschreiben. Aber das muss er wissen, welchen Preis das dann hat.


----------



## mrBrown (26. Jun 2018)

NeuHier6 hat gesagt.:


> Glauben ist so eine Sache, ich würd ihn für die zukunft raten, NICHT weiter Sachen abzuschreiben. Aber das muss er wissen, welchen Preis das dann hat.


Und dir würde ich raten, solche haltlosen Unterstellungen sein zu lassen 
Abgesehen davon ist der Code auch noch so unglaublich einfach, dass das vermutlich selbst wenn niemand ernsthaft als abschreiben bezeichnen würde... (und wenn doch: Die Worte "Glauben ist so eine Sache" hab ich auch schon mal gesagt, du solltest sowas nicht klauen  )


----------



## NeuHier6 (26. Jun 2018)

mrBrown hat gesagt.:


> und wenn doch: Die Worte "Glauben ist so eine Sache" hab ich auch schon mal gesagt,


ja es kommt dann darauf an, wer als erstes wann was gesagt hat.



mrBrown hat gesagt.:


> solche haltlosen Unterstellungen


Ich würd mir ja auch für ihn wünschen das ich unrecht behalte. Allerdings ist ein Pessimist Optimist mit Erfahrung und realistisch betrachtet wird das wohl nicht konsequenzfrei bleiben.

Aber was solls wiss. Arbeiten liegt nicht jedem.



mrBrown hat gesagt.:


> ist der Code auch noch so unglaublich einfach


So trivial ist es nicht, aber naja das ist deine meinung, die zählt nicht viel.


----------



## mihe7 (26. Jun 2018)

NeuHier6 hat gesagt.:


> ja es kommt dann darauf an, wer als erstes wann was gesagt hat.


Die vom TE angegebene Quelle enthält den Java-Code in der Form seit einem halben Jahr. Dein Post ist gerade mal etwas mehr als eine Woche her. Oh, oh... Ein Schelm, wer Böses dabei denkt.


----------



## AliasAlreadyTaken (27. Jun 2018)

1. Wenn du vermutest, daß das Bild in weiten Teilen ohnehin gleich ist, könntest du die Pixel zunächst auf Gleichheit prüfen, bevor du das Rechnen anfängst.

2. Du mußt irgendwo Abstriche machen bei der Qualität der Aussage. Also zB nur jeden zehnten Pixel überprüfen.

3. Klar, zwei von drei Farben weglassen bringt auch was. Der größte Zeitfresser ist aber eben, daß du wirklich jeden Pixel ankucken willst.

4. Du verwendest nicht ImageBuffer, sondern DataBufferByte

Vielleicht so:

Je nachdem, wie du SKIP einstellst, prüft er wirklich jede Farbe, nur die Graustufen oder eben noch seltener.

final int SKIP = 1 //echt jeden einzelnen Pixel
final int SKIP = 3 //nur Graustufen
final int SKIP = 12 //Graustufen und nur jeden vierten Pixel


```
private static double getDifferencePercent(BufferedImage img1, BufferedImage img2) {
        final int SKIP = 1;

        byte[] b1 = ((DataBufferByte) img1.getRaster().getDataBuffer()).getData();
        byte[] b2 = ((DataBufferByte) img2.getRaster().getDataBuffer()).getData();
  
        int size = b1.length;
  
        if (img1.getWidth() != img2.getWidth() || img1.getHeight() != img2.getHeight()) {
            throw new IllegalArgumentException(String.format("Images must have the same dimensions: (%d,%d) vs. (%d,%d)", img1.getWidth(), img1.getHeight(), img2.getWidth(), img2.getHeight()));
        }
        long diff = 0;
        int p1=0,p2=0;
  
        for (int p = 0;p < size; p+=SKIP) {
            p1 = ((int) b1[p] & 0xff);
            p2 = ((int) b2[p] & 0xff);
            diff += Math.abs(p1 - p2);
        }

        long maxDiff = 255 * size;
        return 100.0 * diff / maxDiff;
    }
```

Bei einem Bild mit 901x596 braucht diese Lösung mit SKIP=1 etwa 3,5% der Zeit, mit SKIP=3 sinds noch 1,7% und mit SKIP=12 sinds 0,8%


----------



## windl (3. Jul 2018)

Hallo,

ich verstehe nicht wozu man die Abweichung in % zu einem Bild benötigt welches sich nur auf Pixelebene bewegt.
Weil ich gedacht habe - ich denke nicht richtig - habe ich zwei unterschiedliche Bilder eingeladen. Beide Bilder haben wirklich nichts miteinander zu tun und haben dennoch eine Ähnlichkeit von über 41%. Was sagt mir jetzt diese Zahl?
Dann habe ich eines der Bilder verkleinert und künstlich mit einem schwarzen Rand wieder auf die Größe gebracht.
Diese Bilder haben optisch eine sehr hohe Änlichkeit - aber lt. Programm gerade einmal 35%.

Wenn es Dir nur darum geht - die Anzahl der RGB's zu vergleichen - dann laufe durch jedes Bild genau einmal und speichere diese Werte ab und vergleiche beim zweiten Aufruf nur noch diese!!

Das wäre mein Vorschlag um das zu optimieren.

Gruß
Uwe


----------



## mrBrown (3. Jul 2018)

windl hat gesagt.:


> Wenn es Dir nur darum geht - die Anzahl der RGB's zu vergleichen - dann laufe durch jedes Bild genau einmal und speichere diese Werte ab und vergleiche beim zweiten Aufruf nur noch diese!!


Was meinst du mit "Anzahl der RGB's vergleichen"?


----------



## windl (3. Jul 2018)

Du addierst die einzelnen Werte und  hast danach eine Summe.
Dann vergleichst Du R mit R / G mit G und B mit B.
Hat den Vorteil dass Du halt das Bild nicht immer neu scannen musst - denn die Informationen liegen ja schon vor.


----------



## AliasAlreadyTaken (3. Jul 2018)

Da bräuchten wir dann wohl mal die beiden Beispielbilder, um dir sagen zu könne, warum die so gleich (noch nichtmal ähnlich, sondern gleich) sind. Immerhin vergleichen wir da recht exakte Werte und noch nichtmal +-x zum RGB-Wert.

Aus der Summe läßt sich aber doch keine Ähnlichkeit ableiten? Nimm ein Bild 1 Pixel hoch und 200 Pixel breit. Mach die ersten 100 Pixel schwarz und die zweiten 100 machst du weiß.  Die Summe ist die gleiche wie wenn du das umgekehrt hast, nämlich die ersten 100 weiß und die letzten 100 schwarz. Die Bilder sind sich aber nicht grade ähnlich.

Oder möchtest du die beiden Arrays in eines summieren, also pixelErstesBild[1] + pixelZweitesBild[1] =pixelSumme[1], und dieses Array dann durchkucken??

Ansonsten kann ich mir das grad schwer vorstellen.


----------

