sequenz.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  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 das vom ausgewählten Bild um offset Bilder entfernte Bild zurück
  141. Frame *Sequenz::getFrame( int offset ) const
  142. {
  143. int currCam = cameraIndex;
  144. int currFrame = frameIndex;
  145. int oldCOunt = offset;
  146. do
  147. { // Schleife durch alle bilder (in die angegebene Richtung) bis ein Bild gefunden wird auf dem das Objekt vorkommt
  148. if( currFrame >= cams.at( currCam )->getChildCount() )
  149. {
  150. currCam++;
  151. if( currCam >= cams.size() )
  152. currCam = 0;
  153. currFrame = 0;
  154. }
  155. Frame *f = cams.at( currCam )->getFrame( currFrame );
  156. offset--;
  157. currFrame++;
  158. if( offset <= 0 ) // das gesuchte Bild wurde erreicht
  159. return f;
  160. if( currFrame == frameIndex && currCam == cameraIndex )
  161. {
  162. if( oldCOunt == offset )
  163. break;
  164. }
  165. } while( offset > 0 );
  166. return 0;
  167. }
  168. // Gibt den Index der ausgewählten Kamera zurück
  169. int Sequenz::getSelectedCamera() const
  170. {
  171. return cameraIndex;
  172. }
  173. // Gibt den Index des Ausgewählten Bildes (innerhalb der Kamera) zurück
  174. int Sequenz::getSelectedFrame() const
  175. {
  176. return frameIndex;
  177. }
  178. // Gibt eine Liste mit Kameras zurück
  179. const QList< Kamera* > &Sequenz::getCameras() const
  180. {
  181. return cams;
  182. }
  183. // Wählt das nachfolgende Bild aus
  184. void Sequenz::nextFrame()
  185. {
  186. if( !hasNextFrame() )
  187. return;
  188. if( ++frameIndex == cams.at( cameraIndex )->getChildCount() )
  189. {
  190. frameIndex = 0;
  191. cameraIndex++;
  192. }
  193. }
  194. // Wählt das vorherige Bild aus
  195. void Sequenz::previousFrame()
  196. {
  197. if( !hasPreviousFrame() )
  198. return;
  199. if( --frameIndex < 0 )
  200. frameIndex = cams.at( --cameraIndex )->getChildCount() - 1;
  201. }
  202. // Gibt 1 zurück, wenn in der Sequenz ein nachfolgendes Bild existiert
  203. bool Sequenz::hasNextFrame() const
  204. {
  205. return cameraIndex < cams.count() - 1 || frameIndex < cams.at( cameraIndex )->getChildCount() - 1;
  206. }
  207. // Gibt 1 zurück, wenn in der Sequenz ein vorheriges Bild existiert
  208. bool Sequenz::hasPreviousFrame() const
  209. {
  210. return frameIndex > 0 || cameraIndex > 0;
  211. }
  212. // Gibt eine Liste mit allen vergebenen ObjektIds zurück
  213. QList< QString > Sequenz::getObjectNames() const
  214. {
  215. QList<QString> result;
  216. foreach( Object obj, objects )
  217. result.append( obj.getId() );
  218. return result;
  219. }
  220. // Gibt von dem ausgewählten Bild aus das count-nächste Bild von dem Objekt mit ID objektId zurück.
  221. QImage Sequenz::previousObjectImage( QString packetName, int count ) const
  222. {
  223. int currCam = cameraIndex;
  224. int currFrame = frameIndex;
  225. QImage img;
  226. int dir = 1;
  227. if( count < 0 )
  228. { // falls count negativ ist, wird weiter vorne in der sequenz gesucht
  229. dir = -1;
  230. count = -count;
  231. }
  232. int oldCOunt = count;
  233. do
  234. { // Schleife durch alle bilder (in die angegebene Richtung) bis ein Bild gefunden wird auf dem das Objekt vorkommt
  235. if( (currFrame += dir) < 0 || currFrame >= cams.at( currCam )->getChildCount() )
  236. {
  237. if( (currCam += dir) < 0 || currCam >= cams.size() )
  238. {
  239. currCam = cams.size() - 1;
  240. if( dir > 0 )
  241. currCam = 0;
  242. }
  243. currFrame = cams.at( currCam )->getChildCount() - 1;
  244. if( dir > 0 )
  245. currFrame = 0;
  246. }
  247. Frame *f = cams.at( currCam )->getFrame( currFrame );
  248. if( f->hasObject( packetName ) )
  249. {
  250. count--;
  251. if( count <= 0 ) // das gesuchte Bild wurde erreicht
  252. img = f->getObjectImage( packetName );
  253. }
  254. if( currFrame == frameIndex && currCam == cameraIndex )
  255. {
  256. if( oldCOunt == count )
  257. break;
  258. }
  259. } while( count > 0 );
  260. return img;
  261. }
  262. // Gibt die größte vergebene Objekt Id zurück;
  263. int Sequenz::getMaxObjectId() const
  264. {
  265. int max = -1;
  266. for( auto o : objects )
  267. {
  268. if( o.getId().toInt() > max )
  269. max = o.getId().toInt();
  270. }
  271. return max;
  272. }
  273. // Fügt eine neue ObjektID mit der Klassen ID classID hinzu
  274. void Sequenz::addObjectName( QString name, int classId )
  275. {
  276. if( objects.indexOf( Object( name, classId ) ) < 0 )
  277. objects.append( Object( name, classId ) );
  278. }
  279. // Fügt eine neue ObjektID hinzu
  280. void Sequenz::addObjectName( QString name )
  281. {
  282. if( classes.size() > 0 )
  283. addObjectName( name, classes.first().id );
  284. else
  285. addObjectName( name, 0 );
  286. }
  287. // Speichert die Sequenz.
  288. // status: Ein Label, in denen Fortschrittsinformationen geschrieben werden
  289. void Sequenz::saveToPath( QLabel *status ) const
  290. {
  291. int numOps = 0;
  292. for( Kamera *k : cams )
  293. numOps += k->getChildCount();
  294. QProgressDialog progress( "Annotation wird gespeichert...", "", 0, numOps );
  295. progress.setWindowModality(Qt::WindowModal);
  296. progress.setCancelButton( 0 );
  297. if( !QFile( path + "/ImageSets/Main/train.txt" ).exists() )
  298. QDir( path + "/ImageSets/Main" ).mkpath(".");
  299. std::ofstream trainTxt( (path + "/ImageSets/Main/train.txt").toStdString().c_str() );
  300. for( int cam = 0; cam < cams.size(); cam++ )
  301. { // Schleife durch alle Kameras
  302. Kamera *currentCam = cams.at( cam );
  303. int frameCount = currentCam->getChildCount();
  304. for( int frame = 0; frame < frameCount; frame++ )
  305. { // Schleife durch alle Bilder
  306. if( status )
  307. {
  308. QString text = "save Annotations " + QString::number( cam + 1 ) + "/" + QString::number( cams.size() ) + " " + QString::number( frame + 1 ) + "/" + QString::number( cams.at( cam )->getChildCount() );
  309. QMetaObject::invokeMethod( status, "setText", Q_ARG( QString, text ) );
  310. }
  311. Frame *currentFrame = currentCam->getFrame( frame );
  312. if( !currentFrame->isNotAnnotated() || currentFrame->getObjects().size() > 0 )
  313. {
  314. trainTxt << ( currentFrame->getName().mid( 0, currentFrame->getName().indexOf( "." ) ) + "\n" ).toStdString().c_str();
  315. }
  316. if( currentFrame->wasChangedSinceLastSave() )
  317. { // Falls das Bild seid dem letzten speichern verändert wurde
  318. tinyxml2::XMLDocument doc; // Erstelle die xml datei
  319. doc.LinkEndChild( doc.NewDeclaration( "xml version=\"1.0\" " ) );
  320. tinyxml2::XMLElement *annotation = doc.NewElement( "annotation");
  321. annotation->LinkEndChild( doc.NewElement( "folder" ) )->LinkEndChild( doc.NewText( "VOC2007" ) );
  322. annotation->LinkEndChild( doc.NewElement( "filename" ) )->LinkEndChild( doc.NewText( currentFrame->getName().toStdString().c_str() ) );
  323. tinyxml2::XMLElement *source = doc.NewElement( "source" );
  324. source->LinkEndChild( doc.NewElement( "database" ) )->LinkEndChild( doc.NewText( "The VOC2007 Database" ) );
  325. source->LinkEndChild( doc.NewElement( "annotation" ) )->LinkEndChild( doc.NewText( "PASCAL VOC 2007" ) );
  326. source->LinkEndChild( doc.NewElement( "image" ) )->LinkEndChild( doc.NewText( currentFrame->getName().toStdString().c_str() ) );
  327. annotation->LinkEndChild( source );
  328. annotation->LinkEndChild( doc.NewElement( "owner" ) )->LinkEndChild( doc.NewElement( "name" ) )->LinkEndChild( doc.NewText( "Kolja Strohm" ) );
  329. annotation->LinkEndChild( doc.NewElement( "camera_id" ) )->LinkEndChild( doc.NewText( currentCam->getName().toStdString().c_str() ) );
  330. tinyxml2::XMLElement *size = doc.NewElement( "size" );
  331. QImage img = currentFrame->getImage();
  332. size->LinkEndChild( doc.NewElement( "width" ) )->LinkEndChild( doc.NewText( std::to_string( img.width() ).c_str() ) );
  333. size->LinkEndChild( doc.NewElement( "height" ) )->LinkEndChild( doc.NewText( std::to_string( img.height() ).c_str() ) );
  334. size->LinkEndChild( doc.NewElement( "depth" ) )->LinkEndChild( doc.NewText( std::to_string( img.depth() ).c_str() ) );
  335. annotation->LinkEndChild( size );
  336. annotation->LinkEndChild( doc.NewElement( "segmented" ) )->LinkEndChild( doc.NewText( "0" ) );
  337. annotation->LinkEndChild( doc.NewElement( "timestamp" ) )->LinkEndChild( doc.NewText( currentFrame->getTimestamp().toStdString().c_str() ) );
  338. QList<ObjectPolygon> objects = currentFrame->getObjects();
  339. for( ObjectPolygon o : objects )
  340. { // Schleife durch alle Objekte
  341. tinyxml2::XMLElement *object = doc.NewElement( "object" );
  342. object->LinkEndChild( doc.NewElement( "name" ) )->LinkEndChild( doc.NewText( getClassName( getClassOfObject( o->getId() ) ).toStdString().c_str() ) );
  343. object->LinkEndChild( doc.NewElement( "id" ) )->LinkEndChild( doc.NewText( o->getId().toStdString().c_str() ) );
  344. object->LinkEndChild( doc.NewElement( "pose" ) )->LinkEndChild( doc.NewText( "Unspecified" ) );
  345. object->LinkEndChild( doc.NewElement( "truncated" ) )->LinkEndChild( doc.NewText( std::to_string( (int)o->isTruncated() ).c_str() ) );
  346. object->LinkEndChild( doc.NewElement( "difficult" ) )->LinkEndChild( doc.NewText( "0" ) );
  347. int xMin = img.width();
  348. int yMin = img.height();
  349. int xMax = 0;
  350. int yMax = 0;
  351. std::vector< tinyxml2::XMLElement* > polygons;
  352. for( QPolygon pol : o->getPolygonList() )
  353. { // Schleife durch alle Polygone
  354. tinyxml2::XMLElement *polygon = doc.NewElement( "polygon" );
  355. for( QPoint point : pol )
  356. { // Schleife durch alle Eckpunkte
  357. tinyxml2::XMLElement *pointE = doc.NewElement( "point" );
  358. pointE->LinkEndChild( doc.NewElement( "x" ) )->LinkEndChild( doc.NewText( std::to_string( point.x() ).c_str() ) );
  359. pointE->LinkEndChild( doc.NewElement( "y" ) )->LinkEndChild( doc.NewText( std::to_string( point.y() ).c_str() ) );
  360. polygon->LinkEndChild( pointE );
  361. if( xMin > point.x() ) // ermittle die Bounding box
  362. xMin = point.x();
  363. if( yMin > point.y() )
  364. yMin = point.y();
  365. if( xMax < point.x() )
  366. xMax = point.x();
  367. if( yMax < point.y() )
  368. yMax = point.y();
  369. }
  370. polygons.push_back( polygon );
  371. }
  372. tinyxml2::XMLElement *bndbox = doc.NewElement( "bndbox" );
  373. bndbox->LinkEndChild( doc.NewElement( "xmin" ) )->LinkEndChild( doc.NewText( std::to_string( xMin ).c_str() ) );
  374. bndbox->LinkEndChild( doc.NewElement( "ymin" ) )->LinkEndChild( doc.NewText( std::to_string( yMin ).c_str() ) );
  375. bndbox->LinkEndChild( doc.NewElement( "xmax" ) )->LinkEndChild( doc.NewText( std::to_string( xMax ).c_str() ) );
  376. bndbox->LinkEndChild( doc.NewElement( "ymax" ) )->LinkEndChild( doc.NewText( std::to_string( yMax ).c_str() ) );
  377. object->LinkEndChild( bndbox );
  378. for( tinyxml2::XMLElement *polygon : polygons )
  379. object->LinkEndChild( polygon );
  380. annotation->LinkEndChild( object );
  381. }
  382. if( objects.size() == 0 && currentFrame->isNotAnnotated() )
  383. annotation->LinkEndChild( doc.NewElement( "noobject" ) )->LinkEndChild( doc.NewText( "need Annotation" ) );
  384. doc.LinkEndChild( annotation );
  385. QString name = currentFrame->getName();
  386. QDir().mkpath( path + "/Annotations" );
  387. doc.SaveFile( (path + "/Annotations/" + name.mid( 0, name.lastIndexOf( '.' ) ) + ".xml").toStdString().c_str() );
  388. }
  389. progress.setValue( progress.value() + 1 );
  390. }
  391. }
  392. trainTxt.close();
  393. }
  394. // Erhöht den Reference Counter um 1
  395. void Sequenz::refNew()
  396. {
  397. ref++;
  398. }
  399. // Verringert den Reference Counter um 1 (bei 0 löscht sich das Objekt selbst)
  400. void Sequenz::refRelease()
  401. {
  402. if( !--ref )
  403. delete this;
  404. }