Montag, Januar 27, 2020

Bestimmen Sie, ob ein Bild vorhanden ist, in einem größeren Bild, und wenn dem so ist, finden es, mit Python

Brauche ich ein Python-Programm, dass ich arbeite, um in der Lage sein zu nehmen, ein kleines Bild, bestimmt, wenn es existiert, in einem größeren Bild, und wenn dem so ist, meldet seine Position. Wenn nicht, melden, die. (In meinem Fall das große Bild wird ein screenshot, und das kleine Bild ein Bild, das möglicherweise oder möglicherweise nicht auf dem Bildschirm, die in einem HTML5-canvas.) Suchen Sie on-line, fand ich heraus, über template-matching in OpenCV, die in der Tat hervorragende Python-bindings. Ich habe versucht, die folgenden, basierend auf sehr ähnlichen code, den ich gefunden auf Linie mit numpy sowie:

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)

Dieser nicht tut, was ich brauche, es zu tun, denn es gibt IMMER einen Punkt in dem größeren Bild, dem Punkt, wo das Spiel am nächsten ist, egal wie schrecklich ein Spiel es ist. Ich etwas will, der findet eine genaue, pixel für pixel entsprechen, der das kleinere Bild im größeren Bild, und wenn keiner vorhanden ist, wirft Sie eine Ausnahme, oder gibt False oder sowas. Und es muss Recht schnell erfolgen. Hat jemand eine gute Idee, wie dies zu tun?

  • Eine kurze Frage: kann man davon ausgehen, dass Ihre small Bild erscheint in der large Bild immer in Originalgröße und genau mit Ihrem original-Werte? Oder müssen Sie den Umgang mit Variablen Größe small Bilder, die möglicherweise interpolated und Griff illumination – Variationen? Ich meine, Sie erwähnen exact match ist es wirklich genau?
  • Sind Sie garantiert IMMER PNG format? Ich Frage beause JPEGs Unterziehen Quantisierung verlustfreie Kompression und verlustbehaftete Kompression und Dinge, die scheinbar identisch können unterscheiden sich in Ihrer internen Darstellung.
InformationsquelleAutor clj | 2015-04-16

2 Kommentare

  1. 17

    Werde ich vorschlagen, eine Antwort, die funktioniert schnell und perfekt, wenn Sie suchen für exact match sowohl in Größe und in der image-Werte.

    Die Idee ist die Berechnung eines brute-force-Suche von das wollte h x w Vorlage in einem größeren H x W Bild. Der bruteforce-Ansatz würde darin bestehen, sich auf alle möglichen h x w windows über das Bild und überprüfen Sie die pixel-by-pixel-Korrespondenz innerhalb der Vorlage. Dieses ist jedoch sehr rechenintensiv, kann aber beschleunigt werden.

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

    Mithilfe der smart integral-Bilder man berechnen kann wirklich schnell die Summe innerhalb eines h x w Fenster, beginnend an jedem pixel. Ein integraler Bild ist ein kombiniertes Bereich Tabelle (kumulativ summiert array) berechnet werden kann, mit numpy wirklich schnell:

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

    und es hat wirklich schöne Eigenschaften, wie zum Beispiel die Berechnung der Summe aller Werte in einem Fenster mit nur 4 arithmetische Operationen:

    Bestimmen Sie, ob ein Bild vorhanden ist, in einem größeren Bild, und wenn dem so ist, finden es, mit Python

    So, durch die Berechnung der Summe der Vorlage und Abgleich mit der Summe der h x w windows über die integrierte Bild, es ist leicht zu finden, eine Liste von „möglichen windows“, wo die Summe der inneren Werte ist die gleiche wie die Summe der Werte in der 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

    Oben ist ein numpy Vektorisierung der Betrieb der in der Abbildung für alle möglichen h x w Rechtecke auf dem Bild (also wirklich schnell).

    Dies verringert eine Menge der Anzahl der möglichen Fenster (2 in einem meiner tests). Der Letzte Schritt wäre zu prüfen, wird nach exakten übereinstimmungen mit der Vorlage:

    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 Sie, dass hier y und x Koordinaten beziehen sich auf den Einen Punkt im Bild, wird die vorhergehende Zeile und Spalte der Vorlage.

    Setzen alle zusammen:

    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")

    Funktioniert es mit beiden Graustufen-und Farbbilder und läuft in 7ms für eine 303x384 Farb-Bild mit einem 50x50 Vorlage.

    Einem Beispiel aus der Praxis:

    >>> 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 ilustrate das Ergebnis:

    Bestimmen Sie, ob ein Bild vorhanden ist, in einem größeren Bild, und wenn dem so ist, finden es, mit Python

    Links Originalbild, rechts die Vorlage. Und hier 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)

    Bestimmen Sie, ob ein Bild vorhanden ist, in einem größeren Bild, und wenn dem so ist, finden es, mit Python

    Und letzten, nur ein Beispiel für die possible_matches für den test:

    Bestimmen Sie, ob ein Bild vorhanden ist, in einem größeren Bild, und wenn dem so ist, finden es, mit Python

    Die Summe über die beiden Fenster im Bild ist die gleiche, aber der Letzte Schritt der Funktion Filter, die nicht exakt der Vorlage.

    • Das war GENAU das was ich brauchte. Es funktioniert in der Tat perfekt, und es ist sehr schnell. Ich danke Ihnen sehr!
    • Ihr willkommen! Froh, dass Sie es nützlich finden.
    • Aber in diesem Fall, die beiden Bilder haben die gleiche Quelle. Also die pixel-Werte werden gleich sein. Was, wenn ich das Bild in „tpl“ aus einer anderen Quelle? Wird es auch in diesem Fall?
    • Wenn es aus einer anderen Quelle, das problem ist anders. Sie sind auf der Suche für template-matching und andere Lösungen gibt (z.B. die normalisierte Kreuz-Korrelation). Allerdings ist der code oben könnte ein Stück verändert zurück der patch mit der kleinsten Summe Unterschied eher als die genaue Summe. Hoffe, es hilft!
    • np.logical_and(*[...]) – erwarten Sie np.logical_and zu nehmen, eine beliebige Anzahl von Dingen zu UND gemeinsam? NumPy ufuncs nicht so funktioniert. Bist du eigentlich angeben das Dritte element in der Liste als array an Stelle der Ausgabe, und nicht als ein array auf UND zusammen. Die ufunc reduce – Methode könnte helfen: np.logical_and.reduce([...]) (keine *) statt np.logical_and(*[...]).
    • Diese Funktion ist toll, aber ich habe festgestellt, bug, wo die Nadel das Bild wird nicht gefunden, wenn es ganz oben oder ganz linken Seite der Heuhaufen-Bild, d.h. seine x oder y 0 ist. Die einzige Lösung, die ich mir ausgedacht habe, denn es ist ziemlich hacky: Verwenden Sie cv2 erstellen einen 1px Rand entlang der oberen und linken Ränder des haystack-Bild, bevor der Suche nach der Nadel.
    • Sie verwenden konnte, Polsterung für, dass ohne die Notwendigkeit von cv2: img = np.pad(img, ((1,0), (1,0), (0,0)), mode='constant') (Syntax vielleicht ein wenig off, Im von Handy und kippe es zu überprüfen). Aber danke für das lassen Sie mich wissen! Ist ein schnelles und schönes Update 🙂

  2. 2

    Da Sie sind zufrieden mit OpenCV, ich würde vorschlagen, dass Sie beginnen mit dem, was Sie bereits getan haben, und Holen Sie sich die besten match. Sobald Sie die Lage des best match, können Sie überprüfen, dass es tatsächlich ein gutes Spiel.

    Überprüfen, dass es ist ein gutes Spiel sollte so einfach wie extrahieren der passenden Bild und dem Vergleich mit der Vorlage. Extrahieren Sie das Bild, das Sie möglicherweise verwenden müssen cv2.minMaxLoc(result) – und Prozess-Ausgang. Die Extraktion-Methode scheint davon abzuhängen, wie die verwendete Methode für den Vergleich der Bilder und ist fertig mit Beispiele hier.

    Sobald Sie extrahiert haben, das Bild, Sie sollte in der Lage sein, Sie zu vergleichen mit numpy.allclose oder eine andere Methode.

Kostenlose Online-Tests