From 74a399aaa93918270a243fa9cb53a251a271fafd Mon Sep 17 00:00:00 2001 From: tentacle Date: Sun, 29 Jan 2006 20:48:05 +0000 Subject: [PATCH] moved events for fextracker & fexmovement into its own file added second button for fexmovement added functionality to manually move sub for all frames / for one frame Originally committed to SVN as r45. --- FexTracker/FexTrackerRel.dll | Bin 114751 -> 114751 bytes FexTracker/FexTrackerRel.lib | Bin 8946 -> 8946 bytes FexTracker/FexTrackerRel_Opti.dll | Bin 208969 -> 208969 bytes FexTracker/FexTrackerRel_Opti.lib | Bin 9108 -> 9108 bytes core/FexTracker.h | 3 + core/bitmaps/button_track_move.bmp | Bin 0 -> 1318 bytes core/bitmaps/button_track_movement.bmp | Bin 1318 -> 1318 bytes core/bitmaps/button_track_point_add.bmp | Bin 1318 -> 1318 bytes core/bitmaps/button_track_point_del.bmp | Bin 1318 -> 1318 bytes core/bitmaps/button_track_trail.bmp | Bin 0 -> 1318 bytes core/dialog_fextracker.cpp | 121 ++++++++++++ core/dialog_fextracker.h | 54 ++++++ core/fextracker_main_events.cpp | 246 ++++++++++++++++++++++++ core/frame_main.h | 6 + core/frame_main_events.cpp | 151 +-------------- core/res.rc | 2 + core/video_box.cpp | 3 + core/video_display.cpp | 40 +++- core/video_display.h | 6 +- 19 files changed, 476 insertions(+), 156 deletions(-) create mode 100644 core/bitmaps/button_track_move.bmp create mode 100644 core/bitmaps/button_track_trail.bmp create mode 100644 core/dialog_fextracker.cpp create mode 100644 core/dialog_fextracker.h create mode 100644 core/fextracker_main_events.cpp diff --git a/FexTracker/FexTrackerRel.dll b/FexTracker/FexTrackerRel.dll index 15a35bbdc36e9b990b75d6ef4599f99df32cb100..6e9ba73908b0bf85823468f91cd3976f3f17b97d 100644 GIT binary patch delta 2024 zcmZuye@q+a8NS1p`ck<$SGj;wn|8+>r4ImhN=f&&K}hOWeMyDUnlXlpuB zH3b}0%9PVv1Jft9)s%mlu8lOQDix~IAJU2m$|X~Vs#ObiC~d0#QE#*g+cbhyt?qla zl&aEBy8FKO{eHa9^L@|z-pAwCkH@Vud5e`>eRs{+ap40CMNtO66s1QQJ<1xgjWb=c z{nV*bhYXpgsBvr@4;P)zhnL+!Lw5c3)~z-}7AVRUx-NThb}dESID9P*!vYJLfe&mr z8#e#*=841tL(M#RAf#P;U|M%E`JFU2iXXZL$v0jvAAz{s16}rBi1XM6u@#ATU-i~lK4Qh0sVM2*SN?QNPsH?i zbnW=BY=}O;wUVMH78#`Am9FVSf^&E;bp5}rdLSlSN zh~O&VqbCOSgqHt1(km!Qvb4{?S2IF`h?biCTgnX~wJ#25lLHg;3_NcGhvhrz`%z0F zG)TPrcR!?!*`Pxu>i+V!5YyKmAAnK83IDEHPuJR^hXtc%!LmHLF;?c=n4HJ&Je(K1 zrF*F|xCiHh-O@7lmZ2j`F7N*{yS9^}9$#RoxuZ?!-P4%8~6~dYs zsDIPs#Aiw-dA5GIuITSentm;V1WX$ZBa$gXgiZ~@gCSY()b#Km+1{}GfCl%Z&9Rzv z@IvNm3-qZFtFWgd_?|8JZcc7+mogm_hQqzouCuru`9*^$YWk?aN(MJIgCgvYqs5yP zVpcm0TbVR(g>cgHFKL~7xz|)_udOBn$TmtoZ3v-|cN`q460<{sqnIBf7goYSw45dD zECMEP9~{QR+TG}(8FCcAQSxl#L7F9hY+R!qb2GjzH0>m>_@As~a+&Ox*{avD1{9Zb z@CUpIXpa(mlN%TKo0>eX&vReg-9v>a>Kva#vF5(awg2cF_Tc%}!Z8P#X&R#ivaLDr zR20*_7S$><1DMw?U}oSM8;B5!p@6*THa#k87(%SB2@UYc{X5bp*t2ufzcCqyn10CL zUzPIu8NtO(A4T5^iUgxavYFg`{w?xWvzvaA{H3{LmxvV=rRcJ(-#Lk~5KP)Xo4c8f z2vMB5lQafiJ1H}(+10F+U(Iq;UQ-fSZ4e_5XW7HjZ4AtFQ?H;pkDo|9F|p`faF}Iv z;+q(ROe!j7lWbNf(Zv0{9UAb)f^a?tG7lHb?2jT5QZH7OUojPJCLm<*uSi)e2}y2x zoIEM=^lkE-xQCu4m&9&+@)3$cGG5rkos#(;@|_sm#-kJRxq0O5&s#}*%XO@HwpKS@ zRYU9Ln9N9se&c_L9*Ze5kl{R{UqGOOf1G0oD^cW;qPF;SC9;hz;IJJ zyw*NI&Gg5yl8{}}xm{{5Qo(1d&S0TUYZZK{*gj;Ks=*3_oem@Edm|1s&X027)4xr~;+p$M+l_R&s+KLw>`?Rf| zZc0km;UB02CpYyD##&>sQt?FxEz=bd>GgwJ|(^(ekk5Xe3F-TFG+Qt?&uf18g5`UCHYhIppsxt8&k-?wzO_FaAab$YIv-udby^K|16 DMf>D^ delta 2054 zcmZuye{2)y8NQ1TVmiZl;vi1v1Q#FJkc5QTvCla}ef8x?;F27PQUNhtS*C7Dj1atMx}yLsbEwp z7?lb}rGil@V?3Yc4W$gxe5nCZ$-Mu>EW*9fT zo)q-7tfy1w(~Y{!^COI|^8A8gzdgkB#RSjasmn>U^YeR4v#ZWH3?)Wdd{5Lz7k^sB z$#?1s-^8RdPK;IIafT8lKlaty9~n7c^Sa6Ua=>1O6C5r2x4 z*_SS080O5!Y3!61=t+?Kem@t3WOP6DIQk&z#9qKYNc`LC*L0e4HO|b)q<7oKXFK(D zr=FA-5C71CY|J&a6qTK2kdj~gNKf(Zp{>yK|F+r>Dlhcyha2YQp2 zGk?7SKe>!Y#0BIZ_;P$Y(*^M$`CDVq6Wk-NjLf5Uofz#9&5>(xl6NHs%(kyfB{-{* z-A#ObLcGCF+(54I6Af>GE7M%c^uazA`cvdwQ;_zP_nW-*0a9#oW4qMUL2D$s!@Efh zd$VBJ;~sRWOn>~y=u#gCm8nSvv{$nQ8)B!q^7wJwb0h=+o(cZ zvkn?qu{d%0ib-B*9%?H4`%{)bkw*fSjfNrT%Mf9o2JwUx)Awn5JVDmCY~G>4194@v zVIn$~|BDU!RZwf36EeQ1N`af>OYE!puB_qm&UNT^+>ZR9MG!Q7gtv-$CkT+WwX>KYPSVhw=@{8cHTB?{Yd{L--1?xh2 zISaqE(xXEr&NeSD2)4EP+4}iIR zS2XpLyobHeg{}qE2p%pM^2KTM3b_*U(pmERP}imi)>u@c$M*2{(|8nOnFzj9yjhU> zPMrBY5(vNY40X3~w;-B#3+&`JOAuIl5FrPrn5V?g@K}zWyolO7d?bA+JL{iuRcdVZ zz6z2>MZ`4#uqP??fV`S*Y87*-|tnAQYAt!~#}?qwIw- z^dWo?!asrVvDzW9dGa%13;iy6P3UzVTT4+G^ur47d(`YB{}H0=HlP#C;xt}C(6kdJ za-EjQ+IBBpM|QTq-c5-}X89{5gOwHu#o#oOnMX1ncJdhd4<9;`&d#bcZi`Izz5{<2 zgMpH0;1LWvS;Vj04=AC5Bo-F3NgUp!7UdeQPPc(gPDd(^4$lTGxucT8ID z;aHfaQ&VqCS4!4D`P!gFkJgk&^9Sha&W7&L&Cp!viSX|5!SI>zufmtYSHmBKR|(%2 z-VlBxd=`1D{c8KQ_K>(&Jalo*B|1{`=g_}GYB&*oPq;4pC^8%wi{v7E+xxB^yhKmc M)3q1ZPSdUb1<$Va$N&HU diff --git a/FexTracker/FexTrackerRel.lib b/FexTracker/FexTrackerRel.lib index b49534a4880ba4181c68ea40e888e494fcdf5668..16572f282005c24fcf5c96b49be5d93dad6bd96a 100644 GIT binary patch delta 688 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 y%q;u~Ud4q@mNOf;9L`^cy;*^nfzW3 zW|D$DG}Po_{sy@kX3|4>WRv_9M0h}c@dlbC$iTud`5?c^n?H)GA%w*z8;c8r6i@aP_d_yyGgS1Xco5tOEwDOY z2_GbNTO}a6PfLVAMK?%_PqvnXhz3eV!9^ju?@A`YMZ_mZOF`5XO2r|GzJ`i2O2xX{Vy%d4RpP;B?AKkCj-mmcsAw94l=q(`Z{GG`sT}oA&COr4c2D{ z)W;3f_mNRyvcIejTm{6nYh?rABI1)z%R@}kmqUb!*yK5KB4CrefF|()O?t>;GWoq6 z%p?VQXsF4<{0(w7%%q3%$R_zIi12{?;te!Okb#9^@}C*PM5gE|A4J|@3X y5CKO7qhbnF6cpr*iV(+5S4=<>6;^_XYAPWIB{0yyCTv%VKr&ZL8Dg%Zaxeg?{KAF+ diff --git a/core/FexTracker.h b/core/FexTracker.h index 09902b456..5787680b0 100644 --- a/core/FexTracker.h +++ b/core/FexTracker.h @@ -17,6 +17,7 @@ class FEXTRACKER_API FexTrackerConfig { public: inline FexTrackerConfig() : + FeatureNumber(0), EdgeDetectSigma(1.f), WindowX(3), WindowY(3), SearchRange(15), @@ -29,6 +30,8 @@ public: MinDistanceSquare(100.f) {}; + int FeatureNumber; + int WindowX, WindowY; //static const int window_size = 7; int SearchRange; diff --git a/core/bitmaps/button_track_move.bmp b/core/bitmaps/button_track_move.bmp new file mode 100644 index 0000000000000000000000000000000000000000..db356c2a73ead19a6e4d55fcdaa38dcb67f11795 GIT binary patch literal 1318 zcmb8tF|O1=494;ANgxo-yMimk38*c4?%<>NAQUbT=Wxv#D13z1Q!M|9_lXr9Nq+e} zlk83=nJ-^IzSXsTej|ONdcJ$o`>X$j^S2L6Pc)8eONm378=NWC-RfVhm!Cf*a|F0x zg~muO7$`iDC^SY2!Qh|~i9%!U;~MD*Bnpj@C{+eWAW>)x4=ETNfkdG(5{Jg%2qX%P zk&DNa;p~A#p)or(Gtv=A6dJSBb|W2uM4>VJO2SA-AW>+{zOFRV5l9pov#+v@bOaKG z#_VfuBOQT6p)uDd@G;U6NE8~QWd13`nR(#sg~ljNFgOBk_;mqfkdG(yIj*qM<7vX%r50J(h*1$8nes1jdTPOrI+6~ zedoU9|D@Y>=yp35*iRRych^Sey?AZjJFaf7p6y(Ez3t)t)3sNrMESRUTK~EI`}-a8 a;s4K5+{Zh`y>&*p%5&OLx4O;`_x}OZGfS5M literal 0 HcmV?d00001 diff --git a/core/bitmaps/button_track_movement.bmp b/core/bitmaps/button_track_movement.bmp index 06a5f1d821477df3ac4f01b25d1f90cb19546c9a..101e7cc694cfe934b55ee8ae1b6dfee6715d0e9d 100644 GIT binary patch delta 198 zcmZ3+wTx?m8tY*$28P2MwdGjq8Q2j3#75;afB;+pLjETRfYpM;z&s$q@Dr>Q#s%_0 r0#GiH14J+YvIxZ2g$l5PZGtHP8v`^Mh=B579+)%Pltpo}8;bw{LJ>!x delta 207 zcmZ3+wTx?m8tZE=28P!gwdGhQbF%W*|3n205H16h{)xe72LlEM2+aA4gi^;I`{wp diff --git a/core/bitmaps/button_track_point_del.bmp b/core/bitmaps/button_track_point_del.bmp index 4757fa4c676164f342bcb095329d291b19ba1d42..7e0fddee22f3a758db65a315b513d8f363bfcba7 100644 GIT binary patch delta 217 zcmZ3+wTx?m8tY*$28P2MwG~A4giG9I>Z0~ diff --git a/core/bitmaps/button_track_trail.bmp b/core/bitmaps/button_track_trail.bmp new file mode 100644 index 0000000000000000000000000000000000000000..51e6b33c0d6173fd8b1220a043c08283f153b16c GIT binary patch literal 1318 zcmZY7v5nk7429u$fQ>brxCKTBSKyd%?jBeQ3vs}}xH=fS1_vx*a|i2xG<$biSkk9A z)Xc6l(tQ8%{87jD?Su4{)|a~{eLAjRIsg2;>4{=Fwv;%Oxq~xJb+`IY>-zgeGDm<8 zD>O!O!9c?Ui9%zf5DX5ANE8}#zps&wK%&qXiKfcn2qX%P;UNWsBakRGM&i&I9Dzik zF>>*kGORt2C^TkI&5U#e5{1U>X}gh*K%&r?{Yt_}M<7vX%zj;Iq$7|hG-kibGSU%9 z6dJQ%a~tUhBnpi=K7o&sjzFT&7$x&h8P?1LYcDiLX@bEKNE8~gKbsrr2qX%P*`G9w zbOaKG#_Z3{O)?#UM4>TzDU^|pK%&r?y-eCjM<7vX%&~-WjC2GNg~q6vf6L$qBnoSv zy|m0oM<7vX%wBeGq$7|hG-fZ!Fwzl76dJRaYZ~bYBnpk$OSz161QLbD>}B3YIs%E( z_3ur;7?=E?bUO~+ZmR|Mb&1pEyy@~#GxS`q-uHU9-s=0%xB5QvwSLUk>as_jZnJwH W``@cI{#;R?e!FJ!U;lY}tN$O{uuatf literal 0 HcmV?d00001 diff --git a/core/dialog_fextracker.cpp b/core/dialog_fextracker.cpp new file mode 100644 index 000000000..3cd5cdd67 --- /dev/null +++ b/core/dialog_fextracker.cpp @@ -0,0 +1,121 @@ +// AEGISUB +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:zeratul@cellosoft.com +// + + +/////////// +// Headers +#include "dialog_fextracker.h" +#include "FexTracker.h" + + +/////////////// +// Constructor +DialogFexTracker::DialogFexTracker(wxWindow *parent, FexTrackerConfig *_cfg) +: wxDialog (parent,-1,_("Tracker configuration"),wxDefaultPosition) +{ + cfg = _cfg; + cfg->FeatureNumber = 0; + + wxNotebook *MainNB = new wxNotebook(this,-1, wxDefaultPosition, wxSize(300,500), wxNO_BORDER ); + + wxWindow *StdWnd = new wxPanel(MainNB,-1); + wxWindow *AdvWnd = new wxPanel(MainNB,-1); + + FeatureNumber = new wxTextCtrl(StdWnd,-1,_T("250")); + MinDistanceSquare = new wxTextCtrl(StdWnd,-1,_T("100")); + SearchRange = new wxTextCtrl(StdWnd,-1,_T("15")); + MaxResidue = new wxTextCtrl(StdWnd,-1,_T("10")); + MaxIterations = new wxTextCtrl(StdWnd,-1,_T("10")); + + EdgeDetectSigma = new wxTextCtrl(AdvWnd,-1,_T("1.0")); + WindowX = new wxTextCtrl(AdvWnd,-1,_T("3")); + WindowY = new wxTextCtrl(AdvWnd,-1,_T("3")); + MinDeterminant = new wxTextCtrl(AdvWnd,-1,_T("0.01")); + MinDisplacement = new wxTextCtrl(AdvWnd,-1,_T("0.1")); + + wxSizer *Sizer = new wxBoxSizer(wxVERTICAL); + wxStaticText *Static; + Static = new wxStaticText(StdWnd,-1,_("Number of points to track:")); + Sizer->Add(Static,0,wxALIGN_LEFT,5); + Sizer->Add(FeatureNumber,0,wxALIGN_LEFT,5); + Static = new wxStaticText(StdWnd,-1,_("Minimal (sqared) distance between two points: ")); + Sizer->Add(Static,0,wxALIGN_LEFT,5); + Sizer->Add(MinDistanceSquare,0,wxALIGN_LEFT,5); + Static = new wxStaticText(StdWnd,-1,_("Maximum feature movement:")); + Sizer->Add(Static,0,wxALIGN_LEFT,5); + Sizer->Add(SearchRange,0,wxALIGN_LEFT,5); + Static = new wxStaticText(StdWnd,-1,_("Maximum feature appearance change:")); + Sizer->Add(Static,0,wxALIGN_LEFT,5); + Sizer->Add(MaxResidue,0,wxALIGN_LEFT,5); + Static = new wxStaticText(StdWnd,-1,_("How much CPU per feature?")); + Sizer->Add(Static,0,wxALIGN_LEFT,5); + Sizer->Add(MaxIterations,0,wxALIGN_LEFT,5); + + wxSizer *SizerAdd = new wxBoxSizer(wxVERTICAL); + Static = new wxStaticText(AdvWnd,-1,_("Edge detect filter size:")); + SizerAdd->Add(Static,0,wxALIGN_LEFT,5); + SizerAdd->Add(EdgeDetectSigma,0,wxALIGN_LEFT,5); + Static = new wxStaticText(AdvWnd,-1,_("Feature comparison width:")); + SizerAdd->Add(Static,0,wxALIGN_LEFT,5); + SizerAdd->Add(WindowX,0,wxALIGN_LEFT,5); + Static = new wxStaticText(AdvWnd,-1,_("Feature comparison height:")); + SizerAdd->Add(Static,0,wxALIGN_LEFT,5); + SizerAdd->Add(WindowY,0,wxALIGN_LEFT,5); + Static = new wxStaticText(AdvWnd,-1,_("Minimal determinant:")); + SizerAdd->Add(Static,0,wxALIGN_LEFT,5); + SizerAdd->Add(MinDeterminant,0,wxALIGN_LEFT,5); + Static = new wxStaticText(AdvWnd,-1,_("Minimal displacement per iteration:")); + SizerAdd->Add(Static,0,wxALIGN_LEFT,5); + SizerAdd->Add(MinDisplacement,0,wxALIGN_LEFT,5); + + StdWnd->SetSizer( Sizer ); + StdWnd->SetAutoLayout( 1 ); + MainNB->AddPage( StdWnd, _T("Standard Settings") ); + + AdvWnd->SetSizer( SizerAdd ); + AdvWnd->SetAutoLayout( 1 ); + MainNB->AddPage( AdvWnd, _T("Advanced Settings") ); + + wxSizer *MainSizer = new wxBoxSizer(wxVERTICAL); + MainSizer->Add(MainNB,1,wxEXPAND|wxALL,5); + MainSizer->AddSpacer(2); + wxButton *but = new wxButton(this,BUTTON_START,_("Go!")); + MainSizer->Add(but,0,wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER,5); + + MainSizer->SetSizeHints( this ); + SetSizer(MainSizer); + SetAutoLayout(true); + CenterOnParent(); +} + + +/////////////// +// Event table +BEGIN_EVENT_TABLE(DialogFexTracker,wxDialog) + EVT_BUTTON(BUTTON_START,DialogFexTracker::OnStart) +END_EVENT_TABLE() + + +//////////// +// OnStart +void DialogFexTracker::OnStart (wxCommandEvent &event) { + cfg->FeatureNumber = 0; + + swscanf( FeatureNumber->GetValue(), _T("%d"), &cfg->FeatureNumber ); + swscanf( WindowX->GetValue(), _T("%d"), &cfg->WindowX ); + swscanf( WindowY->GetValue(), _T("%d"), &cfg->WindowY ); + swscanf( SearchRange->GetValue(), _T("%d"), &cfg->SearchRange ); + swscanf( MaxIterations->GetValue(), _T("%d"), &cfg->MaxIterations ); + + swscanf( EdgeDetectSigma->GetValue(), _T("%f"), &cfg->EdgeDetectSigma ); + swscanf( MinDeterminant->GetValue(), _T("%f"), &cfg->MinDeterminant ); + swscanf( MinDisplacement->GetValue(), _T("%f"), &cfg->MinDisplacement ); + swscanf( MaxResidue->GetValue(), _T("%f"), &cfg->MaxResidue ); + swscanf( MinDistanceSquare->GetValue(), _T("%f"), &cfg->MinDistanceSquare ); + + EndModal(0); +} + diff --git a/core/dialog_fextracker.h b/core/dialog_fextracker.h new file mode 100644 index 000000000..01e287300 --- /dev/null +++ b/core/dialog_fextracker.h @@ -0,0 +1,54 @@ +// AEGISUB +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:zeratul@cellosoft.com +// + + +#ifndef DIALOG_FEXTRACKER_H +#define DIALOG_FEXTRACKER_H + + +/////////// +// Headers +#include + + +////////////// +// Prototypes +class FexTrackerConfig; + + +///////// +// Class +class DialogFexTracker : public wxDialog { +private: + FexTrackerConfig * cfg; + + wxTextCtrl *FeatureNumber; + wxTextCtrl *EdgeDetectSigma; + wxTextCtrl *WindowX, *WindowY; + wxTextCtrl *SearchRange; + wxTextCtrl *MaxIterations; + wxTextCtrl *MinDeterminant; + wxTextCtrl *MinDisplacement; + wxTextCtrl *MaxResidue; + wxTextCtrl *MinDistanceSquare; + + void OnStart (wxCommandEvent &event); + +public: + DialogFexTracker(wxWindow *parent, FexTrackerConfig * cfg); + + DECLARE_EVENT_TABLE() +}; + + +/////// +// IDs +enum { + BUTTON_START = 1520, +}; + + +#endif diff --git a/core/fextracker_main_events.cpp b/core/fextracker_main_events.cpp new file mode 100644 index 000000000..6ccf9e4a2 --- /dev/null +++ b/core/fextracker_main_events.cpp @@ -0,0 +1,246 @@ +// AEGISUB +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:zeratul@cellosoft.com +// + + +/////////////////// +// Include headers +#include +#include +#include +#include +#include +#include "subs_grid.h" +#include "frame_main.h" +#include "video_display.h" +#include "video_slider.h" +#include "video_zoom.h" +#include "video_box.h" +#include "ass_file.h" +#include "dialog_style_manager.h" +#include "dialog_translation.h" +#include "dialog_jumpto.h" +#include "dialog_shift_times.h" +#include "dialog_search_replace.h" +#include "vfr.h" +#include "subs_edit_box.h" +#include "options.h" +#include "dialog_properties.h" +#include "main.h" +#include "fonts_collector.h" +#include "about.h" +#include "automation_gui.h" +#include "dialog_export.h" +#include "audio_box.h" +#include "aspell_wrap.h" +#include "dialog_spellcheck.h" +#include "dialog_selection.h" +#include "dialog_styling_assistant.h" +#include "dialog_resample.h" +#include "audio_display.h" +#include "toggle_bitmap.h" +#include "dialog_hotkeys.h" +#include "dialog_timing_processor.h" +#include "FexTracker.h" +#include "FexTrackingFeature.h" +#include "FexMovement.h" +#include "dialog_progress.h" +#include "dialog_fextracker.h" + + + +/////////////////// +// Tracker Menu +void FrameMain::OnVideoTrackerMenu(wxCommandEvent &event) { + wxMenu menu( _("FexTracker") ); + AppendBitmapMenuItem(&menu, Video_Track_Points, _("track points"), _(""), wxBITMAP(button_track_points)); + menu.AppendSeparator(); + AppendBitmapMenuItem(&menu, Video_Track_Point_Add, _("add points to movement"), _(""), wxBITMAP(button_track_point_add)); + AppendBitmapMenuItem(&menu, Video_Track_Point_Del, _("remove points from movement"), _(""), wxBITMAP(button_track_point_del)); + menu.AppendSeparator(); + AppendBitmapMenuItem(&menu, Video_Track_Movement, _("generate movement from points"), _(""), wxBITMAP(button_track_movement)); + PopupMenu(&menu); +} + + +/////////////////// +// Movement Menu +void FrameMain::OnVideoTrackerMenu2(wxCommandEvent &event) { + wxMenu menu( _("FexMovement") ); + AppendBitmapMenuItem(&menu, Video_Track_Movement_MoveAll, _("move subtitle"), _(""), wxBITMAP(button_track_move)); + AppendBitmapMenuItem(&menu, Video_Track_Movement_MoveOne, _("move subtitle only in this frame"), _(""), wxBITMAP(button_track_move)); + menu.AppendSeparator(); + AppendBitmapMenuItem(&menu, Video_Track_Split_Line, _("split line for movement"), _(""), wxBITMAP(button_track_split_line)); + PopupMenu(&menu); +} + + +/////////////////// +// Track current line +void FrameMain::OnVideoTrackPoints(wxCommandEvent &event) { + videoBox->videoDisplay->Stop(); + + // Get line + AssDialogue *curline = SubsBox->GetDialogue(EditBox->linen); + if (!curline) return; + + FexTrackerConfig config; + DialogFexTracker configDlg( this, &config ); + configDlg.ShowModal(); + + if( !config.FeatureNumber ) return; + + // Get Video + bool usedDirectshow; + VideoProvider *movie = new VideoProvider(videoBox->videoDisplay->videoName, wxString(_T("")), 1.0,usedDirectshow,true); + + // Create Tracker + if( curline->Tracker ) delete curline->Tracker; + curline->Tracker = new FexTracker( movie->GetWidth(), movie->GetHeight(), config.FeatureNumber ); + curline->Tracker->minFeatures = config.FeatureNumber; + curline->Tracker->Cfg = config; + + // Start progress + volatile bool canceled = false; + DialogProgress *progress = new DialogProgress(this,_("FexTracker"),&canceled,_("Tracking points"),0,1); + progress->Show(); + + // Allocate temp image + float* FloatImg = new float[ movie->GetWidth()*movie->GetHeight() ]; + + int StartFrame = VFR_Output.CorrectFrameAtTime(curline->Start.GetMS(),true); + int EndFrame = VFR_Output.CorrectFrameAtTime(curline->End.GetMS(),false); + + for( int Frame = StartFrame; Frame <= EndFrame; Frame ++ ) + { + progress->SetProgress( Frame-StartFrame, EndFrame-StartFrame ); + if( canceled ) break; + + movie->GetFloatFrame( FloatImg, Frame ); + curline->Tracker->ProcessImage( FloatImg ); + } + + delete FloatImg; + delete movie; + + // Clean up progress + if (!canceled) + progress->Destroy(); + else + { + delete curline->Tracker; + curline->Tracker = 0; + } + + videoBox->videoDisplay->RefreshVideo(); +} + + +/////////////////// +// Track current line +void FrameMain::OnVideoTrackMovement(wxCommandEvent &event) { + videoBox->videoDisplay->Stop(); + + // Get line + AssDialogue *curline = SubsBox->GetDialogue(EditBox->linen); + if (!curline) return; + if( !curline->Tracker ) return; + + // Create Movement + if( curline->Movement ) DeleteMovement( curline->Movement ); + curline->Movement = curline->Tracker->GetMovement(); + + // Remove Tracker + delete curline->Tracker; + curline->Tracker = 0; + + videoBox->videoDisplay->RefreshVideo(); +} + + +/////////////////// +// split current line +void FrameMain::OnVideoTrackSplitLine(wxCommandEvent &event) { + videoBox->videoDisplay->Stop(); + + // Get line + AssDialogue *curline = SubsBox->GetDialogue(EditBox->linen); + if (!curline) return; + if( !curline->Movement ) return; + + // Create split lines + int StartFrame = VFR_Output.CorrectFrameAtTime(curline->Start.GetMS(),true); + int EndFrame = VFR_Output.CorrectFrameAtTime(curline->End.GetMS(),false); + + AssFile *subs = AssFile::top; + int ResXValue,ResYValue; + swscanf( subs->GetScriptInfo(_T("PlayResX")), _T("%d"), &ResXValue ); + swscanf( subs->GetScriptInfo(_T("PlayResY")), _T("%d"), &ResYValue ); + int SrcXValue = videoBox->videoDisplay->provider->GetSourceWidth(); + int SrcYValue = videoBox->videoDisplay->provider->GetSourceHeight(); + + float sx = float(ResXValue)/float(SrcXValue); + float sy = float(ResYValue)/float(SrcYValue); + + for( int Frame = StartFrame; Frame < EndFrame; Frame ++ ) + { + int localframe = Frame - StartFrame; + + while( curline->Movement->Frames.size() <= localframe ) localframe--; + FexMovementFrame f = curline->Movement->Frames[localframe]; +// f.Pos.x /= videoBox->videoDisplay->GetW + + AssDialogue *cur = new AssDialogue( curline->data ); + cur->Start.SetMS(VFR_Output.CorrectTimeAtFrame(Frame,true)); + cur->End.SetMS(VFR_Output.CorrectTimeAtFrame(Frame,false)); + cur->Text = wxString::Format( _T("{\\pos(%.0f,%.0f)\\fscx%.2f\\fscy%.2f}"), f.Pos.x*sx, f.Pos.y*sy, f.Scale.x*100, f.Scale.y*100 ) + cur->Text; + cur->UpdateData(); + + SubsBox->InsertLine(cur,EditBox->linen + Frame - StartFrame,true,false); + } + + // Remove Movement + DeleteMovement( curline->Movement ); + curline->Movement = 0; + + // Remove this line + SubsBox->DeleteLines( EditBox->linen, EditBox->linen, false ); + + videoBox->videoDisplay->RefreshVideo(); +} + + +/////////////////// +// Increase Influence +void FrameMain::OnVideoTrackPointAdd(wxCommandEvent &event) { + videoBox->videoDisplay->TrackerEdit = 1; + videoBox->videoDisplay->bTrackerEditing = 0; +} + + +/////////////////// +// Decrease Influence +void FrameMain::OnVideoTrackPointDel(wxCommandEvent &event) { + videoBox->videoDisplay->TrackerEdit = -1; + videoBox->videoDisplay->bTrackerEditing = 0; +} + + +/////////////////// +// Move All +void FrameMain::OnVideoTrackMovementMoveAll(wxCommandEvent &event) { + videoBox->videoDisplay->MovementEdit = 1; + videoBox->videoDisplay->bTrackerEditing = 0; +} + + +/////////////////// +// Move One +void FrameMain::OnVideoTrackMovementMoveOne(wxCommandEvent &event) { + videoBox->videoDisplay->MovementEdit = 2; + videoBox->videoDisplay->bTrackerEditing = 0; +} + + diff --git a/core/frame_main.h b/core/frame_main.h index 794824804..7e18e85ea 100644 --- a/core/frame_main.h +++ b/core/frame_main.h @@ -110,7 +110,10 @@ private: void OnVideoTrackPoints(wxCommandEvent &event); void OnVideoTrackPointAdd(wxCommandEvent &event); void OnVideoTrackPointDel(wxCommandEvent &event); + void OnVideoTrackerMenu2(wxCommandEvent &event); void OnVideoTrackMovement(wxCommandEvent &event); + void OnVideoTrackMovementMoveAll(wxCommandEvent &event); + void OnVideoTrackMovementMoveOne(wxCommandEvent &event); void OnVideoTrackSplitLine(wxCommandEvent &event); void OnKeyDown(wxKeyEvent &event); @@ -333,7 +336,10 @@ enum { Video_Track_Points, Video_Track_Point_Add, Video_Track_Point_Del, + Video_Tracker_Menu2, Video_Track_Movement, + Video_Track_Movement_MoveAll, + Video_Track_Movement_MoveOne, Video_Track_Split_Line, Menu_File_Recent = 2000, diff --git a/core/frame_main_events.cpp b/core/frame_main_events.cpp index 24c1be30c..5ed956c96 100644 --- a/core/frame_main_events.cpp +++ b/core/frame_main_events.cpp @@ -76,6 +76,7 @@ #include "FexTrackingFeature.h" #include "FexMovement.h" #include "dialog_progress.h" +#include "dialog_fextracker.h" //////////////////// @@ -94,6 +95,9 @@ BEGIN_EVENT_TABLE(FrameMain, wxFrame) EVT_MENU(Video_Track_Point_Add, FrameMain::OnVideoTrackPointAdd) EVT_MENU(Video_Track_Point_Del, FrameMain::OnVideoTrackPointDel) EVT_MENU(Video_Track_Movement, FrameMain::OnVideoTrackMovement) + EVT_BUTTON(Video_Tracker_Menu2, FrameMain::OnVideoTrackerMenu2) + EVT_MENU(Video_Track_Movement_MoveAll, FrameMain::OnVideoTrackMovementMoveAll) + EVT_MENU(Video_Track_Movement_MoveOne, FrameMain::OnVideoTrackMovementMoveOne) EVT_MENU(Video_Track_Split_Line, FrameMain::OnVideoTrackSplitLine) EVT_CLOSE(FrameMain::OnCloseWindow) @@ -1135,153 +1139,6 @@ void FrameMain::OnVideoToggleScroll(wxCommandEvent &event) { } -/////////////////// -// Track current line -void FrameMain::OnVideoTrackerMenu(wxCommandEvent &event) { - wxMenu menu( _("FexTracker") ); - AppendBitmapMenuItem(&menu, Video_Track_Points, _("track points"), _(""), wxBITMAP(button_track_points)); - menu.AppendSeparator(); - AppendBitmapMenuItem(&menu, Video_Track_Point_Add, _("add points to movement"), _(""), wxBITMAP(button_track_point_add)); - AppendBitmapMenuItem(&menu, Video_Track_Point_Del, _("remove points from movement"), _(""), wxBITMAP(button_track_point_del)); - menu.AppendSeparator(); - AppendBitmapMenuItem(&menu, Video_Track_Movement, _("generate movement from points"), _(""), wxBITMAP(button_track_movement)); - AppendBitmapMenuItem(&menu, Video_Track_Split_Line, _("split line for movement"), _(""), wxBITMAP(button_track_split_line)); - PopupMenu(&menu); -} - - -/////////////////// -// Track current line -void FrameMain::OnVideoTrackPoints(wxCommandEvent &event) { - videoBox->videoDisplay->Stop(); - - // Get line - AssDialogue *curline = SubsBox->GetDialogue(EditBox->linen); - if (!curline) return; - - // Get Video - bool usedDirectshow; - VideoProvider *movie = new VideoProvider(videoBox->videoDisplay->videoName, wxString(_T("")), 1.0,usedDirectshow,true); - - // Create Tracker - if( curline->Tracker ) delete curline->Tracker; - curline->Tracker = new FexTracker( movie->GetWidth(), movie->GetHeight(), 250 ); - curline->Tracker->minFeatures = 250; - - // Start progress - volatile bool canceled = false; - DialogProgress *progress = new DialogProgress(this,_("FexTracker"),&canceled,_("Tracking points"),0,1); - progress->Show(); - - // Allocate temp image - float* FloatImg = new float[ movie->GetWidth()*movie->GetHeight() ]; - - int StartFrame = VFR_Output.CorrectFrameAtTime(curline->Start.GetMS(),true); - int EndFrame = VFR_Output.CorrectFrameAtTime(curline->End.GetMS(),false); - - for( int Frame = StartFrame; Frame <= EndFrame; Frame ++ ) - { - progress->SetProgress( Frame-StartFrame, EndFrame-StartFrame ); - if( canceled ) break; - - movie->GetFloatFrame( FloatImg, Frame ); - curline->Tracker->ProcessImage( FloatImg ); - } - - delete FloatImg; - delete movie; - - // Clean up progress - if (!canceled) - progress->Destroy(); - else - { - delete curline->Tracker; - curline->Tracker = 0; - } - - videoBox->videoDisplay->RefreshVideo(); -} - - -/////////////////// -// Track current line -void FrameMain::OnVideoTrackMovement(wxCommandEvent &event) { - videoBox->videoDisplay->Stop(); - - // Get line - AssDialogue *curline = SubsBox->GetDialogue(EditBox->linen); - if (!curline) return; - if( !curline->Tracker ) return; - - // Create Movement - if( curline->Movement ) DeleteMovement( curline->Movement ); - curline->Movement = curline->Tracker->GetMovement(); - - // Remove Tracker - delete curline->Tracker; - curline->Tracker = 0; - - videoBox->videoDisplay->RefreshVideo(); -} - - -/////////////////// -// split current line -void FrameMain::OnVideoTrackSplitLine(wxCommandEvent &event) { - videoBox->videoDisplay->Stop(); - - // Get line - AssDialogue *curline = SubsBox->GetDialogue(EditBox->linen); - if (!curline) return; - if( !curline->Movement ) return; - - // Create split lines - int StartFrame = VFR_Output.CorrectFrameAtTime(curline->Start.GetMS(),true); - int EndFrame = VFR_Output.CorrectFrameAtTime(curline->End.GetMS(),false); - - for( int Frame = StartFrame; Frame < EndFrame; Frame ++ ) - { - int localframe = Frame - StartFrame; - - while( curline->Movement->Frames.size() <= localframe ) localframe--; - FexMovementFrame f = curline->Movement->Frames[localframe]; -// f.Pos.x /= videoBox->videoDisplay->GetW - - AssDialogue *cur = new AssDialogue( curline->data ); - cur->Start.SetMS(VFR_Output.CorrectTimeAtFrame(Frame,true)); - cur->End.SetMS(VFR_Output.CorrectTimeAtFrame(Frame,false)); - cur->Text = wxString::Format( _T("{\\pos(%.0f,%.0f)\\fscx%.2f\\fscy%.2f}"), f.Pos.x, f.Pos.y, f.Scale.x*100, f.Scale.y*100 ) + cur->Text; - cur->UpdateData(); - - SubsBox->InsertLine(cur,EditBox->linen + Frame - StartFrame,true,false); - } - - // Remove Movement - DeleteMovement( curline->Movement ); - curline->Movement = 0; - - // Remove this line - SubsBox->DeleteLines( EditBox->linen, EditBox->linen, false ); - - videoBox->videoDisplay->RefreshVideo(); -} - - -/////////////////// -// Increase Influence -void FrameMain::OnVideoTrackPointAdd(wxCommandEvent &event) { - videoBox->videoDisplay->TrackerEdit = 1; -} - - -/////////////////// -// Decrease Influence -void FrameMain::OnVideoTrackPointDel(wxCommandEvent &event) { - videoBox->videoDisplay->TrackerEdit = -1; -} - - /////////////////////////////// // Choose a different language void FrameMain::OnChooseLanguage (wxCommandEvent &event) { diff --git a/core/res.rc b/core/res.rc index bbf9fc79c..3f6149a6f 100644 --- a/core/res.rc +++ b/core/res.rc @@ -85,6 +85,8 @@ button_track_point_add BITMAP "bitmaps/button_track_point_add.bmp" button_track_point_del BITMAP "bitmaps/button_track_point_del.bmp" button_track_movement BITMAP "bitmaps/button_track_movement.bmp" button_track_split_line BITMAP "bitmaps/button_track_split_line.bmp" +button_track_trail BITMAP "bitmaps/button_track_trail.bmp" +button_track_move BITMAP "bitmaps/button_track_move.bmp" button_bold BITMAP "bitmaps/button_bold.bmp" button_italics BITMAP "bitmaps/button_italics.bmp" diff --git a/core/video_box.cpp b/core/video_box.cpp index 7f6253aa6..df7cf8f56 100644 --- a/core/video_box.cpp +++ b/core/video_box.cpp @@ -62,6 +62,8 @@ VideoBox::VideoBox(wxPanel *parent) { wxBitmapButton *VideoTrackerMenuButton = new wxBitmapButton(videoPage,Video_Tracker_Menu,wxBITMAP(button_track_points),wxDefaultPosition,wxSize(25,-1)); VideoTrackerMenuButton->SetToolTip(_("FexTracker")); + wxBitmapButton *VideoTrackerMenu2Button = new wxBitmapButton(videoPage,Video_Tracker_Menu2,wxBITMAP(button_track_trail),wxDefaultPosition,wxSize(25,-1)); + VideoTrackerMenu2Button->SetToolTip(_("FexMovement")); // Seek videoSlider = new VideoSlider(videoPage,-1); @@ -97,6 +99,7 @@ VideoBox::VideoBox(wxPanel *parent) { videoBottomSizer->Add(VideoPosition,1,wxLEFT|wxALIGN_CENTER,5); videoBottomSizer->Add(VideoSubsPos,1,wxALIGN_CENTER,0); videoBottomSizer->Add(VideoTrackerMenuButton,0,wxTOP|wxBOTTOM|wxALIGN_CENTER,2); + videoBottomSizer->Add(VideoTrackerMenu2Button,0,wxTOP|wxBOTTOM|wxALIGN_CENTER,2); VideoSizer = new wxBoxSizer(wxVERTICAL); VideoSizer->Add(videoDisplay,0,wxEXPAND,0); VideoSizer->Add(videoSliderSizer,0,wxEXPAND,0); diff --git a/core/video_display.cpp b/core/video_display.cpp index dae9d34f4..34729477d 100644 --- a/core/video_display.cpp +++ b/core/video_display.cpp @@ -233,27 +233,51 @@ void VideoDisplay::OnMouseEvent(wxMouseEvent& event) { return; } - if( event.ButtonDown(wxMOUSE_BTN_LEFT) ) - bTrackerEditing = 1; - if( event.ButtonUp(wxMOUSE_BTN_LEFT) ) - bTrackerEditing = 0; - // Coords int x = event.GetX(); int y = event.GetY(); + if( event.ButtonDown(wxMOUSE_BTN_LEFT) ) + { + MouseDownX = x; + MouseDownY = y; + bTrackerEditing = 1; + } + if( event.ButtonUp(wxMOUSE_BTN_LEFT) ) + bTrackerEditing = 0; + // Do tracker influence if needed if( bTrackerEditing ) { AssDialogue *curline = grid->GetDialogue(grid->editBox->linen); int StartFrame, EndFrame, localframe; if( curline - && curline->Tracker && (StartFrame = VFR_Output.CorrectFrameAtTime(curline->Start.GetMS(),true)) <= frame_n && (EndFrame = VFR_Output.CorrectFrameAtTime(curline->End.GetMS(),false)) >= frame_n - && (localframe = frame_n - StartFrame) < curline->Tracker->GetFrame() ) - curline->Tracker->InfluenceFeatures( localframe, float(x)/provider->GetZoom(), float(y)/provider->GetZoom(), TrackerEdit ); + { + localframe = frame_n - StartFrame; + if( curline->Tracker && localframe < curline->Tracker->GetFrame() ) + curline->Tracker->InfluenceFeatures( localframe, float(x)/provider->GetZoom(), float(y)/provider->GetZoom(), TrackerEdit ); + else if( curline->Movement && localframe < curline->Movement->Frames.size() ) + {// no /provider->GetZoom() to improve precision + if( MovementEdit==1 ) + { + for( int i=0;iMovement->Frames.size();i++ ) + { + curline->Movement->Frames[i].Pos.x += float(x-MouseDownX); + curline->Movement->Frames[i].Pos.y += float(y-MouseDownY); + } + } + else if( MovementEdit==2 ) + { + curline->Movement->Frames[localframe].Pos.x += float(x-MouseDownX); + curline->Movement->Frames[localframe].Pos.y += float(y-MouseDownY); + } + } + MouseDownX = x; + MouseDownY = y; + } } // Text of current coords diff --git a/core/video_display.h b/core/video_display.h index 68e44c910..3cbfab63c 100644 --- a/core/video_display.h +++ b/core/video_display.h @@ -104,8 +104,12 @@ public: bool loaded; bool IsPlaying; double fps; - double TrackerEdit; + bool bTrackerEditing; + int MovementEdit; + double TrackerEdit; + int MouseDownX, MouseDownY; + VideoSlider *ControlSlider; wxComboBox *zoomBox; wxTextCtrl *PositionDisplay;