From d67477a27ccf7f219af8464d6b93a50b9b9784cc Mon Sep 17 00:00:00 2001 From: Cosmin Vlaicu Date: Thu, 12 Dec 2024 20:25:55 +0200 Subject: [PATCH] Initial detect and track module based on CV alone. --- crop-helper.py | 51 ++++++++++++++++++++++++++++ cropped_image.png | Bin 0 -> 18825 bytes detect.py | 49 +++++++++++++++++++++++++++ detect_and_track.py | 72 +++++++++++++++++++++++++++++++++++++++ detector.py | 81 ++++++++++++++++++++++++++++++++++++++++++++ mov_to_png.py | 41 ++++++++++++++++++++++ requirements.txt | 4 +++ tracker.py | 30 ++++++++++++++++ 8 files changed, 328 insertions(+) create mode 100644 crop-helper.py create mode 100644 cropped_image.png create mode 100644 detect.py create mode 100644 detect_and_track.py create mode 100644 detector.py create mode 100644 mov_to_png.py create mode 100644 requirements.txt create mode 100644 tracker.py diff --git a/crop-helper.py b/crop-helper.py new file mode 100644 index 0000000..a9c1631 --- /dev/null +++ b/crop-helper.py @@ -0,0 +1,51 @@ +import cv2 as cv +import numpy as np + +points = [] + +def click_event(event, x, y, flags, param): + global points, img_copy + if event == cv.EVENT_LBUTTONDOWN: + points.append((x, y)) + cv.circle(img_copy, (x, y), 5, (0, 0, 255), -1) + cv.imshow("Image", img_copy) + + if len(points) == 4: + for i in range(4): + cv.line(img_copy, points[i], points[(i+1) % 4], (0, 255, 0), 2) + cv.imshow("Image", img_copy) + crop_box() + +def crop_box(): + global points, img + src_pts = np.array(points, dtype="float32") + + width = int(max(np.linalg.norm(src_pts[0] - src_pts[1]), np.linalg.norm(src_pts[2] - src_pts[3]))) + height = int(max(np.linalg.norm(src_pts[1] - src_pts[2]), np.linalg.norm(src_pts[3] - src_pts[0]))) + + dst_pts = np.array([ + [0, 0], + [width - 1, 0], + [width - 1, height - 1], + [0, height - 1] + ], dtype="float32") + + M = cv.getPerspectiveTransform(src_pts, dst_pts) + + cropped_img = cv.warpPerspective(img, M, (width, height)) + + cv.imshow("Cropped Image", cropped_img) + cv.imwrite("cropped_image.png", cropped_img) + + cv.waitKey(0) + cv.destroyAllWindows() + +img_path = "/Users/vlacosmi/Documents/Personal/detect_picture/detect-flying-kitties-main/video-frames/frame_0953.png" +img = cv.imread(img_path) +img_copy = img.copy() + +cv.imshow("Image", img_copy) +cv.setMouseCallback("Image", click_event) + +cv.waitKey(0) +cv.destroyAllWindows() diff --git a/cropped_image.png b/cropped_image.png new file mode 100644 index 0000000000000000000000000000000000000000..853d2e399758b91966e58f6383ab523647e3718a GIT binary patch literal 18825 zcmY&=2{_d2+y8f_Nh3>R>L8S%5u%Va#E>*&EtzBq*~ykvJoonb+@JfN6MR$a2Genl;}8Tf5%4NH;CC?i z+Xe{-|5P(pDT5#kL{L%E^?<#v4UWAx<9YVi#@@c)qIjRH9o^0NWBwTeA1w%4P2t5p zu&T&`96fEfAvbhH!S`6&aZB~jDaNe@XA&}GAViR-0CZIMpW`^DnLm{Wi}O#UZkqjb z-|c&@{0YD9e#Km!qd2BN=LCbX5JmNzVDl7&?E7|;NjU&(r>u!$7AKIfT$oxuh=N3= zMg`UnK)22b;4eW~7#Ty4kb>UAu1sQT^e{>`cqoYDVGx!=fyfPPD5m3eFbXbB$wv!K zAYh3{CaEwo;_bAgU~6H*Y(j0Du-|e(DpuPD4}VRkgaV%?!NGCq7%ra_*@|% z7*RMMEmFp$S2O;ndL-h3#~Bz|)l8VIat)373VVt{!r_=dQ7Ssfq`Qh5jb>JAXY-RUWfvH2{}-Nhn^`eUmFdTVdJ8Q`KCM{h=M1ljF0X0 zYENAXB`}k8!?4VlV3V-O=W#(#D8rR5Hv&kfACj<0$ycyC7!2H+sr&C0dJ=+^fxLOj z4guHrrjCUn$p|gaMLlo$^KL$xM3Kt__nex5~(1V~-lCVMGYHD6RCF8{l{YA4l)+0~B zUMjcaj@(-yVJJ3u-e5f&2&;tlRYE}oOcx4crUAFbR^i^#lZ|9lfcH>Xa58_VnL_-T zw$ApY8)FAz|M%cfiV@llj;WY*2JwhMAKo<>%kiGx%15vU%g;nQNjZYSR4D5p1mLK! zj7bWTfL-FCpmYQ5WHiw0^e709f%V})9FgiDk}*hsEKbBz^J|fhDEoiT+mR#uh@XV; zy&%{XD4Uj%Z&?tyw8lwh5?X>TO%+WtVm=0fZ~PG@KVk=mK#?M$BLYYa2PJ(RqzQrL zHN=ibQ7|A#!JjACL(xVrFb&9NK8T~9y_N$9p7`(CUF5)57<#5=7=HN`*?P;=N>ov? z)4h7bom?Z<3?oxvnBXVarR!Kb1dRNa#iWi8IuAny(kaCq!KZ*wF~zPE>J&KW{Y5Ft z7fGt;X3-EZ2cEemI1c|3x=zM4>K^&AVE>wjUeaFza`|MWL*(0-T$p#u77jt3BXHpk zbL3$>7CL;4q!N0az>L#zi4*EHEDER{9_AX`YpuQ>W==VRJ;Oxtc!t2iv33myBGKUJ zV2~j(7a$jyC>Jk169XMdvIYmitTLb%5LuUrj6mk))4}PG2t1W;98$_4T%v~vL1?VD z;6IkL&DZkfo#yA~tvt^vg9jq;X-eo91o#hUh=Rd`vT}qRt>dC6zFYZ@z_s-^dr z3}q2bQwr^3^lzP_!hkX9QE8L#&&eITyFS&5w@!U&Pn33Zb2krSWjuCR1O9ah?Co^j zeQ*U`VobR~?z*Yy-FTB9<$hb{6gar&zky%y+~gk^ejq#U^&~wLT=gfP@+C+Dj;?rmE+Wz+oV$px$qoFsvQ+NEo8#iPfE0%NWWq3=hYld2x`~^RlwC6}C%U`U-_b zMJp!`{+is;*+-xfDmS=spc&r3^5IgVA`i?s}83B>*pM>A1CrjRl~(fH3T zqABHt!l}v0_YTc5wnGo9ei!E1^T^Fb6%tkrp&KyC`;LwP=^W>2V9%jaEHb)8&v#?_ z!z_?*)cAtw9>zCvF%h_mIGRz6ro@=~@qB@nO0&C(N%2YXznX-jgfg*ZqN+;DE^#4Y zsJexP4riI9q@zk);Cd_!uLg>SjLIpHJ%VNBh4D;Q$3hrFcDpwGULL{2 z!@*r#uppyEcu4HGnO>{l0Lmfn%Wx_9{QWzgevC#Fxf6ay(R=z&LxYMKN0|;X*0M|* z6b^bxS=^COI(pK{x_>W;Z4Z?YZ)As6c`WUY*S{!r8q+uQOZu|e$mx_M`Z3Ft?(w&-~EZgMJ0?!ZI;&@s)Nb-<936MJ&L~!E>D4ush~-L!mS~<9v+O2Y>av@7ClJ4C?f2)!ddOM zzq{pF%IP18ryz0Wm-^WubfCblza5H$nI01?R%Ovx_&!C^ucV~JZDl%F&fPJBy4 zVzu8?OYghjcco)qJFD+*@A-}~O7i3VNv}DK#exnkLb=8aDzDh9gpB0m8lq$)h#PR^?m?@Aq@(Ky4O*TTcz(wp-_6ubD-5aH0S67a(~01V2Ro@4}J z$0b1|lp%OR28V}tO-27r9u6!Y40H7BSN0?A(EU&gTmT4IbIQ#gAqauWBa0sQ$3hYu zwpNgNXzhFUFonILwWGbWdTlx}TPu|=zo^_W^EjXal$$4EheZ!K^b-Pi z38MVvsD1&jwC4~ zGVrw?goi7kNZ1!#bqekxtyE!#Za23QZUvvsUtQ?{7h+;2oT~Twe*UDCJ1x# zq$^;AcwU?iyjH$*S=jG$+1BXJqDl4k;Lo}`r~PTCOWgXSv=Q3i;KLxE_|q`hdl=VA zY}p}Ez9#t<2I^Y6a899ckuYs!MBjV$*Z$rPk(m3QOVMw+Z4>TXMky}`J{S8LhY2OX zF~PXk>TnFG3VjHqSjfDax5R}@_dc(VcKY_syH>9_?YAe0TelSY?C*NsieXgc;ILS8ljI+6wx*t6;wIz2PB21SDA*nXL6^m1B5Ay&(Se z8QnXSa>|UDYF;x8_+Qb59*1+Ghhx4Wb(ocOkUTk4Tie@F2ip+`t}EMN;?|w}eNKCQ zfByVgndx-fSij)j%=fVE?@I>I&44P0g%+q~A`uxNRe@8kGaxkJIU9+(-~gmQ2CKw=4iCpD zK?oJlbdUp|P+=5I1(ts2J3a-u?o~NBI5;~ixZiHF>kw;6)Q<$8kI{R{<5oU`3NVs{ zENWnszkEi=Jp@4?_>B*Vpl8>-sit+=DcaI=V*6vN-)8Oh_VzOdwyK?x#SV>5dGG!A z0xzQhA#Lu$(8E!Ob%-5b6O|oJ)s3;F$2>=pEZWkHE>*8KXBxy>n|SUBS$Cv9_-MG0 zqT|8_S}_DkLR>rT7RYW~ML6j9usjf8+5_1f82UPOiZiJ^I~u>fvj?u-+)Tf3;Vpos#iT3lms(cGW%}9oY~4ue8y>!*Z}aPg^2#pm1k!li zxnKxJu~Ic>6^B$`ktv*niH^~;96Shd+R)HvueIL*?G(9~{U)S+Cun2)Zl$!rQQxZ4 z(l|;~G$I%tG%_+D78W*=JW_Z;ZocFD_tn+!uA_D_=3m~jTZx6}ySj^q@Z5R#`SD60 zf1Cn=DC@O5FjzFh8pq1_&vhPp9J01;_zc8p6ZDqA8w?^w6)<^`U_cxJGNBHs)v-_B zF&F&zeEl4K9nH-A{r0REr}blX;0PpBvyyB1o?H1*Pc;JCbd!(J5Z_hEUOwWe_Ktdi zpu`?_oWsyF$3Ft}=-769Cnu-JkJkcDD17o;u1Z!G7P@S&&fd<}-q?8}F4PkFnw>Yy zGllK?!-?&%9KAfpt2D2PI!>p`m6*Y@vO?kK^*l8)toW?x;d?s7Om_2}7;F7lj!R`p zSR76gWFfghBsH3wPEtlAA2Vkf5pux?h=FCXfy_g?GnhL_SkB#?vSWd3Ic`M zH$X2h;szWtc}2bD_w<0`x7o2pBt07rxLh3a_d*iUn$bcf7{ zDC}>&;P&}jJMmGH0=k|4xigBsyUFgOSA2b@23iUbVbAN+gq0_jCiuCZtad3LtSD}H zRUSeo+n9&BsNBGVuTu+i4xKe#!G)6AGw( zE!>(WESG!-IX<{zy|FM-4hm*_b|Sxa%5K=$Zu{1kXNAHy>TgN3uCN9t&nNF}0M_$x zZ#pcozAJxh?u6B`qJY7e38AKN?!|R4R^c+ecNB(i>M|s(9WQfK;Bz|&L9oHs2~mdm z-1)Cuy>dlbT3Sr(e=LFJBSUvHFB2`ZX|o&KtinVB6S*N?^gMkY&#AAXR$tzJdbG3t z0u;i%p^tZRIQ?@K_4&INHzLl;t$)m`Tv?|%xu5p}&{W@b^MhlaVd%@b{ttV5V+VWn zA8*_U=h~aj+Z!5uG^30JHWYqYC@g(evCMV08?c&`Y7a5F_y?slkm^L@8QutoDbtmGi(cT}xf%@a(B6f59*5+n9lEsV0ougYWGq5y-u!;1gz8@=h zU+fV|H7<9%7_X_Nsi~>8wzHR+nR(l~GfBoXt!G{qAQF)X2r}jE|F3QLQ?a3hzXmSS zMT0=@G<9=vp&X`$n{0BSFbs%G`D&I#))C{L@$5CH?lu3 zuRj3*rZRP}ElNb>4A1=1(9rsN$b540ot(9Hr~M(l>g|t!U(glh=2|~^@PMcffEG~W z4MmTGiPpFx;T`U(^^ek*jFVDRLwJ~9)PvsK(cZYyYbr`T4#ay_Hl2Pf6ZqExUVHnA zY$CoZhGW0nKErj0F_vXptF!!i3T2)vv6Fyj$2dKiOYFIQ+mfhsoKY+=js2>}-ye-( zobEsl@bg>S3YqbYEgj00Z}mR8riwSO7k`SL+3HwdUsxD*{-j5=we$MjmLP6&u-(tf$|@x# z1!!1BNr{x0Sl7H;s=TKQ2x(xSb4}q@ThocwohkEcUb%P5gKX!{Cl;fE1j-eCjPXB zrsm_Jd2l(JyQ4{!&sO8woSa;_r;s*rN+)He(pb^z;q0%-l^GGPt8T?Tv$~d&7gQIt zCgN{`))@}eH3{7#K-N+qyuC%Dc&iBpipIY>%}96qcGRxo!Nl0A*GS=eto1d2fGD7b z<@JZ@-vQFo$uzDV#GCV2ESGBcSNX;W`S(PuNi*G^MIt9ZFD{Uc~zb9n}WPx4o7cgO*PZD3$D?DKi6 znLpL2%xkSxCQdLP7WT_DQ0*IhPPGi1u{(!|G&{jI$X-}TYH zmE76jckhCmee?PkH~8!w9Y0A(N=mXbQsPjm>9@*9n8iGnK|h~sZP;020%}EyocnsR zdzGx5VrfCa(oz%m*yqO&WVm99gAU+C7w&LXvB0Qot$V;8o}Pn@AQ$66O9t4(!sz<< z@4BV5Ffop|lPTSxhp4Mlem%c1uQ1~ExvHR`w6uTDtzG%nsY9)c;Z=KkN3!gr?a6ny zfj8z|bi9Of17~^w~#_B-LI|H=xsU~;(*RT+8v_HFS1 zrRuSn)C2A@&?dd3PNw8{W=89<7HO46S(kaMEs%iN+6$Sr5m{8~r=U=f7AWCP7pOC( z^3#)*z9#M`75kITpx(Hc@dlcHM9GJJk>^KZ-N!~oMuvxnM+cdCcyCJ9_*?2La51^N zxh>0|u(A+kU~K~}2Q>K+wB{8Tatf*FCevCxS;F9L7cz4a1lQ9yR*hYNb*;I|a5y+Q zH3`pc>@?|xSFf!b@@pmi($)xi%OMl`f8KOI5c*U;$ zB(imv@eOT$+B3z6kt`2$b|3!-{^9t}_n_UQtt-N<25>iH`>_h&2~cECeNGNffV~e> ztuK7fWz6~oltE6Z;Q_~w${-PDo3BQK=|w_hLwuy}5hg;)@a@z79}VVF{$#ra=9)IM zHuyybp3W6^cp$rS>`Wlgxl^60F=35BcK-6^%SnDME;+aNBaRU*X#(o*+JfVvlmUJm zZ)4!||MJXz1U8Nf7y8i7Dr;;}Q(Jo_;$TBDH8D}WdF13eA9n~(v0SoztC5R)Gtc29 z#14Y#!9hZQFvZ>#FN(LURn8Y3KI7{(+r785F;YpJy^B;!(cxfzaa}(Ha9w@ySM2p$ zp)Zx6v!4rf(f+`J=V))^llTRCxVJ1RT*e9dZH1=ODJ@jEN_U%CsApRtilD}f=`3U~ zVmBueL7-_kh!%bN^hvZ@l%3IQFC~MGMoTZm2wZ{2A7PiS97kZTaQqi0nP9Y);l|Ws;KZ;{TeyJAASNr z{hb^twaZ2~HnWwW2LI6@LT;E5K#?YG@IZuu{INcfm^Uo`ni`sJ<&_Bur}tkRtZC28 z%-y$n5S{?@7BMFIP0ZG zF|wO_XlG|9Do0EG#YSBFF<#%E&B+sZCueFQ-7K0aA$((j8AXC5@oD$Xm_%3*U7|Jj zbkG)7|F$-k`gHkpo)@UmI{Go`UBAABu+6*4buL%L#9c4T|Kz;BngHUfP2`e=ehI*a z((;)F3_fkVK^^-Lc@$0ta{wDKbW}ncUwcbe6PoMD-?{8o-tKo$y*oR+%hjw)gz#!q z9g19gp>PNfN%sg|MkNrb{Ehv`OP)^_R$`4H>^PWS$aR_+ZLPLsryBdN|IrVM#Kq1u zMdTUDfL8P28`|7_*mL)V;WFQeA@DOgnm^+BvHT1HT&FqNiq(HON{(5Sf1LmabOrAM ziGj-4JGUmA{NZ#++FNS$GnuYA0J0zD<_m@O^z^`Nq@=VoYEq6Ki9|K}ous#s4KsI7V&0rT3_BEt-XB}>{AO6j>1(X*@UY$VgRKbAge}`Qt(5!y zhtX0ln>1*!k0!YY0$Bx+^t4NrD42 za951upX+a)yuAW+9aSW&Ib*FEvM)&N)icmdq~E`F3J8s!wp&1mS8r_vl^DyNd-b!= zY=0iX#j(QLR+$FBeGbJ01=ugBS>gwxgtj zAvG9!etp)Df}5(6{B2l^zA6G7tFQZMhU5VaaS_HdhJy9yxyytNRIQsy!hp^RiF<3Q z-{)95a;AB4xa`s1_L^a-<3HC~LT`i%-}~fz-`7#0wea1$cUq-$-J{NV8iK9qgm>&?(9YJYa4@e9zJ|%Wkt4R`O(qQ5zyP4*q=A{+4I5U$C93} zer@R8xucb=@MQhZ;In7XP|Etz>1MjDmdl8mV2&on7xdrb|JT#&6kZr2=iL$y7TgbP zY(1|8lBsGGeX{&kd}JRaKu;d$<3F78gK;(MHKbUq<<{TYfEPJAdWz*GRaK+2u3D*A zp8WaM6%&)rz`$^dOKrL9E!kV2xNx>;V7AySw0`{8Xys1oy}dt;?SP8P?FAc`kIb%l zB|DZ18w-Y{3A9F2^e*wlKmMF-oF{$t>Q#0|(1XWN3xz=xgHcgMS($z;pKVXi?U~Nh zYUlB=FJF%4JQL*z!|Ef!tC(+`I4gg*@=>1K#=<>u!@EYGJb>`EGQ&2_HgwqhS`uTg zC&=?5N&3*?ih=~ft_{T1bD+UZ);&Ouv%%Zn_u4IO_|BY&;JSiV#si5@7@soCrynMH zME8iPNAuDZ3X*41EGOoAK|xvB=g-?f&;Z?6Zm-?NOP5melI5fo6~`QBQYyH@E@*qF z-y#xu5EK$3p`h393;XSa6i3I=GWU(fc1|EK69hlflHJOaXRb6yQ`3MTu_}fr0t&ScrgzyBl@fl$=e?u>uv?w+RxpbKlM3YHFFsJCJ_0FQ%% z{T7Bi9z;#3B#Tw-%oV@IvHjZR$a7+i(UjqK|4BRNHoO{KSKKH36m%V{Y%@L4>lBb5+siT{JhJXlv7R1NLkG+l` z!_UaMfdUEy9FPu;!kl5MAYGs&FhoCw{6EpITpud>>X~rorg!zqi`LfG|GZj*NdoBM zUq@i<3OCgJ^^vs@X#K0brdrnK`coC29N!!)vaa4=%LDT?YX6)*(y%i%#&VWO)tOpm zH!J?J+;Z~PNvH^A&d9S`KB9YPLvL}c!gH=Rpf@-7A`(jsz|%2!3Q3Ei3vRr{c6;goh7F89_0Ot>4URv`b1DvFaV2lKf==bx#DCXfdBZ<>b#ZiE0DIh*k{ zBne9qea^ltKLdnFMFS&)<2)WN&4eRhTnT^_dwQ{4$YejHEE?PRJzz__Rf<8T3sYKV2nJk-*Eij zkOm{*5LUBL{mI3H4(_v8TvU{=Vfi4iApzY4bL0$^8FFA?VDr~R#KLG9ZO*kb^>8Bg zZ0lK>a0I|w07BFYk`Np&(B1aqQnUZ*)1f>KIQ0c>X=(1O9{Ha?du=Qv&xjZ!inOwO zS`4jRC58*HqsL&@Rgi($`+#F&)f zGn8khOrM%ihGG#s7M`rveD?ng<{C-^`O#}*^eRUj_=%0xO1>&CCzm*rTR6UOIGO$b zFikS@VB&!&_(u6YVUB1BEhCTOwrzY0mSblA`YiJ1c#BMu%?H`*WfG7i4 zX3CU)?3CwOGgs|*Y75Lr3_ZOhfd~|D{Bx8Ut6?r{U>eY8?~7e93w^Zm2mm`6I;{MP zOwZLSU)Ck|=CczmPn$(s6r%#NEhLU3zz3F(oG%0WBc^M$y*YY|d86*`5SWw5J^b0Q zyd3FPeh&oW4`odk2_VLU&@B7Qp$uUY#HRH_yZrwx(E!$7rUmhUwKEh`GuTOh)IcqZ zM$|C!JQr^De};>a;8>Vv+Gx>*1&NUnID_`5sB7gTmsFo6d|?-ixqiBRS(xTou-D8V z_rbVq*=GL!tx&U2uy)X3YULUGg8iOxI_`3ysnsQE15F(O9s2l|W%Rj7y}hmdj-u7)j<37! z(y=o>=L!`FDWvimtUuEYj@j(nVxSl`{nL8q!i5k6;lT{`e{P`9-Og+fj7wj>PI0;9 z@+N1pj;M=1pV_T5Nv?lm^}GlkP`P1!b!Mm8Q)>cNevBmJSsBXo<|yV=<^@eJQFejV z+GE^YXSsAUIo4ljj;!Vw2YWal>~D;E%|*$%TNTYZTYl5Q=&HT*B1XeiRESh`*W8A3 zq!uAl_qb(`2Afr;iop4(B_HE{&3m15UQ#)8pQC@*J!6nIelqnab!Rx&FfWxRe?w67 zp7fx_#Fo#rk=-kM9pI8%Y5jB8Rjkf(bB{f7J~$NM{??yx_+V1KKJ=jUl5xddBA@td zJoG2SJTbgh>W4%pD(mE%?i@A2TguhD4As5>zuFpvkpz-MXfnw`)`|ybn)oc^T(AT? z#X35iSB*FVcG%DY}KWgn2MEJJ%j8B!F%taH4YgFUv zF>Xe>%nNT`r{5G3pZlDmY2DMDVf)IpZ^d(n_>MPvB}+0kDxac!e4)nxnFf|0(t6fR9D$>8*Um|`RJs_i|Tgm&b ze~xK8U@dIzWADeHUnl5@MBd}d=rr3x+gDpY3TGp-qnhn6UsX`xh-ey|%pcPex~G<) zm0dI_oH;+wAX4pO{$S20khjG~UTX$S^wsrDKD*6leq39-*(NuuVaSq+(8>F~w!H^F zD_P5mVI}A-^@6hS>4z^JWa((69{FqWT7kT2RBHF)tls{(lTn$EKFc8XA`g9jSi#AB z%_h)jt8 z%t&<%rf6krO4*)-X9(~a=tP4s>3w`Pv3+`FNGmo}=8M#s0EZge6dp#ExBtAMQoRDI zeAn3gR=PX1qJQ4u_@75!Y%akSqsfS`cs!u|RBAEqp7hGr`wPUp{+-DV{;}O@>1r^2 zvH&B&vY7F2VOA@HzzSN~aUv$8VD^2&tG=(L1q|q>*ZY3|ZZQ>oPc8iXS(cp<3mYsH z?@7?ilGE%#VtZG-E}!L|=l)a5ybe^@-9u)70*HuBkMG?$_4>nu*VLD%Nb}<@Er4nn z`%X226~w%I)nFm2?|Zwwlz2u`0?W~1in5LhUP80vk41CP?O`}gcyLZvjUYg0?m$Bh8j{@BoLt7jV2v4a`UnmX)y1_Kd;FC{V{FR6NDrgezW$lmV9?TK* z&@Y3$Hx~A0!ETOp^;Y|mMd6e2I?xxpUQX>_(P>$K#-O-%Tk-L1cV_QeFQB7~8&u!U zr^y)Q__p(MB``wfDOo9hbY?$D`$36Fj6wQDSNgFNi#{&dAFE6KSatEE*$|W6pMY6PmzDrEJS%Dm%)Jl7oOYLPa6kDj(f)cYRl}M{G%jB= zS6q?aZ~PJ>H#hg-R`IuxwxqVKqQT;3SD{p!%TLiTyX$X{B4dK6R5hVAonUmpzW;o) z$K|sT+*iFmm6rM~j*cAL;I7yR*Z@r=z)r8q<2J9jm|x7zNEufxEwfc`eo4%$0#Tvb zlzyJ`#j7kBmHMjPD!ofaIkydg9lUca-)1mtf^}fJEL0}4IElqB&2hM`#i)Augx>^s zub=2wjSd$MAO9lkee;0YB)lH6S7fQr&}lE#Z?|c&>fpo64<=QrKIkOk!5^d2voz ziv1BCd?6E_JrI5!`8|h9vM-EgXMSF3{LiiDLiNVIoDog#i=c3CER-)+tgOo|%6qN8 z)uYy$qF6Gc=R;_v#?@=jz_yQ&Ufz)J>aVW7ofB4?S5rHm*N=l{;rDO59*Lqs`J#e$ z3Raf&Vow26$yUywi@zZY)qM0*ifB*XZh&7!W#v^a<{q$uD63Ukb1~LlJFuH>k$*ScRkTgKR_O2XVSXd~n-fKL@?SraZ z-s*SUyKyi+R`z(VZ((%QRVw$Vz~wUQYQkZk3HD{ zOOJkjvZ>b_z!cKhZ*Q$NE)RNqwNs;}u_O?y709^o?Q)|lc8RO;JZH^i(K*cr?M-4` zaem|drKP1HX1b?^-9<}kT@N1|5?f2kuriL*c^enfsjIm3jD@ z1&`|&ABP`LvkXoAY+DFokYn}Op0A0SY;x67Bj?y=qx8b)mW2$vQJKpcSe5{Q^0}Zu zEV12f!_8@|YGto_x3zL_FL$1SO~lb}evR}k_IP$B8h-qRb5+-Qin0ZB=N1>f; zYRxOmX|+cZOUYG4Qyq+|L`HJUB3jDZD`to4vMXHO*(ztRFr*H&hEGSsOO9! zSYDzzRachpd}@}je(d|`(SyoIbA7qh>rskjRRzAFoJ6R)T}|yTG59u6{QYug=8v90 z0}K{++*xQOP27g*Sgx0`-{$y>vHiYMh20+k>GkPhVQWHqAMEYzB{Yl5OZ_%RM}W*J zsrd-(qgJo?S9<_WsU0kGhJ_jDo#;543bv;wUr$MN-VD+f$1>1oFt%++=_iDnzc<<6 zsV)JCUQ#m6YQ6bRBEATbX1Nj=icJ(?c^h5$u}UhjJv=;O5$seW(TD}b(- z6GBxdvTSQ|HA-c!qsj4Xhfm0OXmw#yRCG4N+EVs|>h=vVJp)Qle}CWbPeykryB1TU zB?!rRDw7QE28C+~ioI7;InDf{()cmh7mzj>^PH%sai5K7iYpP>8}8g29@|ayd*JY7 z{>Lw8sYJlPjC-TLON433I22)nZ)3YCSFWSa(0{CvGG+Z9jHC(W?!W#pN8=vb|CN5i z?{5Hi#lh&#v12>0$DN%QhNm-I;~XpZx7n)xPRQw9YM)tKTI#a6+}?&99I&dzXcc&{ zJlmAG#$lbM%&g9_aii!m=UVt`#D0iLWqu`S&KFoyr}^3WwL|Bi89)&u;%HR*s#v zd%)saNayuZhX^RCr6qf&{3xyb$;|plIVfyy{86*heba{r0gefKe9t=Dmcw9{6{}A9 zg)h`pr^9vy-^`j-3A&Aiu{=9^f-c}tsqF$ouGKiFCkNhRJELHENvhMK%5CnW$nF3e zK(<5iX1Zvr3)pv)JqVe|S9+I%NHgy$WSSNh^k6QfM5`2JOpMzMC5BUv?CBkBiI@xz zUMVfOpWm*(U~0djY}Gui^3BDxM(QRn)!6A92XlJE{{H?vtyFP;6EIuuy!Y>o%H8I- z*8qW@)9leWf09;g&x5BW@djsG;Lyp)!K`z^;aD8tAuN2X5(ydrGdF7wfq20?V&iPy zhxeluo-06_28_!1o=M)Emu&L)+$_ONXFyab9?Gu5veTz^{&G3;2?pa>n(8NPoi0b`(dm!^5VEIPBJunwauOdsSw($1nk=I!Z`t!Q$T-j7-o50`IquybBc)@$ zJEl&41KfX%hCH{nK~*<0*4IyHw`v0PT&n2e8@^ck!we8MRym&1)B(1Nb!_Ch!g9Jk zas6&R_`&Vu;OJ=o-|ly{57@Hz&oDPct7k^nnqq9F62ltPN1DokK(n*612TN)=Q_ZT zOG(w_gq2xg@!G?yd9V;%PsOU-&=Kr4{T3&|5vH*HYXTsFwV$8gqlw|1ykVcI7(Fn7 z;ATl*+Whgu^m5{LB=!xn$ob&Ixb&YX5VysGYhC7w$XNo{>fdkmD=YxR=mO>p;AKb) zK=E`DJtf=$hdx7KiA-Pt;%bjX`Vv^Yz5$q2YP%KiZJfwG$2GMCjjV*`75wyRiVPo| zfai(PS=+AMsu&%kc^~YZSQxHKP5>721^Ce#=eAwBZzJ(aga6~b{>Op5{(OXrcx>!{ z87d=I<<^7CT-wy;PqN>gcDunq1{#b1Owt!%AI477F%Hn#tHZH_ z9c_m_j4ZH{pWgx4X#ziw@0pajOf|MjZ&w;yEz6_NJbH=MV!1=%pps@_VQiYl~zSQ#w- zFlVoG#{BWGj7=f@&r|<;Y$eGvP?@FMMg|nWbeD|0{T9EAGJg9NSXxqyF=YR!ZeUtG z|Dw*PFXC9(!rPN9nWs!aC^eY_KvfA0b?BfpoTNKK@hHf$J$u#5b!UCP*`ng(W)uf3XyZ1ArYCcy2FQ0~6c;y=Nyz!4S> zrev4qjX*xNx1CSis)*I(c=|`;HR=pOSU-Ly>fckrPWCy`#*{`=FBXdQcL%>bCW z!gaJZR-2s+&%X#W6D&&5IL~7F87)hqBpd^BOg zPkI;yb)JQx5v%r^Uir9C#*(T0Z|(?cr0<51NvZ}v;L<`YCHfQ#PCRFRJHwkp}*G8=}EqZ2CI3fNYw=LvO)JKE;A&xvpb%yK`nxf`Tex!3z`2nx)jinMu6O zKg+OPk^bSz=fi3TzBYIP*1yG+U>S3ZD!TZ}az1o))CVThj;XxBL(!>Y40JsxS7^Z=IfdaPS8tO4oGRqs&uU1s9w7J?f+|oQ(7Xjq)+_ zJSYYbJ)m7aRhr*ZY_EmHiUI~lxqEql?z@?iRqep^b^H6kh{wUVo)wN9R)c7)FaBce zDYyo&tS!IVUn7AuCt~+o#VcG~VJ#})>nn@g5#gOq4%bhKT5ll~Ey_s+BT$K$wxraV zr+4!YZOE4lPK-ZEL7fTke2zn#=7))~{tRR(xfL=~bS6HNk&r}gh~N$GL7-E!ShEHG zeHA;0^BLvehA|SqwV99In27&<=&FgXC9uM!cIq(UN=uL7{mF+dKY(l#^lb10d0?+B|iI5*t^|*so0+X$H}{2-3m=PksXI& zC`+j^m38YDGd)5_W2Yf`%nhcWg@SM}#-ZXfRaJf=)Pb+0I?pwOEM>*A3Zvpcz^e<|%+H&8F843`Oqp<SoH=_ z=aMWF!yP(~Ye|$mLuvKcRzMl|WG>!y2{|hFu)Bbh1|qOTe_0t$XU#h}9cX*nycj}D z{X(1}6n9g8eGS9XNPK|~vL&ZzzMV>|7Rc0dT`Z{y*bbM!(b$@SyYOy+F+8sY z7(Bmoj=ej(pt-&V*tru}f_*a8^3Qe1toEX@fIX}5!#XL`VTlAOQ#qN79?u7q>5>#+7E+o~IF)Gh%9i}Raqp2o(P`0j6s*=Q4*L9iqUw@_8^;M1B!?89;P9jH zb1Tt@1?bSihUi@6Yk`32e2%dX3yQKsz13Tb2Qw!WH=V6#%!tHY0XqAqHhiEgOq@5Q zvp<%7v@`!AJ>&D@DC_uVZ5b01-{y#WwXZLHal0p-pihiRZfa`MjAE&!U}+S1R{_(2 z>a-`ez#=gmU}z^AtKK1y&AQfoq;Wlbu7gznHYR<`vb9h)nRG zb#-&jSL6sw%!&oGvjJ8lkf1?l0JJ?6=Be%J9!i5gD?hf2g;jwE*<;sWOF`Y~jy#1A zf_Nl#9^GwRoQrC@QNCU3w^?1e(jf=59=+6 zzUT7Ap5yfS7lW;3fKt+fHq`{#|YONLZbpsgeTxUaFZNPn`57)Da%Y|PTJ%AFSz z*Y>&&maD6`rZ@Wf`tQ6D!We^WO~FsbVrjU~1x%k}=m)Y+vKXTnY~=tVoTRf4;CqVE zN8a>bIypFCY-mCo8a6OAIT9Wbu1*Y86WpT?(P)+Ki@rS)nWqR}feHkNFPX6hi8I;~ z77Yv;M7u$Md*n z)G%b~L}@b6u5*71*2J_nl1d?-6c5IcAgkq)@D~xPr9!q(D3MV0)NA8t@3Z^GY^%ELrx4$?^@ z(CAeHdyW%{?-DMeo^6zJ#NMm+ zee(G6N5|h2=@YJS;=Aw1+d+sml^=WYV$V1tw(T|m#Nd-s40TeSmrHEv3G$XY^awor zX&@w(!=jaL=maX^8%-@@Uy;@B+FmY7=<8|f89DKr)-(}WwQhLeayfzVIk@BNJ65U) z^@Kr*Fo)OFz=Qvlkc0F9>6EwCfeWPt&oli{aoY^_H({!V$j)%qc2*rk= zOj0(hZIl9O9t)-o0PP9FcaPVw|Gxmm0y_N=EgKsH!3kpm0k&FJY5`-QViqw#3(VE@6RhxhmH9rX5w!=b+Z+yA<0>VAI!Gz;~7K93HN>87dY^ST98Rmn6M z$V|1u5|RK(bzRTrb3|3Dd8cU_pkI}Uuni^=M6ZenI{_&qnt5$gA_jwD)$2D+Q%V{1 z`)UQHl)<1k91O0%e0?|^9vvMW9v;^7T9R>QHgz+dPDkU>d_I>QQiSM80)+x0q!1vm z!5y%T0fUU~1gC9bCnO++ZK(hPBw=tmEepgGf*`3(>Nk# z(`jAL!M$EJTp6sdZPax$9v?SNgUC$Vr4>a|krb*FrBo3iVH=R51%#v!h^K5MKs;f) zabqWvF*uz-NCsOHCnRhqDNxH8140TR3Y1bzwk*Ga_6;Qsyl z+n2U~{_p(!zxSmt%@c+6-+c8Cv_R7|QrJmL3aP4kr36xD)^+VpW=cXh6FEv$tx}>C zwIX_@s6;mDRyIxDWF};Uq>vOLkZd5cjwlf-QAjnpU^}7$>UljLj~+aH_~60)!^4B7 zo*8H3>1>uwQ&nX$nUqpCHa4zYy|S~jQ self.length_ratio_tolerance: + print(f'Not a valid rectangle, length criterion') + return False + + return True + + def match_feature_find_object(self, train_img): + features2, des2 = self.orb.detectAndCompute(train_img, None) + + bf = cv.BFMatcher(cv.NORM_HAMMING) + matches = bf.knnMatch(self.target_des, des2, k=2) + + good = [] + good_without_lists = [] + matches = [match for match in matches if len(match) == 2] + for m, n in matches: + if m.distance < 0.8 * n.distance: + good.append([m]) + good_without_lists.append(m) + + if len(good) >= self.min_matches: + src_pts = np.float32([self.target_features[m.queryIdx].pt for m in good_without_lists]).reshape(-1, 1, 2) + dst_pts = np.float32([features2[m.trainIdx].pt for m in good_without_lists]).reshape(-1, 1, 2) + + M, _ = cv.findHomography(src_pts, dst_pts, cv.RANSAC, 5.0) + + h, w = self.target_image_h, self.target_image_w + pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2) + + try: + dst = cv.perspectiveTransform(pts, M) + except cv.error as e: + print(f"Perspective transform failed: {e}") + return None, train_img + + rectangle_points = np.squeeze(dst) + if not self.valid_rectangle(rectangle_points): + return None, train_img + + train_img = cv.polylines(train_img, [np.int32(dst)], True, (0, 255, 0), 2, cv.LINE_AA) + x, y, w, h = cv.boundingRect(np.int32(dst)) + return (x, y, w, h), train_img + + else: + print(f"Not enough good matches are found - {len(good)}/{self.min_matches}") + return None, train_img diff --git a/mov_to_png.py b/mov_to_png.py new file mode 100644 index 0000000..1dea046 --- /dev/null +++ b/mov_to_png.py @@ -0,0 +1,41 @@ +import cv2 +import os + +def extract_frames_from_video(video_path, output_folder, frame_interval=30): + os.makedirs(output_folder, exist_ok=True) + + video_capture = cv2.VideoCapture(video_path) + + if not video_capture.isOpened(): + print(f"Error: Could not open video {video_path}") + return + + frame_count = 0 + saved_count = 0 + + while True: + success, frame = video_capture.read() + + if not success: + print("Finished extracting frames.") + break + + if frame_count % frame_interval == 0: + frame_file_path = os.path.join(output_folder, f"frame_{saved_count:04d}.png") + cv2.imwrite(frame_file_path, frame) + print(f"Saved {frame_file_path}") + saved_count += 1 + + frame_count += 1 + + video_capture.release() + +def main(): + video_path = "/Users/vlacosmi/Downloads/drone-detect/capture_6_dec/fhd50fps/nvcamtest_6833_s00_00001.mp4" + output_folder = "video-frames" + frame_interval = 1 + + extract_frames_from_video(video_path, output_folder, frame_interval) + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e075dae --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +pillow==10.4.0 +opencv-python==4.10.0.84 +numpy==2.1.1 +matplotlib==3.9.2 diff --git a/tracker.py b/tracker.py new file mode 100644 index 0000000..eef6ab3 --- /dev/null +++ b/tracker.py @@ -0,0 +1,30 @@ +import dlib +import cv2 as cv + + +class Tracker: + def __init__(self): + self.tracker = dlib.correlation_tracker() + self.is_tracking = False + + def start_tracking(self, img, bbox): + """Initialize the tracker with the given bounding box.""" + x, y, w, h = bbox + self.tracker.start_track(img, dlib.rectangle(x, y, x + w, y + h)) + self.is_tracking = True + + def update(self, img): + """Update the tracker with the new frame.""" + if not self.is_tracking: + return None + + self.tracker.update(img) + pos = self.tracker.get_position() + x1, y1, x2, y2 = int(pos.left()), int(pos.top()), int(pos.right()), int(pos.bottom()) + + # Validate the bounding box + if (x2 - x1) > 0 and (y2 - y1) > 0: + return (x1, y1, x2 - x1, y2 - y1) # Valid bounding box + else: + self.is_tracking = False # Stop tracking if the box is invalid + return None