[Python] Geben Sie den Bereich des Bildes durch Ziehen der Maus an

Was du machen willst

"Geben Sie den Bereich vom Bild an" an, den Sie häufig mit Trimmwerkzeugen usw. sehen. Ich möchte dies durch Ziehen der Maus beim Anzeigen der Richtlinie ermöglichen. ↓ Das Bild sieht so aus ↓ 画像領域取得デモ.gif

Umgebung

Windows10 Home Python3.8.2(32bit) Visual Studio Code 1.45.1

Was ich studiert habe (Flow)

  1. Zeigen Sie ein beliebiges Bild im tkinter-Fenster an
  2. Zeichnen Sie ein Rechteck auf das angezeigte Bild
  3. Transformieren Sie das Rechteck durch Ziehen der Maus
  4. Rufen Sie die Koordinateninformationen des Rechtecks ab

1. Zeigen Sie ein beliebiges Bild im tkinter-Fenster an

In diesem Beispiel planen wir, ein Rechteck (Richtlinie) für den Screenshot zu zeichnen. Machen Sie daher zuerst einen Screenshot mit screenhot () der pyautogui-Bibliothek. Da das vorbereitete Bild nicht wie in tkinter verwendet werden kann, ** verwenden Sie ImageTk.PthoImage, um es in ein Format zu konvertieren, das in tkinter angezeigt werden kann **. img_tk = ImageTk.PhotoImage(img) (Beachten Sie, dass diese Konvertierung einen Fehler wie "Zu früh konvertieren!" Ausgibt, es sei denn, es ist nach Tk ()) (ImageTk ist eine Pillow-Methode, daher muss sie separat importiert werden.)

Erstellen Sie anschließend mit tkinter ein Canvas-Widget und platzieren Sie das Bild darin.

canvas1 = tkinter.Canvas(root, bg="black", width=img.width, height=img.height)
canvas1.create_image(0, 0, image=img_tk, anchor=tkinter.NW)

Canvas wird nicht automatisch an das Bild angepasst. Daher müssen Sie die Widget-Größe so angeben, dass sie mit dem Bild übereinstimmt.

Die Option "Anker" von create_image gibt an, "wo das zu platzierende Bild basieren soll". Der Wert wird als tkinter. und Nord, Süd, Ost und West geschrieben, und das Bild ist N: Nord ⇒ Nord = oben. Schreiben Sie außer N W: links, S: unten, E: rechts, MITTE: Mitte. Im Fall des Beispiels wird NW = oben links im Bild von img_tk bei x-Koordinate = 0 und y-Koordinate = 0 platziert (angegeben durch das erste und zweite Argument).

2. Zeichnen Sie ein Rechteck auf das angezeigte Bild

Geben Sie zunächst an, was passiert, wenn Sie mit dem Ziehen auf Canvas beginnen.

Leinwand Widget.bind("<ButtonPress-1>", <Rückruffunktion>)

Die Verarbeitung der Richtlinienzeichnung erfolgt in der aufgerufenen Rückruffunktion. (Rechteck bedeutet Rechteck)

Canvas-Widget.create_rectangle(X-Koordinate des Startpunktes,Y-Koordinate des Startpunktes,X-Koordinate des Endpunkts,Y-Koordinate des Endpunkts, outline="Linienfarbe" ,tag="Verlinke den Namen")

Da das gezeichnete Rechteck später transformiert wird, muss der Tag-Name mit der Option "Tag" angegeben werden.

Wenn das Argument event beim Deklarieren der Rückruffunktion angegeben wird, in event.x, event.y Da Sie die Mauskoordinaten zum Zeitpunkt des Klickens erhalten können, setzen Sie diesen Wert auf die Startpunktkoordinaten (der Endpunkt ist angemessen).

3. Transformieren Sie das Rechteck durch Ziehen der Maus

Geben Sie als Nächstes die Operation an, wenn sich die Maus beim Ziehen mit Canvas bewegt.

Canvas-Widget.bind("<Button1-Motion>", <Rückruffunktion>)

Beschreiben Sie den Prozess der Transformation der Richtlinie in der aufgerufenen Rückruffunktion.

Canvas-Widget.coords("Tag-Name der zu transformierenden Figur",X-Koordinate des Startpunktes,Y-Koordinate des Startpunktes,X-Koordinate des Endpunkts,Y-Koordinate des Endpunkts)

Sie können die Größe der gezeichneten Figur mit ändern. (Koordinaten scheinen Koordination zu bedeuten) Beim Ändern der Rechteckgröße durch Ziehen habe ich auf die folgenden zwei Unregelmäßigkeiten geachtet.

① Was tun, wenn nach links oder über den Startpunkt gezogen wird?

Wenn Sie die aktuellen Grafikkoordinaten auf die Koordinaten des Startpunkts einstellen, ohne an irgendetwas zu denken, Es verursacht einen Fehler, wenn sich die ziehende Maus nach links oder über den Startpunkt bewegt. .. (Die Koordinateninformationen des Startpunkts werden nach dem Ziehen in die Koordinaten umgeschrieben.) 画像領域取得失敗2デモ.gif Durch Speichern der Koordinateninformationen in der globalen Variablen beim Klicken mit der Maus und Verwenden dieses Werts als Startpunktkoordinate zum Zeitpunkt des erneuten Zeichnens Verhinderner Austausch ↓

#Ereignis beim Ziehen beginnt- - - - - - - - - - - - - - - - - - - - - - - - - - 
def start_point_get(event):
    global start_x, start_y #Deklariert, um in globale Variablen zu schreiben
    :
(Zeichnung)
    :
    #Speichern Sie Koordinaten in globalen Variablen
    start_x, start_y = event.x, event.y

#Ereignisse werden gezogen- - - - - - - - - - - - - - - - - - - - - - - - - - 
def rect_drawing(event):
      :
    # "rect1"Tag-Bild neu zeichnen
    canvas1.coords("rect1", start_x, start_y, event.x, event.y)
(2) Was tun, wenn die Maus den Bildschirmbereich verlässt?

In diesem Fall bleiben die Koordinaten der Bildschirmkante erhalten, wenn die Maus den Zeichenbereich verlässt. Abhängig davon, ob die Mauskoordinaten "Zeichenbereich (0 <x ≤ Bildbreite)", "außerhalb des Zeichenbereichs (x <0)" oder "außerhalb des Zeichenbereichs (Breite <x)" sind. Sie müssen die Endpunktkoordinaten neu schreiben. Sie können zwei if-Anweisungen überlappen, aber dieses Mal habe ich versucht, den Code mithilfe der min-Funktion zu verkürzen. (Wenn Sie es neu anordnen, können Sie die Max-Funktion verwenden.)

    if event.x < 0:
        end_x = 0 #Setzen Sie 0, wenn die erfassten Koordinaten 0 oder weniger sind
    else:
        end_x = min(img.width, event.x) #Stellen Sie die Breite des Bildes oder die erfassten Koordinaten ein, je nachdem, welcher Wert kleiner ist

4. Rufen Sie die Koordinateninformationen des Rechtecks ab

Geben Sie die Operation an, damit die Koordinaten erfasst werden können, wenn das Ziehen abgeschlossen ist.

Canvas-Widget.bind("<ButtonRelease-1>", <Rückruffunktion>)

Sie können die oben beschriebene "Koordinaten" -Methode verwenden, um die Koordinaten der Figur zu erhalten.

start_x, start_y, end_x, end_y =Canvas-Widget.coords("Verlinke den Namen")

In diesem Fall ist es schwierig, einen Vollbild-Screenshot im tk-Fenster anzuzeigen Ich zeige eine etwas reduzierte Version an und zeichne ein Rechteck darüber. Wenn Sie also Koordinaten mit realer Größe erhalten möchten, müssen Sie die durch "Koordinaten" erhaltenen Koordinaten mit der Verkleinerungsvergrößerung multiplizieren. Dieses Mal habe ich die Listeneinschlussnotation verwendet und den Code so kurz wie möglich geschrieben.

    start_x, start_y, end_x, end_y = [
        round(n * RESIZE_RETIO) for n in canvas1.coords("rect1")]

Das Obige ist eine Reihe von Schritten. Danke für deine harte Arbeit.

Code abgeschlossen

import tkinter
import time
import pyautogui  #Externe Bibliothek
from PIL import Image, ImageTk  #Externe Bibliothek

RESIZE_RETIO = 2 #Regulierung des Reduktionsverhältnisses

#Ereignis beim Ziehen beginnt- - - - - - - - - - - - - - - - - - - - - - - - - - 
def start_point_get(event):
    global start_x, start_y #Deklariert, um in globale Variablen zu schreiben

    canvas1.delete("rect1")  #Bereits"rect1"Löschen Sie eine beliebige Tag-Form

    #Zeichnen Sie ein Rechteck auf Leinwand1 (Rechteck bedeutet Rechteck)
    canvas1.create_rectangle(event.x,
                             event.y,
                             event.x + 1,
                             event.y + 1,
                             outline="red",
                             tag="rect1")
    #Speichern Sie Koordinaten in globalen Variablen
    start_x, start_y = event.x, event.y

#Ereignisse werden gezogen- - - - - - - - - - - - - - - - - - - - - - - - - - 
def rect_drawing(event):

    #Verarbeitung, wenn der Mauszeiger beim Ziehen den Bereich verlässt
    if event.x < 0:
        end_x = 0
    else:
        end_x = min(img_resized.width, event.x)
    if event.y < 0:
        end_y = 0
    else:
        end_y = min(img_resized.height, event.y)

    # "rect1"Tag-Bild neu zeichnen
    canvas1.coords("rect1", start_x, start_y, end_x, end_y)

#Ereignis, wenn das Ziehen losgelassen wird- - - - - - - - - - - - - - - - - - - - - - - - - - 
def release_action(event):

    # "rect1"Stellen Sie die Koordinaten des Tag-Bilds wieder auf den ursprünglichen Maßstab ein
    start_x, start_y, end_x, end_y = [
        round(n * RESIZE_RETIO) for n in canvas1.coords("rect1")
    ]

    #Zeigen Sie die erfassten Koordinaten an
    pyautogui.alert("start_x : " + str(start_x) + "\n" + "start_y : " +
                    str(start_y) + "\n" + "end_x : " + str(end_x) + "\n" +
                    "end_y : " + str(end_y))

#Hauptverarbeitung- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
if __name__ == "__main__":

    #Aufnahme des anzuzeigenden Bildes (Screenshot)
    img = pyautogui.screenshot()
    #Bildgröße ändern, da das Screenshot-Bild nicht angezeigt werden kann
    img_resized = img.resize(size=(int(img.width / RESIZE_RETIO),
                                   int(img.height / RESIZE_RETIO)),
                             resample=Image.BILINEAR)

    root = tkinter.Tk()
    root.attributes("-topmost", True) #Stellen Sie das tkinter-Fenster immer in den Vordergrund

    #Bildkonvertierung, damit sie mit tkinter angezeigt werden kann
    img_tk = ImageTk.PhotoImage(img_resized)

    #Zeichen-Leinwand-Widget
    canvas1 = tkinter.Canvas(root,
                             bg="black",
                             width=img_resized.width,
                             height=img_resized.height)
    #Zeichnen Sie das aufgenommene Bild im Canvas-Widget
    canvas1.create_image(0, 0, image=img_tk, anchor=tkinter.NW)

    #Platzieren Sie das Canvas-Widget und legen Sie verschiedene Ereignisse fest
    canvas1.pack()
    canvas1.bind("<ButtonPress-1>", start_point_get)
    canvas1.bind("<Button1-Motion>", rect_drawing)
    canvas1.bind("<ButtonRelease-1>", release_action)

    root.mainloop()

Zukunftspläne

Nachdem wir nun eine Schnittstelle haben, um den Bereich des Bildes festzulegen, möchte ich ihn mit verschiedenen Werkzeugen verbinden. Zum Beispiel ein Tool, das "kontinuierlich aus dem Screenshot-Bildschirm herausschneidet ⇒ zum aktuellen Zeitpunkt als Name speichert" Tools wie "OCR aus angegebenem Bereich". Nicht nur der Screenshot-Bildschirm, sondern auch Tools zum Verarbeiten von Bildern in der Zwischenablage können interessant sein.

Die Seite, die ich als Referenz verwendet habe

Transformiere das auf der Python-Leinwand angezeigte Rechteck

Recommended Posts

[Python] Geben Sie den Bereich des Bildes durch Ziehen der Maus an
Entfernen Sie den Rahmen aus dem Bild
Bildverarbeitung mit Python (Pillow)
Rufen Sie die Bing Image Search API v5 von Python auf, um Bilder zu sammeln
Suchen Sie mit Pythonista3 nach einem Bild von der Kamerarolle
Verwenden Sie Python-Code, um die Körperhaltung durch Öffnen des USB-Kamerabilds zu erkennen
Existenz aus Sicht von Python
Verwenden Sie die Flickr-API von Python
Schneiden wir das Gesicht aus dem Bild
Python3> Liste aus iterierbarer> Liste erstellen (Bereich (5))
[Python Kivy] So erhalten Sie den Dateipfad durch Ziehen und Ablegen
[Python] Geben Sie den Bildbereich an und wenden Sie OCR (Automatic Monitor Recording Device) an.
[Python] Senden Sie das von der Webkamera aufgenommene Bild an den Server und speichern Sie es
[Python] Legen Sie den Diagrammbereich mit matplotlib fest
Bildverarbeitung durch Python 100 Knock # 1 Kanalersatz
[Python] Visualisieren Sie die von Wireshark erfassten Informationen
Notizen vom Anfang von Python 1 lernen
Effektives Python-Memo Punkt 10 Aufzählung aus der Reichweite
Graustufen durch Matrix-Reinventor der Python-Bildverarbeitung-
Bildverarbeitung mit Python 100 Knock # 6 Farbreduktionsverarbeitung
Bildaufnahme von der Kamera mit Python + OpenCV
Lesen Sie die Datei Zeile für Zeile mit Python
Lesen Sie die Datei Zeile für Zeile mit Python
Starten Sie den Python-Interpreter über Git Bash
Pandas des Anfängers, vom Anfänger, für den Anfänger [Python]
Analyse des Röntgenmikrotomographiebildes durch Python
Ab Python 3.4 wird pip zum Standardinstallationsprogramm! ??
Notizen vom Anfang von Python 2 lernen
[Python] Holen Sie sich die Hauptfarbe aus dem Screenshot
Stellen Sie die von Eigen of C ++ erstellte Bibliothek mit Boost.Numpy in Python zur Verfügung.
Flächenextraktionsmethode mit dem Zellautomaten Versuchen Sie die Flächenextraktion aus dem Bild mit Growcut (Python).
Suchen Sie die Position im Originalbild anhand der Koordinaten nach der affinen Konvertierung (Python + OpenCV).
Wenn Sie mit der Maus über Matplotlib fahren, wird das entsprechende Bild angezeigt.
[Python] Laden Sie das Originalbild von der Google Bildsuche herunter
Holen Sie sich den Inhalt von Git Diff aus Python
Die erste Web-App, die von Python-Anfängern erstellt wurde
Ich habe versucht, das Bild mit Python + OpenCV zu "differenzieren"
Bildverarbeitung von Grund auf mit Python (5) Fourier-Transformation
Laden Sie Bilder aus einer Textdatei herunter, die die URL enthält
Was ist im Docker Python-Image pfeifend?
Geben Sie die ausführbare Python-Datei an, die mit virtualenv verwendet werden soll
Angeben des Bereichs von Ruby- und Python-Arrays
[Python] Sortieren Sie die Tabelle nach sort_values (pandas DataFrame)
Bildverarbeitung von Grund auf mit Python (4) Konturextraktion
Bildverarbeitung? Die Geschichte, Python für zu starten
Ich habe versucht, das Bild mit Python + OpenCV zu "binarisieren"
So löschen Sie die von Python ausgegebenen Zeichen
Ich habe versucht, das Datetime-Modul von Python zu verwenden
[Python numpy] Geben Sie den Index des Arrays dynamisch an
Bildverarbeitung mit Python 100 Knock # 11 Glättungsfilter (Durchschnittsfilter)
Lesen Sie mit Python Zeile für Zeile aus der Datei
Verwenden Sie das nghttp2 Python-Modul von Homebrew aus pyenvs Python
Rufen Sie Polly aus dem AWS SDK für Python auf
Versuchen Sie, direkt von Python 3 aus auf die YQL-API zuzugreifen
[Python + OpenCV] Malen Sie den transparenten Teil des Bildes weiß
Objektverfolgung mit OpenCV3 und Python3 (Verfolgung von Funktionspunkten, die mit der Maus mithilfe der Lucas-Kanade-Methode festgelegt wurden)