2015-04-16 5 views
5

Ich brauche ein Python-Programm, an dem ich arbeite, um ein kleines Bild zu machen, festzustellen, ob es in einem größeren Bild existiert. und wenn ja, melden Sie seinen Standort. Wenn nicht, melde das. (In meinem Fall ist das große Bild ein Screenshot und das kleine Bild ein Bild, das in einem HTML5-Canvas auf dem Bildschirm sein kann oder nicht.) In der Online-Version habe ich in OpenCV etwas über das Template-Matching herausgefunden habe ausgezeichnete Python-Bindungen. Ich habe versucht, die folgenden, basierend auf sehr ähnlichen Code, den ich auf der Linie gefunden, mit numpy auch:Bestimmen Sie, ob ein Bild in einem größeren Bild existiert, und wenn es so ist, finden Sie es mit Python

import cv2 
import numpy as np 
image = cv2.imread("screenshot.png") 
template = cv2.imread("button.png") 
result = cv2.matchTemplate(image,template,cv2.TM_CCOEFF_NORMED) 
StartButtonLocation = np.unravel_index(result.argmax(),result.shape) 

dies nicht tun, was ich brauche, es zu tun, weil es immer einen Punkt, in dem größeren Bild zurückkehrt; der Punkt, wo das Spiel am nächsten ist, egal wie schrecklich es ist. Ich möchte etwas, das eine exakte Pixel-zu-Pixel-Übereinstimmung des kleineren Bildes im größeren Bild findet, und wenn keine existiert, löst eine Ausnahme aus oder gibt False oder etwas Ähnliches zurück. Und es muss ziemlich schnell sein. Hat jemand eine gute Idee, wie man das macht?

+1

Eine kurze Frage: können Sie davon ausgehen, dass Ihr 'kleines' Bild im' großen' Bild immer in seiner Originalgröße und exakt mit seinen Originalwerten erscheint? Oder Sie müssen sich mit "kleinen" Bildern von variabler Größe beschäftigen, die "interpoliert" werden und "Beleuchtungs" -Variationen behandeln können? Ich meine, du nennst 'exact match', ist das wirklich genau? –

+2

Garantieren Sie IMMER das 'PNG' Format? Ich frage, ob 'JPEG's Quantisierung und verlustbehaftete Komprimierung erfahren und scheinbar identische Dinge sich in ihrer internen Darstellung unterscheiden können. –

Antwort

14

Ich werde eine Antwort vorschlagen, die schnell und perfekt funktioniert, wenn Sie sowohl in Größe als auch in Bildwerten nach exact match suchen.

Die Idee ist es, eine Brute-Force-Methode der wollte h x wVorlage in einem größeren H x W Bild zu berechnen. Der Bruteforce-Ansatz würde darin bestehen, alle möglichen h x w Fenster über dem Bild zu betrachten und Pixel für Pixel innerhalb der Vorlage zu überprüfen. Dies ist jedoch sehr rechenintensiv, kann jedoch beschleunigt werden.

im = np.atleast_3d(im) 
H, W, D = im.shape[:3] 
h, w = tpl.shape[:2] 

Durch die intelligente integral images eine Verwendung kann innerhalb eines h x w Fenster wirklich schnell die Summe berechnen bei jedem Pixel zu starten. Integraler Bild ist eine summierte Bereichstabelle (kumulativ summiert Array), die wirklich mit numpy berechnet werden kann schnell wie:

sat = im.cumsum(1).cumsum(0) 

und es hat wirklich schöne Eigenschaften, wie die Berechnung der Summe aller Werte innerhalb ein Fenster mit nur vier arithmetischen Operationen:

From wikipedia

Somit wird durch die Summe der Vorlage zu berechnen und sie mit der Summe aus h x w Fenstern über das integrale Bild übereinstimmt, ist es einfach, eine Liste von „möglich zu finden Fenster ", wobei die Summe der inneren Werte gleich der Summe der Werte in t ist Die Vorlage (eine schnelle Annäherung).

iA, iB, iC, iD = sat[:-h, :-w], sat[:-h, w:], sat[h:, :-w], sat[h:, w:] 
lookup = iD - iB - iC + iA 

Das Vorstehende ist eine numpy Vektorisierung des Betriebes in dem Bild für alle möglichen h x w Rechtecken auf das Bild gezeigt (also wirklich schnell).

Dies wird die Anzahl der möglichen Fenster (auf 2 in einem meiner Tests) viel reduzieren. Der letzte Schritt wäre für genaue Übereinstimmungen mit der Schablone zu überprüfen:

posible_match = np.where(np.logical_and.reduce([lookup[..., i] == tplsum[i] for i in range(D)])) 
for y, x in zip(*posible_match): 
    if np.all(im[y+1:y+h+1, x+1:x+w+1] == tpl): 
     return (y+1, x+1) 

beachten, das hier y und x Koordinaten an den A-Punkt in dem Bild entsprechen, das die vorherige Zeile und Spalte der Vorlage ist.

alle zusammen Putting:

def find_image(im, tpl): 
    im = np.atleast_3d(im) 
    tpl = np.atleast_3d(tpl) 
    H, W, D = im.shape[:3] 
    h, w = tpl.shape[:2] 

    # Integral image and template sum per channel 
    sat = im.cumsum(1).cumsum(0) 
    tplsum = np.array([tpl[:, :, i].sum() for i in range(D)]) 

    # Calculate lookup table for all the possible windows 
    iA, iB, iC, iD = sat[:-h, :-w], sat[:-h, w:], sat[h:, :-w], sat[h:, w:] 
    lookup = iD - iB - iC + iA 
    # Possible matches 
    possible_match = np.where(np.logical_and.reduce([lookup[..., i] == tplsum[i] for i in range(D)])) 

    # Find exact match 
    for y, x in zip(*possible_match): 
     if np.all(im[y+1:y+h+1, x+1:x+w+1] == tpl): 
      return (y+1, x+1) 

    raise Exception("Image not found") 

Es arbeitet sowohl mit Graustufen- und Farbbilder und läuft in 7ms für eine 303x384 Farbbild mit einer 50x50 Vorlage.

Ein praktisches Beispiel:

>>> from skimage import data 
>>> im = gray2rgb(data.coins()) 
>>> tpl = im[170:220, 75:130].copy() 

>>> y, x = find_image(im, tpl) 
>>> y, x 
(170, 75) 

Und das Ergebnis mitströmen:

enter image description here

Left Originalbild, rechts die Vorlage. Und hier ist die genaue Übereinstimmung:

>>> fig, ax = plt.subplots() 
>>> imshow(im) 
>>> rect = Rectangle((x, y), tpl.shape[1], tpl.shape[0], edgecolor='r', facecolor='none') 
>>> ax.add_patch(rect) 

und zuletzt nur ein Beispiel für die possible_matches für den Test:

enter image description here

Die Summe über die beiden Fenster im Bild das gleiche, aber der letzte Schritt der Funktion filtert denjenigen, der nicht genau mit der Vorlage übereinstimmt.

+0

Das war genau das, was ich brauchte. Es funktioniert tatsächlich perfekt und es ist sehr schnell. Vielen Dank! – clj

+0

@clj Ihre Begrüßung! Froh, dass Sie es nützlich finden. –

+0

Aber in diesem Fall haben die zwei Bilder die gleiche Quelle. Die Pixelwerte sind also gleich. Was passiert, wenn ich das Bild in "tpl" von einer anderen Quelle bekomme? Wird es auch in diesem Fall funktionieren? – Neelesh

1

Da Sie mit OpenCV zufrieden sind, würde ich vorschlagen, dass Sie mit dem beginnen, was Sie bereits getan haben und die beste Übereinstimmung erhalten. Sobald Sie den Ort der besten Übereinstimmung gefunden haben, können Sie überprüfen, ob es tatsächlich eine gute Übereinstimmung ist.

Die Überprüfung, ob es eine gute Übereinstimmung ist, sollte so einfach sein wie das Entnehmen des passenden Bildes und den Vergleich mit der Vorlage. Um das Bild zu extrahieren, müssen Sie möglicherweise cv2.minMaxLoc(result) verwenden und die Ausgabe verarbeiten. Die Extraktionsmethode scheint von der für den Vergleich der Bilder verwendeten Methode abzuhängen und wird mit Beispielen here durchgeführt. Wenn Sie das Bild extrahiert haben, sollten Sie in der Lage sein, sie unter Verwendung von numpy.allclose oder einer anderen Methode zu vergleichen.

Verwandte Themen