#include "sequenz.h" #include #include #include #include Sequenz::Sequenz( QString p, QList< Kamera* > c, QList< Object > o ) : ref( 1 ), path( p ), frameIndex( 0 ), cameraIndex( 0 ), cams( c ), objects( o ) { addClass( "packingbox" ); } Sequenz::~Sequenz() { for( auto k = cams.begin(); k != cams.end(); k++ ) (*k)->refRelease(); } // Gibt eine Liste mit allen bekannten Objekt Klassen zurück QList< Sequenz::SegmentationClass > Sequenz::getClasses() const { return classes; } // Setzt den Namen der Objekt Klasse mit der ID id auf name bool Sequenz::setClassName( int id, QString name ) { int i = getClassId( name ); if( i == id ) return true; if( i != -1 ) return false; for( auto c = classes.begin(); c != classes.end(); c++ ) { if( c->id == id ) { c->name = name; return true; } } return false; } // Prüft, ob bereits annotierte Objekte in der Sequenz vorhanden sind QString Sequenz::getClassName( int id ) const { for( auto c = classes.begin(); c != classes.end(); c++ ) { if( c->id == id ) return c->name; } return "NULL"; } // Gibt den Namen der Objekt Klasse mit der ID id zurück int Sequenz::getClassId( QString name ) const { for( auto c = classes.begin(); c != classes.end(); c++ ) { if( c->name == name ) return c->id; } return -1; } // Gibt die ID der Objekt Klasse mit dem Namen name zurück int Sequenz::getClassOfObject( QString id ) const { for( auto obj = objects.begin(); obj != objects.end(); obj++ ) { if( obj->getId() == id ) return obj->getClassId(); } return -1; } // Gibt die ID der Klasse des Objektes mit der ID objektId zurück void Sequenz::setClassOfObject( QString id, int classId ) { for( auto obj = objects.begin(); obj != objects.end(); obj++ ) { if( obj->getId() == id ) obj->setClassId( classId ); } } // Setzt die ID der Klasse des Objektes mit der ID objektId auf classId bool Sequenz::hasAnnotatedObjects() const { for( Object o : objects ) { if( o.getId() != "-1" ) return true; } return false; } // Fügt eine neue Objekt Klasse mit Namen name hinzu int Sequenz::addClass( QString name ) { if( getClassId( name ) != -1 ) return -1; int max = -1; for( auto c = classes.begin(); c != classes.end(); c++ ) { if( c->id > max ) max = c->id; } max++; classes.append( { max, name } ); return max; } // Entfernt die Objektklasse mit der ID id bool Sequenz::removeClass( int id ) { for( auto c = classes.begin(); c != classes.end(); c++ ) { if( c->id == id ) { classes.erase( c ); int newId = 0; if( classes.size() > 0 ) newId = classes.first().id; for( auto obj = objects.begin(); obj != objects.end(); obj++ ) { if( obj->getClassId() == id ) obj->setClassId(newId); } return true; } } return false; } // Wählt das frame-te Bild der cam-ten Kamera aus void Sequenz::selectFrame( int cam, int frame ) { cameraIndex = cam; frameIndex = frame; } // Gibt das ausgewählte Bild zurück 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 { return cameraIndex; } // Gibt den Index des Ausgewählten Bildes (innerhalb der Kamera) zurück int Sequenz::getSelectedFrame() const { return frameIndex; } // Gibt eine Liste mit Kameras zurück const QList< Kamera* > &Sequenz::getCameras() const { return cams; } // Wählt das nachfolgende Bild aus void Sequenz::nextFrame() { if( !hasNextFrame() ) return; if( ++frameIndex == cams.at( cameraIndex )->getChildCount() ) { frameIndex = 0; cameraIndex++; } } // Wählt das vorherige Bild aus void Sequenz::previousFrame() { if( !hasPreviousFrame() ) return; if( --frameIndex < 0 ) frameIndex = cams.at( --cameraIndex )->getChildCount() - 1; } // Gibt 1 zurück, wenn in der Sequenz ein nachfolgendes Bild existiert bool Sequenz::hasNextFrame() const { return cameraIndex < cams.count() - 1 || frameIndex < cams.at( cameraIndex )->getChildCount() - 1; } // Gibt 1 zurück, wenn in der Sequenz ein vorheriges Bild existiert bool Sequenz::hasPreviousFrame() const { return frameIndex > 0 || cameraIndex > 0; } // Gibt eine Liste mit allen vergebenen ObjektIds zurück QList< QString > Sequenz::getObjectNames() const { QList result; foreach( Object obj, objects ) result.append( obj.getId() ); return result; } // Gibt von dem ausgewählten Bild aus das count-nächste Bild von dem Objekt mit ID objektId zurück. QImage Sequenz::previousObjectImage( QString packetName, int count ) const { int currCam = cameraIndex; int currFrame = frameIndex; QImage img; int dir = 1; if( count < 0 ) { // falls count negativ ist, wird weiter vorne in der sequenz gesucht dir = -1; count = -count; } int oldCOunt = count; do { // Schleife durch alle bilder (in die angegebene Richtung) bis ein Bild gefunden wird auf dem das Objekt vorkommt if( (currFrame += dir) < 0 || currFrame >= cams.at( currCam )->getChildCount() ) { if( (currCam += dir) < 0 || currCam >= cams.size() ) { currCam = cams.size() - 1; if( dir > 0 ) currCam = 0; } currFrame = cams.at( currCam )->getChildCount() - 1; if( dir > 0 ) currFrame = 0; } Frame *f = cams.at( currCam )->getFrame( currFrame ); if( f->hasObject( packetName ) ) { count--; 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 ) { if( objects.indexOf( Object( name, classId ) ) < 0 ) objects.append( Object( name, classId ) ); } // Fügt eine neue ObjektID hinzu void Sequenz::addObjectName( QString name ) { if( classes.size() > 0 ) addObjectName( name, classes.first().id ); else addObjectName( name, 0 ); } // Speichert die Sequenz. // status: Ein Label, in denen Fortschrittsinformationen geschrieben werden void Sequenz::saveToPath( QLabel *status ) const { int numOps = 0; for( Kamera *k : cams ) numOps += k->getChildCount(); QProgressDialog progress( "Annotation wird gespeichert...", "", 0, numOps ); progress.setWindowModality(Qt::WindowModal); progress.setCancelButton( 0 ); if( !QFile( path + "/ImageSets/Main/train.txt" ).exists() ) QDir( path + "/ImageSets/Main" ).mkpath("."); std::ofstream trainTxt( (path + "/ImageSets/Main/train.txt").toStdString().c_str() ); for( int cam = 0; cam < cams.size(); cam++ ) { // Schleife durch alle Kameras Kamera *currentCam = cams.at( cam ); int frameCount = currentCam->getChildCount(); for( int frame = 0; frame < frameCount; frame++ ) { // Schleife durch alle Bilder if( status ) { QString text = "save Annotations " + QString::number( cam + 1 ) + "/" + QString::number( cams.size() ) + " " + QString::number( frame + 1 ) + "/" + QString::number( cams.at( cam )->getChildCount() ); QMetaObject::invokeMethod( status, "setText", Q_ARG( QString, text ) ); } Frame *currentFrame = currentCam->getFrame( frame ); if( !currentFrame->isNotAnnotated() || currentFrame->getObjects().size() > 0 ) { trainTxt << ( currentFrame->getName().mid( 0, currentFrame->getName().indexOf( "." ) ) + "\n" ).toStdString().c_str(); } if( currentFrame->wasChangedSinceLastSave() ) { // Falls das Bild seid dem letzten speichern verändert wurde tinyxml2::XMLDocument doc; // Erstelle die xml datei doc.LinkEndChild( doc.NewDeclaration( "xml version=\"1.0\" " ) ); tinyxml2::XMLElement *annotation = doc.NewElement( "annotation"); annotation->LinkEndChild( doc.NewElement( "folder" ) )->LinkEndChild( doc.NewText( "VOC2007" ) ); annotation->LinkEndChild( doc.NewElement( "filename" ) )->LinkEndChild( doc.NewText( currentFrame->getName().toStdString().c_str() ) ); tinyxml2::XMLElement *source = doc.NewElement( "source" ); source->LinkEndChild( doc.NewElement( "database" ) )->LinkEndChild( doc.NewText( "The VOC2007 Database" ) ); source->LinkEndChild( doc.NewElement( "annotation" ) )->LinkEndChild( doc.NewText( "PASCAL VOC 2007" ) ); source->LinkEndChild( doc.NewElement( "image" ) )->LinkEndChild( doc.NewText( currentFrame->getName().toStdString().c_str() ) ); annotation->LinkEndChild( source ); annotation->LinkEndChild( doc.NewElement( "owner" ) )->LinkEndChild( doc.NewElement( "name" ) )->LinkEndChild( doc.NewText( "Kolja Strohm" ) ); annotation->LinkEndChild( doc.NewElement( "camera_id" ) )->LinkEndChild( doc.NewText( currentCam->getName().toStdString().c_str() ) ); tinyxml2::XMLElement *size = doc.NewElement( "size" ); QImage img = currentFrame->getImage(); size->LinkEndChild( doc.NewElement( "width" ) )->LinkEndChild( doc.NewText( std::to_string( img.width() ).c_str() ) ); size->LinkEndChild( doc.NewElement( "height" ) )->LinkEndChild( doc.NewText( std::to_string( img.height() ).c_str() ) ); size->LinkEndChild( doc.NewElement( "depth" ) )->LinkEndChild( doc.NewText( std::to_string( img.depth() ).c_str() ) ); annotation->LinkEndChild( size ); annotation->LinkEndChild( doc.NewElement( "segmented" ) )->LinkEndChild( doc.NewText( "0" ) ); annotation->LinkEndChild( doc.NewElement( "timestamp" ) )->LinkEndChild( doc.NewText( currentFrame->getTimestamp().toStdString().c_str() ) ); QList objects = currentFrame->getObjects(); for( ObjectPolygon o : objects ) { // Schleife durch alle Objekte tinyxml2::XMLElement *object = doc.NewElement( "object" ); object->LinkEndChild( doc.NewElement( "name" ) )->LinkEndChild( doc.NewText( getClassName( getClassOfObject( o->getId() ) ).toStdString().c_str() ) ); object->LinkEndChild( doc.NewElement( "id" ) )->LinkEndChild( doc.NewText( o->getId().toStdString().c_str() ) ); object->LinkEndChild( doc.NewElement( "pose" ) )->LinkEndChild( doc.NewText( "Unspecified" ) ); object->LinkEndChild( doc.NewElement( "truncated" ) )->LinkEndChild( doc.NewText( std::to_string( (int)o->isTruncated() ).c_str() ) ); object->LinkEndChild( doc.NewElement( "difficult" ) )->LinkEndChild( doc.NewText( "0" ) ); int xMin = img.width(); int yMin = img.height(); int xMax = 0; int yMax = 0; std::vector< tinyxml2::XMLElement* > polygons; for( QPolygon pol : o->getPolygonList() ) { // Schleife durch alle Polygone tinyxml2::XMLElement *polygon = doc.NewElement( "polygon" ); for( QPoint point : pol ) { // Schleife durch alle Eckpunkte tinyxml2::XMLElement *pointE = doc.NewElement( "point" ); pointE->LinkEndChild( doc.NewElement( "x" ) )->LinkEndChild( doc.NewText( std::to_string( point.x() ).c_str() ) ); pointE->LinkEndChild( doc.NewElement( "y" ) )->LinkEndChild( doc.NewText( std::to_string( point.y() ).c_str() ) ); polygon->LinkEndChild( pointE ); if( xMin > point.x() ) // ermittle die Bounding box xMin = point.x(); if( yMin > point.y() ) yMin = point.y(); if( xMax < point.x() ) xMax = point.x(); if( yMax < point.y() ) yMax = point.y(); } polygons.push_back( polygon ); } tinyxml2::XMLElement *bndbox = doc.NewElement( "bndbox" ); bndbox->LinkEndChild( doc.NewElement( "xmin" ) )->LinkEndChild( doc.NewText( std::to_string( xMin ).c_str() ) ); bndbox->LinkEndChild( doc.NewElement( "ymin" ) )->LinkEndChild( doc.NewText( std::to_string( yMin ).c_str() ) ); bndbox->LinkEndChild( doc.NewElement( "xmax" ) )->LinkEndChild( doc.NewText( std::to_string( xMax ).c_str() ) ); bndbox->LinkEndChild( doc.NewElement( "ymax" ) )->LinkEndChild( doc.NewText( std::to_string( yMax ).c_str() ) ); object->LinkEndChild( bndbox ); for( tinyxml2::XMLElement *polygon : polygons ) object->LinkEndChild( polygon ); annotation->LinkEndChild( object ); } if( objects.size() == 0 && currentFrame->isNotAnnotated() ) annotation->LinkEndChild( doc.NewElement( "noobject" ) )->LinkEndChild( doc.NewText( "need Annotation" ) ); doc.LinkEndChild( annotation ); QString name = currentFrame->getName(); QDir().mkpath( path + "/Annotations" ); doc.SaveFile( (path + "/Annotations/" + name.mid( 0, name.lastIndexOf( '.' ) ) + ".xml").toStdString().c_str() ); } progress.setValue( progress.value() + 1 ); } } trainTxt.close(); } // Erhöht den Reference Counter um 1 void Sequenz::refNew() { ref++; } // Verringert den Reference Counter um 1 (bei 0 löscht sich das Objekt selbst) void Sequenz::refRelease() { if( !--ref ) delete this; }