123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432 |
- #include "frame.h"
- #include "kamera.h"
- #include <QImage>
- #include <QMessageBox>
- #include <QDebug>
- // Erstellt das Bild
- // imgPath: Der Pfad zu dem Quellbild
- // timestamp: Der Zeitpunkt der Aufnahme des Bildes
- // index: Der Index des Bildes in der Liste aller Bilder der Kamera
- // kam: Die Kamera, die das Bild aufgenommen hat
- // needAnnotation: true, falls das Bild noch nicht annotiert wurde
- Frame::Frame( QString imgPath, QString timestamp, int index, Kamera *kam, bool needAnnotation )
- : FrameTreeNode( index, kam, 1 ),
- path( imgPath ),
- timestamp( timestamp ),
- needAnnotation( needAnnotation ),
- size( QSize( 0, 0 ) ),
- needSave( 0 )
- {}
- 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
- {
- return (void*)this;
- }
- // Gibt die Anzahl aller Objekte auf dem Bild zurück
- int Frame::getChildCount() const
- {
- return objects.size();
- }
- // Entfernt alle Eckpunkte in einem Gebit
- // area: Das Gebiet, in dem die Eckpunkte gelöscht werden sollen
- void Frame::removeSelectedVertices( QRect area )
- {
- needSave = 1;
- int anz = objects.size();
- for( int i = 0; i < anz; i++ )
- {
- ObjectPolygon o = objects.at( i );
- if( o->isSelected() )
- {
- if( !o->removeVertices( area ) )
- {
- objects.removeAt( i );
- i--;
- anz--;
- }
- }
- }
- }
- // Löscht ein bestimmtes Objekt
- // o: Das Objekt, welches gelöscht werden soll
- void Frame::removeObject( ObjectPolygon o )
- {
- needSave = 1;
- objects.removeOne( o );
- }
- // Fügt ein Objekt zu dem Bild hinzu. Das Objekt wird automatisch am
- // Bildrand abgeschnitten
- // name: Die ID des Objektes
- // truncated: true, falls das Objekt abgeschnitten ist
- // po: Eine Liste mit Polygonen, welche die Umrisse des Objektes sind
- void Frame::addObject( QString id, bool truncated, QList< QPolygon > po )
- {
- needSave = 1;
- if( po.size() < 1 )
- return;
- if( size != QSize( 0, 0 ) )
- {
- QPolygon cliped = clipPolygon( po.at( 0 ) );
- ObjectPolygon newObject( id, cliped, truncated || cliped.boundingRect() != po.at( 0 ).boundingRect(), objects.size(), this );
- int pAnz = po.count();
- for( int i = 1; i < pAnz; i++ )
- {
- cliped = clipPolygon( po.at( i ) );
- if( cliped.boundingRect() != po.at( i ).boundingRect() )
- newObject->setTruncated( true );
- newObject->getPolygonList().append( cliped );
- }
- objects.append( newObject );
- }
- else
- {
- ObjectPolygon newObject( id, po.at( 0 ), truncated, objects.size(), this );
- int pAnz = po.count();
- for( int i = 1; i < pAnz; i++ )
- newObject->getPolygonList().append( po.at( i ) );
- objects.append( newObject );
- }
- }
- // Wendet die Maske auf das Bild an und löscht alle Objekte, welche sich in
- // verbotenen Bereichen befinden
- // m: die Maske
- void Frame::applyMask( Mask &m )
- {
- needSave = 1;
- int count = objects.count();
- for( int i = 0; i < count; i++ )
- {
- int pAnz = objects.at( i )->getPolygonList().count();
- for( int j = 0; j < pAnz; j++ )
- {
- if( !m.isPolygonInside( objects.at( i )->getPolygonList().at( j ) ) )
- {
- pAnz--;
- objects.at( i )->getPolygonList().removeAt( j-- );
- if( pAnz <= 0 )
- {
- count--;
- objects.removeAt( i-- );
- }
- }
- }
- }
- }
- // Spaltet ein Objekt in zwei Teile
- // object: Das Objekt welches zerteilt werden soll
- // beginn: Der Index des Start Eckpunktes
- // end: Der Index des End Eckpunktes
- // pIndex: Der Index des Polygons, welches zerteilt werden soll
- void Frame::splitObject( ObjectPolygon object, int begin, int end, int pIndex )
- {
- needSave = 1;
- QPolygon newP = object->split( begin, end, pIndex );
- QList< QPolygon > newPols;
- newPols.append( newP );
- addObject( object->getId(), object->isTruncated(), newPols );
- }
- // gibt den Namen des Bildes zurück
- QString Frame::getName() const
- {
- return path.mid( path.lastIndexOf( '/' ) + 1 );
- }
- // Gibt den Aufnahmezeitpunkt des Bildes zurück
- QString Frame::getTimestamp() const
- {
- return timestamp;
- }
- // Gibt eine Liste mit Objekten zurück, welche sich auf dem Bild befinden
- QList< ObjectPolygon > &Frame::getObjects()
- {
- return objects;
- }
- // Setzt die Objekte, welche sich auf dem Bild befinden. Alle vorherigen
- // Objekte werden entfernt.
- // objects: die Liste mit den neuen Objekten
- void Frame::setObjects( std::vector< std::vector< cv::Point > > obs )
- {
- needSave = 1;
- needAnnotation = false;
- objects.clear();
- for( auto p = obs.begin(); p != obs.end(); p++ )
- {
- std::vector< cv::Point > pol;
- cv::approxPolyDP( *p, pol, 15, 1 );
- if( pol.size() > 2 )
- {
- QPolygon polygon;
- int count = 0;
- for( auto point = pol.begin(); point != pol.end(); point++, count++ )
- {
- polygon.append( QPoint( point->x, point->y ) );
- }
- QList< QPolygon > newPols;
- newPols.append( polygon );
- addObject( "-1", 0, newPols );
- }
- }
- }
- // Gibt das geladene Bild als Objekt des Qt Frameworks zurück
- QImage Frame::getImage()
- {
- QImage img( path );
- size = img.size();
- return img;
- }
- // Gibt das geladene Bild als Objekt der OpenCV Bibliotek zurück
- cv::Mat Frame::getImageMatrix() const
- {
- return cv::imread( path.toStdString() );
- }
- // Gibt den Bildausschnitt zurück, auf dem ein Objekt komplett sichtbar ist
- // objectId: die ID des Objektes, welches auf dem Bild sein soll
- QImage Frame::getObjectImage( QString objectId )
- {
- for( ObjectPolygon o : objects )
- {
- if( o->getId() == objectId )
- {
- 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;
- }
- }
- return QImage();
- }
- // Gibt den Bildausschnitt zurück, auf dem ein Objekt komplett sichtbar ist
- // object: das Objekt, welches auf dem Bild sein soll
- QImage Frame::getObjectImage( ObjectPolygon o )
- {
- 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;
- }
- // Prüft ob ein Objekt auf dem Bild vorhanden ist
- // id: Die ID des Objektes
- bool Frame::hasObject( QString id )
- {
- for( ObjectPolygon o : objects )
- {
- if( o->getId() == id )
- return true;
- }
- return false;
- }
- // Gibt true zurück, falls kein Fehler in der Annotation des Bildes gefunden
- // wurde
- bool Frame::isCorrectAnnotated() const
- {
- bool good = true;
- for( ObjectPolygon o1 : objects )
- {
- for( ObjectPolygon o2 : objects)
- {
- if( o1 == o2 )
- continue;
- good &= o2->getId() != o1->getId();
- }
- good &= o1->getId() != "-1";
- }
- return good;
- }
- // Gibt true zurück, falls das Bild noch nicht annotiert wurde
- bool Frame::isNotAnnotated() const
- {
- return needAnnotation;
- }
- // Gibt das Objekt zurück, welches an einer bestimmten Position im Bild ist.
- // 0 falls an der Stelle kein Objekt ist
- // pos: die Position, an der ein Objekt gesucht werden soll
- // pIndex: wird auf den Index des Polygons gesetzt, welches an der Stelle
- // ist, falls dort ein Objekt existiert
- ObjectPolygon Frame::getObjectAt( QPoint pos, int &pIndex ) const
- {
- for( ObjectPolygon o : objects )
- {
- pIndex = 0;
- for( QPolygon pol : o->getPolygonList() )
- {
- if( pol.containsPoint( pos, Qt::FillRule::OddEvenFill ) )
- return o;
- pIndex++;
- }
- }
- return ObjectPolygon();
- }
- // Setzt das Objekt an einer bestimmten Position im Bild.
- // Fals an der Position bereits ein Objekt existiert, so wird nur die Objekt
- // ID gesetzt.
- // pos: die Position
- // object: Das neue Objekt
- // center: Der Mittelpunkt des neuen Objektes
- // rotation: Die Drehung des neuen Objektes um den Mittelpunkt
- void Frame::setObjectAt( QPoint pos, ObjectPolygon copy, QPoint center, float rotation )
- {
- needSave = 1;
- for( ObjectPolygon o : objects )
- {
- for( QPolygon pol : o->getPolygonList() )
- {
- if( pol.containsPoint( pos, Qt::FillRule::OddEvenFill ) )
- {
- bool needQ = false;
- if( copy->getId() != "-1" )
- {
- for( ObjectPolygon o2 : objects )
- {
- if( o2 != o && o2->getId() == copy->getId() )
- needQ = 1;
- }
- }
- o->setId( copy->getId() );
- if( needQ )
- {
- QMessageBox::StandardButton reply = QMessageBox::question(0, "Warnung", "Auf diesem Bild gibt es bereits ein Objekt mit der gleichen Id. Möchten sie beide Objekte vereinen?",
- QMessageBox::Yes|QMessageBox::No);
- if (reply == QMessageBox::Yes)
- connectObjects( copy->getId() );
- }
- return;
- }
- }
- }
- QMatrix m;
- m.QMatrix::translate( pos.x(), pos.y() );
- m.rotate( rotation );
- m.translate( -center.x(), -center.y() );
- QList< QPolygon > newPols;
- for( QPolygon p : copy->getPolygonList() )
- newPols.append( m.map( p ) );
- bool needQ = false;
- if( copy->getId() != "-1" )
- {
- for( ObjectPolygon o2 : objects )
- {
- if( o2->getId() == copy->getId() )
- needQ = 1;
- }
- }
- addObject( copy->getId(), copy->isTruncated(), newPols );
- if( needQ )
- {
- QMessageBox::StandardButton reply = QMessageBox::question(0, "Warnung", "Auf diesem Bild gibt es bereits ein Objekt mit der gleichen Id. Möchten sie beide Objekte vereinen?",
- QMessageBox::Yes|QMessageBox::No);
- if (reply == QMessageBox::Yes)
- connectObjects( copy->getId() );
- }
- }
- // Macht ein Objekt an einer bestimmten Stelle sichtbar oder unsichtbar
- // pos: Die Position
- void Frame::selectObjectAt( QPoint pos )
- {
- for( ObjectPolygon o : objects )
- {
- for( QPolygon pol : o->getPolygonList() )
- {
- if( pol.containsPoint( pos, Qt::FillRule::OddEvenFill ) )
- o->setSelected( !o->isSelected() );
- }
- }
- }
- // Schneidet ein Polygon am rand des Bildes ab und gibt das Ergebnis zurück
- // uncliped: Das nicht abgeschnittene Polygon
- QPolygon Frame::clipPolygon( QPolygon uncliped ) const
- {
- QPolygon cliped = uncliped.intersected( QPolygon( QRect( QPoint( 0, 0 ), size ), true ) );
- if( !cliped.isEmpty() )
- cliped.pop_back();
- return cliped;
- }
- // Vereiniegt verschiedene Objekte mit der gleichen Objekt ID zu einem
- // id: Die ID, deren Objekte vereiniegt werden sollen
- void Frame::connectObjects( QString id )
- {
- needSave = 1;
- ObjectPolygon o;
- int oAnz = objects.count();
- for( int i = 0; i < oAnz; i++ )
- {
- ObjectPolygon o2 = objects.at( i );
- if( o2 != o && o2->getId() == id )
- {
- if( o.isNull() )
- o = o2;
- else
- {
- o->getPolygonList().append( o2->getPolygonList() );
- o->setTruncated( o->isTruncated() || o2->isTruncated() );
- o->setSelected( o->isSelected() || o2->isSelected() );
- objects.removeAt( i );
- i--;
- oAnz--;
- }
- }
- }
- }
- // Zerteilt ein Objekt, welches aus mehreren Polygonen besteht
- // o: Das Objekt welches zerteilt werden soll
- void Frame::disconnectObject( ObjectPolygon o )
- {
- needSave = 1;
- for( QPolygon p : o->getPolygonList() )
- {
- QList< QPolygon > plist;
- plist.append( p );
- addObject( o->getId(), o->isTruncated(), plist );
- }
- removeObject( o );
- }
- // Gibt 1 zurück, falls die Annotation zu dem Bild gespeichert werden muss
- // und setzt den Flag auf 0, so dass erst nach einer änderung wieder 1 zurückgegeben wird
- bool Frame::wasChangedSinceLastSave()
- {
- bool ret = needSave;
- needSave = 0;
- return ret;
- }
|