sequenz.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. #include "sequenz.h"
  2. #include <tinyxml2.h>
  3. #include <QtConcurrent/QtConcurrent>
  4. #include <QProgressDialog>
  5. #include <fstream>
  6. Sequenz::Sequenz( QString p, QList< Kamera* > c, QList< Object > o )
  7. : ref( 1 ),
  8. path( p ),
  9. frameIndex( 0 ),
  10. cameraIndex( 0 ),
  11. cams( c ),
  12. objects( o )
  13. {
  14. addClass( "packingbox" );
  15. }
  16. Sequenz::~Sequenz()
  17. {
  18. for( auto k = cams.begin(); k != cams.end(); k++ )
  19. (*k)->refRelease();
  20. }
  21. // Gibt eine Liste mit allen bekannten Objekt Klassen zurück
  22. QList< Sequenz::SegmentationClass > Sequenz::getClasses() const
  23. {
  24. return classes;
  25. }
  26. // Setzt den Namen der Objekt Klasse mit der ID id auf name
  27. bool Sequenz::setClassName( int id, QString name )
  28. {
  29. int i = getClassId( name );
  30. if( i == id )
  31. return true;
  32. if( i != -1 )
  33. return false;
  34. for( auto c = classes.begin(); c != classes.end(); c++ )
  35. {
  36. if( c->id == id )
  37. {
  38. c->name = name;
  39. return true;
  40. }
  41. }
  42. return false;
  43. }
  44. // Prüft, ob bereits annotierte Objekte in der Sequenz vorhanden sind
  45. QString Sequenz::getClassName( int id ) const
  46. {
  47. for( auto c = classes.begin(); c != classes.end(); c++ )
  48. {
  49. if( c->id == id )
  50. return c->name;
  51. }
  52. return "NULL";
  53. }
  54. // Gibt den Namen der Objekt Klasse mit der ID id zurück
  55. int Sequenz::getClassId( QString name ) const
  56. {
  57. for( auto c = classes.begin(); c != classes.end(); c++ )
  58. {
  59. if( c->name == name )
  60. return c->id;
  61. }
  62. return -1;
  63. }
  64. // Gibt die ID der Objekt Klasse mit dem Namen name zurück
  65. int Sequenz::getClassOfObject( QString id ) const
  66. {
  67. for( auto obj = objects.begin(); obj != objects.end(); obj++ )
  68. {
  69. if( obj->getId() == id )
  70. return obj->getClassId();
  71. }
  72. return -1;
  73. }
  74. // Gibt die ID der Klasse des Objektes mit der ID objektId zurück
  75. void Sequenz::setClassOfObject( QString id, int classId )
  76. {
  77. for( auto obj = objects.begin(); obj != objects.end(); obj++ )
  78. {
  79. if( obj->getId() == id )
  80. obj->setClassId( classId );
  81. }
  82. }
  83. // Setzt die ID der Klasse des Objektes mit der ID objektId auf classId
  84. bool Sequenz::hasAnnotatedObjects() const
  85. {
  86. for( Object o : objects )
  87. {
  88. if( o.getId() != "-1" )
  89. return true;
  90. }
  91. return false;
  92. }
  93. // Fügt eine neue Objekt Klasse mit Namen name hinzu
  94. int Sequenz::addClass( QString name )
  95. {
  96. if( getClassId( name ) != -1 )
  97. return -1;
  98. int max = -1;
  99. for( auto c = classes.begin(); c != classes.end(); c++ )
  100. {
  101. if( c->id > max )
  102. max = c->id;
  103. }
  104. max++;
  105. classes.append( { max, name } );
  106. return max;
  107. }
  108. // Entfernt die Objektklasse mit der ID id
  109. bool Sequenz::removeClass( int id )
  110. {
  111. for( auto c = classes.begin(); c != classes.end(); c++ )
  112. {
  113. if( c->id == id )
  114. {
  115. classes.erase( c );
  116. int newId = 0;
  117. if( classes.size() > 0 )
  118. newId = classes.first().id;
  119. for( auto obj = objects.begin(); obj != objects.end(); obj++ )
  120. {
  121. if( obj->getClassId() == id )
  122. obj->setClassId(newId);
  123. }
  124. return true;
  125. }
  126. }
  127. return false;
  128. }
  129. // Wählt das frame-te Bild der cam-ten Kamera aus
  130. void Sequenz::selectFrame( int cam, int frame )
  131. {
  132. cameraIndex = cam;
  133. frameIndex = frame;
  134. }
  135. // Gibt das ausgewählte Bild zurück
  136. Frame *Sequenz::getFrame() const
  137. {
  138. return cams.at( cameraIndex )->getFrame( frameIndex );
  139. }
  140. // Gibt den Index der ausgewählten Kamera zurück
  141. int Sequenz::getSelectedCamera() const
  142. {
  143. return cameraIndex;
  144. }
  145. // Gibt den Index des Ausgewählten Bildes (innerhalb der Kamera) zurück
  146. int Sequenz::getSelectedFrame() const
  147. {
  148. return frameIndex;
  149. }
  150. // Gibt eine Liste mit Kameras zurück
  151. const QList< Kamera* > &Sequenz::getCameras() const
  152. {
  153. return cams;
  154. }
  155. // Wählt das nachfolgende Bild aus
  156. void Sequenz::nextFrame()
  157. {
  158. if( !hasNextFrame() )
  159. return;
  160. if( ++frameIndex == cams.at( cameraIndex )->getChildCount() )
  161. {
  162. frameIndex = 0;
  163. cameraIndex++;
  164. }
  165. }
  166. // Wählt das vorherige Bild aus
  167. void Sequenz::previousFrame()
  168. {
  169. if( !hasPreviousFrame() )
  170. return;
  171. if( --frameIndex < 0 )
  172. frameIndex = cams.at( --cameraIndex )->getChildCount() - 1;
  173. }
  174. // Gibt 1 zurück, wenn in der Sequenz ein nachfolgendes Bild existiert
  175. bool Sequenz::hasNextFrame() const
  176. {
  177. return cameraIndex < cams.count() - 1 || frameIndex < cams.at( cameraIndex )->getChildCount() - 1;
  178. }
  179. // Gibt 1 zurück, wenn in der Sequenz ein vorheriges Bild existiert
  180. bool Sequenz::hasPreviousFrame() const
  181. {
  182. return frameIndex > 0 || cameraIndex > 0;
  183. }
  184. // Gibt eine Liste mit allen vergebenen ObjektIds zurück
  185. QList< QString > Sequenz::getObjectNames() const
  186. {
  187. QList<QString> result;
  188. foreach( Object obj, objects )
  189. result.append( obj.getId() );
  190. return result;
  191. }
  192. // Gibt von dem ausgewählten Bild aus das count-nächste Bild von dem Objekt mit ID objektId zurück.
  193. QImage Sequenz::previousObjectImage( QString packetName, int count ) const
  194. {
  195. int currCam = cameraIndex;
  196. int currFrame = frameIndex;
  197. QImage img;
  198. int dir = 1;
  199. if( count < 0 )
  200. { // falls count negativ ist, wird weiter vorne in der sequenz gesucht
  201. dir = -1;
  202. count = -count;
  203. }
  204. int oldCOunt = count;
  205. do
  206. { // Schleife durch alle bilder (in die angegebene Richtung) bis ein Bild gefunden wird auf dem das Objekt vorkommt
  207. if( (currFrame += dir) < 0 || currFrame >= cams.at( currCam )->getChildCount() )
  208. {
  209. if( (currCam += dir) < 0 || currCam >= cams.size() )
  210. {
  211. currCam = cams.size() - 1;
  212. if( dir > 0 )
  213. currCam = 0;
  214. }
  215. currFrame = cams.at( currCam )->getChildCount() - 1;
  216. if( dir > 0 )
  217. currFrame = 0;
  218. }
  219. if( currFrame == frameIndex && currCam == cameraIndex )
  220. {
  221. if( oldCOunt == count )
  222. break;
  223. }
  224. Frame *f = cams.at( currCam )->getFrame( currFrame );
  225. if( f->hasObject( packetName ) )
  226. {
  227. count--;
  228. if( count == 0 ) // das gesuchte Bild wurde erreicht
  229. img = f->getObjectImage( packetName );
  230. }
  231. } while( count > 0 );
  232. return img;
  233. }
  234. // Fügt eine neue ObjektID mit der Klassen ID classID hinzu
  235. void Sequenz::addObjectName( QString name, int classId )
  236. {
  237. if( objects.indexOf( Object( name, classId ) ) < 0 )
  238. objects.append( Object( name, classId ) );
  239. }
  240. // Fügt eine neue ObjektID hinzu
  241. void Sequenz::addObjectName( QString name )
  242. {
  243. if( classes.size() > 0 )
  244. addObjectName( name, classes.first().id );
  245. else
  246. addObjectName( name, 0 );
  247. }
  248. // Speichert die Sequenz.
  249. // status: Ein Label, in denen Fortschrittsinformationen geschrieben werden
  250. void Sequenz::saveToPath( QLabel *status ) const
  251. {
  252. int numOps = 0;
  253. for( Kamera *k : cams )
  254. numOps += k->getChildCount();
  255. QProgressDialog progress( "Annotation wird gespeichert...", "", 0, numOps );
  256. progress.setWindowModality(Qt::WindowModal);
  257. progress.setCancelButton( 0 );
  258. if( !QFile( path + "/ImageSets/Main/train.txt" ).exists() )
  259. QDir( path + "/ImageSets/Main" ).mkpath(".");
  260. std::ofstream trainTxt( (path + "/ImageSets/Main/train.txt").toStdString().c_str() );
  261. for( int cam = 0; cam < cams.size(); cam++ )
  262. { // Schleife durch alle Kameras
  263. Kamera *currentCam = cams.at( cam );
  264. int frameCount = currentCam->getChildCount();
  265. for( int frame = 0; frame < frameCount; frame++ )
  266. { // Schleife durch alle Bilder
  267. if( status )
  268. {
  269. QString text = "save Annotations " + QString::number( cam + 1 ) + "/" + QString::number( cams.size() ) + " " + QString::number( frame + 1 ) + "/" + QString::number( cams.at( cam )->getChildCount() );
  270. QMetaObject::invokeMethod( status, "setText", Q_ARG( QString, text ) );
  271. }
  272. Frame *currentFrame = currentCam->getFrame( frame );
  273. if( !currentFrame->isNotAnnotated() || currentFrame->getObjects().size() > 0 )
  274. {
  275. trainTxt << ( currentFrame->getName().mid( 0, currentFrame->getName().indexOf( "." ) ) + "\n" ).toStdString().c_str();
  276. }
  277. if( currentFrame->wasChangedSinceLastSave() )
  278. { // Falls das Bild seid dem letzten speichern verändert wurde
  279. tinyxml2::XMLDocument doc; // Erstelle die xml datei
  280. doc.LinkEndChild( doc.NewDeclaration( "xml version=\"1.0\" " ) );
  281. tinyxml2::XMLElement *annotation = doc.NewElement( "annotation");
  282. annotation->LinkEndChild( doc.NewElement( "folder" ) )->LinkEndChild( doc.NewText( "VOC2007" ) );
  283. annotation->LinkEndChild( doc.NewElement( "filename" ) )->LinkEndChild( doc.NewText( currentFrame->getName().toStdString().c_str() ) );
  284. tinyxml2::XMLElement *source = doc.NewElement( "source" );
  285. source->LinkEndChild( doc.NewElement( "database" ) )->LinkEndChild( doc.NewText( "The VOC2007 Database" ) );
  286. source->LinkEndChild( doc.NewElement( "annotation" ) )->LinkEndChild( doc.NewText( "PASCAL VOC 2007" ) );
  287. source->LinkEndChild( doc.NewElement( "image" ) )->LinkEndChild( doc.NewText( currentFrame->getName().toStdString().c_str() ) );
  288. annotation->LinkEndChild( source );
  289. annotation->LinkEndChild( doc.NewElement( "owner" ) )->LinkEndChild( doc.NewElement( "name" ) )->LinkEndChild( doc.NewText( "Kolja Strohm" ) );
  290. annotation->LinkEndChild( doc.NewElement( "camera_id" ) )->LinkEndChild( doc.NewText( currentCam->getName().toStdString().c_str() ) );
  291. tinyxml2::XMLElement *size = doc.NewElement( "size" );
  292. QImage img = currentFrame->getImage();
  293. size->LinkEndChild( doc.NewElement( "width" ) )->LinkEndChild( doc.NewText( std::to_string( img.width() ).c_str() ) );
  294. size->LinkEndChild( doc.NewElement( "height" ) )->LinkEndChild( doc.NewText( std::to_string( img.height() ).c_str() ) );
  295. size->LinkEndChild( doc.NewElement( "depth" ) )->LinkEndChild( doc.NewText( std::to_string( img.depth() ).c_str() ) );
  296. annotation->LinkEndChild( size );
  297. annotation->LinkEndChild( doc.NewElement( "segmented" ) )->LinkEndChild( doc.NewText( "0" ) );
  298. annotation->LinkEndChild( doc.NewElement( "timestamp" ) )->LinkEndChild( doc.NewText( currentFrame->getTimestamp().toStdString().c_str() ) );
  299. QList<ObjectPolygon> objects = currentFrame->getObjects();
  300. for( ObjectPolygon o : objects )
  301. { // Schleife durch alle Objekte
  302. tinyxml2::XMLElement *object = doc.NewElement( "object" );
  303. object->LinkEndChild( doc.NewElement( "name" ) )->LinkEndChild( doc.NewText( getClassName( getClassOfObject( o->getId() ) ).toStdString().c_str() ) );
  304. object->LinkEndChild( doc.NewElement( "id" ) )->LinkEndChild( doc.NewText( o->getId().toStdString().c_str() ) );
  305. object->LinkEndChild( doc.NewElement( "pose" ) )->LinkEndChild( doc.NewText( "Unspecified" ) );
  306. object->LinkEndChild( doc.NewElement( "truncated" ) )->LinkEndChild( doc.NewText( std::to_string( (int)o->isTruncated() ).c_str() ) );
  307. object->LinkEndChild( doc.NewElement( "difficult" ) )->LinkEndChild( doc.NewText( "0" ) );
  308. int xMin = img.width();
  309. int yMin = img.height();
  310. int xMax = 0;
  311. int yMax = 0;
  312. std::vector< tinyxml2::XMLElement* > polygons;
  313. for( QPolygon pol : o->getPolygonList() )
  314. { // Schleife durch alle Polygone
  315. tinyxml2::XMLElement *polygon = doc.NewElement( "polygon" );
  316. for( QPoint point : pol )
  317. { // Schleife durch alle Eckpunkte
  318. tinyxml2::XMLElement *pointE = doc.NewElement( "point" );
  319. pointE->LinkEndChild( doc.NewElement( "x" ) )->LinkEndChild( doc.NewText( std::to_string( point.x() ).c_str() ) );
  320. pointE->LinkEndChild( doc.NewElement( "y" ) )->LinkEndChild( doc.NewText( std::to_string( point.y() ).c_str() ) );
  321. polygon->LinkEndChild( pointE );
  322. if( xMin > point.x() ) // ermittle die Bounding box
  323. xMin = point.x();
  324. if( yMin > point.y() )
  325. yMin = point.y();
  326. if( xMax < point.x() )
  327. xMax = point.x();
  328. if( yMax < point.y() )
  329. yMax = point.y();
  330. }
  331. polygons.push_back( polygon );
  332. }
  333. tinyxml2::XMLElement *bndbox = doc.NewElement( "bndbox" );
  334. bndbox->LinkEndChild( doc.NewElement( "xmin" ) )->LinkEndChild( doc.NewText( std::to_string( xMin ).c_str() ) );
  335. bndbox->LinkEndChild( doc.NewElement( "ymin" ) )->LinkEndChild( doc.NewText( std::to_string( yMin ).c_str() ) );
  336. bndbox->LinkEndChild( doc.NewElement( "xmax" ) )->LinkEndChild( doc.NewText( std::to_string( xMax ).c_str() ) );
  337. bndbox->LinkEndChild( doc.NewElement( "ymax" ) )->LinkEndChild( doc.NewText( std::to_string( yMax ).c_str() ) );
  338. object->LinkEndChild( bndbox );
  339. for( tinyxml2::XMLElement *polygon : polygons )
  340. object->LinkEndChild( polygon );
  341. annotation->LinkEndChild( object );
  342. }
  343. if( objects.size() == 0 && currentFrame->isNotAnnotated() )
  344. annotation->LinkEndChild( doc.NewElement( "noobject" ) )->LinkEndChild( doc.NewText( "need Annotation" ) );
  345. doc.LinkEndChild( annotation );
  346. QString name = currentFrame->getName();
  347. QDir().mkpath( path + "/Annotations" );
  348. doc.SaveFile( (path + "/Annotations/" + name.mid( 0, name.lastIndexOf( '.' ) ) + ".xml").toStdString().c_str() );
  349. }
  350. progress.setValue( progress.value() + 1 );
  351. }
  352. }
  353. trainTxt.close();
  354. }
  355. // Erhöht den Reference Counter um 1
  356. void Sequenz::refNew()
  357. {
  358. ref++;
  359. }
  360. // Verringert den Reference Counter um 1 (bei 0 löscht sich das Objekt selbst)
  361. void Sequenz::refRelease()
  362. {
  363. if( !--ref )
  364. delete this;
  365. }