Ich spiele aktuell damit, Informationen aus Bildern zu parsen.
Problem: Ich habe einen Satz unterschiedlicher Icons, bei denen der Hintergrund ausgenommen ist.
Diese Icons kommen irgendwo in einem größerem Bild vor (oder auch nicht). Teilweise können die Icons auch verdeckt sein.
Was mich interessiert ist das beste Matching der Bilder (hat z.B. das icon 30 Pixel, davon sind 10 nicht pink und es existiert eine Position im großen Bild, an der 8 von den 10 Pixeln exakt matchen, dann hätte ich gerne den Wert 8/10 heraus).
Im ersten Ansatz habe ich das kleine Bild über das große geschoben und dann Pixel für Pixel verglichen. Das funktioniert zwar super, aber ist auch krauchend langsam (>10 sekunden für den Vergleich von 20 300x12 bildern mit 10 12x12 icons)
Ich könnte mir gut vorstellen, dass es dazu schon bessere Lösungen gibt, bin beim suchen bis jetzt aber nur auf ähnliche (oder sehr abgehobene) Ansätze gestoßen.
Kleines KSKB mit 3 Testbildern:
import java.io.File;
import javax.imageio.ImageIO;
public class MatchingTryout {
private static final int TEMPLATE_COLOR = 0xffff00ff;
public static void main(String[] args) throws Exception {
BufferedImage image = ImageIO.read(new File("test1.png"));
BufferedImage icon1 = ImageIO.read(new File("test2.png"));
BufferedImage icon2 = ImageIO.read(new File("test3.png"));
System.out.println(maxMatch(image, icon1));
System.out.println(maxMatch(image, icon2));
}
private static double maxMatch(BufferedImage image, BufferedImage icon) {
double maxMatch = Double.MIN_VALUE;
// halbes icon über die seiten verschieben für abgeschnittene bilder
// (mehr als 50% verdeckt: kein matching)
for (int x = -icon.getWidth() / 2; x < image.getWidth()
+ icon.getWidth() / 2; x++) {
for (int y = -icon.getHeight() / 2; y < image.getHeight()
+ icon.getHeight() / 2; y++) {
double match = matchAt(image, x, y, icon);
if (match > maxMatch) {
maxMatch = match;
}
}
}
return maxMatch;
}
private static double matchAt(BufferedImage image, int x, int y,
BufferedImage icon) {
int matches = 0;
for (int ix = 0; ix < icon.getWidth(); ix++) {
for (int iy = 0; iy < icon.getHeight(); iy++) {
int currentX = ix + x;
int currentY = iy + y;
if (currentX >= 0 && currentX < image.getWidth()
&& currentY >= 0 && currentY < image.getHeight()) {
int rgb = icon.getRGB(ix, iy);
if (rgb != TEMPLATE_COLOR
&& image.getRGB(currentX, currentY) == rgb) {
matches++;
}
}
}
}
return (double) matches / realPixels(icon);
}
// nur zur demo, wert wird nicht jedes mal neu berechnet =)
private static int realPixels(BufferedImage image) {
int count = 0;
for (int x = 0; x < image.getWidth(); x++) {
for (int y = 0; y < image.getHeight(); y++) {
if (image.getRGB(x, y) == TEMPLATE_COLOR) {
count++;
}
}
}
return image.getWidth() * image.getHeight() - count;
}
}```
Bild
Icon1 (Matching 1.0)
Icon2 (Matching 0.7758620689655172)
Danke für Antworten :idea:
Gruß