frame.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. #include "frame.h"
  2. #include "kamera.h"
  3. #include <QImage>
  4. #include <QMessageBox>
  5. #include <QDebug>
  6. // Erstellt das Bild
  7. // imgPath: Der Pfad zu dem Quellbild
  8. // timestamp: Der Zeitpunkt der Aufnahme des Bildes
  9. // index: Der Index des Bildes in der Liste aller Bilder der Kamera
  10. // kam: Die Kamera, die das Bild aufgenommen hat
  11. // needAnnotation: true, falls das Bild noch nicht annotiert wurde
  12. Frame::Frame( QString imgPath, QString timestamp, int index, Kamera *kam, bool needAnnotation )
  13. : FrameTreeNode( index, kam, 1 ),
  14. path( imgPath ),
  15. timestamp( timestamp ),
  16. needAnnotation( needAnnotation ),
  17. size( QSize( 0, 0 ) ),
  18. needSave( 0 )
  19. {}
  20. Frame::~Frame()
  21. {}
  22. // Legt fest, dass das Bild seit dem letzten speichern verändert wurde
  23. void Frame::setNeedSave()
  24. {
  25. needSave = 1;
  26. }
  27. // Gibt this zurück
  28. void *Frame::getNodeObject() const
  29. {
  30. return (void*)this;
  31. }
  32. // Gibt die Anzahl aller Objekte auf dem Bild zurück
  33. int Frame::getChildCount() const
  34. {
  35. return objects.size();
  36. }
  37. // Entfernt alle Eckpunkte in einem Gebit
  38. // area: Das Gebiet, in dem die Eckpunkte gelöscht werden sollen
  39. void Frame::removeSelectedVertices( QRect area )
  40. {
  41. needSave = 1;
  42. int anz = objects.size();
  43. for( int i = 0; i < anz; i++ )
  44. {
  45. ObjectPolygon o = objects.at( i );
  46. if( o->isSelected() )
  47. {
  48. if( !o->removeVertices( area ) )
  49. {
  50. objects.removeAt( i );
  51. i--;
  52. anz--;
  53. }
  54. }
  55. }
  56. }
  57. // Löscht ein bestimmtes Objekt
  58. // o: Das Objekt, welches gelöscht werden soll
  59. void Frame::removeObject( ObjectPolygon o )
  60. {
  61. needSave = 1;
  62. objects.removeOne( o );
  63. }
  64. // Fügt ein Objekt zu dem Bild hinzu. Das Objekt wird automatisch am
  65. // Bildrand abgeschnitten
  66. // name: Die ID des Objektes
  67. // truncated: true, falls das Objekt abgeschnitten ist
  68. // po: Eine Liste mit Polygonen, welche die Umrisse des Objektes sind
  69. void Frame::addObject( QString id, bool truncated, QList< QPolygon > po )
  70. {
  71. needSave = 1;
  72. if( po.size() < 1 )
  73. return;
  74. if( size != QSize( 0, 0 ) )
  75. {
  76. QPolygon cliped = clipPolygon( po.at( 0 ) );
  77. ObjectPolygon newObject( id, cliped, truncated || cliped.boundingRect() != po.at( 0 ).boundingRect(), objects.size(), this );
  78. int pAnz = po.count();
  79. for( int i = 1; i < pAnz; i++ )
  80. {
  81. cliped = clipPolygon( po.at( i ) );
  82. if( cliped.boundingRect() != po.at( i ).boundingRect() )
  83. newObject->setTruncated( true );
  84. newObject->getPolygonList().append( cliped );
  85. }
  86. objects.append( newObject );
  87. }
  88. else
  89. {
  90. ObjectPolygon newObject( id, po.at( 0 ), truncated, objects.size(), this );
  91. int pAnz = po.count();
  92. for( int i = 1; i < pAnz; i++ )
  93. newObject->getPolygonList().append( po.at( i ) );
  94. objects.append( newObject );
  95. }
  96. }
  97. // Wendet die Maske auf das Bild an und löscht alle Objekte, welche sich in
  98. // verbotenen Bereichen befinden
  99. // m: die Maske
  100. void Frame::applyMask( Mask &m )
  101. {
  102. needSave = 1;
  103. int count = objects.count();
  104. for( int i = 0; i < count; i++ )
  105. {
  106. int pAnz = objects.at( i )->getPolygonList().count();
  107. for( int j = 0; j < pAnz; j++ )
  108. {
  109. if( !m.isPolygonInside( objects.at( i )->getPolygonList().at( j ) ) )
  110. {
  111. pAnz--;
  112. objects.at( i )->getPolygonList().removeAt( j-- );
  113. if( pAnz <= 0 )
  114. {
  115. count--;
  116. objects.removeAt( i-- );
  117. }
  118. }
  119. }
  120. }
  121. }
  122. // Spaltet ein Objekt in zwei Teile
  123. // object: Das Objekt welches zerteilt werden soll
  124. // beginn: Der Index des Start Eckpunktes
  125. // end: Der Index des End Eckpunktes
  126. // pIndex: Der Index des Polygons, welches zerteilt werden soll
  127. void Frame::splitObject( ObjectPolygon object, int begin, int end, int pIndex )
  128. {
  129. needSave = 1;
  130. QPolygon newP = object->split( begin, end, pIndex );
  131. QList< QPolygon > newPols;
  132. newPols.append( newP );
  133. addObject( object->getId(), object->isTruncated(), newPols );
  134. }
  135. // gibt den Namen des Bildes zurück
  136. QString Frame::getName() const
  137. {
  138. return path.mid( path.lastIndexOf( '/' ) + 1 );
  139. }
  140. // Gibt den Aufnahmezeitpunkt des Bildes zurück
  141. QString Frame::getTimestamp() const
  142. {
  143. return timestamp;
  144. }
  145. // Gibt eine Liste mit Objekten zurück, welche sich auf dem Bild befinden
  146. QList< ObjectPolygon > &Frame::getObjects()
  147. {
  148. return objects;
  149. }
  150. // Setzt die Objekte, welche sich auf dem Bild befinden. Alle vorherigen
  151. // Objekte werden entfernt.
  152. // objects: die Liste mit den neuen Objekten
  153. void Frame::setObjects( std::vector< std::vector< cv::Point > > obs )
  154. {
  155. needSave = 1;
  156. needAnnotation = false;
  157. objects.clear();
  158. for( auto p = obs.begin(); p != obs.end(); p++ )
  159. {
  160. std::vector< cv::Point > pol;
  161. cv::approxPolyDP( *p, pol, 15, 1 );
  162. if( pol.size() > 2 )
  163. {
  164. QPolygon polygon;
  165. int count = 0;
  166. for( auto point = pol.begin(); point != pol.end(); point++, count++ )
  167. {
  168. polygon.append( QPoint( point->x, point->y ) );
  169. }
  170. QList< QPolygon > newPols;
  171. newPols.append( polygon );
  172. addObject( "-1", 0, newPols );
  173. }
  174. }
  175. }
  176. // Gibt das geladene Bild als Objekt des Qt Frameworks zurück
  177. QImage Frame::getImage()
  178. {
  179. QImage img( path );
  180. size = img.size();
  181. return img;
  182. }
  183. // Gibt das geladene Bild als Objekt der OpenCV Bibliotek zurück
  184. cv::Mat Frame::getImageMatrix() const
  185. {
  186. return cv::imread( path.toStdString() );
  187. }
  188. // Gibt den Bildausschnitt zurück, auf dem ein Objekt komplett sichtbar ist
  189. // objectId: die ID des Objektes, welches auf dem Bild sein soll
  190. QImage Frame::getObjectImage( QString objectId )
  191. {
  192. for( ObjectPolygon o : objects )
  193. {
  194. if( o->getId() == objectId )
  195. {
  196. QImage img = getImage();
  197. QRect bndBox = o->getBoundingBox();
  198. bndBox.setLeft( MAX( bndBox.left() - 200, 0 ) );
  199. bndBox.setTop( MAX( bndBox.top() - 200, 0 ) );
  200. bndBox.setRight( MIN( bndBox.right() + 200, img.width() ) );
  201. bndBox.setBottom( MIN( bndBox.bottom() + 200, img.height() ) );
  202. QImage ret = img.copy( bndBox );
  203. return ret;
  204. }
  205. }
  206. return QImage();
  207. }
  208. // Gibt den Bildausschnitt zurück, auf dem ein Objekt komplett sichtbar ist
  209. // object: das Objekt, welches auf dem Bild sein soll
  210. QImage Frame::getObjectImage( ObjectPolygon o )
  211. {
  212. QImage img = getImage();
  213. QRect bndBox = o->getBoundingBox();
  214. bndBox.setLeft( MAX( bndBox.left() - 200, 0 ) );
  215. bndBox.setTop( MAX( bndBox.top() - 200, 0 ) );
  216. bndBox.setRight( MIN( bndBox.right() + 200, img.width() ) );
  217. bndBox.setBottom( MIN( bndBox.bottom() + 200, img.height() ) );
  218. QImage ret = img.copy( bndBox );
  219. return ret;
  220. }
  221. // Prüft ob ein Objekt auf dem Bild vorhanden ist
  222. // id: Die ID des Objektes
  223. bool Frame::hasObject( QString id )
  224. {
  225. for( ObjectPolygon o : objects )
  226. {
  227. if( o->getId() == id )
  228. return true;
  229. }
  230. return false;
  231. }
  232. // Gibt true zurück, falls kein Fehler in der Annotation des Bildes gefunden
  233. // wurde
  234. bool Frame::isCorrectAnnotated() const
  235. {
  236. bool good = true;
  237. for( ObjectPolygon o1 : objects )
  238. {
  239. for( ObjectPolygon o2 : objects)
  240. {
  241. if( o1 == o2 )
  242. continue;
  243. good &= o2->getId() != o1->getId();
  244. }
  245. good &= o1->getId() != "-1";
  246. }
  247. return good;
  248. }
  249. // Gibt true zurück, falls das Bild noch nicht annotiert wurde
  250. bool Frame::isNotAnnotated() const
  251. {
  252. return needAnnotation;
  253. }
  254. // Gibt das Objekt zurück, welches an einer bestimmten Position im Bild ist.
  255. // 0 falls an der Stelle kein Objekt ist
  256. // pos: die Position, an der ein Objekt gesucht werden soll
  257. // pIndex: wird auf den Index des Polygons gesetzt, welches an der Stelle
  258. // ist, falls dort ein Objekt existiert
  259. ObjectPolygon Frame::getObjectAt( QPoint pos, int &pIndex ) const
  260. {
  261. for( ObjectPolygon o : objects )
  262. {
  263. pIndex = 0;
  264. for( QPolygon pol : o->getPolygonList() )
  265. {
  266. if( pol.containsPoint( pos, Qt::FillRule::OddEvenFill ) )
  267. return o;
  268. pIndex++;
  269. }
  270. }
  271. return ObjectPolygon();
  272. }
  273. // Setzt das Objekt an einer bestimmten Position im Bild.
  274. // Fals an der Position bereits ein Objekt existiert, so wird nur die Objekt
  275. // ID gesetzt.
  276. // pos: die Position
  277. // object: Das neue Objekt
  278. // center: Der Mittelpunkt des neuen Objektes
  279. // rotation: Die Drehung des neuen Objektes um den Mittelpunkt
  280. void Frame::setObjectAt( QPoint pos, ObjectPolygon copy, QPoint center, float rotation )
  281. {
  282. needSave = 1;
  283. for( ObjectPolygon o : objects )
  284. {
  285. for( QPolygon pol : o->getPolygonList() )
  286. {
  287. if( pol.containsPoint( pos, Qt::FillRule::OddEvenFill ) )
  288. {
  289. bool needQ = false;
  290. if( copy->getId() != "-1" )
  291. {
  292. for( ObjectPolygon o2 : objects )
  293. {
  294. if( o2 != o && o2->getId() == copy->getId() )
  295. needQ = 1;
  296. }
  297. }
  298. o->setId( copy->getId() );
  299. if( needQ )
  300. {
  301. 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?",
  302. QMessageBox::Yes|QMessageBox::No);
  303. if (reply == QMessageBox::Yes)
  304. connectObjects( copy->getId() );
  305. }
  306. return;
  307. }
  308. }
  309. }
  310. QMatrix m;
  311. m.QMatrix::translate( pos.x(), pos.y() );
  312. m.rotate( rotation );
  313. m.translate( -center.x(), -center.y() );
  314. QList< QPolygon > newPols;
  315. for( QPolygon p : copy->getPolygonList() )
  316. newPols.append( m.map( p ) );
  317. bool needQ = false;
  318. if( copy->getId() != "-1" )
  319. {
  320. for( ObjectPolygon o2 : objects )
  321. {
  322. if( o2->getId() == copy->getId() )
  323. needQ = 1;
  324. }
  325. }
  326. addObject( copy->getId(), copy->isTruncated(), newPols );
  327. if( needQ )
  328. {
  329. 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?",
  330. QMessageBox::Yes|QMessageBox::No);
  331. if (reply == QMessageBox::Yes)
  332. connectObjects( copy->getId() );
  333. }
  334. }
  335. // Macht ein Objekt an einer bestimmten Stelle sichtbar oder unsichtbar
  336. // pos: Die Position
  337. void Frame::selectObjectAt( QPoint pos )
  338. {
  339. for( ObjectPolygon o : objects )
  340. {
  341. for( QPolygon pol : o->getPolygonList() )
  342. {
  343. if( pol.containsPoint( pos, Qt::FillRule::OddEvenFill ) )
  344. o->setSelected( !o->isSelected() );
  345. }
  346. }
  347. }
  348. // Schneidet ein Polygon am rand des Bildes ab und gibt das Ergebnis zurück
  349. // uncliped: Das nicht abgeschnittene Polygon
  350. QPolygon Frame::clipPolygon( QPolygon uncliped ) const
  351. {
  352. QPolygon cliped = uncliped.intersected( QPolygon( QRect( QPoint( 0, 0 ), size ), true ) );
  353. if( !cliped.isEmpty() )
  354. cliped.pop_back();
  355. return cliped;
  356. }
  357. // Vereiniegt verschiedene Objekte mit der gleichen Objekt ID zu einem
  358. // id: Die ID, deren Objekte vereiniegt werden sollen
  359. void Frame::connectObjects( QString id )
  360. {
  361. needSave = 1;
  362. ObjectPolygon o;
  363. int oAnz = objects.count();
  364. for( int i = 0; i < oAnz; i++ )
  365. {
  366. ObjectPolygon o2 = objects.at( i );
  367. if( o2 != o && o2->getId() == id )
  368. {
  369. if( o.isNull() )
  370. o = o2;
  371. else
  372. {
  373. o->getPolygonList().append( o2->getPolygonList() );
  374. o->setTruncated( o->isTruncated() || o2->isTruncated() );
  375. o->setSelected( o->isSelected() || o2->isSelected() );
  376. objects.removeAt( i );
  377. i--;
  378. oAnz--;
  379. }
  380. }
  381. }
  382. }
  383. // Zerteilt ein Objekt, welches aus mehreren Polygonen besteht
  384. // o: Das Objekt welches zerteilt werden soll
  385. void Frame::disconnectObject( ObjectPolygon o )
  386. {
  387. needSave = 1;
  388. for( QPolygon p : o->getPolygonList() )
  389. {
  390. QList< QPolygon > plist;
  391. plist.append( p );
  392. addObject( o->getId(), o->isTruncated(), plist );
  393. }
  394. removeObject( o );
  395. }
  396. // Gibt 1 zurück, falls die Annotation zu dem Bild gespeichert werden muss
  397. // und setzt den Flag auf 0, so dass erst nach einer änderung wieder 1 zurückgegeben wird
  398. bool Frame::wasChangedSinceLastSave()
  399. {
  400. bool ret = needSave;
  401. needSave = 0;
  402. return ret;
  403. }