From 19c47100c24c7c9a5a449fc9e708ed5673c62f7c Mon Sep 17 00:00:00 2001 From: Filip Orsag Date: Mon, 14 Mar 2016 12:14:39 +0100 Subject: [PATCH] Initial commit. --- customgraphicsview.cpp | 13 + customgraphicsview.h | 28 + images/application.ico | Bin 0 -> 67646 bytes images/icons/analyzeEdges.png | Bin 0 -> 162 bytes images/icons/btn_addLayers.png | Bin 0 -> 808 bytes images/icons/btn_analyzeLayers.png | Bin 0 -> 1353 bytes images/icons/close.png | Bin 0 -> 1772 bytes images/icons/delete.png | Bin 0 -> 2292 bytes images/icons/exit.png | Bin 0 -> 1725 bytes images/icons/help.png | Bin 0 -> 2231 bytes images/icons/newProject.png | Bin 0 -> 671 bytes images/icons/openImage.png | Bin 0 -> 1163 bytes images/icons/openProject.png | Bin 0 -> 1550 bytes images/icons/save-as.png | Bin 0 -> 1984 bytes images/icons/save.png | Bin 0 -> 1391 bytes images/icons/settings.png | Bin 0 -> 2129 bytes images/icons/zoom-fit.png | Bin 0 -> 3022 bytes images/icons/zoom-in.png | Bin 0 -> 2684 bytes images/icons/zoom-orig.png | Bin 0 -> 3114 bytes images/icons/zoom-out.png | Bin 0 -> 2704 bytes images/wizard/wmark.png | Bin 0 -> 100751 bytes layercomposer.cpp | 87 +++ layercomposer.h | 40 ++ layerrecord.cpp | 42 ++ layerrecord.h | 43 ++ libs/staticsingleton.h | 183 +++++ main.cpp | 26 + mainwindow.cpp | 1022 ++++++++++++++++++++++++++++ mainwindow.h | 155 +++++ mainwindow.ui | 870 +++++++++++++++++++++++ microAnalyzer.pro | 38 ++ microAnalyzer.rc | 1 + opencvprocessor.cpp | 164 +++++ opencvprocessor.h | 44 ++ project.cpp | 456 +++++++++++++ project.h | 104 +++ projectwizard.cpp | 148 ++++ projectwizard.h | 81 +++ tableformat.cpp | 146 ++++ tableformat.h | 41 ++ xmlparser.cpp | 87 +++ xmlparser.h | 37 + 42 files changed, 3856 insertions(+) create mode 100644 customgraphicsview.cpp create mode 100644 customgraphicsview.h create mode 100644 images/application.ico create mode 100644 images/icons/analyzeEdges.png create mode 100644 images/icons/btn_addLayers.png create mode 100644 images/icons/btn_analyzeLayers.png create mode 100644 images/icons/close.png create mode 100644 images/icons/delete.png create mode 100644 images/icons/exit.png create mode 100644 images/icons/help.png create mode 100644 images/icons/newProject.png create mode 100644 images/icons/openImage.png create mode 100644 images/icons/openProject.png create mode 100644 images/icons/save-as.png create mode 100644 images/icons/save.png create mode 100644 images/icons/settings.png create mode 100644 images/icons/zoom-fit.png create mode 100644 images/icons/zoom-in.png create mode 100644 images/icons/zoom-orig.png create mode 100644 images/icons/zoom-out.png create mode 100644 images/wizard/wmark.png create mode 100644 layercomposer.cpp create mode 100644 layercomposer.h create mode 100644 layerrecord.cpp create mode 100644 layerrecord.h create mode 100644 libs/staticsingleton.h create mode 100644 main.cpp create mode 100644 mainwindow.cpp create mode 100644 mainwindow.h create mode 100644 mainwindow.ui create mode 100644 microAnalyzer.pro create mode 100644 microAnalyzer.rc create mode 100644 opencvprocessor.cpp create mode 100644 opencvprocessor.h create mode 100644 project.cpp create mode 100644 project.h create mode 100644 projectwizard.cpp create mode 100644 projectwizard.h create mode 100644 tableformat.cpp create mode 100644 tableformat.h create mode 100644 xmlparser.cpp create mode 100644 xmlparser.h diff --git a/customgraphicsview.cpp b/customgraphicsview.cpp new file mode 100644 index 0000000..db2b31a --- /dev/null +++ b/customgraphicsview.cpp @@ -0,0 +1,13 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file customgraphicsview.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "customgraphicsview.h" + +void CustomGraphicsView::mousePressEvent(QMouseEvent *event) { + emit colorPickerPosition(event->x(), event->y()); + } diff --git a/customgraphicsview.h b/customgraphicsview.h new file mode 100644 index 0000000..947157a --- /dev/null +++ b/customgraphicsview.h @@ -0,0 +1,28 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file customgraphicsview.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef CUSTOMGRAPHICSVIEW_H +#define CUSTOMGRAPHICSVIEW_H + +#include +#include + +class CustomGraphicsView : public QGraphicsView +{ + Q_OBJECT +public: + void mousePressEvent(QMouseEvent *event); + +signals: + void colorPickerPosition(int, int); + +public slots: + +}; + +#endif // CUSTOMGRAPHICSVIEW_H diff --git a/images/application.ico b/images/application.ico new file mode 100644 index 0000000000000000000000000000000000000000..6b87afc5131bc83210df2cdef9b5285d2b16d5cd GIT binary patch literal 67646 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 JF+Aq~|9^ZqMPC2_ literal 0 HcmV?d00001 diff --git a/images/icons/analyzeEdges.png b/images/icons/analyzeEdges.png new file mode 100644 index 0000000000000000000000000000000000000000..bd889305e4f8fe59ec032328b9d9c14b76b3fedf GIT binary patch literal 162 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJOivfbkcwN$DGOLMuKiEnasPxz zr=UotTpJ&Qq=ybeBu_EJ%3mL>8bss+9sjOic9S)D)ey+eW5mwGps-fPo$bjr){Hcs zCIJUF=6P&T*&eHe0E>nQhskw}D-(W{o^6}Myn=y2M(3g8vpLr|fR-|Ny85}Sb4q9e E08?l&j{pDw literal 0 HcmV?d00001 diff --git a/images/icons/btn_addLayers.png b/images/icons/btn_addLayers.png new file mode 100644 index 0000000000000000000000000000000000000000..070e4aab466de172221ffde140108a3732682077 GIT binary patch literal 808 zcmV+@1K0eCP)njCgK^fW6G!i z!4yzc1BqxXe1LTHK-cmeMVOAK!UsrLDJib*2$iQ`GL;Dq z5TwH)0CA|N4-g@aYlO<~pArD3fgRH_?Qm{vleTm~38VdA|82nL_BXhB^p^2++>WUM z4kwSu9eIuz5j!Nl>t4&(n`^Mq{4B)rRO}kuXNH3?m^(ACQ>6hii9^1|;E z(N9WzXs84uA9I)h$eqjg0*uEFc6Y7BP#CM+wft9m3qIB>u-;gM4(*tE&AQ^$<^VQ8 z{!$-+RAkI&x$A&D=M+}|E<>fh0)N`Sjq@zUan}Hppg4!%>*CcyFF*{EeJ!tcs<2Y~ z0IT)o;dve;ZmZop@_O-F9{^wxPluDo>ql!7%GGzG$^!*c`F50ehlw=cbt?i;xY7r} zcKnuq;RRN%Ey2&$Rxn{KIx4MZ?#_w)*otD~u^@l3PYsyH({gFxXLnBKjGyBJF#QsO z4gx@nXHVsVcESaG7o6bZhMETk2Q3T&5c%b{&z{x|<|UZ@D6JsC7#~?R?*{O?2f)oa zo^f7qxw9JJ8JPVjZ3KQBYJeRDhn1eckPrWLECAg0D!Ln}4##}QD^vhC=U#C<^Tq3< z0C-=LJ6E>5;`k(QhYJnh$x=zY(NJ7>IFL=IaCrm(kKZnK#XTJ^61QOf{0NG0ScD2- mdT%HIVAwHLU;{Gx@AyB0EKYMH^yXs#0000 zYfKzf6vxjjebCwmpvHv{E!{%-U}8vp)M$)GO9&Q&wiOqVLM>@igQkh8CN^n(B@z;~ zZAeT^Y+9>fO(kt9&;}YG(Znw*n5v1U*jfRBA_xmRv+T^hp8J^Dnc0~IlJ#zG&g?LI z|G)D;ckaC?;c%Ej23sT&DaJ5@eP$ugD-58mtt}(sH8nL1plL-xU8~hNjB6X2!G z`+-sl1V1cNiV;5qqrKbj8Pu?@KYy~r1UQNS2i|<+6^HQnqz1>29`^@m>fOf&0wzF+ z1;RwUK->W5ws$)K+?iMIXn@Z4ll}lN^fV^3q*4%wr*JBO0i8R0EdU(%6!v~o1cB(S zp$hotkBj~QdoMLCT9}&G=-8!azH|Vf=!+PiXCm2a*1;{e-3hbfzkoJ}27$}9-=sKz5Fev>-PW>4;k&+3t|}qEMkgL|IMC4btfQv(9!t!^gf;=w z@hONVqM+$2#PvAn#DFC<3zp(%;-KnT0)+U8Il)SR;snJbC|;XVg6A$&TlO17fQ-dP zc^{A61QkUcjf#%UpkR+3qUq+qx9G%!D1HXTt3BsHxMRB|Jc-#3%?!eDbcnl>(wHy< zVB+}VP#xdz!~Osgq6@{hxredbN=RHR9_bWeSLjU zSXcu`DRsQVDqlCFm$y)bJ4=Wyi522k*7Y zWdW>xe;Fi5BE9XzC2R;6SSi#N0r2x^0E+Ibgq(Z{AjJ(77Lh{xt6Ne5R=%tFi&LBR zQq;U=Fzmbbo&dNq5`Yc&AV5JechVpNf<=QTLE+q?`xgN~U6alfW#9GWwRTJZ^bac# zLVz{-#g^rUX+I8T=oGq+Jg`6jGjoy@23IuiYpwDv7*e3{?rpF-Sj>f~%$|c726hTP zZ#}dC0Gl|NncKu^!s&?ifdKen5MbTr$3a;ef~cB+Sqjt znp$sr))ox*_=f`Ei{BHlY{O$Pw{m@QIJv{JSxoV@7;k$j6(AFh4chUO3fZBpup}=e z#Z6(#w{426?Zjt0od6k8myH8#M1b57U$2SGn!7*@em!}nIthTkDZ*YZBP_qYvMPSF z^SsyKB_$;XDk>_V>-!O2)2OOrbnX>ds|#RR!Da}o$``_{mTb!=B73%dPqo)L09IiS zvX~uwx@ASqrZR16pkMtvvfB+%US8hU+}sR}tv|x(zj27g4KZJAO<9@^f$SWBz;avm zLfCX*`fRNOfH&N&KE*9F{MyUmz~Lh;?A8g~z4q7#H|NX7y*)6adF&SoNI`k1HNb$iy|obC3SCo>lS?DQ1t z+?@nK@p}C2Nj8Ab+0Amo6M&^ale3*z;?BBLn*(ZBV`>Sc6Etsq8BF}yn{s+h>wwQ} zx7$u|0pe##ypCVoH$Q;8F(5Ah%W@Dkw@)}CK`5Rt#5Lt0b3Oah1Gt;%h#SC~Y=pS# zo)jl2&i`h}`}mCB+vE=bKFto0iRK9~U;7{alU^JExK_;!w5$ICw7o@@A?z>U00000 LNkvXXu0mjfIp=)N literal 0 HcmV?d00001 diff --git a/images/icons/close.png b/images/icons/close.png new file mode 100644 index 0000000000000000000000000000000000000000..2b317024a5a68bb753106913d7d2acf238fe9c73 GIT binary patch literal 1772 zcmVJ1)H6{~omcu+?Kl|uhOB86Ojrnz&~-Zz9*%3$Qu%3R^kT1*sVYP^q=hXu0d4)iwxkWuD{u)j%9Por9CV zOE;t?MMpFQAq4He!~#4ABO|}W>V`_KdFx5@m{`;`1k8uyd9l0(zz9)RiMUfaNJ)^c zNlTJO*9ReN+;@?!_Hx6`doQg-EcL3(g2i}OTY1GBJbzJ&86N$t+Bw95l-o#2lm?tV z8WU3&gb)~$&er}o6q)y5S%0iqwYtnF9D}V@156*=*XG_!f(TE@K;YaF9#p+buCM`E zAANzXn>`F!4_@J2?Dgw6cv@15@4x9=>;1s!bgZ8{d_5Hpli#-iSQ~YY1c0MANFYkh6n=r6Hu?|E#P=gwDzlw4*55D<~Zf)9+l<#t8B^)+bb?d+D6boKB8u>+KHp{Gb5^Kxb7X?v^mS{KH1Mf9&4zbwL*v^-6 zpRR52^R80}UOXns)xqKVK!c(64uCI99yYD9>t&%SY}=ACxc{`=?yy&9<+6}1kT|tO zp-hHr9X~~{X`X1^x(z{yjlA93J7IZP3gUe|&Kwy!@+)VFM7S=?&X_FAoJqHza8BW; zkYu*qZ#*78f8D6DzZVgPzO*(Sn>GbA81Ojj7Sh|c!=O3dMhFo>bpE&{mV2(iq^H^F z)Ts-YP6tip8w4dEJuX#M`cpTLgeBXKvCw4`QBYiAw|EYv`H!+P(Rsi?fW$cfzZTrO zg^TS!fh$3@YTXu=g-h%gu4|0)9Wb`S-9lvjE<5|(f({2iFY%$TLR=}--0wZTb959yf-JZ@RgJC z^rgjes%<~En1l+29DgmEhk<$ndJZ391pp3_oo#IE_<47eumwO4MJ_^?S@I$bcy*mRHs_(QQnlR->q>5a<2a!P0dQwJ{eQydYfk13glFC0;%BLw zE94i2xq*k-p0(eiL{Zi7)VCniXw)bye1db!{ov*xM$e(cj6&Li$Iw10g6^MU7)ncF zP?{o}D>5KXt+Wy+e=N*ecZf;XPosTY)#%-jM}k9~UG9ti@^W-#BB<}?o1$PjX=%yF zLR)$gNVXIwR|`L^KEQt6I0K3bb=_ZFPa;wi#1-itG!G1dL{Fs--LqtFmLeoE#s>K{anC2hN4h7FfrOM7Tpm{j%khsEk zDV$4fQ+SRk&7&6_8-x(1F5AnFY?}j>#?H?m%T0)fYI`VJW#!f?e!4?Dh#kck`KYKt z2w{p}B#RH34~@=X*KVjNc!a$J`=c|&=u1Z~8*%4$&{2l$*6lOsQcj@zAn1x>8Q-QD5p;)?zQ`a|U4fM3Q< z#l)hAH4s-x{5FZxK9Ei`FxsNzC6hPe&ljFG6>?DpC3Ax$nidfh>Ppp zN5aL`1#WIbAdyH2K*0Dpn;?$cSm6c77D@`^P3V;Iz-2mtW>9zO!bG2)?AY!_HplJy z%s^?kyu2K;8#i!%p%2Pv>#cHg!vNYHhYT@^H>GWwC$0(JAvhknG=37$;zOYKA>b0_ z+}kiEqg-LUcNj|!Uu?g+MI@9;CGzgxMP7bBnl)>NK7IPsh*#SLpD-Mc@a3nVNHHZJ zT5J3VBH!#v!DIdob|TWZ(E!yDRaI5SXoy52I5|04iE|t89f}i?ejI@Rrtw2*3z&XT z_~yfevGcb#BKYrSDN#%LnvX?or(*Ih`|cr literal 0 HcmV?d00001 diff --git a/images/icons/delete.png b/images/icons/delete.png new file mode 100644 index 0000000000000000000000000000000000000000..ce4eb1874f5ec025f6e3a9e9bbc17189868bd781 GIT binary patch literal 2292 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 O0000@Zvc|T?kRczL0SQE%p*r{ang#Is zmDhe5MbWkIxJawjB8nn{ARr7wq9{s79LGp0u`G*Xp}^IvR~a8ah7h6?6wq4Zc^>cm`ubJi z?T+(-QLxer%fd8GEXzVlnO-ZUP)d=c$}kKZ$Dv%Vkk98ZO$#AJ2civ7DwP-+sRERM zW`}M#fa5q=mW6HGNGZ`;ca6lf);Nwsu~@{i+MzcLBNG7yK&ey$$kAONg8^LE#c>>@ zl-RZnkSf<&rz*A9*tU)1I2eYJQ7<|(8Gy!V&tYaB33TiN8Gkbm5OeoEsW} zB$S3>V45bb>!$Y-V2Cf^gqS@n+r28R}4 z{fjS3x8Hi}uT!tQGLt`ctZy-P0c0Kb0wvXMnr5c*VNi_;&*QWC`A@$0>Z{X}SFTut zXsxc7G7!B$uIn;2HO1cE9^2d7nf&j!aBGYFudegt%P-eYy!4W(c6UK3<4;07>iOw6 z`vCf>PjYYDHb;*h<;amEG@Hr#l6@ci^$k9o`vKE)bBv!qZ+bUxQaE>xxp&{SF$^26 zL2Gmz^S3wNC>|Jr?BDOkjT=-d6=r8=ab0(xa(``&PoIB*<1;fHJAE3j(LhVd&gY*a z%ytQAr67(eU$`(h1-;8Q{ePNE;^fX6Loub)jfRtca zZRbhND20|1<$3!7dZW;rj!LD%*|TR^Sy}1SK}Y%ODt|x!9JR?wj*N}5_vM$M6vDQ_ zG!dqWjv};D7_K`UV32y-wwalkVRLhng@pxbwc2C#4;~P1ZQ)K#5G*Ybt*#<03mpU~ z&qFqw=pbkdv@DE5f&A&yZGVFz(5rrWdYU+nX*3$?YMI!`%nY-?`-H`>zM}Q$5oWne zu(CpU?;i2yX6hV3$1!qehj?S7KR|C9gb;%x^)Z7vdHCf={k_4p?2{iXFvX! ze=RTLM-llmXVSvMF!l`{Mg3EdO+)hOc^(T33uvv$=kr*Wl|D<%_k9k%_##hz_#t=R ze3QwsF^Xr-(E9poiqAfaa2zlULWx3{pyNHyV))L%YY-!+`+(iZKgfnkGw2%hc<2s?};I741E+JUh$1 z*M5Zf{U7`%q9|9Im_TVAUWW64544goa69XDnzU$1GoqBjYkBPM?hwaOdy}%0=PtqI zDc0xaezCm1?rkkCCC$Pvu-AbIfW4sr*$pV^3mnHG3`2x~Vxd5(R7$(1v{TOKFin%< z<;#u#)M`KZ@AkGw9BbeaumfxX+gj_WZwj&iiE<$X4Sdk!K)i_kC(^7%Y#>udNek9xh%$&)83 zSIW4KivXf1Ox^-CN@-*q;|D&~YSo{gpAYf~f6 zLC(!#**02fq9`PavK?Rd^jd4AlK8C_Ku9||2Lk|%j2!0v>bI23C7$~JlQ^z}VOqpe z5-Zhq+F5+Eoj}*@TBDSr<);8c51%Q(`o=0s$Bd3vJ4FX^6d~id?eL%m@UefCQUvYw zKRKKZ2e57X?T>!@(Y1cN;6culW~CcKW83yS91wm0(dT&H+w6Zg>D{I?W2pTPhRcoT TV_b!o00000NkvXXu0mjf;6OQF literal 0 HcmV?d00001 diff --git a/images/icons/help.png b/images/icons/help.png new file mode 100644 index 0000000000000000000000000000000000000000..d60425f7ec65f748d6e5d2a61d5a3cf6da8d6ee3 GIT binary patch literal 2231 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 FV1isSCa3@a literal 0 HcmV?d00001 diff --git a/images/icons/openImage.png b/images/icons/openImage.png new file mode 100644 index 0000000000000000000000000000000000000000..6f118cd0875464017b8b9ace2419b4f03f10d1a2 GIT binary patch literal 1163 zcmV;61a$j}P)Cu96a@{{M-ibf{UzT7J%ZIs~Nv3TSLqY6<&0hP$ z`F(q>wKoS|*#F%Wz{Rko3*yH zuf6B=ryuXo+X0}IBH{aNrQgEy6iPuptI1|9wWcDdcxa<=POwg})^+^2w@!Af+b*0F zCY#p>N?{-ZzVDOIrSUyDcBH|(Z~IJ)6{*y#T>GuTt-HfSmbSP^ENtTlb^U%wCxYMd z_6AT2vgsuGT*Q0FecpWKeG*=g$?n?)m_Cr0MM=8Oge!` zhDt5KjBnz5Q*$c)o$rOBkcZl+=YXO0PooV zA_C4al1tLRO?G)*VF2rdNE_yVzs~mNG601_fsK`i0KEFfaSn{O0sOrpAR^QoAwU0m zpZuBy@Kl6LzeKfZV7p8zqk(pM_XLQvrqTfbg>w#LEXG>2 zvF!(Cz&!li6k)YYE!f04%V^;c%|?|{aEJWZ1i5^1Zvbm8K@bq>b)1udJG-Z;6q%7j zG^$&ytvq71I7OpUre0s5FyY8L2SBM@LOT8vQV_Adz5UOGcbk_Xk@YE+);ROYhkXkt zSXy0VX=M?u^&kMW^Hix-{~bWj(r9COdFlwRb7Er*ODjv#2peBL72t4oW1j#Z3PY^5 zY;A4f`#vjcD-yQC$LGE|cV+-UDaDsxobLJk^Sk}OJ9qQeFBoIcTJw1Mv8&apYv0ez zoSK`PGcka|Ip@6T>FIqtIkcmB<)_Qse=yJ1_Lf~;UcGq!+=b5<78VwPMhpPoUb=GW zqwas&ewc``vA#jIQl(tpesJyb)z4;Tez*zLfej!6*e$4lp-xNf7Yyw;JnFOt;P&y` dFYG^Ve*q5@n(l(H*RlWr002ovPDHLkV1jy_DSZF{ literal 0 HcmV?d00001 diff --git a/images/icons/openProject.png b/images/icons/openProject.png new file mode 100644 index 0000000000000000000000000000000000000000..f35f2583540678b7a544d9175245096082f302af GIT binary patch literal 1550 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 literal 0 HcmV?d00001 diff --git a/images/icons/settings.png b/images/icons/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..6e52db7cfd482e228dae640a7717ea1dcaf523e8 GIT binary patch literal 2129 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 Nwk0^=?^=4r{09%VDoFqU literal 0 HcmV?d00001 diff --git a/images/icons/zoom-in.png b/images/icons/zoom-in.png new file mode 100644 index 0000000000000000000000000000000000000000..0ab0f8a8be46523e9bf58a22fc507f70617b2a42 GIT binary patch literal 2684 zcmaJ@dpMMN8-CIHL^{~Ea>{E$3Uf4=$;6m(%wSMaN^^LbF-J3#nMjFEQCdZmNhOC? zUpXX1EH;Z$*|cprr@1nck)_C?`bJyr_s7@wUf28n4%dC(&;2~V=XYIiN`RlIzOIoj z008>lUgSXa2rj%j+Ul=3HujBrFqF85NP+|r5-Cjt0Ys*N4uRf0S|k(*(U|+9??BD~ zparsnLnI*-Upzy=gVPo;a2ZdiW&?n;i%dvka3Bdtha%a00_^pz1{la@5@6f06eLAR zf>>;?SP>Ky>le(3fFywk0uF_f}bClI+} zb+5_C^Ww3LIWIV@?Y2!KC@p3sH?OKmZd}rQ^(ixyqRK0oUndUXQ+Ziw?DC;rpY64{ z>>=B1 zwxfNEwr<;Yojh)aO$LxlFe8bkn_@zQA8_8MvJ}&XClr$A)#Zcl7L9#e`_jwZ{qUU2 zcV%Lw9|O6jms!!Zd3T)*^;8vuJnNeP08PLHVtBZjJr>(k$$8?s{6}6=QqqO|n7WTf zu3NXBHl0y!@$oU}?CflO^)|6Xxz1c7-V?g&#*S;6ZS?YlR>h&(T0D!-pHhTQR&l!~ zlrGu{8~syLQ%Az;W3eoIqZe6rxl-qWKL=_bO4`lZ_43vLtB&KV22L_#uEj>RjJBG@ ztQ$MDB^yqRk0<=-me;kjn$OF%PZ$}AiU*gocHN5M8KmV_?;5`&y}!M*DsJ?z=%DV) zzlG#RWHfn-cbf@n`wk*Xp5W3?osLq?ju*CKidx9G59_TyI`&L#p%A}o)w)PsCVVt| z>Cz>O+I{~1h`P7XZ8MFN$L_Y@`8l5MchwHt&vi7m*WR7J=t+HoGD=zB|EgNM+enT# zi+@`&J0<83MPqDi^kU=Ucq)}jKHm1z`l}jfeEsg%;S~}3x~~si$-mza{%UZqzp|h@ zbMyJ(Gf|IshG>USGYcxdp~|xc4<{d?gcL0WmkhmWktpJCrmea zR51)Ytj$=!z%{4!>pf97;n|MD^2Y=_#HRPk=Z90yKD5eBVHo2U#R)5*%=&gPMG$Mxq$(__1k zYnGH*t5yj6{%Wb}6>SnM8;AS53YY1g>QU)W-KeS4cL^KaJp20w5{N`v4n?%Eiv3q) z4$j2l;P4z)n0~-E4x1e+&&kn+{2v^D0Do|qGU?eJT(HX7_o?6L!T6NU835F9@vj)Q zk>!i_TiqV7IH8-MoXL?p3i>_le8mNpeUVFRo($yp3~OzAT8+4ukC-?!XXMbBtgq++ zJg$OPm!upHr(s7q-TmFOp`o&WKXh_yBkjMmXMAwR5My;-FEB9h7e0rxGk&bM=CW?e zph&}N?qMaeJEX7G7Dodh2zoxH>Ir9Yxz0y`2%CF#b>qB01e@;}d+SB@yV!aa{Zh}_ zK5+9^Hlm@FelMYn-*;w+{GuHcmurJb1?iso--_?KDXK8*{yUy7Amya&@Y^Vy7 zSvnSG)kt2x|E)>rtG-H_Xf(P}6=SnCNGh!k#8Qt|o4R~p&}f5lEEXGQwKelnbW~aQ zomP105G>4pZ40-!aU73?P5LLEO6Nf?-0F6s@^;T=v7(IGiXlHHx&YD1|r*~b4d{uj9i|ap7+#P3;p~Sjy^w9Ts5M1rMnt1^l4jg7)^|&qAkx%moLFnJ^a$O!u&{9DzVKjU^To>K zqiLf`rP4Fc+)6<-lpVv#;OLd4Q)(FIfwCZhF zxUg7*PSac$uGXkm;<{N|-9Mk@B^MM}TrsOWBP1^gbK`Jq7N5SWudUbb)!i{EO%5z~ z;{0iAGn8HWyVgYd#fAp6snM<^)PqXZAH_jEk3HJRx+ZxYORq5=Yvay!1X~m@#C2FS)IX?u2!p3KXy!I b16n}mskk^3Gq-yS|AXG{e&iCjJ&FGTX5oB| literal 0 HcmV?d00001 diff --git a/images/icons/zoom-orig.png b/images/icons/zoom-orig.png new file mode 100644 index 0000000000000000000000000000000000000000..3f5d89d41a53ab2250c559a35f386a23d65036cb GIT binary patch literal 3114 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�ti*j@8Ho3T%YwmU39X&oacG!{Z6 zCY=)BHQJy+(G{CD`d%@E%XhxQNh0j0bzW+%nSlgUcSr7b6i>Ob*=%^u;_HjSQ=cJAw~zYz!cDUo!DVFXHG-nG;PD9RNl9a-RJ!d5 zigNVkQ`zGU$LKZ;lerV`o^loKvOpt|RQv&iL1}&uUMdI%Nol!@K;8%ga|CHFxnfs+pe| z?J|-b48P;QqWL;v9c0RJ9jp&6E|y2-oDj*b@lDUfEmV5#daO(R0o5W z>Lf3nB&p7{tGfxp6j+n?t)_{&(fgw7&6+Dfo)tGV2hRB_m;MpGJ$(t6-NX0&2PC7O AMgRZ+ literal 0 HcmV?d00001 diff --git a/images/wizard/wmark.png b/images/wizard/wmark.png new file mode 100644 index 0000000000000000000000000000000000000000..79c1ba2469e7bb6937bc17fadb69570b0beb523f GIT binary patch literal 100751 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

(oNgmW3HKnZ_!&o0m8 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¥`2HOfCZr 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 DX!Mbz literal 0 HcmV?d00001 diff --git a/layercomposer.cpp b/layercomposer.cpp new file mode 100644 index 0000000..835ccd5 --- /dev/null +++ b/layercomposer.cpp @@ -0,0 +1,87 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file layercomposer.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "layercomposer.h" +#include + +LayerComposer::LayerComposer(QWidget *parent) : QMainWindow(parent) { +} + +QImage LayerComposer::composeLayers (std::vector importedLayers, + std::vector analysingLayers, + std::vector importedIndexes, + std::vector analysingIndexes, + QString &bgRootDir, + QString &overLayRootDir) { + + + QString bgImgFileName; + for (unsigned int i = 0; i < importedIndexes.size(); i++) { + bgImgFileName = importedLayers[importedIndexes[i]]; + } + bgImgFileName = bgRootDir + bgImgFileName; + + // final image + // size is taken from the background bitmap + QImage bgImage(bgImgFileName); + QImage resultImage = QImage(bgImage.width(), bgImage.height(), QImage::Format_ARGB32_Premultiplied); + QPainter painter(&resultImage); + + // draw background + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(resultImage.rect(), Qt::transparent); + + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + painter.drawImage(0, 0, bgImage); + // ---------------------- + + QString overlayFileName; + QString srcAddr = overLayRootDir; + for (unsigned int i = 0; i < analysingIndexes.size(); i++) { + overlayFileName = srcAddr + analysingLayers[analysingIndexes[i]]; + + // mask black colour + QPixmap mypixmap(overlayFileName); + mypixmap.setMask(mypixmap.createMaskFromColor(Qt::black)); + + // draw given image + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + painter.drawPixmap(0, 0, mypixmap); + } + + painter.end(); + return resultImage; + } + + +QImage LayerComposer::maskSelectedLayer(QString &bgImageFileName, QString &bgRootDir, QRgb maskColor, int rThrsh, int gThrsh, int bThrsh ) { + + QImage image(bgRootDir + bgImageFileName); + OpenCVprocessor * cvProcessor = new OpenCVprocessor(); + + image = cvProcessor->normalizeImage(&image, qRed(maskColor), qGreen(maskColor), qBlue(maskColor), rThrsh, gThrsh, bThrsh); + QPixmap maskPixmap = QPixmap::fromImage(image); + + QPixmap myPixmap(bgRootDir + bgImageFileName); + QImage resultImage = QImage(myPixmap.width(), myPixmap.height(), QImage::Format_ARGB32_Premultiplied); + QPainter painter(&resultImage); + + // draw background - black + painter.setCompositionMode(QPainter::CompositionMode_Source); + painter.fillRect(resultImage.rect(), Qt::black); + + // draw background masked from OpenCV + myPixmap.setMask(maskPixmap.createMaskFromColor(Qt::black)); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + painter.drawPixmap(0, 0, myPixmap); + + painter.end(); + + return resultImage; +} + diff --git a/layercomposer.h b/layercomposer.h new file mode 100644 index 0000000..832b3c4 --- /dev/null +++ b/layercomposer.h @@ -0,0 +1,40 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file layercomposer.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef LAYERCOMPOSER_H +#define LAYERCOMPOSER_H + +#include +#include + +#include "opencvprocessor.h" + +// singleton +#include "project.h" + +class LayerComposer : public QMainWindow +{ + Q_OBJECT +public: + explicit LayerComposer(QWidget *parent = 0); + QImage composeLayers (std::vector importedLayers, + std::vector analysingLayersLayers, + std::vector importedIndexes, + std::vector analysingIndexes, + QString &bgRootDir, + QString &overLayRootDir); + QImage maskSelectedLayer(QString &bgImageFileName, QString &bgRootDir, QRgb maskColor, int rThrsh, int gThrsh, int bThrsh); + QImage composeHistograms (QImage * bgImage); + +signals: + +public slots: + +}; + +#endif // LAYERCOMPOSER_H diff --git a/layerrecord.cpp b/layerrecord.cpp new file mode 100644 index 0000000..c124ec4 --- /dev/null +++ b/layerrecord.cpp @@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file layerrecord.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "layerrecord.h" + +LayerRecord::LayerRecord(QObject *parent) : QObject(parent) { +} + +LayerRecord::LayerRecord(bool b, QString s1, QString s2) { + this->checkBox = b; + this->name = s1; + this->opacity = s2; +} + +void LayerRecord::setCheckBox (bool b) { + this->checkBox = b; +} + +bool LayerRecord::getCheckBox (void) { + return this->checkBox; +} + +void LayerRecord::setName (QString s) { + this->name = s; +} + +QString LayerRecord::getName (void) { + return this->name; +} + +void LayerRecord::setOpacity (QString s) { + this->opacity = s; +} + +QString LayerRecord::getOpacity (void) { + return this->opacity; +} diff --git a/layerrecord.h b/layerrecord.h new file mode 100644 index 0000000..c7def25 --- /dev/null +++ b/layerrecord.h @@ -0,0 +1,43 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file layerrecord.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef LAYERRECORD_H +#define LAYERRECORD_H + +#include +#include + +class LayerRecord : public QObject +{ + Q_OBJECT + +public: + explicit LayerRecord(QObject *parent = 0); + explicit LayerRecord(bool b, QString s1, QString s2); + + void setCheckBox (bool b); + bool getCheckBox (void); + + void setName (QString s); + QString getName (void); + + void setOpacity (QString s); + QString getOpacity (void); + +signals: + +public slots: + +private: + bool checkBox; + QString name; + QString opacity; + +}; + +#endif // LAYERRECORD_H diff --git a/libs/staticsingleton.h b/libs/staticsingleton.h new file mode 100644 index 0000000..97a6169 --- /dev/null +++ b/libs/staticsingleton.h @@ -0,0 +1,183 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file static_singleton.hpp + * \date 6.8.2009 + * \author Potěšil Josef xpotes03 + * \brief Soubor obsahuje šablonu třídy cStaticSingleton. + */ +//////////////////////////////////////////////////////////////////////////////// + + +#ifndef _STATIC_SINGLETON_HPP_ +#define _STATIC_SINGLETON_HPP_ + +#include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Předdefinovaná třída podporující model větvení do vláken pro + * spolupráci s šablonou cStaticSingleton pro použití ve vícevláknových + * aplikacích. Využívá zámky z knihovny Boost::Threads. + */ +//////////////////////////////////////////////////////////////////////////////// +struct MultiThreading +{ + typedef boost::mutex mutex; + typedef boost::mutex::scoped_lock scoped_lock; +}; + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Předdefinovaná třída pro spolupráci s šablonou cStaticSingleton pro + * použití v jednovláknových aplikacích. + */ +//////////////////////////////////////////////////////////////////////////////// +class SingleThreading +{ + struct empty {}; + struct scoped_guard + { + scoped_guard(empty& ) {} + }; +public: + typedef empty mutex; + typedef scoped_guard scoped_lock; +}; + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Šablonová třída obsahující jednoduchou implementaci návrhového vzoru + * Singleton, která umožňuje vytvořit jedináčka z jakékoli třídy, která + * má bezparametrový konstruktor. + */ +//////////////////////////////////////////////////////////////////////////////// +template +class cStaticSingleton +{ +public: + static Host* Instance(); + static Host& GetInstance(); + +private: + cStaticSingleton(); + cStaticSingleton(const cStaticSingleton& s); + cStaticSingleton& operator=(const cStaticSingleton& s); + ~cStaticSingleton(); + static Host& Create(); + static Host& Access(); + + typedef Host& (*access_function)(); + + static Host* _instance; + static bool _destroyed; + static access_function _access; + static typename ThreadingModel::mutex _mutex; +}; + + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Funkce pro přístup k jediné instanci třídy. + * \return Ukazatele na instanci. + */ +//////////////////////////////////////////////////////////////////////////////// +template +inline Host* cStaticSingleton::Instance() +{ + return &(GetInstance()); +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Funkce pro přístup k jediné instanci třídy. + * \return Referenci instanci. + */ +//////////////////////////////////////////////////////////////////////////////// +template +inline Host& cStaticSingleton::GetInstance() +{ + return _access(); +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Konstruktor. + */ +//////////////////////////////////////////////////////////////////////////////// +template +cStaticSingleton::cStaticSingleton() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Destruktor. + */ +//////////////////////////////////////////////////////////////////////////////// +template +cStaticSingleton::~cStaticSingleton() +{ + _instance = 0; + _destroyed = true; + _access = &cStaticSingleton::Create; +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Interní funkce třídy vytvářející samotnou instanci objektu. + * Pro korektní práci ve vícevláknovém prostředí je potřeba + * odkomentovat/upravit testující a uzamykací část + */ +//////////////////////////////////////////////////////////////////////////////// +template +Host& cStaticSingleton::Create() +{ + typename ThreadingModel::scoped_lock scoped_lock(_mutex); + if (!_instance) + { + if (!_destroyed) + { // Vytvoř jedinou instanci a změň ukazatele _access, kterým byla + // tato metoda zavolána, aby se již nezavolala a místo toho + // se volala funkce zpřístupňující samotnou instanci + static Host staticInstance; + _instance = &staticInstance; + _access = &cStaticSingleton::Access; + } + else + { // Došlo k přístupu k již zničenému jedináčkovi + throw std::runtime_error("Access to dead reference of an object."); + } + } + return *_instance; +} + +//////////////////////////////////////////////////////////////////////////////// +/** + * \brief Funkce zpřístupňující instanci hostující třídy. + */ +//////////////////////////////////////////////////////////////////////////////// +template +Host& cStaticSingleton::Access() +{ + return *_instance; +} + +//////////////////////////////////////////////////////////////////////////////// +// Jedináčkova data +//////////////////////////////////////////////////////////////////////////////// +template + Host* cStaticSingleton::_instance = 0; + +template + bool cStaticSingleton::_destroyed = false; + +template typename cStaticSingleton::access_function + cStaticSingleton::_access = &cStaticSingleton::Create; + +template typename ThreadingModel::mutex + cStaticSingleton::_mutex; + +#endif // _STATIC_SINGLETON_HPP_ diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..81c7046 --- /dev/null +++ b/main.cpp @@ -0,0 +1,26 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file main.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include "mainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + a.setOrganizationName("FIT BUT in Brno"); + a.setApplicationName("microAnalyzer"); + + MainWindow microAnalyzer; + microAnalyzer.setWindowTitle("microAnalyzer :: imalcik at FIT BUT in Brno"); + + microAnalyzer.showMaximized(); + + return a.exec(); +} diff --git a/mainwindow.cpp b/mainwindow.cpp new file mode 100644 index 0000000..aeaeb87 --- /dev/null +++ b/mainwindow.cpp @@ -0,0 +1,1022 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file mainwindow.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include "projectwizard.h" +#include "xmlparser.h" +#include "layercomposer.h" +#include "customgraphicsview.h" + + +#include +#include +#include +#include + +// CONSTS +const QString MainWindow::APPL_NAME = QString("microAnalyzer ::"); + +// -------------------------------------------- +/** + * @brief = CONSTRUCTOR + */ +// -------------------------------------------- +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) +{ + ui->setupUi(this); + + // signals + connect(cProject::Instance(), SIGNAL(imagesValueChanged()), this, SLOT(reloadImagesList())); + connect(cProject::Instance(), SIGNAL(layersValueChanged()), this, SLOT(reloadLayersList())); + + imageView = new CustomGraphicsView(); + imageView->setBackgroundRole(QPalette::Dark); + imageView->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + setCentralWidget(imageView); + + connect(imageView, SIGNAL(colorPickerPosition(int, int)), this, SLOT(graphicsClicked(int, int))); + connect(this, SIGNAL(colorPickerPosition(int, int)), this, SLOT(graphicsClicked(int, int))); + + histogramBtn = false; + + // init values + initStageAndValues(); + + // limit cache + QPixmapCache::setCacheLimit(4194304); + + // statusbar init + statusBar()->showMessage("To activate function do Open project or Open image action."); // + tr("%1").arg(QPixmapCache::cacheLimit() +} + +void MainWindow::initStageAndValues() { + + // disable functions that are available only after a project is loaded + menuChangeAvailability(false); + + openedNewProjDialog = false; + + // setup of bitmap layers table + bitmapLayersTBL = NULL; + bitmapLayersTBL = new TableFormat(); + ui->bitmapTableView->setModel(bitmapLayersTBL); + ui->bitmapTableView->resizeRowsToContents(); // Adjust the row height. + ui->bitmapTableView->resizeColumnsToContents(); // Adjust the column width. + ui->bitmapTableView->setColumnWidth( 0, 20 ); + ui->bitmapTableView->setColumnWidth( 1, 150 ); + ui->bitmapTableView->setColumnWidth( 2, 20 ); + + // setup of vector layers table + vectorLayersTBL = NULL; + vectorLayersTBL = new TableFormat(); + ui->vectorTableView->setModel(vectorLayersTBL); + ui->vectorTableView->resizeRowsToContents(); // Adjust the row height. + ui->vectorTableView->resizeColumnsToContents(); // Adjust the column width. + ui->vectorTableView->setColumnWidth( 0, 20 ); + ui->vectorTableView->setColumnWidth( 1, 150 ); + ui->vectorTableView->setColumnWidth( 2, 20 ); + + // init the dial element + lastDialValue = 0; + onOpenNew_dialReset(); + + // colorpicker initial reset + QImage tmpImg(1,1, QImage::Format_ARGB32); + actualizeGraphicsView(&tmpImg); + + ui->frame->setStyleSheet("QFrame {border: 1px solid #828790;}"); + actualColor = qRgb(255,255,255); + actualizeFrameColor(); + + imageView->resetMatrix(); + + // channel correction sliders + ui->rLabel->setStyleSheet("QLabel { background-color: red; color: white;}"); + ui->gLabel->setStyleSheet("QLabel { background-color: green; color: white;}"); + ui->bLabel->setStyleSheet("QLabel { background-color: blue; color: white;}"); + + // colour analysis button + for (int i = 0; i < ui->menuTools->actions().count(); i++) { + if (ui->menuTools->actions().at(i)->isCheckable()) { + ui->menuTools->actions().at(i)->setChecked(false); + } + } + + resetSlidersValues(); +} + +void MainWindow::resetSlidersValues() { + ui->rSlider->setValue(DEF_SLIDER_VALUE); + ui->gSlider->setValue(DEF_SLIDER_VALUE); + ui->bSlider->setValue(DEF_SLIDER_VALUE); +} + +void MainWindow::closeThisProject() { + // project init + cProject::Instance()->valueInit(); + initStageAndValues(); + } + + +bool MainWindow::importImage(QString &imageFileName, bool addToVector) { + if (imageFileName.isEmpty()) { + return false; + } + else { + + if (addToVector) { + // add an image to project + cProject::Instance()->addToImages(imageFileName); + cProject::Instance()->setFileImported(true); + } + + QImage image(imageFileName); + + if (image.isNull()) { + return false; + } + + actualizeGraphicsView(&image); + + // align an image to center after import + imageResizer(0.99999999999999); + imageView->resetMatrix(); + + onOpenNew_dialReset(); + + // allow functions from menu + menuChangeAvailability(true); + + return true; + } +} + +void MainWindow::menuChangeAvailability(bool setting, bool sliders) { + + ui->imageDial->setEnabled(setting); + + ui->rSlider->setEnabled(sliders); + ui->gSlider->setEnabled(sliders); + ui->bSlider->setEnabled(sliders); + + ui->bitmapTableView->setEnabled(!sliders); + ui->vectorTableView->setEnabled(!sliders); +} + + + +// -------------------------------------------- +/** + * @brief = DESTRUKTOR + */ +// -------------------------------------------- +MainWindow::~MainWindow() +{ + delete ui; +} + +// -------------------------------------------- +/** + * @brief = TLACITKO EXIT + */ +// -------------------------------------------- +void MainWindow::on_actionExit_triggered() { + close(); +} + +bool MainWindow::saveAskDialog() { + + return true; + +} + + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionHelp_triggered() +{ + QMessageBox::about(this, APPL_NAME + tr(" HELP"), tr("


Under construction.

")); +} + + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionAbout_microAnalyzer_triggered() +{ + QMessageBox::about(this, APPL_NAME + tr(" About"), + QString::fromLocal8Bit("

 

microAnalyzer.

" + "

Author: Ing. Dominik Malci­k

" + "

E-mail: imalcik@fit.vutbr.cz

" + "

Year: 2014-2016

 

")); +} + + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionOpen_Image_triggered() +{ + QString imageFileName = QFileDialog::getOpenFileName(this, tr("Open Image"), QDir::currentPath(), "*.bmp *.png *.tif *.jpg *.jpeg"); + + if (importImage(imageFileName, true)) { + statusBar()->showMessage("Image loaded."); + menuChangeAvailability(true); + } + else { + QMessageBox::critical(this, APPL_NAME + tr(" ERROR"), tr("Error: The image %1 could not be loaded.").arg(imageFileName)); + } +} + +void MainWindow::onOpenNew_dialReset() { + ui->imageDial->setValue(0); +} + + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionZoom_in_25_triggered() +{ + imageResizer (1.2); +} + + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionZoom_out_25_triggered() +{ + imageResizer (0.8); +} + + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::imageResizer(double resizeCoeff) +{ + imageView->scale(resizeCoeff, resizeCoeff); + + QString statusMessage = " OUT -" + tr("%1").arg((1.0 - resizeCoeff) * 100) + " %"; + if (resizeCoeff > 1.0) { + statusMessage = " IN +" + tr("%1").arg((resizeCoeff - 1.0) * 100) + " %"; + } + statusBar()->showMessage("Zoom" + statusMessage); +} + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionFit_in_Window_triggered() +{ + imageView->fitInView(imageView->scene()->sceneRect(), Qt::KeepAspectRatio); + statusBar()->showMessage("Fit in window"); +} + +// -------------------------------------------- +/** + * + */ +// -------------------------------------------- +void MainWindow::on_actionOriginal_Size_triggered() +{ + imageView->resetMatrix(); + statusBar()->showMessage("Original size."); +} + +// -------------------------------------------- +/** + * @brief = ZMENA VELIKOSTI OBRAZKU NA ZAKLADE POHYBU DIALU + */ +// -------------------------------------------- +void MainWindow::on_imageDial_actionTriggered(int action) { + double newRatio = 1.0; + int dialValue = ui->imageDial->value(); + + int difference = lastDialValue - dialValue; + lastDialValue = dialValue; + + newRatio += ((double)(difference * (-1.0)) / 10000.0); + + if (newRatio <= 1.1 && newRatio >= 0.9) { + imageResizer (newRatio); + } +} + +void MainWindow::invertOpenedDialog_slot() { + openedNewProjDialog = !openedNewProjDialog; + this->setEnabled(true); +} + +void MainWindow::on_actionNew_Project_triggered() { + ProjectWizard * pw = new ProjectWizard; + + if (!openedNewProjDialog) { + openedNewProjDialog = true; + Qt::WindowFlags flags = pw->windowFlags(); + pw->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint); + pw->show(); + + this->setEnabled(false); + + connect(pw, SIGNAL(accepted()), this, SLOT(openProject_slot())); + connect(pw, SIGNAL(rejected()), this, SLOT(invertOpenedDialog_slot())); + } +} + +/* + * SLOT after accepting of the wizard + */ +void MainWindow::openProject_slot() { + + invertOpenedDialog_slot(); + + menuChangeAvailability(true); + openProject(cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getProjectFileName()); +} + +void MainWindow::on_actionOpen_Project_triggered() { + + QString projectFileName = QFileDialog::getOpenFileName(this, tr("Open microAnalyzer Project"), QDir::currentPath(), "*.mapro"); + + if (!projectFileName.isEmpty()) { + openProject(projectFileName); + } +} + +void MainWindow::openProject(QString projectFileName) { + + // if a project file was chosen + if (!projectFileName.isEmpty()) { + + // close currently opened project + closeThisProject(); + + QFile projFile(projectFileName); + + // set root directory of the project + QFileInfo fi(projFile); + cProject::Instance()->setProjectRootDir(fi.path()); + + // open file for reading + if(!projFile.open(QIODevice::ReadOnly)) { + QMessageBox::critical(0, APPL_NAME + " ERROR", projFile.errorString()); + } + else { + + XMLparser * xml = new XMLparser; + + if (!xml->read(&projFile)) { + QMessageBox::critical(0, APPL_NAME + " ERROR", "Project could not be loaded!"); + statusBar()->showMessage(tr("Error within project loading! Try again, please."), 3000); + } + else { + // import bitmap layers + if (cProject::Instance()->getFileImported()) { + for (uint i = 0; i < cProject::Instance()->getImages().size(); i++) { + QString imageFileNameToOpen = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/" + cProject::Instance()->getImages()[i]; + importImage(imageFileNameToOpen, false); + } + } + + menuChangeAvailability(true); + + setWindowTitle(APPL_NAME + " project - " + projectFileName); + statusBar()->showMessage(tr("Project loaded ...")); + } + + projFile.close(); + } + } + +} + + +// --------------------------------------------------------------------- +// --------------------------------------------------------------------- + +void MainWindow::on_actionSave_Project_triggered() { + bool removeSubDirs = false; + saveProjectToDest(cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getProjectFileName(), removeSubDirs); +} + +void MainWindow::on_actionSave_Project_As_triggered() { + + QString saveFileName = QFileDialog::getSaveFileName(this, "Save file", "", "*" + Project::PROJ_FILE_EXT); + + if (!saveFileName.isEmpty()) { + bool removeSubDirs = true; + saveProjectToDest(saveFileName, removeSubDirs); + } +} + +void MainWindow::saveProjectToDest(QString projectFileName_withPath, bool removeSubDirs) { + + QFile projFile(projectFileName_withPath); + QFileInfo fi(projFile); + + cProject::Instance()->prepareProject(fi.path(), fi.baseName(), + fi.fileName(), cProject::Instance()->getFileImported(), + cProject::Instance()->getImages(), + cProject::Instance()->getLayers()); + + // attempt to save + appropriate reaction + if (!cProject::Instance()->saveToFile(removeSubDirs)) { + QMessageBox::critical(0, APPL_NAME + " ERROR", "Project could not be saved!"); + statusBar()->showMessage(tr("Error within project saving! Try again, please."), 3000); + } + else { + statusBar()->showMessage(tr("Project saved to ") + projectFileName_withPath); + setWindowTitle(APPL_NAME + " project - " + projectFileName_withPath); + } +} + +void MainWindow::reloadImagesList() { + + // show updated list/table of images + TableFormat * thisTable = reloadTableList(TABLE_BITMAPS); + bitmapLayersTBL = thisTable; + ui->bitmapTableView->setModel(thisTable); + ui->bitmapTableView->setStyleSheet("QTableView {selection-background-color: #D10000; selection-color: #FFFFFF;}"); +} + +void MainWindow::reloadLayersList() { + + // show updated list/table of images + TableFormat * thisTable = reloadTableList(TABLE_LAYERS); + vectorLayersTBL = thisTable; + ui->vectorTableView->setModel(thisTable); + ui->vectorTableView->setStyleSheet("QTableView {selection-background-color: #2D60ED; selection-color: #FFFFFF;}"); +} + +TableFormat * MainWindow::reloadTableList(int tableSpec) { + + QString name = ""; + QString opacity = "100"; + + TableFormat * table = new TableFormat; + + unsigned int size = 0; + if (tableSpec == TABLE_LAYERS) { + size = cProject::Instance()->getLayers().size(); + } + else { + size = cProject::Instance()->getImages().size(); + } + + for (int i = (size - 1); i >= 0; i--) { + + if (tableSpec == TABLE_LAYERS) { + name = cProject::Instance()->getSelectedLayer(i); + } + else { + name = cProject::Instance()->getSelectedImage(i); + } + + // insert row + table->insertRows(0, 1, QModelIndex()); + + // insert information to the row + QModelIndex index = table->index(0, 0, QModelIndex()); + table->setData(index, QVariant(Qt::Checked), Qt::CheckStateRole); + + index = table->index(0, 1, QModelIndex()); + table->setData(index, name, Qt::EditRole); + + index = table->index(0, 2, QModelIndex()); + table->setData(index, opacity, Qt::EditRole); + } + + return table; +} + + + +void MainWindow::on_bitmapTableView_activated(QModelIndex index) +{ + std::vector selectedIndexes = getImportedIndexes(); + if (selectedIndexes.size() > 0) { + + QString imageName = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/"; + // !!!!! MAGIC 0 > we are allowing only one layer !! + imageName += cProject::Instance()->getSelectedImage (selectedIndexes[0]); + + // load image + QImage image(imageName); + actualizeGraphicsView(&image); + } +} + +std::vector MainWindow::getImportedIndexes () { + QModelIndexList indexes = ui->bitmapTableView->selectionModel()->selectedRows(1); + + return getSelectedIndexes(indexes); +} + +std::vector MainWindow::getAnalysingIndexes () { + QModelIndexList indexes = ui->vectorTableView->selectionModel()->selectedRows(1); + + return getSelectedIndexes(indexes); +} + + +std::vector MainWindow::getSelectedIndexes (QModelIndexList indexes) { + std::vector selectedIndexes; + + for (int i = 0; i < indexes.count(); ++i) { + QModelIndex index = indexes.at(i); + selectedIndexes.push_back(index.row()); + } + + return selectedIndexes; +} + + + + +void MainWindow::on_actionClose_Project_Image_triggered() +{ + switch( QMessageBox::question( + this, + APPL_NAME + tr(" Close project?"), + tr("Do you really want to close this project?"), + + QMessageBox::Yes | + QMessageBox::Cancel, + + QMessageBox::Cancel ) ) + { + case QMessageBox::Yes: { + closeThisProject(); + break; + } + case QMessageBox::Cancel: { + } + default: { + break; + } + } +} + + + + + + +void MainWindow::on_actionAnalyze_edges_triggered() +{ + if (cProject::Instance()->getImages().size() > 0) { + + std::vector selectedIdx = getImportedIndexes(); + if (!(selectedIdx.size() > 0)) { + QMessageBox::information(this, APPL_NAME + " No bitmap layer selected.", tr("Please select a BACKGROUND layer in the left tools panel." + " Click on the demanded layer and try again.")); + } + else { + QString fileName = cProject::Instance()->getImages()[ selectedIdx[0] ]; + QString test = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/" + fileName; + QImage imgToAnalyze( test ); + + if (imgToAnalyze.isNull()) { + QMessageBox::critical(this, APPL_NAME + " ERROR", "Bad file name or out of memory limit - shrink the image resolution please!\n\n" + test); + } + else { + + // ram limit !!! + if ( (imgToAnalyze.width() / 1000) * (imgToAnalyze.height() / 1000) <= 75) { + + OpenCVprocessor * openCVproc = new OpenCVprocessor(); + int resultDialog = getIntDialog(); + bool edgeSearch = true; + if (resultDialog >= 0) { + QImage result = openCVproc->processThreshold_Edges(&imgToAnalyze, edgeSearch, resultDialog); + + // ---------------- SAVE + int number = cProject::Instance()->layersCount(); + QString dstDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getLayersDir() + "/"; + QString ext = ".png"; + QString addition = "_E"; + QString destFileName = saveAnalysingImageToDir(fileName, dstDir, ext, addition, number); + + result.save(dstDir + destFileName, "PNG"); + cProject::Instance()->addToLayers(destFileName); + + // autoSave + on_actionSave_Project_triggered(); + // ---------------- // SAVE + + // show saved image + actualizeGraphicsView(&result); + + statusBar()->showMessage(tr("Edges found ...")); + } + } + else { + QMessageBox::critical(this, APPL_NAME + " TOO BIG IMAGE", "The selected image is too big, please shrink resolution. Max. total amount of pixels is 75 mil (for example 10000 x 7500)."); + } + } + } + } +} + + +void MainWindow::on_actionHough_triggered() { + makeCvFunction(2, -1); +} + +void MainWindow::on_actionThreshold_triggered() { + int resultDialog = getIntDialog(); + if (resultDialog >= 0) { + makeCvFunction(1, resultDialog); + } +} + +void MainWindow::makeCvFunction(int number, int param = 0) { + + std::vector selectedIdx = getImportedIndexes(); + + QString fileName = cProject::Instance()->getImages()[selectedIdx[0]]; + QImage imgToAnalyze(cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/" + fileName); + + OpenCVprocessor * openCVproc = new OpenCVprocessor(); + + QImage result; + QString suffix = ""; + switch(number) { + case 0: { + break; + } + case 1: { + statusBar()->showMessage(tr("Threshold found ...")); + bool edgeSearch = false; + result = openCVproc->processThreshold_Edges(&imgToAnalyze, edgeSearch, param); + suffix = "TH"; + break; + } + case 2: { + statusBar()->showMessage(tr("Hough proceded ...")); + bool edgeSearch = true; + result = openCVproc->processThreshold_Edges(&imgToAnalyze, edgeSearch, param); + suffix = "H"; + break; + } + default: { + break; + } + } + + QFileInfo fi(fileName); + QString newPngFile = fi.baseName() + suffix + ".png"; + result.save(cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/" + newPngFile, "PNG"); + + cProject::Instance()->addToImages(newPngFile); + + actualizeGraphicsView(&result); + + // autoSave + on_actionSave_Project_triggered(); +} + + + + + + + +int MainWindow::getIntDialog() { + bool ok; + int i = QInputDialog::getInt(this, tr("QInputDialog::getInteger()"), + tr("Threshold value"), 100, 0, 255, 1, &ok); + if (ok) { + return i; + } + + return -1; +} + + +void MainWindow::closeEvent(QCloseEvent *event) { + + if (!openedNewProjDialog && saveAskDialog()) { + // close window + event->accept(); + } + else { + // push cancel - does not close the window + event->ignore(); + } + +} + + + + + +void MainWindow::on_pushButton_2_clicked() { + + LayerComposer * composer = new LayerComposer(); + + importedIndexes = getImportedIndexes(); + analysingIndexes = getAnalysingIndexes(); + + if (importedIndexes.size() > 0 && analysingIndexes.size() > 0) { + + // merging of selected layers + QString bgRootDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/"; + QString overlayRootDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getLayersDir() + "/"; + QImage result = composer->composeLayers(cProject::Instance()->getImages(), + cProject::Instance()->getLayers(), + importedIndexes, analysingIndexes, + bgRootDir, overlayRootDir); + + actualizeGraphicsView(&result); + + statusBar()->showMessage("Layers merged ..."); + } + else { + statusBar()->showMessage("Layers NOT merged, select layers to merge first, please."); + } +} + + +void MainWindow::on_pushButton_clicked() { + LayerComposer * composer = new LayerComposer(); + + analysingIndexes = getAnalysingIndexes(); + + if (analysingIndexes.size() > 0) { + + std::vector bgVector; + bgVector.push_back(analysingIndexes[0]); // !!!!!!! 0 v indexu + + std::vector analysingVector; + for (unsigned int i = 1; i < analysingIndexes.size(); i++) { + analysingVector.push_back(analysingIndexes[i]); + } + + // merging of selected layers + QString bgRootDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getLayersDir() + "/"; + QString overlayRootDir = bgRootDir; + QImage result = composer->composeLayers(cProject::Instance()->getLayers(), + cProject::Instance()->getLayers(), + bgVector, analysingVector, bgRootDir, overlayRootDir); + + actualizeGraphicsView(&result); + + statusBar()->showMessage("Layers merged ..."); + } + else { + statusBar()->showMessage("Layers NOT merged, select layers to merge first, please."); + } + +} + +void MainWindow::on_actionAnalyze_Colors_triggered() { + + bool setting = ui->imageDial->isEnabled(); + bool sliders = !(ui->rSlider->isEnabled()); + + menuChangeAvailability(setting, sliders); + + if (sliders) { + makeColorAnalyzeStep(); + } + else { + QString bgImageFileName = cProject::Instance()->getSelectedImage(importedIndexes[0]); // !!!!!! 0 + + switch( QMessageBox::question( + this, + APPL_NAME + tr(" Save this layer?"), + tr("

Would you like to save this layer?

Choose Yes to proceed, No to abort.

"), + + QMessageBox::Yes | + QMessageBox::No, + + QMessageBox::Yes ) ) + { + case QMessageBox::Yes: { + // ---------------- SAVE + int number = cProject::Instance()->layersCount(); + QString dstDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getLayersDir() + "/"; + QString ext = ".png"; + QString addition = "_C"; + QString destFileName = saveAnalysingImageToDir(bgImageFileName, dstDir, ext, addition, number); + + visibleImage.save(dstDir + destFileName, "PNG"); + cProject::Instance()->addToLayers(destFileName); + + // autoSave + on_actionSave_Project_triggered(); + // ---------------- // SAVE + + statusBar()->showMessage("Layer SAVED ..."); + + break; + } + case QMessageBox::No: { + } + default: { + QString srcDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/"; + QImage image(srcDir + bgImageFileName); + if (!(image.isNull())) { + actualizeGraphicsView(&image); + } + statusBar()->showMessage("Layer saving aborted ..."); + } + } + } + + resetSlidersValues(); +} + +void MainWindow::on_rSlider_valueChanged(int value) { + if (ui->rSlider->isEnabled()) { + makeColorAnalyzeStep(); + } +} + +void MainWindow::on_gSlider_valueChanged(int value) { + if (ui->gSlider->isEnabled()) { + makeColorAnalyzeStep(); + } +} + +void MainWindow::on_bSlider_valueChanged(int value) { + if (ui->bSlider->isEnabled()) { + makeColorAnalyzeStep(); + } +} + + +void MainWindow::makeColorAnalyzeStep () { + + importedIndexes = getImportedIndexes(); + if (importedIndexes.size() > 0) { + + QString bgRootDir = cProject::Instance()->getProjectRootDir() + "/" + cProject::Instance()->getImagesDir() + "/"; + QString bgImageFileName = cProject::Instance()->getSelectedImage(importedIndexes[0]); // !!!!!! 0 + QRgb maskColor = actualColor; + + LayerComposer * composer = new LayerComposer(); + visibleImage = composer->maskSelectedLayer(bgImageFileName, bgRootDir, maskColor, ui->rSlider->value(), ui->gSlider->value(), ui->bSlider->value()); + + actualizeGraphicsView(&visibleImage); + + statusBar()->showMessage("Layer processed ..."); + } +} + + + +void MainWindow::graphicsClicked(int xPos, int yPos) { + + if (!(ui->rSlider->isEnabled())) { + + // find coordinates of the cursor position + QPointF point = imageView->mapToScene(xPos, yPos); + + actualColor = visibleImage.pixel(point.x(), point.y()); + actualizeFrameColor(); + } +} + +void MainWindow::actualizeFrameColor() { + + QPalette palette = ui->frame->palette(); + palette.setColor( backgroundRole(), actualColor); + + ui->frame->setPalette(palette); + ui->frame->setAutoFillBackground(true); + +} + +void MainWindow::actualizeGraphicsView(QImage * toShow) { + QPixmapCache::clear(); + QPixmap pm = QPixmap::fromImage(*toShow); + QPixmapCache::insert("loadedImage", pm); + + // show result + visibleImage = *toShow; + QGraphicsScene * thisScene = new QGraphicsScene; + thisScene->addPixmap(pm); + + if (histogramBtn) { + // DOES NOT WORK YET + } + + imageView->setScene(thisScene); +} + + + +QString MainWindow::saveAnalysingImageToDir(QString origFN, QString dstDir, QString ext, QString addition, int number) { + + QFileInfo fi(origFN); + + QString newExt = ext; + QString newPngFile = fi.baseName() + addition; + QString numStr = QString::number(number); + + + while (1) { + QFile destFile(dstDir + newPngFile + numStr + newExt); + + if (!destFile.exists()) { + newPngFile = newPngFile + numStr + newExt; + break; + } + else { + number++; + } + + numStr = QString::number(number); + } + + return newPngFile; +} + + + +bool MainWindow::deleteDialog(QString layerType) { + switch( QMessageBox::question( + this, + APPL_NAME + tr(" Delete selected layers?"), + tr("

Do you really want to permanently remove selected ") + layerType + tr(" layers.

"), + + QMessageBox::Yes | + QMessageBox::No, + + QMessageBox::No ) ) + { + case QMessageBox::Yes: { + return true; + } + case QMessageBox::No: { + } + default: { + return false; + } + } +} + +// delete analysing +void MainWindow::on_pushButton_3_clicked() { + QString layerType = "ANALYSING"; + + if (deleteDialog(layerType)) { + analysingIndexes = getAnalysingIndexes(); + + for (unsigned int i = 0; i < analysingIndexes.size(); i++) { + cProject::Instance()->deleteAnalysing(analysingIndexes[i]); + } + } + + cProject::Instance()->emitDeleteAnalysings(); + + // autoSave + on_actionSave_Project_triggered(); +} + +// delete imported +void MainWindow::on_pushButton_4_clicked() { + QString layerType = "BACKGROUND"; + + if (deleteDialog(layerType)) { + importedIndexes = getImportedIndexes(); + + for (unsigned int i = 0; i < importedIndexes.size(); i++) { + cProject::Instance()->deleteImported(importedIndexes[i]); + } + } + + cProject::Instance()->emitDeleteImported(); + + // autoSave + on_actionSave_Project_triggered(); +} + +void MainWindow::on_actionHistogram_triggered() { + histogramBtn = !histogramBtn; +} diff --git a/mainwindow.h b/mainwindow.h new file mode 100644 index 0000000..3690424 --- /dev/null +++ b/mainwindow.h @@ -0,0 +1,155 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file mainwindow.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// openCV +#include "opencv/cv.h" + +#include "opencvprocessor.h" +#include "tableformat.h" + +// singleton +#include "project.h" + +class QLabel; + +namespace Ui { + class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + static const QString APPL_NAME; + static const int TABLE_BITMAPS = 0; + static const int TABLE_LAYERS = 1; + static const int DEF_SLIDER_VALUE = 20; + + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); + +private slots: + // File menu + void on_actionNew_Project_triggered(); + void on_actionOpen_Project_triggered(); + void on_actionSave_Project_triggered(); + void on_actionOpen_Image_triggered(); + void on_actionClose_Project_Image_triggered(); + void on_actionExit_triggered(); + void on_actionSave_Project_As_triggered(); + + // Tools menu + void on_actionZoom_in_25_triggered(); + void on_actionZoom_out_25_triggered(); + void on_actionFit_in_Window_triggered(); + void on_actionOriginal_Size_triggered(); + + // Tools menu > analyza + void on_actionAnalyze_edges_triggered(); + void on_actionHough_triggered(); + void on_actionThreshold_triggered(); + + void on_actionAnalyze_Colors_triggered(); + void on_rSlider_valueChanged(int value); + void on_gSlider_valueChanged(int value); + void on_bSlider_valueChanged(int value); + + // Help menu + void on_actionHelp_triggered(); + void on_actionAbout_microAnalyzer_triggered(); + + // Layers buttons + void on_pushButton_2_clicked(); // add ANALYSING + void on_pushButton_clicked(); // show only ANALYSING + void on_pushButton_3_clicked(); // delete ANALYSING + void on_pushButton_4_clicked(); // delete IMPORTED + + // Additional slots + void on_imageDial_actionTriggered(int action); + void openProject_slot(); + + void reloadImagesList(); + void reloadLayersList(); + + void graphicsClicked(int xPos, int yPos); + + void on_bitmapTableView_activated(QModelIndex index); + + // Wizard - singleton instance + void invertOpenedDialog_slot(); + + void on_actionHistogram_triggered(); + +private: + Ui::MainWindow *ui; + void menuChangeAvailability(bool setting, bool sliders = false); + void imageResizer(double resizeCoeff); + void onOpenNew_dialReset(); + bool importImage(QString &imageFileName, bool addToVector); + void saveProjectToDest(QString projectFileName_withPath, bool removeSubDirs); + + QString saveAnalysingImageToDir(QString origFN, QString dstDir, QString ext, QString addition, int number); + + bool deleteDialog(QString layerType); + void actualizeGraphicsView(QImage * toShow); + void actualizeFrameColor(); + + // tableView indexes (imported / analysing) + std::vector getImportedIndexes (); + std::vector getAnalysingIndexes (); + std::vector getSelectedIndexes (QModelIndexList indexes); + + void makeColorAnalyzeStep(); + + void makeCvFunction(int number, int param); + + int getIntDialog(); + + void closeThisProject(); + void initStageAndValues(); + void resetSlidersValues(); + + void closeEvent(QCloseEvent *event); + bool saveAskDialog(); + + void openProject(QString projectFileName); + + TableFormat * reloadTableList(int tableSpec); + + std::vector importedIndexes; + std::vector analysingIndexes; + + QImage visibleImage; + QRgb actualColor; + QGraphicsView * imageView; + + int lastDialValue; + bool openedNewProjDialog; + + TableFormat *bitmapLayersTBL; + TableFormat *vectorLayersTBL; + + bool histogramBtn; +}; + +#endif // MAINWINDOW_H diff --git a/mainwindow.ui b/mainwindow.ui new file mode 100644 index 0000000..4961c4c --- /dev/null +++ b/mainwindow.ui @@ -0,0 +1,870 @@ + + + MainWindow + + + + 0 + 0 + 724 + 704 + + + + MainWindow + + + + + + 0 + 0 + 724 + 25 + + + + + File + + + + + + + + + + + + + + + Tools + + + + + + + + + + + + + + + Help + + + + + + + + + + + + + + 250 + 625 + + + + false + + + QDockWidget::NoDockWidgetFeatures + + + Tools + + + 1 + + + + + Arial + + + + + + 26 + 19 + 201 + 151 + + + + -999 + + + 999 + + + 10 + + + 0 + + + 0 + + + true + + + Qt::Vertical + + + true + + + 10.000000000000000 + + + true + + + + + + 10 + 170 + 220 + 20 + + + + Qt::Horizontal + + + + + + 10 + 187 + 191 + 16 + + + + + Sans + 10 + + + + Background layers (dbl click) + + + + + + 14 + 299 + 111 + 16 + + + + + Sans + 10 + + + + Analysing layers + + + + + + 92 + 0 + 71 + 16 + + + + + Sans + 10 + 50 + false + + + + Fine zoom + + + + + + 10 + 209 + 221 + 71 + + + + + Arial + 9 + 50 + false + + + + false + + + true + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + Qt::DashLine + + + false + + + false + + + true + + + 140 + + + false + + + 25 + + + false + + + true + + + false + + + 19 + + + false + + + 15 + + + + + + 10 + 279 + 220 + 20 + + + + Qt::Horizontal + + + + + + 10 + 320 + 221 + 161 + + + + + Arial + 9 + 50 + false + + + + false + + + true + + + QAbstractItemView::MultiSelection + + + QAbstractItemView::SelectRows + + + Qt::DashLine + + + false + + + false + + + true + + + 140 + + + false + + + 25 + + + false + + + true + + + false + + + 19 + + + false + + + 15 + + + + + + 165 + 295 + 31 + 21 + + + + Show only selected Analysing layers (blue) + + + + + + + images/icons/btn_analyzeLayers.pngimages/icons/btn_analyzeLayers.png + + + + + + 200 + 295 + 31 + 21 + + + + Add selected Analysing layers (blue) to selected Imported layers (red) + + + + + + + images/icons/btn_addLayers.pngimages/icons/btn_addLayers.png + + + + + + 150 + 499 + 81 + 21 + + + + true + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + 13 + 501 + 131 + 16 + + + + + Sans + 10 + + + + Mask colour: + + + + + + 10 + 480 + 220 + 20 + + + + Qt::Horizontal + + + + + + 130 + 295 + 31 + 21 + + + + Delete selected ANALYSING layers (blue ones) + + + + + + + images/icons/delete.pngimages/icons/delete.png + + + + + + 200 + 184 + 31 + 21 + + + + Delete selected IMPORTED layers (blue ones) + + + + + + + images/icons/delete.pngimages/icons/delete.png + + + + + + 70 + 529 + 160 + 19 + + + + -5 + + + 45 + + + 5 + + + 5 + + + Qt::Horizontal + + + + + + 70 + 553 + 160 + 19 + + + + -5 + + + 45 + + + 5 + + + 5 + + + Qt::Horizontal + + + + + + 70 + 578 + 160 + 19 + + + + -5 + + + 45 + + + 5 + + + 5 + + + Qt::Horizontal + + + + + + 13 + 530 + 46 + 16 + + + + + Sans + 10 + 50 + false + + + + Red + + + Qt::AlignCenter + + + + + + 13 + 553 + 46 + 16 + + + + + Sans + 10 + + + + Green + + + Qt::AlignCenter + + + + + + 13 + 577 + 46 + 16 + + + + + Sans + 10 + + + + Blue + + + Qt::AlignCenter + + + + + + + + 0 + 32 + + + + false + + + TopToolBarArea + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + images/icons/newProject.pngimages/icons/newProject.png + + + New Project + + + Ctrl+N + + + + + + images/icons/openProject.pngimages/icons/openProject.png + + + Open Project + + + Ctrl+O + + + + + + images/icons/save.pngimages/icons/save.png + + + Save Project + + + Ctrl+S + + + + + + images/icons/openImage.pngimages/icons/openImage.png + + + Import Image + + + Ctrl+I + + + + + + images/icons/exit.pngimages/icons/exit.png + + + Exit + + + Ctrl+Q + + + + + + images/icons/zoom-in.pngimages/icons/zoom-in.png + + + Zoom in (+ 20 %) + + + Ctrl++ + + + + + + images/icons/zoom-out.pngimages/icons/zoom-out.png + + + Zoom out (- 20 %) + + + Ctrl+- + + + + + + images/icons/zoom-fit.pngimages/icons/zoom-fit.png + + + Fit in Window + + + Ctrl+Enter + + + + + + images/icons/zoom-orig.pngimages/icons/zoom-orig.png + + + Original Size + + + Ctrl+0 + + + + + + images/icons/help.pngimages/icons/help.png + + + Help + + + F1 + + + + + About microAnalyzer + + + + + Analyze Edges + + + + + Threshold + + + + + + images/icons/save-as.pngimages/icons/save-as.png + + + Save Project As + + + Ctrl+Shift+S + + + + + show project + + + + + + images/icons/close.pngimages/icons/close.png + + + Close Project / Image + + + Ctrl+W + + + + + Hough + + + + + true + + + Analyze Colour + + + + + true + + + false + + + false + + + Histogram + + + + + + + diff --git a/microAnalyzer.pro b/microAnalyzer.pro new file mode 100644 index 0000000..6ecd674 --- /dev/null +++ b/microAnalyzer.pro @@ -0,0 +1,38 @@ +TEMPLATE = app +TARGET = microAnalyzer +DEPENDPATH += . + +# OpenCV +LIBS += -lopencv_core -lopencv_imgproc -lboost_system + +INCLUDEPATH += . + +QT += widgets +QT += xml + +# Input +HEADERS += layerrecord.h \ + mainwindow.h \ + project.h \ + projectwizard.h \ + ./libs/staticsingleton.h \ + tableformat.h \ + xmlparser.h \ + opencvprocessor.h \ + layercomposer.h \ + customgraphicsview.h + + +FORMS += mainwindow.ui +SOURCES += layerrecord.cpp \ + main.cpp \ + mainwindow.cpp \ + project.cpp \ + projectwizard.cpp \ + tableformat.cpp \ + xmlparser.cpp \ + opencvprocessor.cpp \ + layercomposer.cpp \ + customgraphicsview.cpp + +RC_FILE = microAnalyzer.rc diff --git a/microAnalyzer.rc b/microAnalyzer.rc new file mode 100644 index 0000000..a20295d --- /dev/null +++ b/microAnalyzer.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "images/application.ico" \ No newline at end of file diff --git a/opencvprocessor.cpp b/opencvprocessor.cpp new file mode 100644 index 0000000..559ac64 --- /dev/null +++ b/opencvprocessor.cpp @@ -0,0 +1,164 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file opencvprocessor.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "opencvprocessor.h" + +#include "string.h" +#include +#include + +OpenCVprocessor::OpenCVprocessor(QWidget *parent) : + QMainWindow(parent) +{ +} + +IplImage * OpenCVprocessor::qImageToCvImage(QImage *qimg) { + + IplImage *imgHeader = cvCreateImageHeader( cvSize(qimg->width(), qimg->height()), IPL_DEPTH_8U, 4); + imgHeader->imageData = (char*) qimg->bits(); + + uchar* newdata = (uchar*) malloc(sizeof(uchar) * qimg->byteCount()); + memcpy(newdata, qimg->bits(), qimg->byteCount()); + imgHeader->imageData = (char*) newdata; + + return imgHeader; +} + +QImage OpenCVprocessor::cvImageToQImage(const IplImage *iplImage) { + int height = iplImage->height; + int width = iplImage->width; + + if (iplImage->depth == IPL_DEPTH_8U && iplImage->nChannels == 3) { + const uchar *qImageBuffer = (const uchar*)iplImage->imageData; + + QImage img(qImageBuffer, width, height, QImage::Format_RGB888); + return img.rgbSwapped(); + + } else if (iplImage->depth == IPL_DEPTH_8U && iplImage->nChannels == 1){ + + const uchar *qImageBuffer = (const uchar*)iplImage->imageData; + QImage img(qImageBuffer, width, height, QImage::Format_Indexed8); + + QVector colorTable; + for (int i = 0; i < 256; i++){ + colorTable.push_back(qRgb(i, i, i)); + } + + img.setColorTable(colorTable); + return img; + + }else{ + return QImage(); + } +} + +QImage OpenCVprocessor::processThreshold_Edges(QImage * input, bool processEdges, int threshValue) { + + IplImage * img = NULL; + img = qImageToCvImage(input); + + // transform source image to greyscale + IplImage *dst = cvCreateImage( cvSize( img->width, img->height ), IPL_DEPTH_8U, 1 ); + cvCvtColor( img, dst, CV_RGB2GRAY ); + + // make threshold + cvThreshold(dst, dst, threshValue, 255, CV_THRESH_BINARY); + + if (processEdges) { + cvCanny( dst, dst, 1.0, 1.0, 3); + } + + QImage qEdges = cvImageToQImage(dst); + cvReleaseImage(&dst); + cvReleaseImage(&img); + return qEdges; +} + + +QImage OpenCVprocessor::normalizeImage(QImage * input, int red, int green, int blue, int rThrs, int gThrs, int bThrs) { + + // load image + IplImage * img = NULL; + img = qImageToCvImage(input); + + // prepare particular channels + IplImage* imgRed = cvCreateImage(cvGetSize(img), 8, 1); + IplImage* imgGreen = cvCreateImage(cvGetSize(img), 8, 1); + IplImage* imgBlue = cvCreateImage(cvGetSize(img), 8, 1); + + // split channels + cvSplit(img, imgBlue, imgGreen, imgRed, NULL); + + // change to bitmask! + int lowRed = red-rThrs; + if (lowRed < 0) { + lowRed = 0; + } + if (lowRed > 255) { + lowRed = 255; + } + + int highRed = red+rThrs; + if (highRed < 0) { + highRed = 0; + } + if (highRed > 255) { + highRed = 255; + } + + int lowGreen = green-gThrs; + if (lowGreen < 0) { + lowGreen = 0; + } + if (lowGreen > 255) { + lowGreen = 255; + } + + int highGreen = green+gThrs; + if (highGreen < 0) { + highGreen = 0; + } + if (highGreen > 255) { + highGreen = 255; + } + + int lowBlue = blue-bThrs; + if (lowBlue < 0) { + lowBlue = 0; + } + if (lowBlue > 255) { + lowBlue = 255; + } + + int highBlue = blue+bThrs; + if (highBlue < 0) { + highBlue = 0; + } + if (highBlue > 255) { + highBlue = 255; + } + + // mask each channle + cvInRangeS(imgRed, cvScalar(lowRed), cvScalar(highRed), imgRed); + cvInRangeS(imgGreen, cvScalar(lowGreen), cvScalar(highGreen), imgGreen); + cvInRangeS(imgBlue, cvScalar(lowBlue), cvScalar(highBlue), imgBlue); + + cvMul(imgRed, imgGreen, imgRed); + cvMul(imgRed, imgBlue, imgRed); + + // transform result to QImage format + QImage qOutput = cvImageToQImage(imgRed); + + // release memory + cvReleaseImage(&img); + cvReleaseImage(&imgRed); + cvReleaseImage(&imgGreen); + cvReleaseImage(&imgBlue); + return qOutput; +} + diff --git a/opencvprocessor.h b/opencvprocessor.h new file mode 100644 index 0000000..98bdde4 --- /dev/null +++ b/opencvprocessor.h @@ -0,0 +1,44 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file opencvprocessor.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef OPENCVPROCESSOR_H +#define OPENCVPROCESSOR_H + +#include +#include "opencv/cv.h" +#include "opencv/highgui.h" + +class OpenCVprocessor : public QMainWindow +{ + Q_OBJECT +public: + explicit OpenCVprocessor(QWidget *parent = 0); + IplImage * qImageToCvImage(QImage *qimg); + QImage cvImageToQImage(const IplImage *iplImage); + + QImage processThreshold_Edges(QImage * input, bool processEdges, int threshValue); + QImage normalizeImage(QImage * input, int red, int green, int blue, int rThrs, int gThrs, int bThrs); + + QImage detectDrawQuads(QImage * input); + + + + std::vector makeHistogram(QImage * input); + IplImage* DrawHistogram(CvHistogram *hist, float scaleX=1, float scaleY=1); + +signals: + +public slots: + +private: + IplImage * cvImage; + QImage qtImage; + +}; + +#endif // OPENCVPROCESSOR_H diff --git a/project.cpp b/project.cpp new file mode 100644 index 0000000..52b1bca --- /dev/null +++ b/project.cpp @@ -0,0 +1,456 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file project.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "project.h" +#include "mainwindow.h" +#include "xmlparser.h" + +// Konstanty +const QString Project::PROJVERSION = QString("1.0"); +const QString Project::PROJSUBDIR_IMAGES = QString("images"); +const QString Project::PROJSUBDIR_LAYERS = QString("layers"); +const QString Project::PROJ_FILE_EXT = QString(".mapro"); +const QString Project::XML_TRUE = QString("1"); +const QString Project::XML_FALSE = QString("0"); + +// -------------------------------------------- +/** + * @brief = KONSTRUKTOR + */ +// -------------------------------------------- +Project::Project(QObject *parent) : QObject(parent){ + valueInit(); +} + +// -------------------------------------------- +/** + * @brief = DESTRUKTOR + */ +// -------------------------------------------- +Project::~Project() +{ +} + +void Project::valueInit() { + setProjectName(""); + setProjectFileName(""); + setProjectRootDir(""); + setProjectRootDir_old(""); + setImagesDir(PROJSUBDIR_IMAGES); + setLayersDir(PROJSUBDIR_LAYERS); + setFileImported(false); + std::vector imgs; + setImages(imgs); + std::vector lrs; + setLayers(lrs); +} + +void Project::setProjectName (QString s) { + this->projectName = s; +} + +QString Project::getProjectName (void) { + return this->projectName; +} + +void Project::setProjectFileName (QString s) { + this->projectFileName = s; +} + +QString Project::getProjectFileName (void) { + return this->projectFileName; +} + +void Project::setProjectRootDir (QString s) { + this->projectRootDir = s; +} + +QString Project::getProjectRootDir (void) { + return this->projectRootDir; +} + +void Project::setProjectRootDir_old (QString s) { + this->projectRootDir_old = s; +} + +QString Project::getProjectRootDir_old (void) { + return this->projectRootDir_old; +} + +void Project::setImagesDir (QString s) { + this->imagesDir = s; +} + +QString Project::getImagesDir (void) { + return this->imagesDir; +} + +void Project::setLayersDir (QString s) { + this->layersDir = s; +} + +QString Project::getLayersDir (void) { + return this->layersDir; +} + +void Project::setFileImported (bool i) { + this->fileImported = i; +} + +bool Project::getFileImported (void) { + return this->fileImported; +} + + +void Project::setImages (std::vector i) { + if (i != getImages()) { + this->images = i; + emit imagesValueChanged(); + } +} + +std::vector Project::getImages (void) { + return this->images; +} + +void Project::addToImages (QString s) { + this->images.push_back(s); + emit imagesValueChanged(); +} + +QString Project::getSelectedImage (unsigned int index) { + if (images.size() > index) { + return this->images[index]; + } + else { + return "ERROR"; + } +} + +void Project::eraseSelectedImage(unsigned int index) { + if (images.size() > index) { + std::vector::iterator it = images.begin(); + it += index; + images.erase(it); + } +} + +void Project::emitDeleteImported() { + emit imagesValueChanged(); +} + + + + +void Project::setLayers (std::vector i) { + if (i != getLayers()) { + this->layers = i; + emit layersValueChanged(); + } +} + +std::vector Project::getLayers (void) { + return this->layers; +} + +void Project::addToLayers (QString s) { + this->layers.push_back(s); + emit layersValueChanged(); +} + +QString Project::getSelectedLayer (unsigned int index) { + if (layers.size() > index) { + return this->layers[index]; + } + else { + return "ERROR"; + } +} + +void Project::eraseSelectedLayer(unsigned int index) { + if (layers.size() > index) { + std::vector::iterator it = layers.begin(); + it += index; + layers.erase(it); + } +} + +void Project::emitDeleteAnalysings() { + emit layersValueChanged(); +} + +int Project::layersCount() { + return this->layers.size(); +} + + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +void Project::prepareProject(QString rootDir, QString projectName, QString projectFileName, + bool fileImported, std::vector images, std::vector layers) { + + setProjectRootDir_old(getProjectRootDir()); + setProjectRootDir(rootDir); + setProjectName(projectName); + setProjectFileName(projectFileName); + setFileImported(fileImported); + setImagesDir(Project::PROJSUBDIR_IMAGES); + setLayersDir(Project::PROJSUBDIR_LAYERS); + setImages(images); + setLayers(layers); +} + +bool Project::fileCopy(QString fileName, QString destDir, QString destFilename, QString * newFileName) { + + // remembering of the filename + QFileInfo fi(fileName); + + // get the number for filename (filename_number.ext) + QDir dir(destDir); + int number = dir.count(); + number--; + + while (1) { + QString numStr = QString::number(number); + QFile destFile(destDir + "/" + destFilename + "_" + numStr + "." + fi.completeSuffix()); + + if (!destFile.exists()) { + break; + } + else { + number++; + } + } + + // copy the file to the project directory with a specified filename + QString numStr = QString::number(number); + QString finalDestFileString = destDir + "/" + destFilename + "_" + numStr + "." + fi.completeSuffix(); + QFile sourceFile(fileName); + QFile finalDestFile(finalDestFileString); + + QFileInfo finalFi(finalDestFileString); + *newFileName = finalFi.baseName() + "." + finalFi.completeSuffix(); + + if (sourceFile.exists()) { + if (!sourceFile.copy(finalDestFile.fileName())) { + return false; + } + } + + return true; +} + +bool Project::removeDir(QString dirName) { + bool result = true; + QDir dir(dirName); + + if (dir.exists(dirName)) { + Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) { + if (info.isDir()) { + result = this->removeDir(info.absoluteFilePath()); + } + else { + result = QFile::remove(info.absoluteFilePath()); + } + + if (!result) { + return result; + } + } + result = dir.rmdir(dirName); + } + + return result; +} + + +bool Project::saveToFile(bool removeSubDirs) { + + if (getProjectRootDir() == getProjectRootDir_old()) { + removeSubDirs = false; + } + + QFile mapro(getProjectRootDir() + "/" + getProjectFileName()); + if (mapro.exists()) { + if (!mapro.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + return false; + } + } + else { + if (!mapro.open(QIODevice::ReadWrite)) { + return false; + } + } + + // make an entry in XML for an imported image + QString importedInt = XML_FALSE; + if (getFileImported()) { + importedInt = XML_TRUE; + } + + // prepare directory structure for the project + QString projImages_dir = getProjectRootDir(); + projImages_dir.append("/").append(getImagesDir()); + QString projLayers_dir = getProjectRootDir(); + projLayers_dir.append("/").append(getLayersDir()); + + if (removeSubDirs) { + if (QDir(projImages_dir).exists()) { + removeDir(projImages_dir); + } + QDir().mkpath(projImages_dir); + + if (QDir(projLayers_dir).exists()) { + removeDir(projLayers_dir); + } + QDir().mkpath(projLayers_dir); + } + else { + if (!QDir(projImages_dir).exists()) { + QDir().mkpath(projImages_dir); + } + + if (!QDir(projLayers_dir).exists()) { + QDir().mkpath(projLayers_dir); + } + } + + // copying of the files and creating an XML entry + // BACKGROUNDs + QString importedImageFilesXML = ""; + std::vector tmpB = getImages(); + for (uint i = 0; i < getImages().size(); i++) { + QString scrImage = getImages()[i]; // source file + QFileInfo scrFi(scrImage); + + // if the file is already in the right place, do not perform the copying + bool fileFromProjectDir = false; + if (scrImage == (scrFi.baseName() + "." + scrFi.completeSuffix())) { + scrImage = getProjectRootDir_old() + "/" + getImagesDir() + "/" + scrImage; + fileFromProjectDir = true; + } + + QString destAddr = getProjectRootDir() + "/" + getImagesDir(); // destination directory + QString newFileName_part = "pict"; // renaming of the file + QString newFileName_whole; // final file name for XML entry + + // for SAVE it does not copy files that already exist in the project + bool makeCopy = true; + QFile testExist(scrImage); + if (!removeSubDirs && fileFromProjectDir && testExist.exists()) { + makeCopy = false; + newFileName_whole = getImages()[i]; + } + + if (makeCopy && !fileCopy(scrImage, destAddr, newFileName_part, &newFileName_whole)) { + removeDir(getProjectRootDir()); + return false; + } + + if (makeCopy) { + tmpB[i] = newFileName_whole; + } + + importedImageFilesXML += "\t\t" + newFileName_whole + "\n"; + } + setImages(tmpB); + + + // copying of the files and creating an XML entry + // LAYERs + QString importedLayerFilesXML = ""; + std::vector tmpL = getLayers(); + for (uint i = 0; i < getLayers().size(); i++) { + + QString scrImage = getLayers()[i]; // source file + QFileInfo scrFi(scrImage); + + bool fileFromProjectDir = false; + if (scrImage == (scrFi.baseName() + "." + scrFi.completeSuffix())) { + scrImage = getProjectRootDir_old() + "/" + getLayersDir() + "/" + scrImage; + fileFromProjectDir = true; + } + + QString destAddr = getProjectRootDir() + "/" + getLayersDir(); // destination directory + QString newFileName_part = scrFi.baseName(); // renaming of the file + QString newFileName_whole; // final file name for XML entry + + // for SAVE it does not copy files that already exist in the project + bool makeCopy = true; + QFile testExist(scrImage); + if (!removeSubDirs && fileFromProjectDir && testExist.exists()) { + makeCopy = false; + newFileName_whole = getLayers()[i]; + } + + if (makeCopy && !fileCopy(scrImage, destAddr, newFileName_part, &newFileName_whole)) { + removeDir(getProjectRootDir()); + return false; + } + + if (makeCopy) { + tmpL[i] = newFileName_whole; + } + + importedLayerFilesXML += "\t\t" + newFileName_whole + "\n"; + } + setLayers(tmpL); + + + // XML format of the project file + QTextStream ts( &mapro ); + ts << "" << endl << + "\t" + PROJVERSION + "" << endl << + "\t" + getProjectName() + "" << endl << + "\t" + importedInt + "" << endl << + "\t" + getImagesDir() + "" << endl << + "\t" + getLayersDir() + "" << endl << + "\t" << endl; + if (importedImageFilesXML.length() > 0) { + ts << importedImageFilesXML; + } + ts << "\t" << endl << + "\t" << endl; + if (importedLayerFilesXML.length() > 0) { + ts << importedLayerFilesXML; + } + ts << "\t" << endl << + "" << endl; + + mapro.close(); + return true; +} + +bool Project::deleteAnalysing(int index) { + // prepare path for removing of a file + QString fileToRemove = getProjectRootDir() + "/"; + fileToRemove += getLayersDir() + "/"; + fileToRemove += getSelectedLayer(index); + + // remove file from LAYERs + eraseSelectedLayer(index); + return QFile::remove(fileToRemove); +} + + +bool Project::deleteImported(int index) { + // prepare path for removing of a file + QString fileToRemove = getProjectRootDir() + "/"; + fileToRemove += getImagesDir() + "/"; + fileToRemove += getSelectedImage(index); + + // remove file from BACKGROUNDs + eraseSelectedImage(index); + + // samotne smazani souboru + return QFile::remove(fileToRemove); +} + + diff --git a/project.h b/project.h new file mode 100644 index 0000000..c01f23b --- /dev/null +++ b/project.h @@ -0,0 +1,104 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file project.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef PROJECT_H +#define PROJECT_H + +#include +#include +#include +#include +#include + +#include + +// singleton +#include "./libs/staticsingleton.h" + +class Project : public QObject +{ + Q_OBJECT + +public: + static const QString PROJVERSION; + static const QString PROJSUBDIR_IMAGES; + static const QString PROJSUBDIR_LAYERS; + static const QString XML_TRUE; + static const QString XML_FALSE; + static const QString PROJ_FILE_EXT; + + void valueInit(); + + void setProjectName (QString name); + QString getProjectName (void); + void setProjectFileName (QString name); + QString getProjectFileName (void); + void setProjectRootDir (QString s); + QString getProjectRootDir (void); + void setProjectRootDir_old (QString s); + QString getProjectRootDir_old (void); + void setImagesDir (QString s); + QString getImagesDir (void); + void setLayersDir (QString s); + QString getLayersDir (void); + void setFileImported (bool i); + bool getFileImported (void); + + void setImages (std::vector i); + std::vector getImages (void); + void addToImages (QString s); + QString getSelectedImage (unsigned int index); + void eraseSelectedImage(unsigned int index); + void emitDeleteImported(); + + void setLayers (std::vector i); + std::vector getLayers (void); + void addToLayers (QString s); + QString getSelectedLayer (unsigned int index); + void eraseSelectedLayer(unsigned int index); + void emitDeleteAnalysings(); + int layersCount(); + + void prepareProject(QString rootDir, QString projectName, + QString projectFileName, bool fileImported, + std::vector images, std::vector layers); + bool saveToFile(bool removeSubDirs); + bool fileCopy(QString fileName, QString destDir, QString destFilename, QString * newFileName); + bool removeDir(QString dirName); + + bool deleteAnalysing(int index); + bool deleteImported(int index); + +signals: + void imagesValueChanged(); + void layersValueChanged(); + +public slots: + +private: + // constructor, destructor private = singleton + explicit Project(QObject *parent = 0); + ~Project(); + // friend allows singleton to be created by this object + friend class cStaticSingleton; + + QString projectRootDir; + QString projectRootDir_old; + QString projectFileName; + QString projectName; + bool fileImported; + QString imagesDir; + QString layersDir; + std::vector images; + std::vector layers; +}; + +// singleton instance of the project +typedef cStaticSingleton cProject; + +#endif // PROJECT_H diff --git a/projectwizard.cpp b/projectwizard.cpp new file mode 100644 index 0000000..65e7117 --- /dev/null +++ b/projectwizard.cpp @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file projectwizard.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include "projectwizard.h" +#include "xmlparser.h" +#include "mainwindow.h" + +ProjectWizard::ProjectWizard(QWidget *parent) : QWizard(parent) { + + addPage(new WelcomePage); + addPage(new ProjectInfoPage); + + setWindowTitle(tr("New Project Wizard")); +} + +void ProjectWizard::accept() { + + QString projectName = field("projectName").toString(); + QString projectDir = field("projectDir").toString(); + bool checkBox = field("importFileCheck").toBool(); + QString imageFileName = field("imageFile").toString(); + + std::vector imagesVect; + std::vector layersVect; + + // import of a file + if (checkBox) { + imagesVect.push_back(imageFileName); + } + + QString projectFileName = projectName + Project::PROJ_FILE_EXT; + + // make the new project file in the project root + cProject::Instance()->prepareProject(projectDir, projectName, projectFileName, checkBox, imagesVect, layersVect); + bool removeSubDirs = true; + cProject::Instance()->saveToFile(removeSubDirs); + + QDialog::accept(); + + QMessageBox::information(this, tr("microAnalyzer :: PROJECT CREATED"), tr("The project \"%1\" was successfully created.").arg(projectName)); +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + +WelcomePage::WelcomePage(QWidget *parent): QWizardPage(parent) { + + setTitle(tr("Welcome to New Project Wizard!")); + + label = new QLabel(tr("

This wizard will create a New Project directory " + "with basic configuration. It is needed to fill only few information.

" + "

Click next to continue, please.

")); + + label->setWordWrap(true); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(label); + setLayout(layout); +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- + +ProjectInfoPage::ProjectInfoPage(QWidget *parent): QWizardPage(parent) { + + setTitle(tr("Project details
")); + + // name of the project + projectNameLabel = new QLabel(tr("Project name:")); + projectNameLineEdit = new QLineEdit; + projectNameLabel->setBuddy(projectNameLineEdit); + + // root dir of the project + projectDirLabel = new QLabel(tr("Choose &project root directory:")); + projectDirLineEdit = new QLineEdit; + projectDirLabel->setBuddy(projectDirLineEdit); + chooseDirBtn = new QPushButton("Choose dir"); + connect(chooseDirBtn, SIGNAL(clicked()), this, SLOT(browseDirs())); + + // image import + imageImportLabel = new QLabel(tr("Choose &image file to import:")); + imageImportLineEdit = new QLineEdit; + imageImportLineEdit->setEnabled(false); + imageImportLabel->setBuddy(imageImportLineEdit); + importFileCheckBox = new QCheckBox(tr("Import image file now.")); + importImageBtn = new QPushButton("Import image"); + importImageBtn->setEnabled(false); + connect(importImageBtn, SIGNAL(clicked()), this, SLOT(openImageFile())); + connect(importFileCheckBox, SIGNAL(toggled(bool)), importImageBtn, SLOT(setEnabled(bool))); + connect(importFileCheckBox, SIGNAL(toggled(bool)), imageImportLineEdit, SLOT(setEnabled(bool))); + + registerField("projectName*", projectNameLineEdit); + registerField("projectDir*", projectDirLineEdit); + registerField("importFileCheck", importFileCheckBox); + registerField("imageFile", imageImportLineEdit); + + // UI wizard + QGridLayout *layout = new QGridLayout; + layout->addWidget(projectNameLabel, 0, 0); + layout->addWidget(projectNameLineEdit, 0, 1, 1, 3); + + QLabel *separatorLabel1 = new QLabel(tr(" ")); + layout->addWidget(separatorLabel1, 1, 0); + + layout->addWidget(projectDirLabel, 2, 0); + layout->addWidget(projectDirLineEdit, 3, 0, 1, 3); + layout->addWidget(chooseDirBtn, 3, 3); + + QLabel *separatorLabel = new QLabel(tr(" ")); + layout->addWidget(separatorLabel, 4, 0); + + layout->addWidget(importFileCheckBox, 5, 0); + layout->addWidget(imageImportLabel, 6, 0); + layout->addWidget(imageImportLineEdit, 7, 0, 1, 3); + layout->addWidget(importImageBtn, 7, 3); + + setLayout(layout); +} + + +void ProjectInfoPage::browseDirs() { + QString directory = QFileDialog::getExistingDirectory(0 , "Choose project root directory", QDir::currentPath()); + if (!directory.isEmpty()) { + projectDirLineEdit->setText(directory); + } +} + +/* + * Load image + */ +void ProjectInfoPage::openImageFile() { + QString imageFileName = QFileDialog::getOpenFileName(this, tr("Open Image"), QDir::currentPath(), "*.bmp *.png *.tif *.jpg *.jpeg"); + if (!imageFileName.isEmpty()) { + imageImportLineEdit->setText(imageFileName); + } +} + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- diff --git a/projectwizard.h b/projectwizard.h new file mode 100644 index 0000000..e79b99e --- /dev/null +++ b/projectwizard.h @@ -0,0 +1,81 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file projectwizard.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef PROJECTWIZARD_H +#define PROJECTWIZARD_H + +#include + +// singleton +#include "project.h" + +class QCheckBox; +class QMessageBox; +class QGroupBox; +class QLabel; +class QLineEdit; +class QRadioButton; +class QPushButton; +class MainWindow; + +class ProjectWizard : public QWizard +{ + Q_OBJECT + +public: + explicit ProjectWizard(QWidget *parent = 0); + void accept(); + +signals: + +public slots: + +}; + +// -------------------------------------------- +class WelcomePage : public QWizardPage +{ + Q_OBJECT + +public: + WelcomePage(QWidget *parent = 0); + +private: + QLabel *label; +}; + +// -------------------------------------------- +class ProjectInfoPage : public QWizardPage +{ + Q_OBJECT + +public: + ProjectInfoPage(QWidget *parent = 0); + +private slots: + void openImageFile(); + void browseDirs(); + +private: + QLabel *projectNameLabel; + QLineEdit *projectNameLineEdit; + + QLabel *projectDirLabel; + QLineEdit *projectDirLineEdit; + + QCheckBox *importFileCheckBox; + QGroupBox *groupBox; + + QLabel *imageImportLabel; + QLineEdit *imageImportLineEdit; + + QPushButton *importImageBtn; + QPushButton *chooseDirBtn; +}; + +#endif // PROJECTWIZARD_H diff --git a/tableformat.cpp b/tableformat.cpp new file mode 100644 index 0000000..304e3f2 --- /dev/null +++ b/tableformat.cpp @@ -0,0 +1,146 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file tebleformat.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "tableformat.h" + +TableFormat::TableFormat(QObject *parent): QAbstractTableModel(parent) { +} + +TableFormat::TableFormat(QList pairs, QObject *parent) : QAbstractTableModel(parent) { + listOfPairs = pairs; +} + +Qt::ItemFlags TableFormat::flags(const QModelIndex &index) const { + + Qt::ItemFlags result = QAbstractTableModel::flags(index); + if (index.column() == 0) { + result = Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsEnabled; + return result; + } + + if (!index.isValid()) { + return Qt::ItemIsEnabled; + } + + return QAbstractTableModel::flags(index); +} + +int TableFormat::rowCount(const QModelIndex &parent) const { + Q_UNUSED(parent); + return listOfPairs.size(); +} + +int TableFormat::columnCount(const QModelIndex &parent) const { + Q_UNUSED(parent); + return 3; +} + +QVariant TableFormat::data(const QModelIndex &index, int role) const { + if (!index.isValid()) { + return QVariant(); + } + + if (index.row() >= listOfPairs.size() || index.row() < 0) { + return QVariant(); + } + + LayerRecord * currentRow = listOfPairs.at(index.row()); + if (role == Qt::CheckStateRole && index.column() == 0) { + return currentRow->getCheckBox(); + } + + if (role == Qt::DisplayRole) { + if (index.column() == 0) { + // checkBox + } + else if (index.column() == 1) { + return currentRow->getName(); + } + else if (index.column() == 2) { + return currentRow->getOpacity(); + } + } + return QVariant(); +} + +QVariant TableFormat::headerData(int section, Qt::Orientation orientation, int role) const { + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) { + switch (section) { + case 0: + return tr(""); + case 1: + return tr("Layer"); + case 2: + return tr("%"); + + default: + return QVariant(); + } + } + return QVariant(); +} + +bool TableFormat::insertRows(int position, int rows, const QModelIndex &index) { + Q_UNUSED(index); + beginInsertRows(QModelIndex(), position, position+rows-1); + + for (int row = 0; row < rows; row++) { + QString s1 = " "; + listOfPairs.insert(0, new LayerRecord(true, s1, s1)); + } + + endInsertRows(); + return true; +} + +bool TableFormat::removeRows(int position, int rows, const QModelIndex &index) { + Q_UNUSED(index); + beginRemoveRows(QModelIndex(), position, position+rows-1); + + for (int row=0; row < rows; ++row) { + listOfPairs.removeAt(position); + } + + endRemoveRows(); + return true; +} + +bool TableFormat::setData(const QModelIndex &index, const QVariant &value, int role) { + + if (index.isValid() && role == Qt::EditRole) { + int row = index.row(); + + LayerRecord * p = listOfPairs.value(row); + + if (index.column() == 0) { + } + else if (index.column() == 1) { + p->setName(value.toString()); + } + else if (index.column() == 2) { + p->setOpacity(value.toString()); + } + else { + return false; + } + + listOfPairs.replace(row, p); + emit(dataChanged(index, index)); + + return true; + } + + return false; +} + +QList TableFormat::getList() { + return listOfPairs; +} diff --git a/tableformat.h b/tableformat.h new file mode 100644 index 0000000..e2be16a --- /dev/null +++ b/tableformat.h @@ -0,0 +1,41 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file tableformat.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TABLEFORMAT_H +#define TABLEFORMAT_H + +#include +#include + +#include "layerrecord.h" + + class TableFormat : public QAbstractTableModel + { + Q_OBJECT + + public: + TableFormat(QObject *parent=0); + TableFormat(QList listofPairs, QObject *parent=0); + + Qt::ItemFlags flags(const QModelIndex &index) const; + + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + + bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole); + bool insertRows(int position, int rows, const QModelIndex &index=QModelIndex()); + bool removeRows(int position, int rows, const QModelIndex &index=QModelIndex()); + QList getList(); + + private: + QList listOfPairs; + }; + +#endif // TABLEFORMAT_H diff --git a/xmlparser.cpp b/xmlparser.cpp new file mode 100644 index 0000000..01bb39d --- /dev/null +++ b/xmlparser.cpp @@ -0,0 +1,87 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file xmlparser.cpp + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#include "xmlparser.h" +#include "project.h" +#include "mainwindow.h" + +XMLparser::XMLparser(QWidget *parent) : + QMainWindow(parent) +{ +} + +bool XMLparser::read(QIODevice *device) { + + QString errorStr; + int errorLine; + int errorColumn; + + if (!domDocument.setContent(device, true, &errorStr, &errorLine, &errorColumn)) { + QMessageBox::information(this, tr("microAnalyzer :: ERROR"), + tr("Project file parse error at line %1, column %2:\n%3") + .arg(errorLine) + .arg(errorColumn) + .arg(errorStr)); + return false; + } + + QDomElement root = domDocument.documentElement(); + + if (root.tagName() != "ma_project") { + QMessageBox::critical(window(), tr("microAnalyzer :: ERROR"), tr("The file is not a microAnalyzer project file.")); + return false; + } else if (root.hasAttribute("version") && root.attribute("version") != "1.0") { + QMessageBox::critical(window(), tr("microAnalyzer :: ERROR"), tr("The file is not a microAnalyzer project file version 1.0.")); + return false; + } + + // basic values + QString childName = root.firstChildElement("name").text(); + QString childFileImported = root.firstChildElement("fileImported").text(); + QString childImagesDir = root.firstChildElement("imagesDir").text(); + QString childLayersDir = root.firstChildElement("layersDir").text(); + + // load information from xml to the project instance + cProject::Instance()->setProjectName(childName); + cProject::Instance()->setFileImported((childFileImported == Project::XML_TRUE) ? true : false); + cProject::Instance()->setImagesDir(childImagesDir); + cProject::Instance()->setLayersDir(childLayersDir); + cProject::Instance()->setProjectFileName(cProject::Instance()->getProjectName() + Project::PROJ_FILE_EXT); + + // load imported images for backgrounds + std::vector imgVect; + if (childFileImported == Project::XML_TRUE) { + + QDomElement childImagesRoot = root.firstChildElement("images"); + if (!childImagesRoot.isNull()) { + + QDomElement childImages = childImagesRoot.firstChildElement("image"); + while (!childImages.isNull()) { + imgVect.push_back(childImages.text()); + childImages = childImages.nextSiblingElement("image"); + } + } + } + cProject::Instance()->setImages(imgVect); + + // load imported layers + std::vector layers; + QDomElement childLayersRoot = root.firstChildElement("layers"); + if (!childLayersRoot.isNull()) { + + QDomElement childLayers = childLayersRoot.firstChildElement("layer"); + while (!childLayers.isNull()) { + layers.push_back(childLayers.text()); + childLayers = childLayers.nextSiblingElement("layer"); + } + } + cProject::Instance()->setLayers(layers); + + return true; +} + diff --git a/xmlparser.h b/xmlparser.h new file mode 100644 index 0000000..2a1ed13 --- /dev/null +++ b/xmlparser.h @@ -0,0 +1,37 @@ +//////////////////////////////////////////////////////////////////////////////// +/** + * \file xmlparser.h + * \version v1.0 + * \author Ing. Dominik Malcik + */ +//////////////////////////////////////////////////////////////////////////////// + +#ifndef XMLPARSER_H +#define XMLPARSER_H + +#include +#include +#include +#include + +// singleton +#include "project.h" + +class XMLparser : public QMainWindow +{ + Q_OBJECT + +public: + explicit XMLparser(QWidget *parent = 0); + bool read(QIODevice *file); + +signals: + +public slots: + +private: + QDomDocument domDocument; + +}; + +#endif // XMLPARSER_H