ImageLabeler.cpp 96 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039
  1. /*!
  2. * \file ImageLabeler.cpp
  3. * \brief implementation of the ImageLabeler class
  4. *
  5. * Main widget which contains all GUI elements
  6. * and connect them with each other.
  7. *
  8. * Created on: Oct 4, 2011
  9. * Author: Gapchich Vladislav
  10. */
  11. #include "ImageLabeler.h"
  12. #include "functions.h"
  13. #include <QApplication>
  14. #include <QFrame>
  15. #include <QMenuBar>
  16. #include <QMenu>
  17. #include <QAction>
  18. #include <QBoxLayout>
  19. #include <QGridLayout>
  20. #include <QPixmap>
  21. #include <QLabel>
  22. #include <QCheckBox>
  23. #include <QScrollArea>
  24. #include <QPushButton>
  25. #include <QButtonGroup>
  26. #include <QListWidget>
  27. #include <QListWidgetItem>
  28. #include <QDesktopWidget>
  29. #include <QFileDialog>
  30. #include <QColorDialog>
  31. #include <QDir>
  32. #include <QMessageBox>
  33. #include <QListIterator>
  34. #include <QDomDocument>
  35. #include <QFile>
  36. #include <QKeyEvent>
  37. #include <QSettings>
  38. #include <QDebug>
  39. //! A constructor of the main class
  40. /*!
  41. * \param[in,out] aParent a pointer to the parent widget.
  42. * If aParent is 0, then ImageLabeler becomes a window, otherwise
  43. * it becomes a child of some other widget
  44. * \param[in] aSettingPath alters the path to the file with settings
  45. * (default path is /path/to/binary/ImageLabeler.ini)
  46. *
  47. * A constructor is responsible for allocating memory for all the
  48. * GUI objects, arranging and connecting them in the right order.
  49. */
  50. ImageLabeler::ImageLabeler(QWidget *aParent, QString aSettingsPath) :
  51. QMainWindow(aParent)
  52. {
  53. /*
  54. * Variables
  55. */
  56. list_images_ = new QList< Image >;
  57. main_label_ = -1;
  58. pure_data_ = 0;
  59. //label_ID_ = -1;
  60. /* options */
  61. auto_color_generation_ = 0;
  62. /* flags */
  63. interrupt_search_ = 0;
  64. unsaved_data_ = 0;
  65. /*
  66. * menu bar part begins
  67. */
  68. menu_bar_ = new QMenuBar(this);
  69. setMenuBar(menu_bar_);
  70. menu_file_ = new QMenu(menu_bar_);
  71. menu_file_->setTitle(tr("&File"));
  72. menu_pascal_ = new QMenu(menu_bar_);
  73. menu_pascal_->setTitle(tr("&Pascal"));
  74. menu_view_ = new QMenu(menu_bar_);
  75. menu_view_->setTitle(tr("&View"));
  76. menu_edit_ = new QMenu(menu_bar_);
  77. menu_edit_->setTitle(tr("&Edit"));
  78. menu_help_ = new QMenu(menu_bar_);
  79. menu_help_->setTitle(tr("&Help"));
  80. /* menu file */
  81. action_open_image_ = new QAction(this);
  82. action_open_image_->setText(tr("&Load image"));
  83. action_open_images_ = new QAction(this);
  84. action_open_images_->setText(tr("&Load images(recursively)"));
  85. action_open_labeled_image_ = new QAction(this);
  86. action_open_labeled_image_->setText(tr("&Load labeled image"));
  87. action_load_legend_ = new QAction(this);
  88. action_load_legend_->setText(tr("&Load legend"));
  89. action_save_all_ = new QAction(this);
  90. action_save_all_->setText(tr("&Save all info"));
  91. action_save_all_->setEnabled(false);
  92. action_save_segmented_ = new QAction(this);
  93. action_save_segmented_->setText(tr("Save segmented &picture"));
  94. action_save_segmented_->setEnabled(false);
  95. action_save_legend_ = new QAction(this);
  96. action_save_legend_->setText(tr("Save &legend"));
  97. action_save_legend_->setEnabled(false);
  98. action_quit_ = new QAction(this);
  99. action_quit_->setText(tr("&Quit"));
  100. /* menu pascal */
  101. action_load_pascal_file_ = new QAction(this);
  102. action_load_pascal_file_->setText(tr("&Load pascal file"));
  103. action_load_pascal_poly_ = new QAction(this);
  104. action_load_pascal_poly_->setText(tr("&Load poly info"));
  105. /* menu view */
  106. action_view_normal_ = new QAction(this);
  107. action_view_normal_->setText(tr("&Normal"));
  108. action_view_normal_->setEnabled(false);
  109. action_view_segmented_ = new QAction(this);
  110. action_view_segmented_->setText(tr("&Segmented"));
  111. action_view_segmented_->setEnabled(false);
  112. /* menu edit */
  113. action_undo_ = new QAction(this);
  114. action_undo_->setText(tr("&Undo"));
  115. action_undo_->setEnabled(false);
  116. action_redo_ = new QAction(this);
  117. action_redo_->setText(tr("&Redo"));
  118. action_redo_->setEnabled(false);
  119. action_bound_box_tool_ = new QAction(this);
  120. action_bound_box_tool_->setText(tr("Bounding box tool"));
  121. action_bound_box_tool_->setEnabled(false);
  122. action_polygon_tool_ = new QAction(this);
  123. action_polygon_tool_->setText(tr("&Polygon tool"));
  124. action_polygon_tool_->setEnabled(false);
  125. action_tagging_tool_ = new QAction(this);
  126. action_tagging_tool_->setText(tr("&Tagging tool"));
  127. action_tagging_tool_->setEnabled(false);
  128. action_add_description_ = new QAction(this);
  129. action_add_description_->setText(tr("&Add image description"));
  130. action_add_description_->setEnabled(false);
  131. action_options_ = new QAction(this);
  132. action_options_->setText(tr("&Options"));
  133. /* menu help */
  134. action_help_content_ = new QAction(this);
  135. action_help_content_->setText(tr("&Help content"));
  136. action_help_content_->setEnabled(false);
  137. action_about_ = new QAction(this);
  138. action_about_->setText(tr("&About"));
  139. action_about_->setEnabled(false);
  140. /* ------------------ */
  141. menu_file_->addAction(action_open_image_);
  142. menu_file_->addAction(action_open_images_);
  143. menu_file_->addAction(action_open_labeled_image_);
  144. menu_file_->addAction(action_load_legend_);
  145. menu_file_->addAction(menu_pascal_->menuAction());
  146. menu_file_->addSeparator();
  147. menu_file_->addAction(action_save_segmented_);
  148. menu_file_->addAction(action_save_legend_);
  149. menu_file_->addAction(action_save_all_);
  150. menu_file_->addSeparator();
  151. menu_file_->addAction(action_quit_);
  152. menu_pascal_->addAction(action_load_pascal_file_);
  153. menu_pascal_->addAction(action_load_pascal_poly_);
  154. menu_view_->addAction(action_view_normal_);
  155. menu_view_->addAction(action_view_segmented_);
  156. menu_edit_->addAction(action_undo_);
  157. menu_edit_->addAction(action_redo_);
  158. menu_edit_->addSeparator();
  159. menu_edit_->addAction(action_bound_box_tool_);
  160. menu_edit_->addAction(action_polygon_tool_);
  161. menu_edit_->addAction(action_tagging_tool_);
  162. menu_edit_->addSeparator();
  163. menu_edit_->addAction(action_add_description_);
  164. menu_edit_->addAction(action_options_);
  165. menu_help_->addAction(action_help_content_);
  166. menu_help_->addAction(action_about_);
  167. menu_bar_->addAction(menu_file_->menuAction());
  168. menu_bar_->addAction(menu_view_->menuAction());
  169. menu_bar_->addAction(menu_edit_->menuAction());
  170. menu_bar_->addAction(menu_help_->menuAction());
  171. /*
  172. * popup menu part begins
  173. */
  174. popup_area_list_ = new QMenu;
  175. action_delete_area_ = new QAction(this);
  176. action_delete_area_->setText(tr("&Delete area"));
  177. action_edit_area_ = new QAction(this);
  178. action_edit_area_->setText(tr("&Change area"));
  179. popup_area_list_->addAction(action_delete_area_);
  180. popup_area_list_->addAction(action_edit_area_);
  181. popup_label_list_ = new QMenu;
  182. action_set_color_ = new QAction(this);
  183. action_set_color_->setText(tr("Set &color"));
  184. action_toggle_priority_ = new QAction(this);
  185. action_toggle_priority_->setText(tr("Toggle &priority"));
  186. action_delete_label_ = new QAction(this);
  187. action_delete_label_->setText(tr("&Delete"));
  188. popup_label_list_->addAction(action_set_color_);
  189. popup_label_list_->addAction(action_toggle_priority_);
  190. popup_label_list_->addAction(action_delete_label_);
  191. popup_images_list_ = new QMenu;
  192. action_remove_image_ = new QAction(this);
  193. action_remove_image_->setText(tr("&remove image"));
  194. popup_images_list_->addAction(action_remove_image_);
  195. /*
  196. * widgets part begins
  197. */
  198. central_widget_ = new QWidget(this);
  199. setCentralWidget(central_widget_);
  200. frame_toolbox_ = new QFrame(central_widget_);
  201. frame_toolbox_->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
  202. frame_toolbox_->setLineWidth(0);
  203. frame_toolbox_->setMidLineWidth(0);
  204. frame_center_ = new QFrame(central_widget_);
  205. frame_image_ = new QScrollArea(frame_center_);
  206. frame_image_->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
  207. frame_image_->setLineWidth(0);
  208. frame_image_->setMidLineWidth(0);
  209. frame_image_->setWidgetResizable(false);
  210. frame_image_->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
  211. frame_image_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
  212. frame_labelbox_ = new QFrame(central_widget_);
  213. frame_labelbox_->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
  214. frame_labelbox_->setLineWidth(0);
  215. frame_labelbox_->setMidLineWidth(0);
  216. /* just dummy */
  217. image_ = new QPixmap(500, 500);
  218. image_->fill(QColor(Qt::white));
  219. image_holder_ = new ImageHolder;//(frame_image_);
  220. image_holder_->setPixmap(*image_);
  221. image_holder_->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
  222. image_holder_->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
  223. image_holder_->setScaledContents(true);
  224. image_holder_->setFrameStyle(QFrame::Box | QFrame::Plain);
  225. image_holder_->setLineWidth(0);
  226. frame_image_->setWidget(image_holder_);
  227. list_label_ = new QListWidget(central_widget_);
  228. list_label_->setContextMenuPolicy(Qt::CustomContextMenu);
  229. list_areas_ = new QListWidget(central_widget_);
  230. list_areas_->setContextMenuPolicy(Qt::CustomContextMenu);
  231. list_images_widget_ = new QListWidget(central_widget_);
  232. list_images_widget_->setContextMenuPolicy(Qt::CustomContextMenu);
  233. label_toolbox_ = new QLabel(tr("Tool box"), frame_toolbox_);
  234. label_list_areas_ = new QLabel(tr("Selected areas:"), central_widget_);
  235. label_list_images_ = new QLabel(tr("Loaded images:"), central_widget_);
  236. /* buttons */
  237. button_bound_box_tool_ = new QPushButton(frame_toolbox_);
  238. button_bound_box_tool_->setText(tr("bbox"));
  239. button_bound_box_tool_->setEnabled(false);
  240. button_bound_box_tool_->setCheckable(true);
  241. button_polygon_tool_ = new QPushButton(frame_toolbox_);
  242. button_polygon_tool_->setText(tr("poly tool"));
  243. button_polygon_tool_->setEnabled(false);
  244. button_polygon_tool_->setCheckable(true);
  245. button_tagging_tool_ = new QPushButton(frame_toolbox_);
  246. button_tagging_tool_->setText(tr("tagging"));
  247. button_tagging_tool_->setEnabled(false);
  248. button_clear_selection_tool_ = new QPushButton(frame_toolbox_);
  249. button_clear_selection_tool_->setText(tr("clear selection"));
  250. button_clear_selection_tool_->setEnabled(false);
  251. button_generate_colors_ = new QPushButton(frame_toolbox_);
  252. button_generate_colors_->setText(tr("generate label colors"));
  253. button_generate_colors_->setEnabled(false);
  254. button_delete_all_labels_ = new QPushButton(frame_toolbox_);
  255. button_delete_all_labels_->setText(tr("delete all labels"));
  256. button_delete_all_labels_->setEnabled(false);
  257. group_tools_ = new QButtonGroup;
  258. group_tools_->addButton(button_bound_box_tool_);
  259. group_tools_->addButton(button_polygon_tool_);
  260. button_confirm_selection_ = new QPushButton(central_widget_);
  261. button_confirm_selection_->setText(tr("Confirm selection"));
  262. button_confirm_selection_->setEnabled(false);
  263. button_add_label_ = new QPushButton(frame_labelbox_);
  264. button_add_label_->setText(tr("Add label"));
  265. button_add_label_->setEnabled(false);
  266. button_remove_label_ = new QPushButton(frame_labelbox_);
  267. button_remove_label_->setText(tr("Remove label"));
  268. button_remove_label_->setEnabled(false);
  269. button_prev_image_ = new QPushButton(central_widget_);
  270. button_prev_image_->setText("←");
  271. button_next_image_ = new QPushButton(central_widget_);
  272. button_next_image_->setText("→");
  273. /*
  274. * layouts part begins
  275. */
  276. layout_main_ = new QHBoxLayout(central_widget_);
  277. layout_left_ = new QVBoxLayout();
  278. layout_toolbox_ = new QVBoxLayout();
  279. layout_center_ = new QVBoxLayout();
  280. layout_frame_image_ = new QVBoxLayout();
  281. layout_image_widget_ = new QGridLayout();
  282. layout_center_buttons_ = new QHBoxLayout();
  283. layout_right_ = new QVBoxLayout();
  284. layout_labelbox_ = new QVBoxLayout();
  285. layout_labelbox_buttons_ = new QHBoxLayout();
  286. layout_main_->addLayout(layout_left_);
  287. layout_main_->addLayout(layout_center_);
  288. layout_main_->addLayout(layout_right_);
  289. /* making the center part stretchable */
  290. layout_main_->setStretch(1, 1);
  291. /* left part */
  292. layout_left_->addWidget(frame_toolbox_);
  293. frame_toolbox_->setLayout(layout_toolbox_);
  294. layout_toolbox_->addWidget(label_toolbox_);
  295. layout_toolbox_->addWidget(button_bound_box_tool_);
  296. layout_toolbox_->addWidget(button_polygon_tool_);
  297. layout_toolbox_->addSpacing(10);
  298. layout_toolbox_->addWidget(button_tagging_tool_);
  299. layout_toolbox_->addSpacing(10);
  300. layout_toolbox_->addWidget(button_clear_selection_tool_);
  301. layout_toolbox_->addWidget(button_delete_all_labels_);
  302. layout_toolbox_->addSpacing(10);
  303. layout_toolbox_->addWidget(button_generate_colors_);
  304. /* stretch is for making toolbox as small as it can be */
  305. layout_toolbox_->addSpacing(10);
  306. layout_left_->addWidget(label_list_images_);
  307. layout_left_->addWidget(list_images_widget_);
  308. list_images_widget_->setFixedWidth(200);
  309. layout_left_->addStretch(1);
  310. layout_left_->addWidget(button_confirm_selection_);
  311. /* central part */
  312. layout_center_->addWidget(frame_center_);
  313. frame_center_->setLayout(layout_frame_image_);
  314. layout_frame_image_->setContentsMargins(0, 0, 0, 0);
  315. layout_frame_image_->addWidget(frame_image_);
  316. layout_frame_image_->addLayout(layout_center_buttons_);
  317. layout_center_buttons_->addWidget(button_prev_image_);
  318. layout_center_buttons_->addWidget(button_next_image_);
  319. /* right part */
  320. layout_right_->addWidget(frame_labelbox_);
  321. frame_labelbox_->setFixedWidth(200);
  322. frame_labelbox_->setLayout(layout_labelbox_);
  323. layout_labelbox_->addLayout(layout_labelbox_buttons_);
  324. layout_labelbox_buttons_->addWidget(button_add_label_);
  325. layout_labelbox_buttons_->addWidget(button_remove_label_);
  326. layout_labelbox_->addWidget(list_label_);
  327. layout_labelbox_->addWidget(label_list_areas_);
  328. layout_labelbox_->addWidget(list_areas_);
  329. connect(
  330. action_quit_,
  331. SIGNAL(triggered()),
  332. this,
  333. SLOT(close())
  334. );
  335. connect(
  336. action_open_images_,
  337. SIGNAL(triggered()),
  338. this,
  339. SLOT(loadImages())
  340. );
  341. connect(
  342. action_open_image_,
  343. SIGNAL(triggered()),
  344. this,
  345. SLOT(loadImage())
  346. );
  347. connect(
  348. action_open_labeled_image_,
  349. SIGNAL(triggered()),
  350. this,
  351. SLOT(loadInfo())
  352. );
  353. connect(
  354. action_load_legend_,
  355. SIGNAL(triggered()),
  356. this,
  357. SLOT(loadLegendFromFile())
  358. );
  359. connect(
  360. action_load_pascal_file_,
  361. SIGNAL(triggered()),
  362. this,
  363. SLOT(loadPascalFile())
  364. );
  365. connect(
  366. action_load_pascal_poly_,
  367. SIGNAL(triggered()),
  368. this,
  369. SLOT(loadPascalPolys())
  370. );
  371. connect(
  372. action_save_legend_,
  373. SIGNAL(triggered()),
  374. this,
  375. SLOT(saveLegend())
  376. );
  377. connect(
  378. action_save_segmented_,
  379. SIGNAL(triggered()),
  380. this,
  381. SLOT(saveSegmentedPicture())
  382. );
  383. connect(
  384. action_save_all_,
  385. SIGNAL(triggered()),
  386. this,
  387. SLOT(saveAllInfo())
  388. );
  389. connect(
  390. action_view_normal_,
  391. SIGNAL(triggered()),
  392. this,
  393. SLOT(viewNormal())
  394. );
  395. connect(
  396. action_view_segmented_,
  397. SIGNAL(triggered()),
  398. this,
  399. SLOT(viewSegmented())
  400. );
  401. connect(
  402. action_undo_,
  403. SIGNAL(triggered()),
  404. image_holder_,
  405. SLOT(undo())
  406. );
  407. connect(
  408. action_redo_,
  409. SIGNAL(triggered()),
  410. image_holder_,
  411. SLOT(redo())
  412. );
  413. connect(
  414. action_add_description_,
  415. SIGNAL(triggered()),
  416. &line_edit_form_,
  417. SLOT(setDescription())
  418. );
  419. connect(
  420. action_options_,
  421. SIGNAL(triggered()),
  422. &options_form_,
  423. SLOT(showOptions())
  424. );
  425. connect(
  426. button_add_label_,
  427. SIGNAL(clicked()),
  428. this,
  429. SLOT(addLabel())
  430. );
  431. connect(
  432. button_remove_label_,
  433. SIGNAL(clicked()),
  434. this, SLOT(removeLabel())
  435. );
  436. connect(
  437. button_next_image_,
  438. SIGNAL(clicked()),
  439. this,
  440. SLOT(nextImage())
  441. );
  442. connect(
  443. button_prev_image_,
  444. SIGNAL(clicked()),
  445. this,
  446. SLOT(prevImage())
  447. );
  448. connect(
  449. button_bound_box_tool_,
  450. SIGNAL(toggled(bool)),
  451. this,
  452. SLOT(setBoundingBoxTool(bool))
  453. );
  454. connect(
  455. button_polygon_tool_,
  456. SIGNAL(toggled(bool)),
  457. this,
  458. SLOT(setPolygonTool(bool))
  459. );
  460. connect(
  461. button_tagging_tool_,
  462. SIGNAL(clicked()),
  463. &line_edit_form_,
  464. SLOT(setTags())
  465. );
  466. connect(
  467. button_clear_selection_tool_,
  468. SIGNAL(clicked()),
  469. this,
  470. SLOT(clearAllTool())
  471. );
  472. connect(
  473. button_generate_colors_,
  474. SIGNAL(clicked()),
  475. this,
  476. SLOT(generateColors())
  477. );
  478. connect(
  479. button_delete_all_labels_,
  480. SIGNAL(clicked()),
  481. this,
  482. SLOT(clearLabelList())
  483. );
  484. connect(
  485. button_confirm_selection_,
  486. SIGNAL(clicked()),
  487. this,
  488. SLOT(confirmSelection())
  489. );
  490. connect(
  491. list_label_,
  492. SIGNAL(itemChanged(QListWidgetItem *)),
  493. this,
  494. SLOT(editLabel(QListWidgetItem *))
  495. );
  496. connect(
  497. list_label_,
  498. SIGNAL(itemClicked(QListWidgetItem *)),
  499. this,
  500. SLOT(setLabelID(QListWidgetItem *))
  501. );
  502. connect(
  503. list_areas_,
  504. SIGNAL(itemDoubleClicked(QListWidgetItem *)),
  505. image_holder_,
  506. SLOT(focusOnArea(QListWidgetItem *))
  507. );
  508. connect(
  509. list_areas_,
  510. SIGNAL(customContextMenuRequested(const QPoint &)),
  511. this,
  512. SLOT(areaListPopupMenu(const QPoint &))
  513. );
  514. connect(
  515. list_areas_,
  516. SIGNAL(itemChanged(QListWidgetItem *)),
  517. this,
  518. SLOT(onAreaItemChange(QListWidgetItem *))
  519. );
  520. connect(
  521. list_label_,
  522. SIGNAL(customContextMenuRequested(const QPoint &)),
  523. this,
  524. SLOT(labelListPopupMenu(const QPoint &))
  525. );
  526. connect(
  527. list_images_widget_,
  528. SIGNAL(itemDoubleClicked(QListWidgetItem *)),
  529. this,
  530. SLOT(selectImage(QListWidgetItem *))
  531. );
  532. connect(
  533. list_images_widget_,
  534. SIGNAL(customContextMenuRequested(const QPoint &)),
  535. this,
  536. SLOT(imageListPopupMenu(const QPoint &))
  537. );
  538. connect(
  539. action_delete_area_,
  540. SIGNAL(triggered()),
  541. this,
  542. SLOT(deleteArea())
  543. );
  544. connect(
  545. action_edit_area_,
  546. SIGNAL(triggered()),
  547. this,
  548. SLOT(editArea())
  549. );
  550. connect(
  551. action_set_color_,
  552. SIGNAL(triggered()),
  553. this,
  554. SLOT(setLabelColor())
  555. );
  556. connect(
  557. action_toggle_priority_,
  558. SIGNAL(triggered()),
  559. this,
  560. SLOT(toggleLabelPriority())
  561. );
  562. connect(
  563. action_delete_label_,
  564. SIGNAL(triggered()),
  565. this,
  566. SLOT(removeLabel())
  567. );
  568. connect(
  569. action_remove_image_,
  570. SIGNAL(triggered()),
  571. this,
  572. SLOT(removeImage())
  573. );
  574. connect(
  575. image_holder_,
  576. SIGNAL(selectionStarted()),
  577. this,
  578. SLOT(onSelectionStarted())
  579. );
  580. connect(
  581. &line_edit_form_,
  582. SIGNAL(dataSet(QString)),
  583. this,
  584. SLOT(setDataFromForm(QString))
  585. );
  586. connect(
  587. image_holder_,
  588. SIGNAL(areaEdited()),
  589. this,
  590. SLOT(onAreaEdit())
  591. );
  592. QString settingsPath = aSettingsPath;
  593. if (settingsPath.isEmpty())
  594. settingsPath = QString("ImageLabeler.ini");
  595. settings_ = new QSettings(settingsPath, QSettings::IniFormat, this);
  596. readSettings(settings_);
  597. /* giving the pointers to some properties for image_holder_ */
  598. image_holder_->setBoundingBoxList(&list_bounding_box_);
  599. image_holder_->setPolygonList(&list_polygon_);
  600. image_holder_->setLabelColorList(&list_label_colors_);
  601. image_holder_->setMainLabelNum(&main_label_);
  602. image_holder_->setImage(image_);
  603. /* the same for options_form_ */
  604. options_form_.setPASCALpath(&PASCALpath_);
  605. options_form_.setAutoColorGeneration(&auto_color_generation_);
  606. }
  607. //! A destructor of the ImageLabeler class
  608. /*!
  609. * Simply frees all the allocated memory
  610. * in the right order
  611. */
  612. ImageLabeler::~ImageLabeler()
  613. {
  614. delete action_quit_;
  615. delete action_open_labeled_image_;
  616. delete action_open_image_;
  617. delete action_open_images_;
  618. delete action_load_legend_;
  619. delete action_load_pascal_file_;
  620. delete action_load_pascal_poly_;
  621. delete action_save_legend_;
  622. delete action_save_segmented_;
  623. delete action_save_all_;
  624. delete action_view_normal_;
  625. delete action_view_segmented_;
  626. delete action_undo_;
  627. delete action_redo_;
  628. delete action_bound_box_tool_;
  629. delete action_polygon_tool_;
  630. delete action_tagging_tool_;
  631. delete action_add_description_;
  632. delete action_options_;
  633. delete action_about_;
  634. delete action_help_content_;
  635. delete menu_pascal_;
  636. delete menu_file_;
  637. delete menu_view_;
  638. delete menu_edit_;
  639. delete menu_help_;
  640. delete menu_bar_;
  641. delete action_delete_area_;
  642. delete action_edit_area_;
  643. delete popup_area_list_;
  644. delete action_toggle_priority_;
  645. delete action_set_color_;
  646. delete action_delete_label_;
  647. delete popup_label_list_;
  648. delete action_remove_image_;
  649. delete popup_images_list_;
  650. delete image_;
  651. delete image_holder_;
  652. delete button_add_label_;
  653. delete button_remove_label_;
  654. delete button_bound_box_tool_;
  655. delete button_polygon_tool_;
  656. delete button_tagging_tool_;
  657. delete button_clear_selection_tool_;
  658. delete button_generate_colors_;
  659. delete button_delete_all_labels_;
  660. delete button_next_image_;
  661. delete button_prev_image_;
  662. delete button_confirm_selection_;
  663. delete label_list_areas_;
  664. delete label_toolbox_;
  665. delete label_list_images_;
  666. delete list_areas_;
  667. delete list_label_;
  668. delete list_images_widget_;
  669. delete layout_toolbox_;
  670. delete layout_right_;
  671. delete layout_center_buttons_;
  672. delete layout_frame_image_;
  673. delete layout_center_;
  674. delete layout_labelbox_buttons_;
  675. delete layout_labelbox_;
  676. delete layout_left_;
  677. delete layout_main_;
  678. delete frame_labelbox_;
  679. delete frame_toolbox_;
  680. delete frame_image_;
  681. delete frame_center_;
  682. delete central_widget_;
  683. if (pure_data_) {
  684. delete[] *pure_data_;
  685. delete pure_data_;
  686. }
  687. delete list_images_;
  688. delete settings_;
  689. }
  690. //! A member which reads the settings from file to RAM
  691. /*!
  692. * \see writeSettings(QSettings *aSettings)
  693. * \param[in] aSettings a pointer to the QSettings object
  694. * which should be previously created and set to the right
  695. * file with settings.
  696. */
  697. bool
  698. ImageLabeler::readSettings(QSettings *aSettings)
  699. {
  700. aSettings->beginGroup("/global");
  701. auto_color_generation_ =
  702. aSettings->value("/auto_label_color_generation", 0).toBool();
  703. options_form_.setAutoColorGeneration(&auto_color_generation_);
  704. PASCALpath_ = aSettings->value("/PASCAL_root_path", "").toString();
  705. aSettings->endGroup();
  706. return true;
  707. }
  708. //! A member which reads the settings from file to RAM
  709. /*!
  710. * \see readSettings(QSettings *aSettings)
  711. */
  712. void
  713. ImageLabeler::readSettings()
  714. {
  715. readSettings(settings_);
  716. }
  717. //! A member which writes settings from RAM to file
  718. /*!
  719. * \see readSettings(QSettings *aSettings)
  720. * \param[in] aSettings a pointer to the QSettings object
  721. * which should be previously created and set to the right
  722. * file with settings
  723. */
  724. bool
  725. ImageLabeler::writeSettings(QSettings *aSettings)
  726. {
  727. aSettings->beginGroup("/global");
  728. aSettings->setValue("/auto_label_color_generation", auto_color_generation_);
  729. aSettings->setValue("/PASCAL_root_path", PASCALpath_);
  730. aSettings->endGroup();
  731. return true;
  732. }
  733. //! A member which writes settings from RAM to file
  734. /*!
  735. * \see writeSettings(QSettings *aSettings)
  736. */
  737. void
  738. ImageLabeler::writeSettings()
  739. {
  740. writeSettings(settings_);
  741. }
  742. //! \brief A member taking a pointer to the Image struct and adding it to all necessary
  743. //! containers and widgets
  744. /*!
  745. * \param[in] anImage a pointer to the Image struct which should contain path to
  746. * the image, and two boolean flags:
  747. * labeled_ indicates whether it is labeled or not
  748. * pas_ indicates whether it was read from the PASCAL file or not
  749. */
  750. void
  751. ImageLabeler::addImage(Image *anImage)
  752. {
  753. QListWidgetItem *newItem = new QListWidgetItem;
  754. QString itemText = QString("%1: %2").
  755. arg(list_images_widget_->count()).
  756. arg(getFilenameFromPath(&(anImage->image_)));
  757. if (anImage->labeled_)
  758. itemText.append(" #labeled");
  759. if (anImage->pas_)
  760. itemText.append(" #pas");
  761. newItem->setText(itemText);
  762. list_images_widget_->addItem(newItem);
  763. list_images_->append(*anImage);
  764. }
  765. //! A slot member creating new label with default parameters
  766. /*!
  767. * New label will be added to the list_label_ widget and
  768. * it's color will be added to the list_label_colors_ container.
  769. * By default the color of new label is white and it's name is
  770. * "New Label".
  771. * If there was no labels before and the new one get number 0 then
  772. * it becomes a background label width black color and name "BACKGROUND"
  773. */
  774. void
  775. ImageLabeler::addLabel()
  776. {
  777. QListWidgetItem *newItem = new QListWidgetItem;
  778. QString label;
  779. int itemNum = list_label_->count();
  780. label.append(QString("%1: ").arg(itemNum));
  781. if (itemNum) {
  782. newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
  783. label.append("New label");
  784. }
  785. /* label #0 is always BACKGROUND */
  786. else {
  787. newItem->setFlags(
  788. Qt::ItemIsUserCheckable | Qt::ItemIsSelectable |
  789. Qt::ItemIsEnabled
  790. );
  791. label.append("BACKGROUND");
  792. }
  793. newItem->setText(label);
  794. QPixmap iconPix = QPixmap(20, 20);
  795. QColor color;
  796. /* white by default */
  797. if (0 != itemNum)
  798. color = Qt::white;
  799. /* label #0 is always black */
  800. else
  801. color = Qt::black;
  802. iconPix.fill(color);
  803. QIcon icon(iconPix);
  804. list_label_colors_.append(color.rgb());
  805. newItem->setIcon(icon);
  806. list_label_->addItem(newItem);
  807. list_label_->setItemSelected(newItem, true);
  808. label_ID_ = list_label_->count() - 1;
  809. /* adding new label means changing file data */
  810. unsaved_data_ = 1;
  811. }
  812. /* TODO: label color could be specified also */
  813. //! A member creating new specified label
  814. /*!
  815. * \see addLabel()
  816. * \param[in] aLabelID an integer specifying label position(ID also) in the list
  817. * \param[in] isMain a bool flag indicates whether this label is main or not
  818. * \param[in] aLabel a QString object containing new label's name
  819. */
  820. void
  821. ImageLabeler::addLabel(
  822. int aLabelID,
  823. bool isMain,
  824. QString aLabel
  825. )
  826. {
  827. QListWidgetItem *newItem = new QListWidgetItem;
  828. /* label #0 is always BACKGROUND */
  829. if (0 == aLabelID) {
  830. aLabel = QString("BACKGROUND");
  831. newItem->setFlags(
  832. Qt::ItemIsUserCheckable | Qt::ItemIsSelectable |
  833. Qt::ItemIsEnabled
  834. );
  835. }
  836. QString label;
  837. label.append(QString("%1: %2").
  838. arg(aLabelID).
  839. arg(aLabel)
  840. );
  841. /* TODO: check if there is another main label and make it common */
  842. if (isMain) {
  843. main_label_ = aLabelID;
  844. }
  845. QPixmap iconPix = QPixmap(20, 20);
  846. QColor color;
  847. if (0 != aLabelID)
  848. color = Qt::white;
  849. else
  850. color = Qt::black;
  851. iconPix.fill(color);
  852. QIcon icon(iconPix);
  853. list_label_colors_.append(color.rgb());
  854. newItem->setIcon(icon);
  855. newItem->setText(label);
  856. newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
  857. list_label_->addItem(newItem);
  858. list_label_->setItemSelected(newItem, true);
  859. unsaved_data_ = 1;
  860. }
  861. //! A slot member being called after a label gets changed
  862. /*!
  863. * \param[in] anItem a pointer to the QListWidgetItem object
  864. * which contains a text of just edited label
  865. *
  866. * Checking label if it has a label ID and puting a mark #main
  867. * if it is so
  868. */
  869. void
  870. ImageLabeler::editLabel(QListWidgetItem *anItem)
  871. {
  872. QString label = anItem->text();
  873. int itemRow = list_label_->row(anItem);
  874. QString prefix = QString("%1: ").arg(itemRow);
  875. if (-1 == label.indexOf(prefix))
  876. label.prepend(QString("%1: ").arg(itemRow));
  877. if (main_label_ == itemRow) {
  878. label.append(" #main");
  879. }
  880. list_label_->blockSignals(true);
  881. anItem->setText(label);
  882. list_label_->blockSignals(false);
  883. unsaved_data_ = 1;
  884. }
  885. //! A slot member removing selected label
  886. /*!
  887. * \see removeLabel(int aLabelID)
  888. *
  889. * Simply removing selected label. Label no 0 can not be removed
  890. */
  891. void
  892. ImageLabeler::removeLabel()
  893. {
  894. removeLabel(label_ID_);
  895. }
  896. //! A slot member removing selected label
  897. /*!
  898. * \see removeLabel()
  899. * \param[in] aLabelID a integer specifying a label to remove
  900. *
  901. * Removing label number aLabelID. Label no 0 can not be removed
  902. */
  903. void
  904. ImageLabeler::removeLabel(int aLabelID)
  905. {
  906. if (0 == list_label_->count()) {
  907. return;
  908. /* NOTREACHED */
  909. }
  910. /* we need to keep BACKGROUND category */
  911. if (aLabelID < 1) {
  912. return;
  913. /* NOTREACHED */
  914. }
  915. if (list_label_->count() <= aLabelID ||
  916. list_label_colors_.count() <= aLabelID) {
  917. return;
  918. /* NOTREACHED */
  919. }
  920. list_label_->takeItem(aLabelID);
  921. list_label_colors_.takeAt(aLabelID);
  922. unsaved_data_ = 1;
  923. }
  924. //! \brief a slot Member setting label_ID_ variable according to the selected row
  925. //! in the list_label_ widget
  926. /*!
  927. * \param[in] anItem a pointer to the QListWidgetItem object which can be
  928. * used to get current selected label in the list
  929. *
  930. * This slot just duplicates QListWidget::row() functionality to get
  931. * previously selected label even if it is not focused.
  932. */
  933. void
  934. ImageLabeler::setLabelID(
  935. QListWidgetItem *anItem
  936. )
  937. {
  938. if (!list_label_->count()) {
  939. return;
  940. /* NOTREACHED */
  941. }
  942. label_ID_ = list_label_->row(anItem);
  943. }
  944. //! A protected member adding a bbox area to the QListWidget list_areas_
  945. /*!
  946. * \param[in] anID a integer which indicates bbox id in the
  947. * list_bounding_boxes_ container
  948. * \param[in] aBBox a BoundingBox struct containing
  949. * a rectangle data and it's label ID
  950. * \param[in] itemID an integer indicates a position
  951. * of a new item in the list_areas_
  952. *
  953. * itemID is -1 by default so the new area item will be placed in the
  954. * end of the list
  955. */
  956. void
  957. ImageLabeler::addBBoxArea(
  958. int anID,
  959. BoundingBox aBBox,
  960. int itemID
  961. )
  962. {
  963. QListWidgetItem *newItem = new QListWidgetItem;
  964. if (itemID < 0)
  965. itemID = list_areas_->count();
  966. QString label;
  967. label.append(QString("%1: ").arg(itemID));
  968. label.append(QString("BBox #%1; ").arg(anID));
  969. label.append(QString("LabelID: %1; ").arg(aBBox.label_ID_));
  970. label.append(
  971. QString("data:%1;%2;%3;%4; ").
  972. arg(aBBox.rect.topLeft().x()).
  973. arg(aBBox.rect.topLeft().y()).
  974. arg(aBBox.rect.width()).
  975. arg(aBBox.rect.height())
  976. );
  977. newItem->setText(label);
  978. //newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
  979. list_areas_->insertItem(itemID, newItem);
  980. list_areas_->setItemSelected(newItem, true);
  981. }
  982. //! A protected member adding a poly area to the QListWidget list_areas_
  983. /*!
  984. * \param[in] aPolyID a integer which indicates poly id in the
  985. * list_polygon_ container
  986. * \param[in] aPoly a Polygon struct containing
  987. * a polygon data(QPolygon) and it's label ID
  988. * \param[in] itemID an integer indicates a position
  989. * of a new item in the list_areas_
  990. *
  991. * itemID is -1 by default so the new area item will be placed in the
  992. * end of the list
  993. */
  994. void
  995. ImageLabeler::addPolyArea(
  996. int aPolyID,
  997. Polygon aPoly,
  998. int itemID
  999. )
  1000. {
  1001. QListWidgetItem *newItem = new QListWidgetItem;
  1002. if (-1 == itemID)
  1003. itemID = list_areas_->count();
  1004. QString label;
  1005. label.append(QString("%1: ").arg(itemID));
  1006. label.append(QString("Poly #%1; ").arg(aPolyID));
  1007. label.append(QString("LabelID: %1; ").arg(aPoly.label_ID_));
  1008. label.append("points:");
  1009. for (int i = 0; i < aPoly.poly.count(); i++) {
  1010. label.append(
  1011. QString("%1;%2;").
  1012. arg(aPoly.poly.point(i).x()).
  1013. arg(aPoly.poly.point(i).y())
  1014. );
  1015. }
  1016. newItem->setText(label);
  1017. list_areas_->insertItem(itemID, newItem);
  1018. list_areas_->setItemSelected(newItem, true);
  1019. }
  1020. //! A slot member allowing manual editing the selected item in the list_areas_
  1021. /*!
  1022. * Slot being called after "change area" item in the popup menu of the list_areas_
  1023. * widget was clicked
  1024. */
  1025. void
  1026. ImageLabeler::editArea()
  1027. {
  1028. /* signals are blocked to avoid recursive call of the same slot */
  1029. bool oldState = list_areas_->blockSignals(true);
  1030. if (!list_areas_->currentItem() || !list_areas_->count()) {
  1031. return;
  1032. /* NOTREACHED */
  1033. }
  1034. QListWidgetItem *current = list_areas_->currentItem();
  1035. old_area_string_ = current->text();
  1036. current->setFlags(current->flags() | Qt::ItemIsEditable);
  1037. list_areas_->editItem(current);
  1038. list_areas_->blockSignals(oldState);
  1039. }
  1040. //! \brief A slot member parsing a text of the changed item and tries to edit
  1041. //! the corresponding area
  1042. /*!
  1043. * \see polyFromListItemText(QString *aString,int *oldID)
  1044. * \see BBoxFromListItemText(QString *aString,int *oldID)
  1045. * \param[in] anItem a pointer to the QListWidgetItem object which contains
  1046. * area's changed data
  1047. *
  1048. * Slot usually being called after item manual changing is done
  1049. */
  1050. void
  1051. ImageLabeler::onAreaItemChange(QListWidgetItem *anItem)
  1052. {
  1053. /* signals are blocked to avoid recursive call of the same slot */
  1054. list_areas_->blockSignals(true);
  1055. QString areaString = anItem->text();
  1056. int oldID = -1;
  1057. if (-1 != areaString.indexOf("Poly")) {
  1058. Polygon *poly = new Polygon;
  1059. *poly = polyFromListItemText(&areaString, &oldID);
  1060. if (-1 < poly->label_ID_ && !poly->poly.isEmpty() &&
  1061. -1 < oldID) {
  1062. list_polygon_.takeAt(oldID);
  1063. list_polygon_.insert(oldID, poly);
  1064. }
  1065. else
  1066. anItem->setText(old_area_string_);
  1067. }
  1068. else if (-1 != areaString.indexOf("BBox")) {
  1069. BoundingBox *bbox = new BoundingBox;
  1070. *bbox = BBoxFromListItemText(&areaString, &oldID);
  1071. if (-1 < bbox->label_ID_ && -1 < oldID) {
  1072. list_bounding_box_.takeAt(oldID);
  1073. list_bounding_box_.insert(oldID, bbox);
  1074. }
  1075. else
  1076. anItem->setText(old_area_string_);
  1077. }
  1078. else {
  1079. showWarning(tr("record format is corrupted, try again"));
  1080. anItem->setText(old_area_string_);
  1081. }
  1082. anItem->setFlags(anItem->flags() ^ Qt::ItemIsEditable);
  1083. list_areas_->blockSignals(false);
  1084. image_holder_->update();
  1085. unsaved_data_ = 1;
  1086. }
  1087. //! \brief A slot member changing the item in the list_areas_ to meet the changes
  1088. //! being made during area editing(where editing means moving the points of
  1089. //! an area)
  1090. /*!
  1091. * Slot usually being called on every change which was done with any area.
  1092. */
  1093. void
  1094. ImageLabeler::onAreaEdit()
  1095. {
  1096. if (!list_areas_->count() ||
  1097. -1 == image_holder_->focusedSelection()) {
  1098. //showWarning(tr("You haven't added any label"));
  1099. return;
  1100. /* NOTREACHED */
  1101. }
  1102. /* a figure was focused by double click on the list_areas_ widget
  1103. * see ImageHolder::focusOnArea(QListWidgetItem *) */
  1104. int figureID = image_holder_->focusedSelection();
  1105. Figure figure = image_holder_->focusedSelectionType();
  1106. /* looking for the corresponding item in the list_areas_ */
  1107. for (int i = 0; i < list_areas_->count(); i++) {
  1108. QListWidgetItem *item = list_areas_->item(i);
  1109. QString text = item->text();
  1110. if (RectFigure == figure && -1 != text.indexOf("BBox")) {
  1111. bool ok = 0;
  1112. int num = getNumFromString(&text, "BBox #", ";", &ok);
  1113. if (ok && num == figureID) {
  1114. list_areas_->takeItem(i);
  1115. addBBoxArea(num, *list_bounding_box_.at(num), i);
  1116. }
  1117. }
  1118. else if (PolyFigure == figure && -1 != text.indexOf("Poly")) {
  1119. bool ok = 0;
  1120. int num = getNumFromString(&text, "Poly #", ";", &ok);
  1121. if (ok && num == figureID) {
  1122. list_areas_->takeItem(i);
  1123. addPolyArea(num, *list_polygon_.at(num), i);
  1124. }
  1125. }
  1126. }
  1127. unsaved_data_ = 1;
  1128. }
  1129. //! \brief A slot member deleting selected area in the list_areas_ widget
  1130. //! and all other corresponding containers
  1131. /*!
  1132. * \see deleteArea(QListWidgetItem *anItem)
  1133. */
  1134. void
  1135. ImageLabeler::deleteArea()
  1136. {
  1137. if (!deleteArea(list_areas_->currentItem()))
  1138. showWarning(tr("An error occurred while deleting the area"));
  1139. }
  1140. //! A slot member deleting certain area in the list_areas_ widget
  1141. //! and all other corresponding containers
  1142. /*!
  1143. * \param[in] anItem a pointer to the QListWidgetItem which corresponds to
  1144. * some certain area(bbox or poly)
  1145. *
  1146. * Slot parses the text from anItem and deletes area from list_areas_ and
  1147. * from list_bounding_box_ or list_polygon depends on which type of area it
  1148. * was
  1149. *
  1150. * returns true on success
  1151. */
  1152. bool
  1153. ImageLabeler::deleteArea(QListWidgetItem *anItem)
  1154. {
  1155. if (!anItem || !list_areas_->count()) {
  1156. return false;
  1157. /* NOTREACHED */
  1158. }
  1159. QString text = anItem->text();
  1160. bool ok = 0;
  1161. /*
  1162. * 0 - bbox
  1163. * 1 - poly
  1164. */
  1165. QString shape;
  1166. if (-1 != text.indexOf("BBox"))
  1167. shape = QString("BBox");
  1168. else if (-1 != text.indexOf("Poly"))
  1169. shape = QString("Poly");
  1170. else {
  1171. return false;
  1172. /* NOTREACHED */
  1173. }
  1174. int areaNum = getNumFromString(&text, "#", ";", &ok);
  1175. if (!ok) {
  1176. return false;
  1177. /* NOTREACHED */
  1178. }
  1179. int currentItemRow = list_areas_->row(anItem);
  1180. /* changing all shapes(depends on current) which are next in the list */
  1181. for (int i = list_areas_->count() - 1; i > currentItemRow; i--) {
  1182. QListWidgetItem item = *(list_areas_->item(i));
  1183. QString newText = item.text();
  1184. if (-1 == newText.indexOf(shape))
  1185. continue;
  1186. int num = getNumFromString(&newText, "#", ";", &ok);
  1187. num--;
  1188. QString numString = QString("%1").arg(num);
  1189. int numPos = newText.indexOf("#") + 1;
  1190. newText.replace(numPos, numString.size(), numString);
  1191. list_areas_->takeItem(i);
  1192. list_areas_->insertItem(i, newText);
  1193. }
  1194. list_areas_->takeItem(currentItemRow);
  1195. if (shape == "BBox")
  1196. list_bounding_box_.removeAt(areaNum);
  1197. else
  1198. list_polygon_.removeAt(areaNum);
  1199. image_holder_->update();
  1200. unsaved_data_ = 1;
  1201. return true;
  1202. }
  1203. //! A slot member toggling the priority of current item(main\not main)
  1204. /*!
  1205. * \see toggleLabelPriority(QListWidgetItem *anItem)
  1206. * Slot not just only toggles current label priority but also checks other labels
  1207. * if any of them are also main. If so it just makes them common(not main)
  1208. */
  1209. void
  1210. ImageLabeler::toggleLabelPriority()
  1211. {
  1212. if (!toggleLabelPriority(list_label_->currentItem()))
  1213. showWarning(tr("An error occurred while toggling a label priority"));
  1214. }
  1215. //! A slot member toggling the priority of current item(main\not main)
  1216. /*!
  1217. * \param[in] anItem a pointer to the QListWidgetItem object which corresponds to
  1218. * some certain label
  1219. *
  1220. * Slot not just only toggles current label priority but also checks other labels
  1221. * if any of the are also main. If so it just makes them common(not main)
  1222. *
  1223. * returns true on success
  1224. */
  1225. bool
  1226. ImageLabeler::toggleLabelPriority(QListWidgetItem *anItem)
  1227. {
  1228. if (!list_label_->count()) {
  1229. return false;
  1230. /* NOTREACHED */
  1231. }
  1232. /* because we need to keep BACKGROUND category */
  1233. if (0 == list_label_->row(anItem)) {
  1234. return false;
  1235. /* NOTREACHED */
  1236. }
  1237. int itemRow = list_label_->row(anItem);
  1238. QString text = anItem->text();
  1239. /* cleaning previous " #main" mark */
  1240. if (-1 != main_label_) {
  1241. QListWidgetItem *lastMain = list_label_->item(main_label_);
  1242. QString lastMainText = lastMain->text();
  1243. int mainPos = lastMainText.indexOf(" #main");
  1244. lastMainText = lastMainText.mid(0, mainPos);
  1245. list_label_->blockSignals(true);
  1246. lastMain->setText(lastMainText);
  1247. list_label_->blockSignals(false);
  1248. }
  1249. if (main_label_ == itemRow) {
  1250. int mainPos = text.indexOf(" #main");
  1251. text = text.mid(0, mainPos);
  1252. main_label_ = -1;
  1253. }
  1254. else {
  1255. text.append(" #main");
  1256. main_label_ = list_label_->row(anItem);
  1257. }
  1258. list_label_->blockSignals(true);
  1259. anItem->setText(text);
  1260. list_label_->blockSignals(false);
  1261. image_holder_->update();
  1262. unsaved_data_ = 1;
  1263. return true;
  1264. }
  1265. //! A protected member recursively getting all images from directory dir
  1266. /*!
  1267. * \param[in] dir a const QDir object indicating current directory
  1268. *
  1269. * Looking for images in the directory and adding them to the list at once
  1270. *
  1271. * Recursive search can be interrupted by interrupt_search flag being true;
  1272. *
  1273. * If there are any labeled images in the folder they will be loaded with all
  1274. * corresponding data.
  1275. */
  1276. void
  1277. ImageLabeler::getImagesFromDir(const QDir &dir)
  1278. {
  1279. /* avoiding freezing during recursive search for files */
  1280. QApplication::processEvents();
  1281. /* interrupting */
  1282. if (interrupt_search_) {
  1283. clearAll();
  1284. return;
  1285. }
  1286. QStringList filenameFilter;
  1287. /* *.dat are included also but only to indicate labeled images */
  1288. filenameFilter <<
  1289. "*.jpeg" <<
  1290. "*.jpg" <<
  1291. "*.gif" <<
  1292. "*.png" <<
  1293. "*.bmp" <<
  1294. "*.tiff" <<
  1295. "*.dat"
  1296. ;
  1297. QStringList listImages =
  1298. dir.entryList(filenameFilter, QDir::Files);
  1299. foreach (QString file, listImages) {
  1300. /* ignoring segmented images and .dat files */
  1301. if (file.contains("_segmented", Qt::CaseInsensitive) ||
  1302. file.contains(".dat", Qt::CaseInsensitive)) {
  1303. continue;
  1304. }
  1305. Image newImage;
  1306. newImage.image_ = dir.absoluteFilePath(file);
  1307. /* TODO: think about loading pascal files */
  1308. newImage.pas_ = 0;
  1309. /* checking if there is a data for current image */
  1310. QString labeled = alterFileName(file, "_labeled");
  1311. labeled = removePath(labeled);
  1312. labeled.append(".dat");
  1313. if (listImages.contains(labeled, Qt::CaseInsensitive))
  1314. newImage.labeled_ = 1;
  1315. else
  1316. newImage.labeled_ = 0;
  1317. addImage(&newImage);
  1318. }
  1319. /* recursively going into subdirectory */
  1320. QStringList listDir = dir.entryList(QDir::Dirs);
  1321. foreach (QString subdir, listDir) {
  1322. if ("." == subdir || ".." == subdir)
  1323. continue;
  1324. getImagesFromDir(QDir(dir.absoluteFilePath(subdir)));
  1325. }
  1326. }
  1327. //! \brief A slot member changing current image to the next one
  1328. //! and clearing all the data(except legend)
  1329. /*!
  1330. * Asks about unsaved data if there is any. If current picture was the
  1331. * last in the image list then it goes to the first one.
  1332. * Adds to filename of the current image to the window title
  1333. */
  1334. void
  1335. ImageLabeler::nextImage()
  1336. {
  1337. if (list_images_->isEmpty()) {
  1338. return;
  1339. /* NOTREACHED */
  1340. }
  1341. if (askForUnsavedData()) {
  1342. return;
  1343. /* NOTREACHED */
  1344. }
  1345. if (list_images_widget_->count() - 1 == image_ID_) {
  1346. image_ID_ = 0;
  1347. }
  1348. else {
  1349. image_ID_ ++;
  1350. }
  1351. if (!selectImage(image_ID_)) {
  1352. showWarning(tr("Next image is not available"));
  1353. return;
  1354. /* NOTREACHED */
  1355. }
  1356. list_images_widget_->setCurrentRow(image_ID_);
  1357. if (current_image_.isEmpty()) {
  1358. return;
  1359. /* NOTREACHED */
  1360. }
  1361. QString winTitle;
  1362. winTitle.append("ImageLabeler - ");
  1363. winTitle.append(current_image_);
  1364. setWindowTitle(winTitle);
  1365. image_->load(current_image_);
  1366. image_holder_->resize(image_->size());
  1367. image_holder_->setPixmap(*image_);
  1368. list_bounding_box_.clear();
  1369. list_polygon_.clear();
  1370. list_areas_->clear();
  1371. image_holder_->clearAll();
  1372. segmented_image_.clear();
  1373. //clearLabelColorList();
  1374. }
  1375. //! \brief A slot member changing current image to the previous one
  1376. //! and clearing all the data(except legend)
  1377. /*!
  1378. * Asks about unsaved data if there is any. If current picture was the
  1379. * first in the image list then it goes to the last one.
  1380. * Adds to filename of the current image to the window title
  1381. */
  1382. void
  1383. ImageLabeler::prevImage()
  1384. {
  1385. if (!list_images_widget_->count()) {
  1386. return;
  1387. /* NOTREACHED */
  1388. }
  1389. if (askForUnsavedData()) {
  1390. return;
  1391. /* NOTREACHED */
  1392. }
  1393. if (!image_ID_) {
  1394. image_ID_ = list_images_widget_->count() - 1;
  1395. }
  1396. else {
  1397. image_ID_--;
  1398. }
  1399. list_images_widget_->setCurrentRow(image_ID_);
  1400. if (!selectImage(image_ID_)) {
  1401. showWarning(tr("Next image is not available"));
  1402. return;
  1403. /* NOTREACHED */
  1404. }
  1405. QString winTitle;
  1406. winTitle.append("ImageLabeler - ");
  1407. winTitle.append(current_image_);
  1408. setWindowTitle(winTitle);
  1409. image_->load(current_image_);
  1410. image_holder_->resize(image_->size());
  1411. image_holder_->setPixmap(*image_);
  1412. list_bounding_box_.clear();
  1413. list_polygon_.clear();
  1414. list_areas_->clear();
  1415. image_holder_->clearAll();
  1416. segmented_image_.clear();
  1417. //clearLabelColorList();
  1418. }
  1419. //! A Slot member saving all info about labeled image
  1420. /*!
  1421. * It saves a file in xml format which contains:
  1422. * - path to the original image
  1423. * - path to the segmented image(if any)
  1424. * - image description
  1425. * - tags
  1426. * - labels
  1427. * - objects data
  1428. * - segmented representation of the image as 2-dimensional array of label ids
  1429. */
  1430. void
  1431. ImageLabeler::saveAllInfo()
  1432. {
  1433. if (!list_images_widget_->count()) {
  1434. showWarning("You have not opened any image yet");
  1435. return;
  1436. /* NOTREACHED */
  1437. }
  1438. /* ------------------------------------------------------------------------
  1439. * XML part
  1440. */
  1441. QDomDocument doc(tr("ImageLabeler"));
  1442. QDomElement root = doc.createElement(tr("pixelwise_labeling"));
  1443. doc.appendChild(root);
  1444. QDomElement image = doc.createElement(tr("image"));
  1445. root.appendChild(image);
  1446. QDomText pathToImage = doc.createTextNode(current_image_);
  1447. image.appendChild(pathToImage);
  1448. if (!segmented_image_.isEmpty()) {
  1449. QDomElement segmentedImage = doc.createElement(tr("segmented"));
  1450. root.appendChild(segmentedImage);
  1451. QDomText pathToSegmented = doc.createTextNode(segmented_image_);
  1452. segmentedImage.appendChild(pathToSegmented);
  1453. }
  1454. QDomElement description = doc.createElement(tr("description"));
  1455. root.appendChild(description);
  1456. QDomText descriptionText = doc.createTextNode(image_description_);
  1457. description.appendChild(descriptionText);
  1458. QDomElement tags = doc.createElement(tr("tags"));
  1459. root.appendChild(tags);
  1460. QDomText tagsText = doc.createTextNode(tags_);
  1461. tags.appendChild(tagsText);
  1462. legendToXml(&doc, &root);
  1463. objectsToXml(&doc, &root);
  1464. setPureData();
  1465. QDomElement pureData = doc.createElement(tr("pure_data"));
  1466. QSize imageSize = image_->size();
  1467. QString pixelValues;
  1468. for (int i = 0; i < imageSize.height(); i++) {
  1469. for (int j = 0; j < imageSize.width(); j++) {
  1470. pixelValues.append(QString("%1").arg(pure_data_[i][j]));
  1471. }
  1472. pixelValues.append("\n");
  1473. }
  1474. QDomText pureDataText = doc.createTextNode(pixelValues);
  1475. pureData.appendChild(pureDataText);
  1476. root.appendChild(pureData);
  1477. QString xml = doc.toString();
  1478. /* ------------------------------------------------------------------------
  1479. * XML part ends
  1480. */
  1481. QFileDialog fileDialog(0, tr("Save all info"));
  1482. fileDialog.setAcceptMode(QFileDialog::AcceptSave);
  1483. fileDialog.setDefaultSuffix("dat");
  1484. fileDialog.setFileMode(QFileDialog::AnyFile);
  1485. QString dir = getDirFromPath(&current_image_);
  1486. /* altering the name of a new file */
  1487. QString newFileName = alterFileName(current_image_, "_labeled");
  1488. newFileName = removePath(newFileName);
  1489. fileDialog.selectFile(newFileName);
  1490. fileDialog.setDirectory(dir);
  1491. QString filename;
  1492. if (fileDialog.exec()) {
  1493. filename = fileDialog.selectedFiles().last();
  1494. }
  1495. else {
  1496. //showWarning(tr("Can not open file dialog"));
  1497. return;
  1498. /* NOTREACHED */
  1499. }
  1500. if (filename.isEmpty()) {
  1501. return;
  1502. /* NOTREACHED */
  1503. }
  1504. QFile file(filename);
  1505. if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
  1506. showWarning(tr("Can not open file for writing"));
  1507. return;
  1508. /* NOTREACHED */
  1509. }
  1510. file.write(xml.toLocal8Bit());
  1511. file.close();
  1512. unsaved_data_ = 0;
  1513. }
  1514. //! A slot member saving a segmented image from pure_data_ array
  1515. /*!
  1516. * \see setPureData()
  1517. *
  1518. * If label colors are not set it asks user about automatic color generation.
  1519. * New image format is .png
  1520. */
  1521. void
  1522. ImageLabeler::saveSegmentedPicture()
  1523. {
  1524. if (list_bounding_box_.isEmpty() && list_polygon_.isEmpty()) {
  1525. return;
  1526. /* NOTREACHED */
  1527. }
  1528. setPureData();
  1529. QFileDialog fileDialog(0, tr("Save segmented picture"));
  1530. fileDialog.setAcceptMode(QFileDialog::AcceptSave);
  1531. fileDialog.setDefaultSuffix("png");
  1532. fileDialog.setFileMode(QFileDialog::AnyFile);
  1533. QString dir = getDirFromPath(&current_image_);
  1534. /* altering the name of a new file */
  1535. QString newFileName = alterFileName(current_image_, "_segmented");
  1536. newFileName = removePath(newFileName);
  1537. fileDialog.selectFile(newFileName);
  1538. fileDialog.setDirectory(dir);
  1539. QString filename;
  1540. if (fileDialog.exec()) {
  1541. filename = fileDialog.selectedFiles().last();
  1542. }
  1543. else {
  1544. return;
  1545. /* NOTREACHED */
  1546. }
  1547. QSize imageSize = image_holder_->pixmap()->size();
  1548. QImage newImage(imageSize, QImage::Format_RGB32);
  1549. bool generateColorsFlag = auto_color_generation_;
  1550. bool flag = 0;
  1551. /* checking if all the colors are are different from white(default) */
  1552. if (!generateColorsFlag) {
  1553. for (int i = 1; i < list_label_->count(); i++) {
  1554. if (list_label_colors_.at(i) == 0xffffffff && !flag)
  1555. flag = 1;
  1556. else if (list_label_colors_.at(i) == 0xffffffff && flag) {
  1557. QMessageBox msgBox;
  1558. msgBox.setText(tr("There are few labels with default white color."));
  1559. msgBox.setInformativeText(tr("Do you want to generate all colors automatically? Otherwise you'll have to do it manually."));
  1560. msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
  1561. msgBox.setDefaultButton(QMessageBox::Yes);
  1562. msgBox.setIcon(QMessageBox::Question);
  1563. int ret = msgBox.exec();
  1564. if (QMessageBox::Yes == ret) {
  1565. generateColorsFlag = 1;
  1566. break;
  1567. }
  1568. else {
  1569. return;
  1570. /* NOTREACHED */
  1571. }
  1572. }
  1573. }
  1574. }
  1575. /* generating colors for labels */
  1576. if (list_label_colors_.count() < list_label_->count() ||
  1577. generateColorsFlag) {
  1578. generateColors();
  1579. }
  1580. for (int i = 0; i < imageSize.height(); i++)
  1581. for (int j = 0; j < imageSize.width(); j++) {
  1582. newImage.setPixel(j, i, list_label_colors_.at(pure_data_[i][j]));
  1583. }
  1584. if (!newImage.save(filename, "png", 100)) {
  1585. showWarning(tr("An error occurred while saving the segmented image"));
  1586. return;
  1587. /* NOTREACHED */
  1588. }
  1589. segmented_image_ = filename;
  1590. action_view_segmented_->setEnabled(true);
  1591. }
  1592. //! A slot member saving only labels(legend) to the separate xml file
  1593. /*!
  1594. * \see legendToXml(QDomDocument *aDoc, QDomElement *aRoot)
  1595. *
  1596. * Slot asks user where to save a file with the legend and saves it.
  1597. */
  1598. void
  1599. ImageLabeler::saveLegend()
  1600. {
  1601. if (!list_label_->count()) {
  1602. showWarning("You have not added any label yet");
  1603. return;
  1604. /* NOTREACHED */
  1605. }
  1606. /* ------------------------------------------------------------------------
  1607. * XML part
  1608. */
  1609. QDomDocument doc(tr("ImageLabeler"));
  1610. QDomElement root = doc.createElement(tr("root"));
  1611. doc.appendChild(root);
  1612. legendToXml(&doc, &root);
  1613. QString xml = doc.toString();
  1614. /* ------------------------------------------------------------------------
  1615. * XML part ends
  1616. */
  1617. QFileDialog fileDialog(0, tr("Save legend"));
  1618. fileDialog.setAcceptMode(QFileDialog::AcceptSave);
  1619. fileDialog.setDefaultSuffix("dat");
  1620. fileDialog.setFileMode(QFileDialog::AnyFile);
  1621. QString dir = getDirFromPath(&current_image_);
  1622. /* altering the name of a new file */
  1623. QString newFileName = alterFileName(current_image_, "_legend");
  1624. newFileName = removePath(newFileName);
  1625. fileDialog.selectFile(newFileName);
  1626. fileDialog.setDirectory(dir);
  1627. QString filename;
  1628. if (fileDialog.exec()) {
  1629. filename = fileDialog.selectedFiles().last();
  1630. }
  1631. else {
  1632. //showWarning(tr("Can not open file dialog"));
  1633. return;
  1634. /* NOTREACHED */
  1635. }
  1636. if (filename.isEmpty()) {
  1637. return;
  1638. /* NOTREACHED */
  1639. }
  1640. QFile file(filename);
  1641. if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
  1642. showWarning(tr("Can not open file for writing"));
  1643. return;
  1644. /* NOTREACHED */
  1645. }
  1646. file.write(xml.toLocal8Bit());
  1647. file.close();
  1648. }
  1649. //! A slot member loading labeled image from formatted xml file.
  1650. /*!
  1651. * \see loadInfo(QString filename)
  1652. */
  1653. void
  1654. ImageLabeler::loadInfo()
  1655. {
  1656. if (askForUnsavedData()) {
  1657. return;
  1658. /* NOTREACHED */
  1659. }
  1660. QFileDialog fileDialog(0, tr("Load file with info"));
  1661. fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
  1662. fileDialog.setDefaultSuffix("dat");
  1663. fileDialog.setFileMode(QFileDialog::AnyFile);
  1664. QString filename;
  1665. if (fileDialog.exec()) {
  1666. filename = fileDialog.selectedFiles().last();
  1667. }
  1668. else {
  1669. //showWarning(tr("Can not open file dialog"));
  1670. return;
  1671. /* NOTREACHED */
  1672. }
  1673. clearAllTool();
  1674. clearLabelList();
  1675. if (loadInfo(filename)) {
  1676. enableTools();
  1677. Image newImage;
  1678. newImage.image_ = current_image_;
  1679. newImage.labeled_ = 1;
  1680. newImage.pas_ = 0;
  1681. addImage(&newImage);
  1682. image_ID_ = list_images_widget_->count() - 1;
  1683. list_images_widget_->setCurrentRow(image_ID_);
  1684. }
  1685. unsaved_data_ = 0;
  1686. }
  1687. //! A slot member loading labeled image from formatted xml file.
  1688. /*!
  1689. * \param[in] filename a QString object containing a path to the file
  1690. * we need to load data from
  1691. *
  1692. * \see loadLegendFromNode(QDomElement *)
  1693. * \see addBBoxFromData(QString *aBBoxData, int *ID)
  1694. * \see addPolyFromData(QString *aPolyData, int *labelID)
  1695. */
  1696. bool
  1697. ImageLabeler::loadInfo(QString filename)
  1698. {
  1699. QDomDocument doc("Image Labeler");
  1700. QFile file(filename);
  1701. if (!file.open(QIODevice::ReadOnly)) {
  1702. showWarning(tr("Can not open such file"));
  1703. return false;
  1704. /* NOTREACHED */
  1705. }
  1706. QString errMsg;
  1707. if (!doc.setContent(&file, &errMsg)) {
  1708. showWarning(errMsg);
  1709. file.close();
  1710. return false;
  1711. /* NOTREACHED */
  1712. }
  1713. file.close();
  1714. /* getting all info */
  1715. QDomElement elements = doc.documentElement();
  1716. QDomNode rootNode = elements.firstChild();
  1717. QString string;
  1718. while(!rootNode.isNull()) {
  1719. QDomElement element = rootNode.toElement();
  1720. if(!element.isNull()) {
  1721. /* path to the image */
  1722. if (element.tagName() == "image") {
  1723. string = element.text();
  1724. if (string.isEmpty()) {
  1725. showWarning(
  1726. tr(
  1727. "The file with data doesn't contain path to the image"
  1728. )
  1729. );
  1730. return false;
  1731. /* NOTREACHED */
  1732. }
  1733. if (!image_->load(string)) {
  1734. return false;
  1735. /* NOTREACHED */
  1736. }
  1737. current_image_ = string;
  1738. QString winTitle;
  1739. winTitle.append("ImageLabeler - ");
  1740. winTitle.append(current_image_);
  1741. setWindowTitle(winTitle);
  1742. image_holder_->resize(image_->size());
  1743. image_holder_->setPixmap(*image_);
  1744. }
  1745. /* path to the segmented image */
  1746. if (element.tagName() == "segmented") {
  1747. string = element.text();
  1748. if (string.isEmpty()) {
  1749. continue;
  1750. }
  1751. segmented_image_ = string;
  1752. action_view_segmented_->setEnabled(true);
  1753. }
  1754. /* image description */
  1755. else if (element.tagName() == "description" &&
  1756. !element.text().isEmpty()) {
  1757. image_description_ = element.text();
  1758. }
  1759. /* tags */
  1760. else if (element.tagName() == "tags" &&
  1761. !element.text().isEmpty()) {
  1762. tags_ = element.text();
  1763. }
  1764. /* legend */
  1765. else if (element.tagName() == "legend") {
  1766. list_label_->clear();
  1767. loadLegendFromNode(&element);
  1768. }
  1769. /* objects */
  1770. else if (element.tagName() == "objects") {
  1771. QDomNode subNode = element.firstChild();
  1772. QDomElement subElement;
  1773. while(!subNode.isNull()) {
  1774. subElement = subNode.toElement();
  1775. if (subElement.isNull() || subElement.text().isEmpty()) {
  1776. subNode = subNode.nextSibling();
  1777. continue;
  1778. }
  1779. string = subElement.attribute("id");
  1780. bool ok = 1;
  1781. int id = string.toInt(&ok, 10);
  1782. if (!ok) {
  1783. qDebug() <<
  1784. "loadInfo: "
  1785. "poly id format is corrupted";
  1786. subNode = subNode.nextSibling();
  1787. continue;
  1788. }
  1789. string = subElement.text();
  1790. if (subElement.tagName() == "bbox") {
  1791. addBBoxFromData(&string, &id);
  1792. }
  1793. if (subElement.tagName() == "poly") {
  1794. addPolyFromData(&string, &id);
  1795. }
  1796. subNode = subNode.nextSibling();
  1797. }
  1798. }
  1799. }
  1800. rootNode = rootNode.nextSibling();
  1801. }
  1802. unsaved_data_ = 0;
  1803. return true;
  1804. }
  1805. //! A slot member loading info about labeled image from PASCAL file(xml)
  1806. /*!
  1807. * \see loadPascalFile(QString aFilename, QString aPath)
  1808. *
  1809. * Slot asks user to set default "root" directory for the PASCAL files if
  1810. * it wan't set before
  1811. */
  1812. void
  1813. ImageLabeler::loadPascalFile()
  1814. {
  1815. if (askForUnsavedData()) {
  1816. return;
  1817. /* NOTREACHED */
  1818. }
  1819. if (PASCALpath_.isEmpty()) {
  1820. showWarning(tr("before opening first PASCAL file please choose \"root\" directory"
  1821. " where a folder with segmentations,"
  1822. " a folder with polygons,"
  1823. " a folder with image descriptions and"
  1824. " a folder with the pure images are."));
  1825. QFileDialog fileDialog(0, tr("root directory for the PASCAL files"));
  1826. fileDialog.setFileMode(QFileDialog::Directory);
  1827. if (fileDialog.exec())
  1828. PASCALpath_ = fileDialog.selectedFiles().last();
  1829. else {
  1830. return;
  1831. /* NOTREACHED */
  1832. }
  1833. }
  1834. QFileDialog fileDialog(0, tr("Load pascal file"));
  1835. fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
  1836. fileDialog.setDefaultSuffix("xml");
  1837. fileDialog.setFileMode(QFileDialog::AnyFile);
  1838. fileDialog.setDirectory(PASCALpath_);
  1839. QStringList filters;
  1840. filters << "PASCAL xml data (*.xml)"
  1841. << "Any files (*)";
  1842. fileDialog.setNameFilters(filters);
  1843. QString filename;
  1844. if (fileDialog.exec()) {
  1845. filename = fileDialog.selectedFiles().last();
  1846. }
  1847. else {
  1848. //showWarning(tr("Can not open file dialog"));
  1849. return;
  1850. /* NOTREACHED */
  1851. }
  1852. clearAllTool();
  1853. clearLabelList();
  1854. if (loadPascalFile(filename, PASCALpath_)) {
  1855. enableTools();
  1856. Image newImage;
  1857. newImage.image_ = current_image_;
  1858. newImage.labeled_ = 1;
  1859. newImage.pas_ = 1;
  1860. addImage(&newImage);
  1861. image_ID_ = list_images_widget_->count() - 1;
  1862. list_images_widget_->setCurrentRow(image_ID_);
  1863. }
  1864. unsaved_data_ = 0;
  1865. }
  1866. //! A slot member loading info about labeled image from PASCAL file(xml)
  1867. /*!
  1868. * Slot parses xml file and gets all needed info out of it
  1869. */
  1870. bool
  1871. ImageLabeler::loadPascalFile(QString aFilename, QString aPath)
  1872. {
  1873. QDomDocument doc;
  1874. QFile file(aFilename);
  1875. if (!file.open(QIODevice::ReadOnly)) {
  1876. showWarning(tr("Can not open such file"));
  1877. return false;
  1878. /* NOTREACHED */
  1879. }
  1880. QString errMsg;
  1881. if (!doc.setContent(&file, &errMsg)) {
  1882. showWarning(errMsg);
  1883. file.close();
  1884. return false;
  1885. /* NOTREACHED */
  1886. }
  1887. file.close();
  1888. //clearAll();
  1889. //enableTools();
  1890. /* getting all info */
  1891. QDomElement elements = doc.documentElement();
  1892. QDomNode rootNode = elements.firstChild();
  1893. QString string;
  1894. QString path;
  1895. if (aPath.isEmpty())
  1896. path = getPathFromFilename(aFilename);
  1897. else
  1898. path = aPath + "/";
  1899. QString filename;
  1900. QStringList labels;
  1901. labels << "BACKGROUND";
  1902. int labelID;
  1903. while(!rootNode.isNull()) {
  1904. QDomElement element = rootNode.toElement();
  1905. if(!element.isNull()) {
  1906. /* folder */
  1907. if (element.tagName() == "folder") {
  1908. string = element.text();
  1909. if (!string.isEmpty()) {
  1910. path.append(string);
  1911. }
  1912. }
  1913. /* filename */
  1914. else if (element.tagName() == "filename") {
  1915. string = element.text();
  1916. if (!string.isEmpty()) {
  1917. filename = string;
  1918. }
  1919. }
  1920. /* object */
  1921. else if (element.tagName() == "object") {
  1922. QDomNode subNode = element.firstChild();
  1923. QDomElement subElement;
  1924. while(!subNode.isNull()) {
  1925. subElement = subNode.toElement();
  1926. if (subElement.isNull() || subElement.text().isEmpty()) {
  1927. subNode = subNode.nextSibling();
  1928. continue;
  1929. }
  1930. /* label */
  1931. if (subElement.tagName() == "name") {
  1932. string = subElement.text();
  1933. if (!string.isEmpty() &&
  1934. !labels.contains(string, Qt::CaseInsensitive))
  1935. {
  1936. addLabel(list_label_->count(), 0, string);
  1937. labelID = labels.count();
  1938. labels << string;
  1939. }
  1940. else if (labels.contains(string, Qt::CaseInsensitive)) {
  1941. for (int i = 0; i < labels.count(); i++) {
  1942. if (labels.at(i) == string)
  1943. labelID = i;
  1944. }
  1945. }
  1946. }
  1947. if (subElement.tagName() == "bndbox") {
  1948. /* 2 points */
  1949. QPoint topLeft;
  1950. QPoint bottomRight;
  1951. QDomNode bboxNode = subElement.firstChild();
  1952. QDomElement bboxElement;
  1953. while(!bboxNode.isNull()) {
  1954. bboxElement = bboxNode.toElement();
  1955. string.clear();
  1956. bool ok = 1;
  1957. if (bboxElement.tagName() == "xmin") {
  1958. string = bboxElement.text();
  1959. if (string.isEmpty())
  1960. ok = 0;
  1961. double xmin = string.toDouble(&ok);
  1962. if (ok)
  1963. topLeft.setX(qRound(xmin));
  1964. }
  1965. else if (bboxElement.tagName() == "ymin") {
  1966. string = bboxElement.text();
  1967. if (string.isEmpty())
  1968. ok = 0;
  1969. double ymin = string.toDouble(&ok);
  1970. if (ok)
  1971. topLeft.setY(qRound(ymin));
  1972. }
  1973. else if (bboxElement.tagName() == "xmax") {
  1974. string = bboxElement.text();
  1975. if (string.isEmpty())
  1976. ok = 0;
  1977. double xmax = string.toDouble(&ok);
  1978. if (ok)
  1979. bottomRight.setX(qRound(xmax));
  1980. }
  1981. else if (bboxElement.tagName() == "ymax") {
  1982. string = bboxElement.text();
  1983. if (string.isEmpty())
  1984. ok = 0;
  1985. double ymax = string.toDouble(&ok);
  1986. if (ok)
  1987. bottomRight.setY(qRound(ymax));
  1988. }
  1989. if (string.isEmpty() || !ok)
  1990. break;
  1991. bboxNode = bboxNode.nextSibling();
  1992. if (bboxNode.isNull()) {
  1993. BoundingBox *bbox = new BoundingBox;
  1994. bbox->rect.setTopLeft(topLeft);
  1995. bbox->rect.setBottomRight(bottomRight);
  1996. bbox->label_ID_ = labelID;
  1997. addBBox(bbox);
  1998. }
  1999. }
  2000. }
  2001. subNode = subNode.nextSibling();
  2002. }
  2003. }
  2004. }
  2005. rootNode = rootNode.nextSibling();
  2006. }
  2007. if (!image_->load(path + "/JPEGImages/" + filename)) {
  2008. return false;
  2009. /* NOTREACHED */
  2010. }
  2011. current_image_ = path + "/JPEGImages/" + filename;
  2012. QString winTitle;
  2013. winTitle.append("ImageLabeler - ");
  2014. winTitle.append(current_image_);
  2015. setWindowTitle(winTitle);
  2016. image_holder_->resize(image_->size());
  2017. image_holder_->setPixmap(*image_);
  2018. unsaved_data_ = 0;
  2019. return true;
  2020. }
  2021. //! A slot member loading only information about polygons on the image
  2022. /*!
  2023. * \see loadPascalPolys(QString aFilename)
  2024. * Slot parses text file with .polygon suffix
  2025. */
  2026. void
  2027. ImageLabeler::loadPascalPolys()
  2028. {
  2029. if (current_image_.isEmpty()) {
  2030. return;
  2031. /* NOTREACHED */
  2032. }
  2033. QFileDialog fileDialog(0, tr("Load pascal polygons"));
  2034. fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
  2035. fileDialog.setDefaultSuffix("polygon");
  2036. fileDialog.setFileMode(QFileDialog::AnyFile);
  2037. QStringList filters;
  2038. filters << "PASCAL polygons (*.polygon)"
  2039. << "Any files (*)";
  2040. fileDialog.setNameFilters(filters);
  2041. QString filename;
  2042. if (fileDialog.exec()) {
  2043. filename = fileDialog.selectedFiles().last();
  2044. }
  2045. else {
  2046. //showWarning(tr("Can not open file dialog"));
  2047. return;
  2048. /* NOTREACHED */
  2049. }
  2050. //clearAllTool();
  2051. //clearLabelList();
  2052. if (!loadPascalPolys(filename)) {
  2053. showWarning(tr("File format is corrupted."));
  2054. }
  2055. unsaved_data_ = 0;
  2056. image_holder_->update();
  2057. }
  2058. //! A slot member loading only information about polygons on the image
  2059. /*!
  2060. * Slot parses text file with .polygon suffix
  2061. *
  2062. * returns true on success
  2063. */
  2064. bool
  2065. ImageLabeler::loadPascalPolys(QString aFilename)
  2066. {
  2067. QFile file(aFilename);
  2068. if (!file.open(QIODevice::ReadOnly)) {
  2069. showWarning(tr("Can not open such file"));
  2070. return false;
  2071. /* NOTREACHED */
  2072. }
  2073. QByteArray data = file.readAll();
  2074. file.close();
  2075. QString label;
  2076. int lastSpace = 0;
  2077. int pointCount = 0;
  2078. Polygon *poly = 0;
  2079. QPoint point;
  2080. bool evenFlag = 0;
  2081. //for (int i = 0; i < data.length(); i++) {
  2082. int i = 0;
  2083. while (i < data.length()) {
  2084. if (data.at(i) == ' ' && label.isEmpty() && !pointCount) {
  2085. label = QString(data.mid(lastSpace, i - lastSpace));
  2086. lastSpace = i + 1;
  2087. }
  2088. else if (data.at(i) == ' ' && !label.isEmpty() && !pointCount) {
  2089. QString num = QString(data.mid(lastSpace, i - lastSpace));
  2090. bool ok = 1;
  2091. pointCount = num.toInt(&ok, 10);
  2092. if (!ok) {
  2093. return false;
  2094. /* NOTREACHED */
  2095. }
  2096. poly = new Polygon;
  2097. poly->label_ID_ = -1;
  2098. lastSpace = i + 1;
  2099. }
  2100. else if (data.at(i) == ' ' &&
  2101. !label.isEmpty() &&
  2102. pointCount &&
  2103. !evenFlag)
  2104. {
  2105. evenFlag = 1;
  2106. QString num = QString(data.mid(lastSpace, i - lastSpace));
  2107. bool ok = 1;
  2108. int coor = qRound(num.toDouble(&ok));
  2109. if (!ok) {
  2110. return false;
  2111. /* NOTREACHED */
  2112. }
  2113. point.setX(coor);
  2114. lastSpace = i + 1;
  2115. }
  2116. else if (data.at(i) == ' ' &&
  2117. !label.isEmpty() &&
  2118. pointCount &&
  2119. evenFlag)
  2120. {
  2121. evenFlag = 0;
  2122. pointCount--;
  2123. QString num = QString(data.mid(lastSpace, i - lastSpace));
  2124. bool ok = 1;
  2125. int coor = qRound(num.toDouble(&ok));
  2126. if (!ok) {
  2127. return false;
  2128. /* NOTREACHED */
  2129. }
  2130. point.setY(coor);
  2131. lastSpace = i + 1;
  2132. poly->poly << point;
  2133. }
  2134. else if (data.at(i) == '\n') {
  2135. if (pointCount || !poly) {
  2136. return false;
  2137. /* NOTREACHED */
  2138. }
  2139. lastSpace = i + 1;
  2140. for (int j = 0; j < list_label_->count(); j++) {
  2141. if (list_label_->item(j)->text().contains(label, Qt::CaseInsensitive)) {
  2142. poly->label_ID_ = j;
  2143. }
  2144. }
  2145. if (-1 == poly->label_ID_) {
  2146. int labelID = list_label_->count();
  2147. addLabel(labelID, 0, label);
  2148. poly->label_ID_ = labelID;
  2149. }
  2150. addPoly(poly);
  2151. label.clear();
  2152. }
  2153. i++;
  2154. }
  2155. return true;
  2156. }
  2157. //! A Slot member loading single image.
  2158. /*!
  2159. * \see loadImages()
  2160. *
  2161. * Slot asks for unsaved data and loads an image.
  2162. * If selected image was previously labeled and the file with data
  2163. * was named like imagename_labeled.dat then it would be loaded
  2164. * with all data
  2165. */
  2166. void
  2167. ImageLabeler::loadImage()
  2168. {
  2169. if (askForUnsavedData()) {
  2170. return;
  2171. /* NOTREACHED */
  2172. }
  2173. QFileDialog fileDialog(0, tr("Load image"));
  2174. fileDialog.setFileMode(QFileDialog::ExistingFile);
  2175. QStringList filters;
  2176. filters << "Image files (*.jpeg *.jpg *.gif *.png *.bmp *.tiff)"
  2177. << "Any files (*)";
  2178. fileDialog.setNameFilters(filters);
  2179. QString filename;
  2180. if (fileDialog.exec()) {
  2181. filename = fileDialog.selectedFiles().last();
  2182. }
  2183. else {
  2184. //showWarning(tr("Could not open file dialog"));
  2185. return;
  2186. /* NOTREACHED */
  2187. }
  2188. if (filename.isEmpty()) {
  2189. return;
  2190. /* NOTREACHED */
  2191. }
  2192. /* checking if it was previously labeled */
  2193. QString dirPath = getPathFromFilename(filename);
  2194. QDir dir(dirPath);
  2195. QStringList filter;
  2196. filter << "*.dat";
  2197. QStringList fileList = dir.entryList(filter, QDir::Files);
  2198. QString labeled = alterFileName(filename, "_labeled");
  2199. labeled = removePath(labeled);
  2200. labeled.append(".dat");
  2201. if (fileList.contains(labeled, Qt::CaseInsensitive)) {
  2202. labeled = dir.absoluteFilePath(labeled);
  2203. loadInfo(labeled);
  2204. Image *newImage = new Image;
  2205. newImage->image_ = filename;
  2206. newImage->labeled_ = 1;
  2207. newImage->pas_ = 0;
  2208. addImage(newImage);
  2209. enableTools();
  2210. return;
  2211. /* NOTREACHED */
  2212. }
  2213. clearAllTool();
  2214. QString winTitle;
  2215. winTitle.append("ImageLabeler - ");
  2216. winTitle.append(current_image_);
  2217. setWindowTitle(winTitle);
  2218. if (!image_->load(filename)) {
  2219. return;
  2220. /* NOTREACHED */
  2221. }
  2222. image_holder_->resize(image_->size());
  2223. image_holder_->setPixmap(*image_);
  2224. current_image_ = filename;
  2225. image_ID_ = list_images_widget_->count() - 1;
  2226. list_images_widget_->setCurrentRow(image_ID_);
  2227. Image *newImage = new Image;
  2228. newImage->image_ = filename;
  2229. newImage->labeled_ = 0;
  2230. newImage->pas_ = 0;
  2231. addImage(newImage);
  2232. if (!list_images_widget_->count()) {
  2233. return;
  2234. /* NOTREACHED */
  2235. }
  2236. enableTools();
  2237. }
  2238. //! A slot member loading images recursively
  2239. /*!
  2240. * \see getImagesFromDir(const QDir &dir)
  2241. *
  2242. * Slot asks for unsaved data.
  2243. * It gives user a possibility to break a recursive search(with the widget
  2244. * and a button "cancel" on it.)
  2245. *
  2246. */
  2247. void
  2248. ImageLabeler::loadImages()
  2249. {
  2250. if (askForUnsavedData()) {
  2251. return;
  2252. /* NOTREACHED */
  2253. }
  2254. QFileDialog fileDialog(0, tr("Load images"));
  2255. fileDialog.setFileMode(QFileDialog::Directory);
  2256. QString dirName("");
  2257. if (fileDialog.exec()) {
  2258. /* TODO: make it possible to select multiple folders */
  2259. dirName = fileDialog.selectedFiles().last();
  2260. }
  2261. else {
  2262. //showWarning(tr("Could not open file dialog"));
  2263. return;
  2264. /* NOTREACHED */
  2265. }
  2266. clearAllTool();
  2267. /* creating a widget with a "cancel" button to
  2268. * give user an opportunity to stop the recursive search */
  2269. QWidget *searchInProgress = new QWidget(0);
  2270. searchInProgress->setWindowTitle(tr("Loading images"));
  2271. QLabel *info = new QLabel(searchInProgress);
  2272. info->setText(
  2273. tr("Program is looking for all image files in your directory recursively."));
  2274. QPushButton *cancel = new QPushButton(tr("Cancel"), searchInProgress);
  2275. connect(cancel, SIGNAL(clicked()), this, SLOT(interruptSearch()));
  2276. QVBoxLayout *layout = new QVBoxLayout(searchInProgress);
  2277. searchInProgress->setLayout(layout);
  2278. layout->addWidget(info);
  2279. layout->addWidget(cancel);
  2280. searchInProgress->adjustSize();
  2281. searchInProgress->move(QApplication::desktop()->screen()->rect().center() - rect().center());
  2282. searchInProgress->show();
  2283. getImagesFromDir(QDir(dirName));
  2284. /* deleting everything related to searchInProgress widget */
  2285. cancel->disconnect();
  2286. searchInProgress->hide();
  2287. delete info;
  2288. delete cancel;
  2289. delete layout;
  2290. delete searchInProgress;
  2291. if (interrupt_search_) {
  2292. interrupt_search_ = 0;
  2293. return;
  2294. /* NOTREACHED */
  2295. }
  2296. if (!list_images_widget_->count()) {
  2297. showWarning(tr("The folder you selected contains no images"));
  2298. return;
  2299. /* NOTREACHED */
  2300. }
  2301. bool ret = 0;
  2302. if (list_images_->at(0).labeled_) {
  2303. QString labeled =
  2304. alterFileName(list_images_->at(0).image_, "_labeled");
  2305. labeled.append(".dat");
  2306. ret = loadInfo(labeled);
  2307. }
  2308. else
  2309. ret = image_->load(list_images_->at(0).image_);
  2310. if (!ret) {
  2311. return;
  2312. /* NOTREACHED */
  2313. }
  2314. current_image_ = list_images_->at(0).image_;
  2315. image_ID_ = 0;
  2316. list_images_widget_->setCurrentRow(image_ID_);
  2317. QString winTitle;
  2318. winTitle.append("ImageLabeler - ");
  2319. winTitle.append(current_image_);
  2320. setWindowTitle(winTitle);
  2321. image_holder_->resize(image_->size());
  2322. image_holder_->setPixmap(*image_);
  2323. enableTools();
  2324. }
  2325. //! A slot member loading legend(labels) from xml file
  2326. /*!
  2327. * \see loadLegendFromNode(QDomElement *anElement)
  2328. */
  2329. void
  2330. ImageLabeler::loadLegendFromFile()
  2331. {
  2332. QFileDialog fileDialog(0, tr("Load legend"));
  2333. fileDialog.setFileMode(QFileDialog::AnyFile);
  2334. QString filename;
  2335. if (fileDialog.exec()) {
  2336. filename = fileDialog.selectedFiles().last();
  2337. }
  2338. else {
  2339. //showWarning(tr("Could not open file dialog"));
  2340. return;
  2341. /* NOTREACHED */
  2342. }
  2343. QDomDocument doc("Image Labeler");
  2344. QFile file(filename);
  2345. if (!file.open(QIODevice::ReadOnly)) {
  2346. showWarning(tr("Can not open such file"));
  2347. return;
  2348. /* NOTREACHED */
  2349. }
  2350. QString errMsg;
  2351. if (!doc.setContent(&file, &errMsg)) {
  2352. showWarning(errMsg);
  2353. file.close();
  2354. return;
  2355. /* NOTREACHED */
  2356. }
  2357. file.close();
  2358. list_label_->clear();
  2359. /* getting legend */
  2360. QDomElement elements = doc.documentElement();
  2361. QDomNode rootNode = elements.firstChild();
  2362. QString string;
  2363. while(!rootNode.isNull()) {
  2364. QDomElement element = rootNode.toElement();
  2365. if(!element.isNull()) {
  2366. if (element.tagName() == "legend") {
  2367. loadLegendFromNode(&element);
  2368. }
  2369. }
  2370. rootNode = rootNode.nextSibling();
  2371. }
  2372. }
  2373. //! A protected member loading legend from xml node
  2374. /*!
  2375. * \see addLabel(int aLabelID, bool isMain, QString aLabel)
  2376. * \see setLabelColor(int anID, QColor aColor)
  2377. *
  2378. * Slot gets all label information from xml node.
  2379. */
  2380. void
  2381. ImageLabeler::loadLegendFromNode(QDomElement *anElement)
  2382. {
  2383. if (!anElement) {
  2384. return;
  2385. /* NOTREACHED */
  2386. }
  2387. QDomNode subNode = anElement->firstChild();
  2388. QDomElement subElement;
  2389. QString string;
  2390. int id = -1;
  2391. bool isMain;
  2392. uint color = 0xff000000;
  2393. while(!subNode.isNull()) {
  2394. subElement = subNode.toElement();
  2395. if (!subElement.isNull() && !subElement.text().isEmpty()) {
  2396. /* id attribute */
  2397. string = subElement.attribute("id");
  2398. bool ok = 0;
  2399. id = string.toInt(&ok, 10);
  2400. if (!ok) {
  2401. qDebug() <<
  2402. "loadLegendFromNode: "
  2403. "label id format is corrupted";
  2404. subNode = subNode.nextSibling();
  2405. continue;
  2406. }
  2407. /* isMain attribute */
  2408. string = subElement.attribute("isMain");
  2409. isMain = string.toInt(&ok, 2);
  2410. if (!ok) {
  2411. qDebug() <<
  2412. "loadLegendFromNode: "
  2413. "label isMain flag format is corrupted";
  2414. subNode = subNode.nextSibling();
  2415. continue;
  2416. }
  2417. /* color attribute */
  2418. string = subElement.attribute("color");
  2419. color = string.toUInt(&ok, 16);
  2420. if (!ok) {
  2421. qDebug() <<
  2422. "loadLegendFromNode: "
  2423. "label color format is corrupted";
  2424. subNode = subNode.nextSibling();
  2425. continue;
  2426. }
  2427. /* label name */
  2428. string = subElement.text();
  2429. addLabel(id, isMain, string);
  2430. setLabelColor(id, color);
  2431. }
  2432. subNode = subNode.nextSibling();
  2433. }
  2434. }
  2435. //! A protected member converting all the label information into xml format
  2436. /*!
  2437. * \see objectsToXml(QDomDocument *aDoc, QDomElement *aRoot)
  2438. * \param[in] aDoc a pointer to QDomDocument object - represents an xml document
  2439. * \param[out] aRoot a pointer to QDomElement object - contains all the results from
  2440. * the converting
  2441. */
  2442. void
  2443. ImageLabeler::legendToXml(QDomDocument *aDoc, QDomElement *aRoot)
  2444. {
  2445. QDomElement legend = aDoc->createElement(tr("legend"));
  2446. aRoot->appendChild(legend);
  2447. /* storing all labels made by user */
  2448. int labelCount = list_label_->count();
  2449. for (int i = 0; i < labelCount; i++) {
  2450. QDomElement label = aDoc->createElement(tr("label"));
  2451. label.setAttribute("color", QString("%1").arg(list_label_colors_.at(i), 0, 16));
  2452. label.setAttribute("id", i);
  2453. QString priority;
  2454. if (main_label_ == i)
  2455. priority.append("1");
  2456. else
  2457. priority.append("0");
  2458. label.setAttribute("isMain", priority);
  2459. QString labelText = list_label_->item(i)->text();
  2460. /* removing the number prefix of label */
  2461. if (-1 != labelText.indexOf(QString("%1: ").arg(i))) {
  2462. labelText = labelText.mid(3, labelText.size() - 3);
  2463. }
  2464. QDomText labelName = aDoc->createTextNode(labelText);
  2465. label.appendChild(labelName);
  2466. legend.appendChild(label);
  2467. }
  2468. /* in case we have no labels */
  2469. if (0 == labelCount) {
  2470. QDomElement label = aDoc->createElement(tr("label"));
  2471. label.setAttribute(tr("id"), -1);
  2472. legend.appendChild(label);
  2473. }
  2474. }
  2475. //! A protected member converting all the objects information into xml format
  2476. /*!
  2477. * \see legendToXml(QDomDocument *aDoc, QDomElement *aRoot)
  2478. * \param[in] aDoc a pointer to the QDomDocument object - represents an xml document
  2479. * \param[out] aRoot a pointer to the QDomElement object - contains all the results from
  2480. * the converting
  2481. */
  2482. void
  2483. ImageLabeler::objectsToXml(QDomDocument *aDoc, QDomElement *aRoot)
  2484. {
  2485. QDomElement objects = aDoc->createElement(tr("objects"));
  2486. aRoot->appendChild(objects);
  2487. /* rects first */
  2488. for (int i = 0; i < list_bounding_box_.size(); i++) {
  2489. QDomElement rectData = aDoc->createElement(tr("bbox"));
  2490. rectData.setAttribute("id", list_bounding_box_.at(i)->label_ID_);
  2491. QRect rect = list_bounding_box_.at(i)->rect.normalized();
  2492. QString rectDataString =
  2493. QString("%1;%2;%3;%4;").
  2494. arg(rect.x()).
  2495. arg(rect.y()).
  2496. arg(rect.width()).
  2497. arg(rect.height());
  2498. QDomText rectDataText = aDoc->createTextNode(rectDataString);
  2499. rectData.appendChild(rectDataText);
  2500. objects.appendChild(rectData);
  2501. }
  2502. /* polys next */
  2503. for (int i = 0; i < list_polygon_.size(); i++) {
  2504. QDomElement polyData = aDoc->createElement(tr("poly"));
  2505. polyData.setAttribute("id", list_polygon_.at(i)->label_ID_);
  2506. QPolygon poly = list_polygon_.at(i)->poly;
  2507. QString polyDataString;
  2508. for (int j = 0; j < poly.count(); j++)
  2509. polyDataString.append(
  2510. QString("%1;%2;").
  2511. arg(poly.point(j).x()).
  2512. arg(poly.point(j).y())
  2513. );
  2514. QDomText polyDataText = aDoc->createTextNode(polyDataString);
  2515. polyData.appendChild(polyDataText);
  2516. objects.appendChild(polyData);
  2517. }
  2518. }
  2519. //! A slot member generating color for all labels
  2520. /*!
  2521. * A very primitive temporary solution for color generation
  2522. */
  2523. void
  2524. ImageLabeler::generateColors()
  2525. {
  2526. int labelCount = list_label_->count();
  2527. if (!labelCount) {
  2528. showWarning(tr("you have not added any labels yet"));
  2529. return;
  2530. /* NOTREACHED */
  2531. }
  2532. int coeff = (0xff / labelCount) * 3;
  2533. list_label_colors_.clear();
  2534. list_label_colors_.append(0);
  2535. uchar red = 0xff;
  2536. uchar green = 0xff;
  2537. uchar blue = 0xff;
  2538. uchar iterationColor = coeff;
  2539. uint color = 0xffffffff;
  2540. int j = 1;
  2541. for (int i = 1; i < labelCount; i++) {
  2542. if (6 == j) {
  2543. iterationColor += coeff;
  2544. j = 1;
  2545. }
  2546. if (5 == j) {
  2547. red = 0xff - iterationColor;
  2548. green = 0xff - iterationColor;
  2549. blue = 0xff;
  2550. }
  2551. else if (4 == j) {
  2552. red = 0xff - iterationColor;
  2553. green = 0xff;
  2554. blue = 0xff - iterationColor;
  2555. }
  2556. else if (3 == j) {
  2557. red = 0xff - iterationColor;
  2558. green = 0xff;
  2559. blue = 0xff;
  2560. }
  2561. else if (2 == j) {
  2562. red = 0xff;
  2563. green = 0xff - iterationColor;
  2564. blue = 0xff;
  2565. }
  2566. else if (1 == j){
  2567. red = 0xff;
  2568. green = 0xff;
  2569. blue = 0xff - iterationColor;
  2570. }
  2571. j++;
  2572. color = red + (green * 0x100) + (blue * 0x10000) + 0xff000000;
  2573. int itemNo = list_label_colors_.count();
  2574. QPixmap iconPix = QPixmap(20, 20);
  2575. iconPix.fill(color);
  2576. QIcon icon(iconPix);
  2577. list_label_->item(itemNo)->setIcon(icon);
  2578. list_label_colors_.append(color);
  2579. }
  2580. image_holder_->update();
  2581. }
  2582. //! A protected member creating new boundary box from text data
  2583. /*!
  2584. * \see addBBoxArea(int anID, BoundingBox aBBox, int itemID)
  2585. * \see BBoxFromData(QString *aBBoxData)
  2586. *
  2587. * It creates bbox both in the container and in the list widget
  2588. */
  2589. void
  2590. ImageLabeler::addBBoxFromData(
  2591. QString *aBBoxData,
  2592. int *ID
  2593. )
  2594. {
  2595. BoundingBox *bbox = new BoundingBox;
  2596. *bbox = BBoxFromData(aBBoxData);
  2597. if (!bbox->rect.isValid() || !ID) {
  2598. return;
  2599. /* NOTREACHED */
  2600. }
  2601. bbox->label_ID_ = *ID;
  2602. list_bounding_box_.append(bbox);
  2603. addBBoxArea(list_bounding_box_.count() - 1, *bbox);
  2604. }
  2605. //! A protected member parsing string data and returning a BoundingBox from it
  2606. /*!
  2607. * \see addBBoxArea(int anID, BoundingBox aBBox, int itemID)
  2608. *
  2609. * format is x;y;w;h where w - width and h - height
  2610. */
  2611. BoundingBox
  2612. ImageLabeler::BBoxFromData(
  2613. QString *aBBoxData
  2614. )
  2615. {
  2616. BoundingBox bbox;
  2617. QString buffer;
  2618. bbox.rect.setRect(-1, -1, -1, -1);
  2619. int startPos = 0;
  2620. bool ok = 1;
  2621. for (int i = 0; i < aBBoxData->size(); i++) {
  2622. if (';' != aBBoxData->at(i))
  2623. continue;
  2624. buffer = aBBoxData->mid(startPos, i - startPos);
  2625. int bboxData = buffer.toInt(&ok, 10);
  2626. if (!ok) {
  2627. qDebug() <<
  2628. "BBoxFromData: "
  2629. "bbox format is corrupted";
  2630. break;
  2631. }
  2632. if (-1 == bbox.rect.x()) {
  2633. bbox.rect.setX(bboxData);
  2634. bbox.rect.setWidth(-1);
  2635. }
  2636. else if (-1 == bbox.rect.y()) {
  2637. bbox.rect.setY(bboxData);
  2638. bbox.rect.setHeight(-1);
  2639. }
  2640. else if (-1 == bbox.rect.width()) {
  2641. bbox.rect.setWidth(bboxData);
  2642. }
  2643. else if (-1 == bbox.rect.height()) {
  2644. bbox.rect.setHeight(bboxData);
  2645. }
  2646. startPos = i + 1;
  2647. }
  2648. if (!bbox.rect.isValid()) {
  2649. qDebug() <<
  2650. "BBoxFromData: "
  2651. "bbox format is corrupted";
  2652. bbox.rect.setRect(-1, -1, -1, -1);
  2653. }
  2654. else if (!ok) {
  2655. bbox.rect.setRect(-1, -1, -1, -1);
  2656. }
  2657. return bbox;
  2658. }
  2659. //! A protected member getting a BoundaryBox from text of the list_areas_ item
  2660. /*!
  2661. * \see BBoxFromData(QString *aBBoxData)
  2662. *
  2663. * Slot gets label ID an points from the string data. BBox ID can not be changed.
  2664. */
  2665. BoundingBox
  2666. ImageLabeler::BBoxFromListItemText(
  2667. QString *aString,
  2668. int *oldID
  2669. )
  2670. {
  2671. BoundingBox bbox;
  2672. bbox.label_ID_ = -1;
  2673. *oldID = -1;
  2674. if (!aString) {
  2675. return bbox;
  2676. /* NOTREACHED */
  2677. }
  2678. if (-1 == aString->indexOf("BBox")) {
  2679. return bbox;
  2680. /* NOTREACHED */
  2681. }
  2682. /* getting bbox id in the list(it cannot be changed) */
  2683. bool ok = 0;
  2684. int bboxID = getNumFromString(aString, "BBox #", ";", &ok);
  2685. if (!ok || bboxID <= -1) {
  2686. qDebug() <<
  2687. "BBoxFromListItemText: bboxID is corrupted";
  2688. return bbox;
  2689. /* NOTREACHED */
  2690. }
  2691. /* getting new label id */
  2692. int labelID = getNumFromString(aString, "LabelID: ", ";", &ok);
  2693. if (!ok || labelID <= -1) {
  2694. showWarning(
  2695. tr("new LabelID is wrong, area can not be changed")
  2696. );
  2697. return bbox;
  2698. /* NOTREACHED */
  2699. }
  2700. /* getting new points */
  2701. int pointsPos = aString->indexOf("data:") + 5;
  2702. int pointsLen = aString->size() - pointsPos;
  2703. if (pointsLen <= 0) {
  2704. showWarning(
  2705. tr("new data is wrong, area can not be changed")
  2706. );
  2707. return bbox;
  2708. /* NOTREACHED */
  2709. }
  2710. QString pointsData = aString->mid(pointsPos, pointsLen);
  2711. bbox = BBoxFromData(&pointsData);
  2712. bbox.label_ID_ = labelID;
  2713. *oldID = bboxID;
  2714. return bbox;
  2715. }
  2716. //! A protected member adding poly to the list widget and to the list container
  2717. /*!
  2718. * \see addBBox(BoundingBox *bbox)
  2719. * \param[in] poly a pointer to the Polygon structure
  2720. * containing new poly information
  2721. *
  2722. */
  2723. void
  2724. ImageLabeler::addPoly(Polygon *poly)
  2725. {
  2726. if (poly->poly.isEmpty() || poly->label_ID_ < 0) {
  2727. return;
  2728. /* NOTREACHED */
  2729. }
  2730. list_polygon_.append(poly);
  2731. addPolyArea(list_polygon_.count() - 1, *poly);
  2732. }
  2733. //! A protected member adding bounding box to the list widget
  2734. //! and to the list container
  2735. /*!
  2736. * \see addPoly(Polygon *poly)
  2737. * \param[in] bbox a pointer to the BoundingBox structure
  2738. * containing new bounding box information
  2739. *
  2740. */
  2741. void
  2742. ImageLabeler::addBBox(BoundingBox *bbox)
  2743. {
  2744. if (bbox->rect.isEmpty() || bbox->label_ID_ < 0) {
  2745. return;
  2746. /* NOTREACHED */
  2747. }
  2748. list_bounding_box_.append(bbox);
  2749. addBBoxArea(list_bounding_box_.count() - 1, *bbox);
  2750. }
  2751. //! A protected member creating new polygon from text data
  2752. /*!
  2753. * \see addPolyArea(int anID, Polygon aPoly, int itemID)
  2754. * \see polyFromData(QString *aPolyData)
  2755. *
  2756. * It creates polygon both in the container and in the list widget
  2757. */
  2758. void
  2759. ImageLabeler::addPolyFromData(
  2760. QString *aPolyData,
  2761. int *labelID
  2762. )
  2763. {
  2764. Polygon *poly = new Polygon;
  2765. *poly = polyFromData(aPolyData);
  2766. if (poly->poly.isEmpty() || !labelID) {
  2767. return;
  2768. /* NOTREACHED */
  2769. }
  2770. poly->label_ID_ = *labelID;
  2771. list_polygon_.append(poly);
  2772. addPolyArea(list_polygon_.count() - 1, *poly);
  2773. }
  2774. //! A protected member parsing string data and returning a Polygon from it
  2775. /*!
  2776. * \see addPolyArea(int anID, Polygon aPoly, int itemID)
  2777. *
  2778. * format is x0;y0;x1;y1;...
  2779. */
  2780. Polygon
  2781. ImageLabeler::polyFromData(
  2782. QString *aPolyData
  2783. )
  2784. {
  2785. Polygon poly;
  2786. poly.label_ID_ = -1;
  2787. QPoint point;
  2788. QString buffer;
  2789. int startPos = 0;
  2790. bool ok = 1;
  2791. /* indicates whether coordinate x or y */
  2792. bool evenFlag = 0;
  2793. for (int i = 0; i < aPolyData->size(); i++) {
  2794. /* ";" is a separator */
  2795. if (';' != aPolyData->at(i))
  2796. continue;
  2797. buffer = aPolyData->mid(startPos, i - startPos);
  2798. int polyCoor = buffer.toInt(&ok, 10);
  2799. if (!ok) {
  2800. qDebug() <<
  2801. "polyFromData: "
  2802. "poly format is corrupted";
  2803. break;
  2804. }
  2805. if (!evenFlag) {
  2806. point.setX(polyCoor);
  2807. evenFlag = 1;
  2808. }
  2809. else {
  2810. point.setY(polyCoor);
  2811. poly.poly.append(point);
  2812. evenFlag = 0;
  2813. }
  2814. startPos = i + 1;
  2815. }
  2816. /* last coordinate was Xi what means an error */
  2817. if (evenFlag) {
  2818. qDebug() <<
  2819. "polyFromData: "
  2820. "poly format is corrupted";
  2821. poly.poly.clear();
  2822. }
  2823. /* last converting from string was not successful */
  2824. else if (!ok) {
  2825. poly.poly.clear();
  2826. }
  2827. return poly;
  2828. }
  2829. //! A protected member getting a Polygon from text of the list_areas_ item
  2830. /*!
  2831. * \see polyFromData(QString *aPolyData)
  2832. *
  2833. * Slot gets label ID an points from the string data. Poly ID can not be changed.
  2834. */
  2835. Polygon
  2836. ImageLabeler::polyFromListItemText(
  2837. QString *aString,
  2838. int *oldID
  2839. )
  2840. {
  2841. Polygon poly;
  2842. poly.label_ID_ = -1;
  2843. *oldID = -1;
  2844. if (!aString) {
  2845. return poly;
  2846. /* NOTREACHED */
  2847. }
  2848. if (-1 == aString->indexOf("Poly")) {
  2849. return poly;
  2850. /* NOTREACHED */
  2851. }
  2852. /* getting poly id in the list(it cannot be changed) */
  2853. bool ok = 0;
  2854. int polyID = getNumFromString(aString, "Poly #", ";", &ok);
  2855. if (!ok || polyID <= -1) {
  2856. qDebug() <<
  2857. "polyFromListItemText: poly ID is corrupted";
  2858. return poly;
  2859. /* NOTREACHED */
  2860. }
  2861. /* getting new label id */
  2862. int labelID = getNumFromString(aString, "LabelID: ", ";", &ok);
  2863. if (!ok || labelID <= -1) {
  2864. showWarning(
  2865. tr("new LabelID is wrong, area can not be changed")
  2866. );
  2867. return poly;
  2868. /* NOTREACHED */
  2869. }
  2870. /* getting new points */
  2871. int pointsPos = aString->indexOf("points:") + 7;
  2872. int pointsLen = aString->size() - pointsPos;
  2873. if (pointsLen <= 0) {
  2874. showWarning(
  2875. tr("new points data is wrong, area can not be changed")
  2876. );
  2877. return poly;
  2878. /* NOTREACHED */
  2879. }
  2880. QString pointsData = aString->mid(pointsPos, pointsLen);
  2881. poly = polyFromData(&pointsData);
  2882. poly.label_ID_ = labelID;
  2883. *oldID = polyID;
  2884. return poly;
  2885. }
  2886. //! A protected member only for internal use. Showing a message box with warning
  2887. /*!
  2888. * \param[in] text a QString object containing message you want
  2889. * to deliver to the user
  2890. */
  2891. void
  2892. ImageLabeler::showWarning(
  2893. const QString &text
  2894. )
  2895. {
  2896. if (text.isEmpty()) {
  2897. return;
  2898. /* NOTREACHED */
  2899. }
  2900. QMessageBox msgBox;
  2901. msgBox.setText(text);
  2902. msgBox.setIcon(QMessageBox::Warning);
  2903. msgBox.exec();
  2904. }
  2905. //! A protected member only for internal use.
  2906. //! Shows a message box asking about unsaved progress
  2907. /*!
  2908. * It depends on object containers(list_bounding_box_ and list_polygon_)
  2909. * and on unsaved_data_ flag which must be true to make this dialog appear
  2910. */
  2911. bool
  2912. ImageLabeler::askForUnsavedData()
  2913. {
  2914. if ((!list_bounding_box_.isEmpty() ||
  2915. !list_polygon_.isEmpty()) &&
  2916. unsaved_data_)
  2917. {
  2918. QMessageBox msgBox;
  2919. msgBox.setText(tr("There is some unsaved data"));
  2920. msgBox.setInformativeText(tr("Do you want to save your progress?"));
  2921. msgBox.setStandardButtons(
  2922. QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
  2923. msgBox.setDefaultButton(QMessageBox::Save);
  2924. msgBox.setIcon(QMessageBox::Question);
  2925. int ret = msgBox.exec();
  2926. if (QMessageBox::Save == ret)
  2927. saveAllInfo();
  2928. else if (QMessageBox::Cancel == ret)
  2929. return true;
  2930. }
  2931. return true;
  2932. }
  2933. //! A slot member setting bbox tool active
  2934. /*!
  2935. * \param[in] aButtonPressed is a bool flag which is needed for toggled buttons
  2936. */
  2937. void
  2938. ImageLabeler::setBoundingBoxTool(bool aButtonPressed)
  2939. {
  2940. if (aButtonPressed)
  2941. image_holder_->setTool(ImageHolder::BoundingBoxTool);
  2942. else {
  2943. image_holder_->setTool(ImageHolder::NoTool);
  2944. image_holder_->clearLast();
  2945. }
  2946. }
  2947. //! A slot member setting polygon tool active
  2948. /*!
  2949. * \param[in] aButtonPressed is a bool flag which is needed for toggled buttons
  2950. */
  2951. void
  2952. ImageLabeler::setPolygonTool(bool aButtonPressed)
  2953. {
  2954. if (aButtonPressed) {
  2955. image_holder_->setTool(ImageHolder::PolygonTool);
  2956. image_holder_->setFocus();
  2957. }
  2958. else {
  2959. image_holder_->setTool(ImageHolder::NoTool);
  2960. image_holder_->clearLast();
  2961. }
  2962. }
  2963. //! A slot member enables button_confirm_selection_ button
  2964. void
  2965. ImageLabeler::onSelectionStarted()
  2966. {
  2967. button_confirm_selection_->setEnabled(true);
  2968. }
  2969. //! A slot member adding information about new selected area
  2970. /*!
  2971. * \see addBBoxArea(int anID, BoundingBox aBBox, int itemID)
  2972. * \see addPolyArea(int aPolyID, Polygon aPoly, int itemID)
  2973. *
  2974. * After user has created a new selection area it should be confirmed or else it
  2975. * wouldn't be added to the item list and containers. This slot takes all data from
  2976. * unconfirmed selection and places it into list widget and corresponding container
  2977. * (list_bounding_box_ or list_polygon_)
  2978. */
  2979. void
  2980. ImageLabeler::confirmSelection()
  2981. {
  2982. if (!list_label_->count()) {
  2983. showWarning(tr("You haven't added any label"));
  2984. return;
  2985. /* NOTREACHED */
  2986. }
  2987. image_holder_->confirmSelection();
  2988. if (label_ID_ < 0)
  2989. label_ID_ = 0;
  2990. ImageHolder::Tool tool = image_holder_->tool();
  2991. switch (tool) {
  2992. case ImageHolder::BoundingBoxTool:
  2993. list_bounding_box_.last()->label_ID_ = label_ID_;
  2994. addBBoxArea(
  2995. list_bounding_box_.count() - 1,
  2996. *(list_bounding_box_.last())
  2997. );
  2998. break;
  2999. case ImageHolder::PolygonTool:
  3000. list_polygon_.last()->label_ID_ = label_ID_;
  3001. addPolyArea(
  3002. list_polygon_.count() - 1,
  3003. *(list_polygon_.last())
  3004. );
  3005. break;
  3006. default:
  3007. break;
  3008. }
  3009. button_confirm_selection_->setEnabled(false);
  3010. unsaved_data_ = 1;
  3011. }
  3012. //! \brief A slot member clears all widgets and containers
  3013. //! (not recommended to use without necessity)
  3014. /*!
  3015. * \see clearAllTool()
  3016. * \see clearLabelList()
  3017. * \see clearLabelColorList()
  3018. */
  3019. void
  3020. ImageLabeler::clearAll()
  3021. {
  3022. clearLabelList();
  3023. list_areas_->clear();
  3024. list_bounding_box_.clear();
  3025. list_polygon_.clear();
  3026. list_images_->clear();
  3027. list_images_widget_->clear();
  3028. main_label_ = -1;
  3029. image_holder_->clearAll();
  3030. segmented_image_.clear();
  3031. action_view_normal_->setEnabled(false);
  3032. action_view_segmented_->setEnabled(false);
  3033. }
  3034. //! A slot member clears only selections made by user
  3035. /*!
  3036. * \see clearAll()
  3037. * \see clearLabelList()
  3038. * \see clearLabelColorList()
  3039. */
  3040. void
  3041. ImageLabeler::clearAllTool()
  3042. {
  3043. list_areas_->clear();
  3044. list_bounding_box_.clear();
  3045. list_polygon_.clear();
  3046. main_label_ = -1;
  3047. image_holder_->clearAll();
  3048. }
  3049. //! A slot member clears label list
  3050. /*!
  3051. * \see clearAll()
  3052. * \see clearAllTool()
  3053. * \see clearLabelColorList()
  3054. *
  3055. * As far as BACKGROUND label should always be present slot adds
  3056. * it after clearing all the label list
  3057. */
  3058. void ImageLabeler::clearLabelList()
  3059. {
  3060. list_label_->clear();
  3061. addLabel(0, false, "BACKGROUND");
  3062. list_label_->item(0)->setFlags(
  3063. Qt::ItemIsUserCheckable | Qt::ItemIsSelectable |
  3064. Qt::ItemIsEnabled
  3065. );
  3066. }
  3067. //! A slot member clears the list of label colors
  3068. /*!
  3069. * \see clearAll()
  3070. * \see clearAllTool()
  3071. * \see clearLabelList()
  3072. *
  3073. * As far as BACKGROUND label should always be present slot adds
  3074. * it's color(black by default) after clearing all the label color list
  3075. */
  3076. void ImageLabeler::clearLabelColorList()
  3077. {
  3078. list_label_colors_.clear();
  3079. list_label_colors_.append(0x0);
  3080. }
  3081. //! A slot member enabling all the tools
  3082. /*!
  3083. * \see disableTools()
  3084. *
  3085. * By default the initial state of all tools is disabled
  3086. * so this slot is recommended to use when at least one image
  3087. * has been loaded
  3088. */
  3089. void
  3090. ImageLabeler::enableTools()
  3091. {
  3092. action_save_all_->setEnabled(true);
  3093. action_save_segmented_->setEnabled(true);
  3094. action_save_legend_->setEnabled(true);
  3095. action_bound_box_tool_->setEnabled(true);
  3096. action_polygon_tool_->setEnabled(true);
  3097. action_add_description_->setEnabled(true);
  3098. action_undo_->setEnabled(true);
  3099. action_redo_->setEnabled(true);
  3100. button_bound_box_tool_->setEnabled(true);
  3101. button_polygon_tool_->setEnabled(true);
  3102. button_tagging_tool_->setEnabled(true);
  3103. button_add_label_->setEnabled(true);
  3104. button_remove_label_->setEnabled(true);
  3105. button_prev_image_->setEnabled(true);
  3106. button_next_image_->setEnabled(true);
  3107. button_clear_selection_tool_->setEnabled(true);
  3108. button_generate_colors_->setEnabled(true);
  3109. button_delete_all_labels_->setEnabled(true);
  3110. }
  3111. //! A slot member disabling all the tools
  3112. /*!
  3113. * \see enableTools()
  3114. */
  3115. void
  3116. ImageLabeler::disableTools()
  3117. {
  3118. action_save_all_->setEnabled(false);
  3119. action_save_segmented_->setEnabled(false);
  3120. action_save_legend_->setEnabled(false);
  3121. action_bound_box_tool_->setEnabled(false);
  3122. action_polygon_tool_->setEnabled(false);
  3123. button_tagging_tool_->setEnabled(false);
  3124. action_add_description_->setEnabled(false);
  3125. action_undo_->setEnabled(false);
  3126. action_redo_->setEnabled(false);
  3127. button_bound_box_tool_->setEnabled(false);
  3128. button_polygon_tool_->setEnabled(false);
  3129. button_add_label_->setEnabled(false);
  3130. button_remove_label_->setEnabled(false);
  3131. button_prev_image_->setEnabled(false);
  3132. button_next_image_->setEnabled(false);
  3133. button_clear_selection_tool_->setEnabled(false);
  3134. button_generate_colors_->setEnabled(false);
  3135. button_delete_all_labels_->setEnabled(false);
  3136. }
  3137. //! \brief A slot member triggering popup_area_list_ menu with the coordinates
  3138. //! of the mouse pointer
  3139. /*!
  3140. * \see deleteArea()
  3141. * \see editArea()
  3142. */
  3143. void
  3144. ImageLabeler::areaListPopupMenu(const QPoint &aPos)
  3145. {
  3146. QPoint globalPos = list_areas_->mapToGlobal(aPos);
  3147. QModelIndex index = list_areas_->indexAt(aPos);
  3148. if (-1 == index.row()) {
  3149. return;
  3150. /* NOTREACHED */
  3151. }
  3152. list_areas_->item(index.row())->setSelected(true);
  3153. popup_area_list_->exec(globalPos);
  3154. }
  3155. //! \brief A slot member triggering popup_label_list_ menu width the coordinates
  3156. //! of the mouse pointer
  3157. /*!
  3158. * \see setLabelColor()
  3159. * \see toggleLabelPriority()
  3160. * \see removeLabel()
  3161. */
  3162. void
  3163. ImageLabeler::labelListPopupMenu(const QPoint &aPos)
  3164. {
  3165. QPoint globalPos = list_label_->mapToGlobal(aPos);
  3166. QModelIndex index = list_label_->indexAt(aPos);
  3167. if (-1 == index.row() || !index.row()) {
  3168. return;
  3169. /* NOTREACHED */
  3170. }
  3171. list_label_->item(index.row())->setSelected(true);
  3172. popup_label_list_->exec(globalPos);
  3173. }
  3174. //! \brief A slot member triggering popup_images_list_ menu width the coordinates
  3175. //! of the mouse pointer
  3176. /*!
  3177. * \see removeImage()
  3178. */
  3179. void
  3180. ImageLabeler::imageListPopupMenu(const QPoint &aPos)
  3181. {
  3182. QPoint globalPos = list_images_widget_->mapToGlobal(aPos);
  3183. QModelIndex index = list_images_widget_->indexAt(aPos);
  3184. if (-1 == index.row()) {
  3185. return;
  3186. /* NOTREACHED */
  3187. }
  3188. list_images_widget_->item(index.row())->setSelected(true);
  3189. popup_images_list_->exec(globalPos);
  3190. }
  3191. //! \brief A slot member gets image description or tags from line_edit_form_
  3192. //! depends on line_edit_form_.purpose()
  3193. /*!
  3194. * \see LineEditForm
  3195. */
  3196. void
  3197. ImageLabeler::setDataFromForm(QString aData)
  3198. {
  3199. if (ImageDescriptionPurpose == line_edit_form_.purpose()) {
  3200. image_description_ = aData;
  3201. setWindowTitle(image_description_);
  3202. }
  3203. else if (TaggingPurpose == line_edit_form_.purpose()) {
  3204. tags_ = aData;
  3205. }
  3206. }
  3207. //! A slot member creating 2-dimensional array for the segmented image
  3208. /*!
  3209. * Array size is equal to a size of the current image loaded
  3210. * and each pixel has the label id which corresponds to the objects in
  3211. * list_bounding_box_ and list_polygon_.
  3212. */
  3213. void
  3214. ImageLabeler::setPureData()
  3215. {
  3216. /* initializing array */
  3217. if (pure_data_) {
  3218. delete[] *pure_data_;
  3219. delete pure_data_;
  3220. }
  3221. /* getting image size */
  3222. QSize imageSize = image_->size();
  3223. pure_data_ = new int *[imageSize.height()];
  3224. if (!pure_data_) {
  3225. return;
  3226. /* NOTREACHED */
  3227. }
  3228. /* allocating memory */
  3229. for (int i = 0; i < imageSize.height(); i++) {
  3230. pure_data_[i] = new int[imageSize.width()];
  3231. if (!pure_data_[i]) {
  3232. return;
  3233. /* NOTREACHED */
  3234. }
  3235. }
  3236. /* getting the number of all selections */
  3237. int bboxCnt = list_bounding_box_.count();
  3238. int polyCnt = list_polygon_.count();
  3239. /* checking if each coordinate(pixel) belongs to any object */
  3240. for (int i = 0; i < imageSize.height(); i++)
  3241. for (int j = 0; j < imageSize.width(); j++) {
  3242. pure_data_[i][j] = 0;
  3243. /* bboxes first */
  3244. for (int cnt = 0; cnt < bboxCnt; cnt++) {
  3245. BoundingBox *bbox = list_bounding_box_.at(cnt);
  3246. if (bbox->rect.contains(j, i)) {
  3247. pure_data_[i][j] = bbox->label_ID_;
  3248. }
  3249. }
  3250. /* polys next */
  3251. for (int cnt = 0; cnt < polyCnt; cnt++) {
  3252. Polygon *poly = list_polygon_.at(cnt);
  3253. if (poly->poly.containsPoint(QPoint(j, i), Qt::OddEvenFill)) {
  3254. pure_data_[i][j] = poly->label_ID_;
  3255. }
  3256. }
  3257. }
  3258. }
  3259. //! \brief A slot member setting new color for
  3260. //! the current label from QColorDialog
  3261. /*!
  3262. * \see setLabelColor(int anID, QColor aColor)
  3263. */
  3264. void
  3265. ImageLabeler::setLabelColor()
  3266. {
  3267. if (list_label_colors_.count() < list_label_->count()) {
  3268. generateColors();
  3269. }
  3270. /* getting current item */
  3271. QListWidgetItem *current = list_label_->currentItem();
  3272. int labelID = list_label_->row(current);
  3273. QColor defaultColor;
  3274. defaultColor.setRgb(list_label_colors_.at(labelID));
  3275. QColor newColor = QColorDialog::getColor(
  3276. defaultColor,
  3277. list_label_
  3278. );
  3279. if (!newColor.isValid()) {
  3280. return;
  3281. /* NOTREACHED */
  3282. }
  3283. list_label_colors_.takeAt(labelID);
  3284. list_label_colors_.insert(labelID, newColor.rgb());
  3285. QPixmap iconPix = QPixmap(20, 20);
  3286. iconPix.fill(newColor);
  3287. QIcon icon(iconPix);
  3288. current->setIcon(icon);
  3289. image_holder_->update();
  3290. }
  3291. //! A protected member setting color aColor for the label number anID
  3292. /*!
  3293. * \param[in] anID an integer indicating label number in the list_label_ widget
  3294. * \param[in] aColor a QColor object contains color you want to set for the label
  3295. */
  3296. void
  3297. ImageLabeler::setLabelColor(int anID, QColor aColor)
  3298. {
  3299. if (anID < 0 || list_label_->count() < anID) {
  3300. return;
  3301. /* NOTREACHED */
  3302. }
  3303. if (list_label_colors_.count() < list_label_->count()) {
  3304. generateColors();
  3305. }
  3306. QListWidgetItem *item = list_label_->item(anID);
  3307. list_label_colors_.takeAt(anID);
  3308. list_label_colors_.insert(anID, aColor.rgb());
  3309. QPixmap iconPix = QPixmap(20, 20);
  3310. iconPix.fill(aColor);
  3311. QIcon icon(iconPix);
  3312. item->setIcon(icon);
  3313. image_holder_->update();
  3314. }
  3315. //! A slot member loading normal image which path is in the current_image_
  3316. /*!
  3317. * \see viewSegmented()
  3318. */
  3319. void
  3320. ImageLabeler::viewNormal()
  3321. {
  3322. if (current_image_.isEmpty()) {
  3323. return;
  3324. /* NOTREACHED */
  3325. }
  3326. image_->load(current_image_);
  3327. image_holder_->setPixmap(*image_);
  3328. action_view_segmented_->setEnabled(true);
  3329. action_view_normal_->setEnabled(false);
  3330. }
  3331. //! A slot member loading segmented image which path is in the segmented_image_
  3332. /*!
  3333. * \see viewNormal()
  3334. */
  3335. void
  3336. ImageLabeler::viewSegmented()
  3337. {
  3338. if (segmented_image_.isEmpty()) {
  3339. return;
  3340. /* NOTREACHED */
  3341. }
  3342. image_->load(segmented_image_);
  3343. image_holder_->setPixmap(*image_);
  3344. action_view_segmented_->setEnabled(false);
  3345. action_view_normal_->setEnabled(true);
  3346. }
  3347. //! \brief A slot member setting interrupt_search_ to true for interrupting
  3348. //! the recursive search
  3349. /*!
  3350. * \see loadImages()
  3351. * \see getImagesFromDir(const QDir &dir)
  3352. */
  3353. void
  3354. ImageLabeler::interruptSearch()
  3355. {
  3356. interrupt_search_ = 1;
  3357. }
  3358. //! \brief A slot member selecting image corresponding to the item
  3359. //! in the list_images_widget_
  3360. /*!
  3361. * \see selectImage(int anImageID)
  3362. * \param[in] anItem a pointer to the QListWidgetItem object which indicates
  3363. * certain image in the image_list_
  3364. */
  3365. void
  3366. ImageLabeler::selectImage(QListWidgetItem *anItem)
  3367. {
  3368. if (!anItem || list_images_widget_->row(anItem) < 0 ||
  3369. list_images_->isEmpty())
  3370. {
  3371. return;
  3372. /* NOTREACHED */
  3373. }
  3374. clearAllTool();
  3375. clearLabelList();
  3376. clearLabelColorList();
  3377. image_ID_ = list_images_widget_->row(anItem);
  3378. selectImage(image_ID_);
  3379. }
  3380. //! A protected member loading image from list_images_
  3381. /*!
  3382. * \see loadInfo(QString filename)
  3383. * \param[in] anImageID an integer indicates certain
  3384. * image in the image_list_
  3385. *
  3386. * if that image was labeled before, selectImage(int anImageID)
  3387. * will try to load all info
  3388. */
  3389. bool
  3390. ImageLabeler::selectImage(int anImageID)
  3391. {
  3392. if (anImageID < 0 || list_images_->isEmpty() ||
  3393. list_images_->count() <= anImageID)
  3394. {
  3395. return false;
  3396. /* NOTREACHED */
  3397. }
  3398. /* checking if it was labeled before */
  3399. if (list_images_->at(anImageID).labeled_ &&
  3400. !list_images_->at(anImageID).pas_)
  3401. {
  3402. list_label_->clear();
  3403. QString labeled =
  3404. alterFileName(list_images_->at(anImageID).image_, "_labeled");
  3405. labeled.append(".dat");
  3406. loadInfo(labeled);
  3407. }
  3408. /* if it was loaded from PASCAL file then we're in trouble */
  3409. else if (list_images_->at(anImageID).labeled_ &&
  3410. list_images_->at(anImageID).pas_)
  3411. {
  3412. /* TODO: do the pascal file selecting */
  3413. showWarning("this function doesn't work at the moment, sorry.");
  3414. }
  3415. /* loading clean unlabeled image */
  3416. else {
  3417. current_image_ = list_images_->at(anImageID).image_;
  3418. image_->load(current_image_);
  3419. image_holder_->setPixmap(*image_);
  3420. image_holder_->resize(image_->size());
  3421. }
  3422. return true;
  3423. }
  3424. //! \brief A slot member removing selected image from list
  3425. //! (image will still be loaded in the image_holder_)
  3426. /*!
  3427. * Image will be removed from list so it will not be possible to load
  3428. * it again without using loadImage() or other slots for image loading.
  3429. * if you want to remove image from image_holder_ just call
  3430. * image_holder_->clear()
  3431. */
  3432. void
  3433. ImageLabeler::removeImage()
  3434. {
  3435. int num = list_images_widget_->currentRow();
  3436. list_images_widget_->takeItem(num);
  3437. list_images_->takeAt(num);
  3438. for (int i = num ; i < list_images_widget_->count(); i++) {
  3439. QString newStr = getFilenameFromPath(&(list_images_->at(i).image_));
  3440. newStr.prepend(QString("%1: ").arg(i));
  3441. list_images_widget_->item(i)->setText(newStr);
  3442. }
  3443. }
  3444. //! A protected member which is being automatically called on every image resize
  3445. /*!
  3446. *
  3447. */
  3448. void
  3449. ImageLabeler::resizeEvent (QResizeEvent *anEvent)
  3450. {
  3451. QWidget::resizeEvent(anEvent);
  3452. }
  3453. //! A protected member which is being automatically called on every mouse press
  3454. /*!
  3455. *
  3456. */
  3457. void
  3458. ImageLabeler::mousePressEvent(QMouseEvent *anEvent)
  3459. {
  3460. QWidget::mousePressEvent(anEvent);
  3461. }
  3462. //! A protected member which is being automatically called on every key press
  3463. /*!
  3464. * current list of available commands:
  3465. * - key left\right - prevImage() \ nextImage()
  3466. * - enter\return - confirmSelection()
  3467. * - esc - clear current selection
  3468. * - ctrl+z - image_holder_->undo()
  3469. * - ctrl+y - iamge_holder_->redo()
  3470. */
  3471. void
  3472. ImageLabeler::keyPressEvent(QKeyEvent *anEvent)
  3473. {
  3474. keyboard_modifier_ = anEvent->modifiers();
  3475. if (Qt::Key_Left == anEvent->key() &&
  3476. Qt::ControlModifier == keyboard_modifier_) {
  3477. prevImage();
  3478. }
  3479. if (Qt::Key_Right == anEvent->key() &&
  3480. Qt::ControlModifier == keyboard_modifier_) {
  3481. nextImage();
  3482. }
  3483. if ((Qt::Key_Enter == anEvent->key() ||
  3484. Qt::Key_Return == anEvent->key()) &&
  3485. // Qt::NoModifier == anEvent->modifiers() &&
  3486. ImageHolder::NewSelection == image_holder_->state()) {
  3487. confirmSelection();
  3488. }
  3489. if ((Qt::Key_Enter == anEvent->key() ||
  3490. Qt::Key_Return == anEvent->key()) &&
  3491. // Qt::NoModifier == anEvent->modifiers() &&
  3492. -1 != image_holder_->focusedSelection()) {
  3493. image_holder_->clearFocusOnArea();
  3494. image_holder_->clearHoveredPoint();
  3495. image_holder_->update();
  3496. }
  3497. if (Qt::Key_Escape == anEvent->key()) {
  3498. image_holder_->clearLast();
  3499. image_holder_->clearFocusOnArea();
  3500. image_holder_->clearHoveredPoint();
  3501. image_holder_->update();
  3502. }
  3503. if (Qt::Key_Z == anEvent->key() &&
  3504. Qt::ControlModifier == anEvent->modifiers()) {
  3505. image_holder_->undo();
  3506. }
  3507. if (Qt::Key_Y == anEvent->key() &&
  3508. Qt::ControlModifier == anEvent->modifiers()) {
  3509. image_holder_->redo();
  3510. }
  3511. QWidget::keyPressEvent(anEvent);
  3512. }
  3513. //!
  3514. /*!
  3515. *
  3516. */
  3517. void
  3518. ImageLabeler::keyReleaseEvent(QKeyEvent *anEvent)
  3519. {
  3520. keyboard_modifier_ = anEvent->modifiers();
  3521. }
  3522. //! A protected member which is being automatically called on every mouse wheel turn
  3523. /*!
  3524. * implements zooming in and out on ctrl+wheel
  3525. */
  3526. void
  3527. ImageLabeler::wheelEvent(QWheelEvent *anEvent)
  3528. {
  3529. /* zoomin */
  3530. if (0 < anEvent->delta() &&
  3531. Qt::ControlModifier == keyboard_modifier_) {
  3532. image_holder_->scaleImage(ZoomIn, 1.1);
  3533. }
  3534. /* zoomout */
  3535. else if (anEvent->delta() < 0 &&
  3536. Qt::ControlModifier == keyboard_modifier_) {
  3537. image_holder_->scaleImage(ZoomOut, 1.1);
  3538. }
  3539. }
  3540. //!
  3541. /*!
  3542. *
  3543. */
  3544. void
  3545. ImageLabeler::closeEvent(QCloseEvent *anEvent)
  3546. {
  3547. Q_UNUSED(anEvent)
  3548. writeSettings();
  3549. }
  3550. /*
  3551. *
  3552. */