frame.cpp 12 KB

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