Explorar el Código

Überraschungsfeature zur effizienten und inteligenten Id vergabe

Kolja Strohm hace 7 años
padre
commit
81397e5b89

+ 1 - 1
annotationGUI/CMakeLists.txt

@@ -20,7 +20,7 @@ set(QT_USE_QTGUI TRUE)
 set(QT_USE_QTXML TRUE)
 
 # Tell CMake to create the helloworld executable
-add_executable(annotation_gui WIN32 model.cpp controller.cpp requestfromserver.cpp requestfromserver.ui newsequenz.cpp newsequenz.ui classoptions.cpp classoptions.ui CSVReader.cpp ZMQClient.cpp DetectionClient.cpp tinyxml2.cpp main.cpp mainwindow.cpp changepacket.cpp changepacket.ui changemask.cpp changemask.ui mask.cpp mainwindow.ui frametree.cpp kmath.cpp frametreemodel.cpp annotationxml.cpp frame.cpp arbeitsview.cpp sequenz.cpp object.cpp kamera.cpp icons.qrc)
+add_executable(annotation_gui WIN32 model.cpp controller.cpp requestfromserver.cpp setids.cpp setids.ui requestfromserver.ui newsequenz.cpp newsequenz.ui classoptions.cpp classoptions.ui CSVReader.cpp ZMQClient.cpp DetectionClient.cpp tinyxml2.cpp main.cpp mainwindow.cpp changepacket.cpp changepacket.ui changemask.cpp changemask.ui mask.cpp mainwindow.ui frametree.cpp kmath.cpp frametreemodel.cpp annotationxml.cpp frame.cpp arbeitsview.cpp sequenz.cpp object.cpp kamera.cpp icons.qrc)
 
 # Use the Widgets module from Qt 5.
 target_link_libraries(annotation_gui Qt5::Widgets ${OpenCV_LIBS} zmq)

+ 20 - 2
annotationGUI/frame.cpp

@@ -23,6 +23,12 @@ Frame::Frame( QString imgPath, QString timestamp, int index, Kamera *kam, bool n
 Frame::~Frame()
 {}
 
+// Legt fest, dass das Bild seit dem letzten speichern verändert wurde
+void Frame::setNeedSave()
+{
+    needSave = 1;
+}
+
 // Gibt this zurück
 void *Frame::getNodeObject() const
 {
@@ -205,7 +211,13 @@ QImage Frame::getObjectImage( QString objectId )
     {
         if( o->getId() == objectId )
         {
-            QImage ret = getImage().copy( o->getBoundingBox() );
+            QImage img = getImage();
+            QRect bndBox = o->getBoundingBox();
+            bndBox.setLeft( MAX( bndBox.left() - 200, 0 ) );
+            bndBox.setTop( MAX( bndBox.top() - 200, 0 ) );
+            bndBox.setRight( MIN( bndBox.right() + 200, img.width() ) );
+            bndBox.setBottom( MIN( bndBox.bottom() + 200, img.height() ) );
+            QImage ret = img.copy( bndBox );
             return ret;
         }
     }
@@ -216,7 +228,13 @@ QImage Frame::getObjectImage( QString objectId )
 //  object: das Objekt, welches auf dem Bild sein soll
 QImage Frame::getObjectImage( ObjectPolygon o )
 {
-    QImage ret = getImage().copy( o->getBoundingBox() );
+    QImage img = getImage();
+    QRect bndBox = o->getBoundingBox();
+    bndBox.setLeft( MAX( bndBox.left() - 200, 0 ) );
+    bndBox.setTop( MAX( bndBox.top() - 200, 0 ) );
+    bndBox.setRight( MIN( bndBox.right() + 200, img.width() ) );
+    bndBox.setBottom( MIN( bndBox.bottom() + 200, img.height() ) );
+    QImage ret = img.copy( bndBox );
     return ret;
 }
 

+ 3 - 0
annotationGUI/frame.h

@@ -39,6 +39,9 @@ public:
           bool    needAnnotation);
     ~Frame();
 
+    // Legt fest, dass das Bild seit dem letzten speichern verändert wurde
+    void setNeedSave();
+
     // Gibt this zurück
     void* getNodeObject() const override;
 

+ 9 - 0
annotationGUI/mainwindow.cpp

@@ -22,6 +22,7 @@
 #include "tinyxml2.h"
 #include "classoptions.h"
 #include "requestfromserver.h"
+#include "setids.h"
 
 // Hilfstexte
 QString toolTitel[] = { "Objekte Verstecken", "Verschieben", "Neues Objekt", "Kopieren", "Einfügen", "Löschen", "Zerschneiden", "Vergrößern", "Allgemeine Information" };
@@ -618,3 +619,11 @@ void MainWindow::on_actionMaske_bearbeiten_triggered()
     chm.exec();
     setupFrameTree();
 }
+
+void MainWindow::on_actionIDs_bearbeiten_triggered()
+{
+    if( !seq )
+        return;
+    SetIds ids( seq, this );
+    ids.exec();
+}

+ 2 - 0
annotationGUI/mainwindow.h

@@ -79,6 +79,8 @@ private slots:
     // Zeigt die Maskenbearbeitungsoberfläche
     void on_actionMaske_bearbeiten_triggered();
 
+    void on_actionIDs_bearbeiten_triggered();
+
 private:
     // Wählt alle Buttons für die Werkzeuge ab
     void unselectButttons();

+ 13 - 1
annotationGUI/mainwindow.ui

@@ -447,7 +447,7 @@
      <x>0</x>
      <y>0</y>
      <width>1119</width>
-     <height>27</height>
+     <height>15</height>
     </rect>
    </property>
    <widget class="QMenu" name="menuFile">
@@ -481,6 +481,7 @@
    <addaction name="actionMaske_anzeigen"/>
    <addaction name="actionObjekte_faerben"/>
    <addaction name="actionIDs_anzeigen"/>
+   <addaction name="actionIDs_bearbeiten"/>
   </widget>
   <widget class="QStatusBar" name="statusBar"/>
   <action name="actionOpen">
@@ -596,6 +597,17 @@
     <bool>true</bool>
    </property>
   </action>
+  <action name="actionIDs_bearbeiten">
+   <property name="text">
+    <string>IDs bearbeiten</string>
+   </property>
+   <property name="toolTip">
+    <string>Öffnet eine Oberfläche, in der Die Objekt IDs effizient zugewiesen werden können</string>
+   </property>
+   <property name="shortcut">
+    <string>I</string>
+   </property>
+  </action>
  </widget>
  <layoutdefault spacing="6" margin="11"/>
  <resources>

+ 6 - 0
annotationGUI/model.cpp

@@ -17,6 +17,12 @@ void Model::notifyViews()
         v->update();
 }
 
+// Entfernt alle Views
+void Model::removeViews()
+{
+    views.clear();
+}
+
 // Inhalt der ArbeitsModel Klasse
 //--------------------------------
 

+ 2 - 0
annotationGUI/model.h

@@ -21,6 +21,8 @@ public:
     void addView( QWidget *v );
     // Aktualisiert die Views
     void notifyViews();
+    // Entfernt alle Views
+    void removeViews();
 };
 
 class MainWindow; // aus mainwindow.h

+ 47 - 6
annotationGUI/sequenz.cpp

@@ -151,6 +151,35 @@ Frame *Sequenz::getFrame() const
     return cams.at( cameraIndex )->getFrame( frameIndex );
 }
 
+// Gibt das vom ausgewählten Bild um offset Bilder entfernte Bild zurück
+Frame *Sequenz::getFrame( int offset ) const
+{
+    int currCam = cameraIndex;
+    int currFrame = frameIndex;
+    int oldCOunt = offset;
+    do
+    { // Schleife durch alle bilder (in die angegebene Richtung) bis ein Bild gefunden wird auf dem das Objekt vorkommt
+        if( currFrame >= cams.at( currCam )->getChildCount() )
+        {
+            currCam++;
+            if( currCam >= cams.size() )
+               currCam = 0;
+            currFrame = 0;
+        }
+        Frame *f = cams.at( currCam )->getFrame( currFrame );
+        offset--;
+        currFrame++;
+        if( offset <= 0 ) // das gesuchte Bild wurde erreicht
+            return f;
+        if( currFrame == frameIndex && currCam == cameraIndex )
+        {
+            if( oldCOunt == offset )
+                break;
+        }
+    } while( offset > 0 );
+    return 0;
+}
+
 // Gibt den Index der ausgewählten Kamera zurück
 int Sequenz::getSelectedCamera() const
 {
@@ -238,22 +267,34 @@ QImage Sequenz::previousObjectImage( QString packetName, int count ) const
             if( dir > 0 )
                 currFrame = 0;
         }
-        if( currFrame == frameIndex && currCam == cameraIndex )
-        {
-            if( oldCOunt == count )
-                break;
-        }
         Frame *f = cams.at( currCam )->getFrame( currFrame );
         if( f->hasObject( packetName ) )
         {
             count--;
-            if( count == 0 ) // das gesuchte Bild wurde erreicht
+            if( count <= 0 ) // das gesuchte Bild wurde erreicht
                 img = f->getObjectImage( packetName );
         }
+        if( currFrame == frameIndex && currCam == cameraIndex )
+        {
+            if( oldCOunt == count )
+                break;
+        }
     } while( count > 0 );
     return img;
 }
 
+// Gibt die größte vergebene Objekt Id zurück;
+int Sequenz::getMaxObjectId() const
+{
+    int max = -1;
+    for( auto o : objects )
+    {
+        if( o.getId().toInt() > max )
+            max = o.getId().toInt();
+    }
+    return max;
+}
+
 // Fügt eine neue ObjektID mit der Klassen ID classID hinzu
 void Sequenz::addObjectName( QString name, int classId )
 {

+ 4 - 0
annotationGUI/sequenz.h

@@ -55,6 +55,8 @@ public:
     void selectFrame( int cam, int frame );
     // Gibt das ausgewählte Bild zurück
     Frame *getFrame() const;
+    // Gibt das vom ausgewählten Bild um offset Bilder entfernte Bild zurück
+    Frame *getFrame( int offset ) const;
     // Gibt den Index der ausgewählten Kamera zurück
     int getSelectedCamera() const;
     // Gibt den Index des Ausgewählten Bildes (innerhalb der Kamera) zurück
@@ -71,6 +73,8 @@ public:
     bool hasPreviousFrame() const;
     // Gibt eine Liste mit allen vergebenen ObjektIds zurück
     QList< QString > getObjectNames() const;
+    // Gibt die größte vergebene Objekt Id zurück;
+    int getMaxObjectId() const;
     // Gibt von dem ausgewählten Bild aus das count-nächste Bild von dem Objekt mit ID objektId zurück.
     QImage previousObjectImage( QString objektId, int count = 1 ) const;
     // Fügt eine neue ObjektID mit der Klassen ID classID hinzu

+ 283 - 0
annotationGUI/setids.cpp

@@ -0,0 +1,283 @@
+#include "setids.h"
+#include "ui_setids.h"
+#include "object.h"
+
+#include <QMouseEvent>
+#include <QPainter>
+#include <QInputDialog>
+
+SetIds::SetIds(Sequenz *s, QWidget *parent) :
+    QDialog(parent),
+    ui(new Ui::SetIds)
+{
+    ui->setupUi(this);
+    this->s = s;
+    m = new SetIdsModel();
+    m->id = -1;
+    SetIdsView *v1 = new SetIdsView( s, m, 0, ui->v1 );
+    SetIdsView *v2 = new SetIdsView( s, m, 1, ui->v2 );
+    SetIdsView *v3 = new SetIdsView( s, m, 2, ui->v3 );
+    SetIdsView *v4 = new SetIdsView( s, m, 3, ui->v4 );
+    SetIdsView *v5 = new SetIdsView( s, m, 4, ui->v5 );
+    SetIdsView *v6 = new SetIdsView( s, m, 5, ui->v6 );
+    SetIdsView *v7 = new SetIdsView( s, m, 6, ui->v7 );
+    SetIdsView *v8 = new SetIdsView( s, m, 7, ui->v8 );
+    SetIdsView *v9 = new SetIdsView( s, m, 8, ui->v9 );
+    views.append( v1 );
+    views.append( v2 );
+    views.append( v3 );
+    views.append( v4 );
+    views.append( v5 );
+    views.append( v6 );
+    views.append( v7 );
+    views.append( v8 );
+    views.append( v9 );
+    m->addView( v1 );
+    m->addView( v2 );
+    m->addView( v3 );
+    m->addView( v4 );
+    m->addView( v5 );
+    m->addView( v6 );
+    m->addView( v7 );
+    m->addView( v8 );
+    m->addView( v9 );
+}
+
+SetIds::~SetIds()
+{
+    delete ui;
+    for( auto i : views )
+        delete (SetIdsView*)i;
+    delete m;
+}
+
+// Die Ids sollen nicht gespeichert werden
+void SetIds::on_abbrechen_clicked()
+{
+    close();
+}
+
+// Es sollen weitere Bilder geladen werden
+void SetIds::on_weiter_clicked()
+{
+    int index = m->list.count() - 3;
+    if( !s->getFrame( index ) )
+        return;
+    m->removeViews();
+    for( auto i : views )
+        delete (SetIdsView*)i;
+    views.clear();
+    SetIdsView *v1 = new SetIdsView( s, m, index, ui->v1 );
+    SetIdsView *v2 = new SetIdsView( s, m, index + 1, ui->v2 );
+    SetIdsView *v3 = new SetIdsView( s, m, index + 2, ui->v3 );
+    SetIdsView *v4 = new SetIdsView( s, m, index + 3, ui->v4 );
+    SetIdsView *v5 = new SetIdsView( s, m, index + 4, ui->v5 );
+    SetIdsView *v6 = new SetIdsView( s, m, index + 5, ui->v6 );
+    SetIdsView *v7 = new SetIdsView( s, m, index + 6, ui->v7 );
+    SetIdsView *v8 = new SetIdsView( s, m, index + 7, ui->v8 );
+    SetIdsView *v9 = new SetIdsView( s, m, index + 8, ui->v9 );
+    views.append( v1 );
+    views.append( v2 );
+    views.append( v3 );
+    views.append( v4 );
+    views.append( v5 );
+    views.append( v6 );
+    views.append( v7 );
+    views.append( v8 );
+    views.append( v9 );
+    m->addView( v1 );
+    m->addView( v2 );
+    m->addView( v3 );
+    m->addView( v4 );
+    m->addView( v5 );
+    m->addView( v6 );
+    m->addView( v7 );
+    m->addView( v8 );
+    m->addView( v9 );
+}
+
+// Die Ids sollen gespeichert werden
+void SetIds::on_speichern_clicked()
+{
+    int i = 0;
+    for( ObjectPolygon p : m->list )
+    {
+        if( p.isNull() )
+        {
+            i++;
+            continue;
+        }
+        p->setId( QString::number( m->id ) );
+        s->getFrame( i++ )->setNeedSave();
+        s->addObjectName( QString::number( m->id ) );
+    }
+    this->close();
+}
+
+// Inhalt der SetIdsView Klasse
+//------------------------------
+
+// Transformiert einen Punkt von Bildkoordinaten nach Bildschirmkoordinaten
+QPoint SetIdsView::translate(QPoint p)
+{
+    return QPoint( (int)(p.x() * xScaleFactor), (int)(p.y() * yScaleFactor) );
+}
+
+// Transformiert ein Polygon von Bildkoordinaten nach Bildschirmkoordinaten
+QPolygon SetIdsView::translatePolygon(QPolygon p)
+{
+    QPolygon result;
+    for( auto point = p.begin(); point != p.end(); point++ )
+        result.append( translate( *point ) );
+    return result;
+}
+
+// Transformiert einen Punkt von Bildschirmkoordinaten nach Bildkoordinaten
+QPoint SetIdsView::inverseTranslate(QPoint p)
+{
+    return QPoint( (int)(p.x() / xScaleFactor), (int)(p.y() / yScaleFactor) );
+}
+
+QPointF centerOfPolygon( QPolygon p ); // siehe arbeitsview.cpp
+
+// Zeichnet die View neu
+void SetIdsView::paintEvent(QPaintEvent *e)
+{
+    QPainter painter( this );
+    if( f )
+    {
+        QImage img = f->getImage();
+        xScaleFactor = width() / (float)img.width();
+        yScaleFactor = height() / (float)img.height();
+        // Zeichne Hintergrund Bild
+        painter.drawImage( QRect( QPoint( 0, 0 ), translate( QPoint( img.width(), img.height() ) ) ), img );
+        QList<ObjectPolygon> objects = f->getObjects();
+        QPen white( QColor( 255, 255, 255 ), 2 ); // Erstellt Stifte zum Zeichnen
+        QPen white1( QColor( 255, 255, 255 ), 1 );
+        QPen lightGreen( QColor( 100, 255, 100 ), 2 );
+        QPen green( QColor( 0, 255, 0 ), 2 );
+        QPen red( QColor( 255, 0, 0 ), 2 );
+        QBrush blackBrush( QColor( 0, 0, 0 ), Qt::SolidPattern );
+        for( ObjectPolygon o : objects )
+        { // Schleife durch alle Objekte des Bildes
+            if( o->isSelected() )
+            {
+                painter.setPen( white );
+                int pIndex;
+                if( o == f->getObjectAt( mousePos, pIndex ) )
+                    painter.setPen( lightGreen );
+                if( ( o->getId() == QString::number( m->id ) || o == m->list.at( i ) ) && m->id != -1 )
+                    painter.setPen( green );
+                if( o->getId() == QString::number( m->id ) && o != m->list.at( i ) && m->id != -1 )
+                    painter.setPen( red );
+                pIndex = 0;
+                for( QPolygon pol : o->getPolygonList() )
+                { // Schleife durch alle Polygone des Bildes
+                    QBrush tmpB = painter.brush();
+                    painter.drawPolygon( translatePolygon( pol ) ); // Zeichne Polygon
+                    QPen tmpPen = painter.pen();
+                    painter.setPen( white1 );
+                    QFont f = painter.font();
+                    f.setPointSize( 12 );
+                    QPainterPath tPath;
+                    QString id = o->getId();
+                    if( o == m->list.at( i ) )
+                    {
+                        id = QString::number( m->id );
+                    }
+                    tPath.addText( centerOfPolygon( translatePolygon( pol ) ), f, id );
+                    painter.setBrush( blackBrush );
+                    painter.drawPath( tPath );
+                    painter.setBrush(tmpB);
+                    painter.setPen( tmpPen );
+                    pIndex++;
+                }
+            }
+        }
+        painter.setPen( red );
+        if( i - 1 >= 0 && !m->set.at( i ) && !m->list.at( i - 1 ).isNull() )
+        {
+            QPoint mid = m->list.at( i - 1 )->getBoundingBox().center();
+            int index;
+            ObjectPolygon p = f->getObjectAt( mid, index );
+            if( !p.isNull() )
+            {
+                m->list.replace( i, p );
+                m->notifyViews();
+            }
+            else
+                painter.drawEllipse( translate(mid), 5, 5 );
+        }
+    }
+}
+
+SetIdsView::SetIdsView(Sequenz *s, SetIdsModel *m, int i, QWidget *parent)
+    : QWidget( parent )
+{
+    this->f = s->getFrame( i );
+    this->s = s;
+    this->m = m;
+    this->i = i;
+    parent->layout()->addWidget( this );
+    this->setMouseTracking( true );
+    if( m->list.count() <= i )
+    {
+        m->list.append( ObjectPolygon() );
+        m->set.append( 0 );
+    }
+}
+
+SetIdsView::~SetIdsView()
+{
+    ((QWidget*)this->parent())->layout()->removeWidget( this );
+}
+
+// Verarbeitet Maus Events und wählt das richtige Objekt aus
+void SetIdsView::mouseReleaseEvent(QMouseEvent *e)
+{
+    if( !f )
+        return;
+    if( e->button() == Qt::LeftButton )
+    { // Wäjlt ein Objekt aus, welches die Id zugewiesen bekommen soll
+        int index;
+        ObjectPolygon p = f->getObjectAt( mousePos, index );
+        if( p.isNull() )
+            return;
+        if( p->getId() == "-1" && m->id == -1 )
+        {
+            bool ok;
+            int max = s->getMaxObjectId();
+            int id = QInputDialog::getInt( this, "ID", "Gebe die neue ID ein", max, 0, max, 1, &ok );
+            if( ok )
+            {
+                m->id = id;
+                m->list.replace( i, p );
+                m->set.replace( i, 1 );
+            }
+        }
+        else if( m->id != -1 )
+        {
+            m->list.replace( i, p );
+            m->set.replace( i, 1 );
+        }
+        else
+        {
+            m->id = p->getId().toInt();
+            m->set.replace( i, 1 );
+            m->list.replace( i, p );
+        }
+    }
+    if( e->button() == Qt::RightButton )
+    { // Lege Fest, dass für dieses Bild kein Objekt mit der Id versehen werden soll
+        m->list.replace( i, ObjectPolygon() );
+        m->set.replace( i, 1 );
+    }
+    m->notifyViews();
+}
+
+// Übernimmt die neue Maus Position
+void SetIdsView::mouseMoveEvent(QMouseEvent *e)
+{
+    mousePos = inverseTranslate( e->pos() );
+    update();
+}

+ 81 - 0
annotationGUI/setids.h

@@ -0,0 +1,81 @@
+#ifndef SETIDS_H
+#define SETIDS_H
+
+#include <QDialog>
+#include "sequenz.h"
+#include "model.h"
+
+namespace Ui {
+class SetIds;
+}
+class SetIdsModel; // Siehe unten
+class SetIdsView; // Siehe unten
+
+/*
+ * Verwaltet die inteligente ID zuweisungs oberfläche
+ */
+class SetIds : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit SetIds(Sequenz *s, QWidget *parent = 0);
+    ~SetIds();
+
+private slots:
+    // Die Ids sollen nicht gespeichert werden
+    void on_abbrechen_clicked();
+    // Es sollen weitere Bilder geladen werden
+    void on_weiter_clicked();
+    // Die Ids sollen gespeichert werden
+    void on_speichern_clicked();
+
+private:
+    Ui::SetIds *ui; // Enthält alle in setids.ui spezifizierten Objekte
+    Sequenz *s; // Enthält die aktuell annotierte Bildsequenz
+    SetIdsModel *m; // Enthält das Model der SetIdViews
+    QList<SetIdsView*> views; // Enthält alle aktuellen SetIdViews (für jedes Bild eine)
+};
+
+/*
+ * Das Model der SetIdViews
+ */
+class SetIdsModel : public Model
+{
+public:
+    int id; // Die Id, welche vergeben werden soll
+    QList<ObjectPolygon> list; // Eine Liste mit Objekten, denen die Id zugewiesen werden soll (eins pro bild)
+    QList<bool> set; // Speichert, ob das Objekt aus der liste vom Nutzer angegeben wurde oder ob es automatisch erkannt wurde
+};
+
+/*
+ * Verwaltet ein Bild der inteligenten ID zuweisungs Oberfläche
+ */
+class SetIdsView : public QWidget
+{
+    float xScaleFactor; // Ein Skallierungsfaktor in x Richtung
+    float yScaleFactor; // Ein Skallierungsfaktor in y Richtung
+    QPoint mousePos; // Die momentane Position der Maus
+    SetIdsModel *m; // Das Model
+    Sequenz *s; // Die aktuelle Bildsequenz
+    int i; // Der Index des Bildes ausgehend vom ersten Bild
+    Frame *f; // Das Bild, welches angezeigt wird
+    // Transformiert einen Punkt von Bildkoordinaten nach Bildschirmkoordinaten
+    QPoint        translate(QPoint p);
+    // Transformiert ein Polygon von Bildkoordinaten nach Bildschirmkoordinaten
+    QPolygon      translatePolygon(QPolygon p);
+    // Transformiert einen Punkt von Bildschirmkoordinaten nach Bildkoordinaten
+    QPoint        inverseTranslate(QPoint p);
+    // Zeichnet die View neu
+    void paintEvent(QPaintEvent *e) override;
+
+public:
+    explicit SetIdsView(Sequenz *s, SetIdsModel *m, int i, QWidget *parent = nullptr);
+    ~SetIdsView();
+    // Verarbeitet Maus Events und wählt das richtige Objekt aus
+    void mouseReleaseEvent(QMouseEvent *e) override;
+    // Übernimmt die neue Maus Position
+    void mouseMoveEvent(QMouseEvent *e) override;
+};
+
+#endif // SETIDS_H

+ 87 - 0
annotationGUI/setids.ui

@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SetIds</class>
+ <widget class="QDialog" name="SetIds">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>830</width>
+    <height>545</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="1" column="1">
+    <widget class="QWidget" name="v5" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_5"/>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="QWidget" name="v2" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_2"/>
+    </widget>
+   </item>
+   <item row="1" column="2">
+    <widget class="QWidget" name="v6" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_6"/>
+    </widget>
+   </item>
+   <item row="2" column="0">
+    <widget class="QWidget" name="v7" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_7"/>
+    </widget>
+   </item>
+   <item row="2" column="1">
+    <widget class="QWidget" name="v8" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_8"/>
+    </widget>
+   </item>
+   <item row="0" column="0">
+    <widget class="QWidget" name="v1" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout"/>
+    </widget>
+   </item>
+   <item row="2" column="2">
+    <widget class="QWidget" name="v9" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_9"/>
+    </widget>
+   </item>
+   <item row="1" column="0">
+    <widget class="QWidget" name="v4" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_4"/>
+    </widget>
+   </item>
+   <item row="0" column="2">
+    <widget class="QWidget" name="v3" native="true">
+     <layout class="QVBoxLayout" name="verticalLayout_3"/>
+    </widget>
+   </item>
+   <item row="3" column="2">
+    <widget class="QPushButton" name="speichern">
+     <property name="text">
+      <string>Speichern</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="0">
+    <widget class="QPushButton" name="abbrechen">
+     <property name="text">
+      <string>Abbrechen</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="1">
+    <widget class="QPushButton" name="weiter">
+     <property name="text">
+      <string>Weiter</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>