Strömende Tensoren – Teil 3

Dies ist der dritte Teil der Artikelserie Strömende Tensoren.

Nun baue ich mir ein kleines GUI, mit dem ich die Daten verwalte und die Eingabe und Verifikation der Daten etwas vereinfachen möchte.

Es soll auf jeden Fall ein Bild angezeigt werden. Auf dem Bild soll die Position des Würfels angezeigt werden. Zusätzlich wird mindestens eine Eingabe für den Wert benötigt, den der Würfel auf dem Bild anzeigt und ein Knopf um ein weiteres Bild mit der Kamera zu machen.

Für den Anfang füge ich noch die Position als Eingabefelder und eine Liste von Bildern hinzu. Des weiteren Knöpfe um das aktuelle Bild dem neuronalen Netzwerk zu füttern, um die geänderten Daten in die Liste zu übernehmen und um eine Trainingsiteration des Netzwerks zu starten.

Der erste Entwurf sieht also im Qt-Designer folgendermaßen aus: MainWindow im Designer

Im linken Bereich wird das Bild zu sehen sein, im Feld zwischen den Knöpfen „Change Data” und „Train” wird die Liste der Bilder angezeigt.

Mit PyQt5 bekommt man in Python sehr schnell ein GUI zusammengebaut. Im Qt-Designer zieht man sich die Elemente seines Fensters zusammen und übersetzt dann das resultierende XML-File mit pyuic3 in Python-Code.

Diesen bindet man einfach in sein Programm ein, hier über from main_window import Ui_main_window, leitet von der entsprechenden Qt-Klasse ab und bindet die erzeugte Klasse ein:

1
2
3
4
5
class MainWindow (QtWidgets.QMainWindow):
    def __init__ (self):
        QtWidgets.QMainWindow.__init__ (self)
        self.ui = Ui_main_window ()
        self.ui.setupUi (self)

Das so erzeugte Gerüst muß nun natürlich noch mit Leben gefüllt werden. Dazu werden die entsprechenden Signale der Elemente mit den Methoden verbunden welche die entsprechenden Aktionen anstoßen. Dies geschieht durch einfache Aufrufe in der Init-Methode: self.ui.snap_image_btn.clicked.connect (self.snapImageClicked). Klickt der Benutzer nun auf den Knopf „Snap Image” wird die Methode snapImageClicked der Klasse MainWindow aufgerufen.

Für die Liste der Bilder verwende ich hier das Model/View Konzept von Qt. Als darstellende Klasse wird ein QTreeView verwendet. Ich möchte hier zwar keine Baumstruktur darstellen sondern nur eine Liste, das wird von dieser Klasse jedoch genauso unterstützt und sie bietet mir auf einfache Art die Möglichkeit, daß immer eine ganze Zeile selektiert wird, mehrere Spalten angezeigt werden und ein Header existiert.

Die Daten werden dementsprechend in einer von QStandardItemModel abgeleitete Klasse verwaltet. In C++ würde man hier ein QAbstractItemModel verwenden. In Python ist dies leider nicht möglich, da das Konzept von pur virtuellen Methoden und damit von abstrakten Klassen nicht existiert.
Ich verwende einfach nicht die Methode setItem des QStandardItemModel sondern überlade die Methoden data und headerData um die entsprechenden Einträge der verwalteten Daten und der Überschriften für die Anzeige zurück zu geben.

Die Liste der Bilder mit ihren zugehörigen Werten sind in einer JSON-formatierten Datei gespeichert. Die Dateinamen der Bilder beziehen sich in dieser Datei immer auf das Verzeichnis, in dem die Datei steht.

Eine solche Liste kann über die Menüpunkte des File-Menüs geladen und gespeichert werden.

Um bei weiteren Programmläufen den Dateidialog wieder im zuletzt benutzten Verzeichnis zu öffnen, habe ich mir eine kleine Konfigurationsklasse gebaut, die das zuletzt benutzte Verzeichnis verwaltet und seine Daten in eine Konfigurationsdatei absenken und aus ihr laden kann (bisher über das Pythonmodul pickle, jedoch werde das noch umbauen auf JSON). Hier werden in Zukunft noch weitere Konfigurationsdaten des Programms landen.

Im nächsten Teil werde ich mich vermutlich um die Aufnahme eines Bildes kümmern. Dies soll, über das Netzwerk angestoßen, auf einem Raspberry-Pi geschehen. Es wird also nötig sein, über ssh ein Kommando auf einem entfernten Rechner anzustoßen und das Bild vorzugsweise über Std-Out der SSH-Verbindung auf den anfragenden Rechner zu übertragen.

Zum vierten Teil

Links zu weiterführenden Informationen dieser Artikelserie:

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.