Bild öffnen und Name in Variable speichern

Fragen zu Tkinter.
Antworten
lucas97de
User
Beiträge: 3
Registriert: Montag 8. Juni 2020, 14:17

Hallo zusammen,

ich bin gerade dabei eine kleine Testanlage zu bauen. Das Ziel dieser ist die Bestimmung eines Farbanteils in einem Bild.
Der Code hierfür funktioniert ohne Probleme.
Das Problem das ich jetzt habe, ist folgendes:

Am Ende soll die Anlage von Leuten benutzt werden, die keine Ahnung haben von Python (ich eigentlich auch nicht).
Derzeit muss man in meinem Code noch jedes mal das Bild manuell eintippen. Da können natürlich schnell Fehler passieren...

Ich habe mir erhofft, dass es eine Möglichkeit gibt, eine Oberfläche zu schaffen, die quasi den Explorer öffnet und man dann ein Bild
anklicken kann, welches dann auch automatisch in meinen Code übernommen wird.

Hat dafür jemand Tipps? Ich habe bisher nicht viel Erfahrung mit Python und noch weniger mit Oberflächen..

Vielen Dank!


Mein bisheriger Code:

Code: Alles auswählen

import cv2
import numpy as np


img = cv2.imread("Testbild 5%.jpg")

hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

lower_range = np.array([100, 50, 50])
upper_range = np.array([130, 255, 255])

mask = cv2.inRange(hsv, lower_range, upper_range)

img_size =img.size/3

# cv2.imshow("Image", img)
# cv2.imshow("Mask", mask)


pixels = cv2.countNonZero(mask)
Ratio = ((100/img_size)*pixels)

print("Das gesamte Bild besteht aus",round(img_size), "Pixeln")
print("Das Bild beinhaltet", pixels, "blaue Pixel")
print("Der Blauanteil beträgt damit: ",round(Ratio,2), "Prozent")

cv2.waitKey(0)
cv2.destroyAllWindows()

Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@lucas97de: Anmerkungen zum Quelltext: Namen sollten nicht kryptisch abgekürzt werden. Wenn man `image` meint, sollte man nicht `img` schreiben.

`mask` könnte man besser benennen, so das der Leser auch weiss was die Maske bedeutet.

`image_size` ist irreführend weil es nicht `image.size` entspricht, sondern die Anzahl der Pixel beschreiben soll. Den Wert sollte man auch nicht runden müssen, zumal man `round()` nicht verwendet um eine Anzeige auf eine bestimmte Anzahl von Nachkommastellen zu begrenzen. Dafür gibt es die Formatanweiungen bei den Platzhaltern bei der Zeichenkettenformatierung.

`pixels` enthält eine Anzahl und keine Pixel, und welche Pixel das sind könnte man auch in den Namen schreiben.

Prozent und Verhältnis sind unterschiedliche Werte. Also ist entweder `ratio` falsch benannt, oder es wird dort der falsche Wert zugewiesen. Ich würde es bei Verhältnis lassen und dann später bei der Ausgabe die Formatierung für Prozent verwenden. Namen schreibt man zudem klein_mit_unterstrichen. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase).

Zwischenstand:

Code: Alles auswählen

#!/usr/bin/env python3
import cv2
import numpy as np


def main():
    show_image = False
    
    image = cv2.imread("Testbild 5%.jpg")
    blue_pixels_mask = cv2.inRange(
        cv2.cvtColor(image, cv2.COLOR_BGR2HSV),
        np.array([100, 50, 50]),
        np.array([130, 255, 255]),
    )
    total_pixel_count = image.size // 3
    
    if show_image:
        cv2.imshow("Image", image)
        cv2.imshow("Mask", blue_pixels_mask)

    blue_pixel_count = cv2.countNonZero(blue_pixels_mask)
    blue_ratio = blue_pixel_count / total_pixel_count

    print(f"Das gesamte Bild besteht aus{total_pixel_count} Pixeln.")
    print(f"Das Bild beinhaltet {blue_pixel_count} blaue Pixel.")
    print(f"Der Blauanteil beträgt damit: {blue_ratio:0.2%}.")

    if show_image:
        cv2.waitKey(0)
        cv2.destroyAllWindows()


if __name__ == "__main__":
    main()
Eine Datei wird man wohl am einfachsten mit dem `tkinter.filedialog`-Modul vom Benutzer erfragen können.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
lucas97de
User
Beiträge: 3
Registriert: Montag 8. Juni 2020, 14:17

Danke schonmal fürs aufräumen von dem Code :)

Mit:

Code: Alles auswählen

a = Tk()

def mfileopen():
    file1 = filedialog.askopenfile()
    label=Label(text=file1).pack()
button = Button(text="open file", command=mfileopen).pack()


a.mainloop()
kann ich ein den Pfad von dem Bild in file1 speichern. Aber wie kann ich von außerhalb der Funktion darauf zugreifen?

Bild
Zuletzt geändert von lucas97de am Dienstag 9. Juni 2020, 09:26, insgesamt 1-mal geändert.
Benutzeravatar
peterpy
User
Beiträge: 188
Registriert: Donnerstag 7. März 2013, 11:35

Hallo Lucas97de,
gib deiner Funktion ein

Code: Alles auswählen

return file1
mit
und greife dann auf die Funktion zu.
Gruss
Peter
lucas97de
User
Beiträge: 3
Registriert: Montag 8. Juni 2020, 14:17

So? Dann schmeißt er mir diesen Fehler:
File "C:/Python/Code/venv/Blautest.py", line 45, in <module>
main()
File "C:/Python/Code/venv/Blautest.py", line 20, in main
image = cv2.imread(mfileopen())
SystemError: <built-in function imread> returned NULL without setting an error

Code: Alles auswählen

import cv2
import numpy as np
from tkinter import *
from PIL import ImageTk, Image
from tkinter import filedialog

a = Tk()

def mfileopen():
    file1 = filedialog.askopenfile()
    label=Label(text=file1).pack()
    return file1

button = Button(text="open file", command=mfileopen).pack()


def main():
    show_image = False

    image = cv2.imread(mfileopen())
    blue_pixels_mask = cv2.inRange(
        cv2.cvtColor(image, cv2.COLOR_BGR2HSV),
        np.array([100, 50, 50]),
        np.array([130, 255, 255]),
    )
    total_pixel_count = image.size // 3

    if show_image:
        cv2.imshow("Image", image)
        cv2.imshow("Mask", blue_pixels_mask)

    blue_pixel_count = cv2.countNonZero(blue_pixels_mask)
    blue_ratio = blue_pixel_count / total_pixel_count

    print(f"Das gesamte Bild besteht aus{total_pixel_count} Pixeln.")
    print(f"Das Bild beinhaltet {blue_pixel_count} blaue Pixel.")
    print(f"Der Blauanteil beträgt damit: {blue_ratio:0.2%}.")

    if show_image:
        cv2.waitKey(0)
        cv2.destroyAllWindows()


if __name__ == "__main__":
    main()


a.mainloop()


Benutzeravatar
peterpy
User
Beiträge: 188
Registriert: Donnerstag 7. März 2013, 11:35

Hallo lucas97de,

Bitte vergiss die Sternimporte!

ein Beispiel:

Code: Alles auswählen

from tkinter import Tk, Button, filedialog

def ausgebe_speicherort():
    pfad_datei = oeffne_file()
    print("Ausgebe", pfad_datei)

def oeffne_file():
    oeffne= filedialog.askopenfilename()
    pfad_datei = oeffne
    print("Datei geoeffnet", pfad_datei)
    return pfad_datei    

def main():
    root = Tk()
    taste_oeffne = Button(root, command=ausgebe_speicherort, text="Öffne")
    taste_oeffne.pack()
    
    root.mainloop()

if __name__ == "__main__":
    main()
Gruss
Peter
Sirius3
User
Beiträge: 17746
Registriert: Sonntag 21. Oktober 2012, 17:20

Keine *-Importe. tkinter wird üblicherweise als `import tkinter as tk` importiert. `a` ist ein besonders schlechter Name für eine Tk-Instanz. Außerdem steht der Code außerhalb der main-Funktion, was nicht sein sollte. `pack` liefert None als Rückgabewert, also sowohl `button` als auch `label` sind unsinnig, werden aber auch gar nicht benutzt. Man erstellt nicht nachträglich irgendwelche Labels. Diese werden am Anfang beim Aufbau des Fensters schon angelegt.
Was soll denn die `1` bei `file1`? Die Funktion askopenfile liefert tatsächlich ein File-Objekt (zu einer Textdatei), Du willst aber einen DateiNAMEN. Dafür gibt es eine andere passendere Funktion.
Antworten