From 72d80771424bd395a2997e9b043a15ea518e2c8a Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Sun, 16 Dec 2018 10:24:57 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E6=89=93=E5=8C=85?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E6=97=B6=E6=97=A0=E6=B3=95=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98=20=E6=96=B0=E5=A2=9E=20images.match?= =?UTF-8?q?Template()=E6=89=BE=E5=9B=BE=E8=BF=94=E5=9B=9E=E5=A4=9A?= =?UTF-8?q?=E4=B8=AA=E4=BD=8D=E7=BD=AE=20=E6=96=B0=E5=A2=9E=20=E6=89=BE?= =?UTF-8?q?=E5=9B=BE=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\346\211\276\345\233\276/block.png" | Bin 0 -> 917 bytes .../\346\211\276\345\233\276/mario.png" | Bin 0 -> 1374 bytes .../\346\211\276\345\233\276/super_mario.jpg" | Bin 0 -> 56242 bytes ...56\345\217\267\346\226\271\345\235\227.js" | 11 + ...73\345\207\272\344\275\215\347\275\256.js" | 23 ++ ...72\351\251\254\351\207\214\345\245\245.js" | 8 + .../autojs/autojs/build/ApkBuilder.java | 2 +- .../autojs/storage/database/Database.java | 1 + .../storage/database/TimedTaskDatabase.java | 1 - autojs/src/main/assets/modules/__images__.js | 203 ++++++++++++++---- .../autojs/core/graphics/ScriptCanvas.java | 1 + .../autojs/core/image/ColorFinder.java | 1 + .../autojs/core/image/TemplateMatching.java | 142 ++++++++---- .../autojs/core/web/InjectableWebClient.java | 15 +- .../autojs/runtime/ScriptBridges.java | 4 + .../stardust/autojs/runtime/api/Images.java | 31 +++ 16 files changed, 346 insertions(+), 97 deletions(-) create mode 100644 "app/src/main/assets/sample/\345\233\276\347\211\207\344\270\216\345\233\276\350\211\262\345\244\204\347\220\206/\346\211\276\345\233\276/block.png" create mode 100644 "app/src/main/assets/sample/\345\233\276\347\211\207\344\270\216\345\233\276\350\211\262\345\244\204\347\220\206/\346\211\276\345\233\276/mario.png" create mode 100644 "app/src/main/assets/sample/\345\233\276\347\211\207\344\270\216\345\233\276\350\211\262\345\244\204\347\220\206/\346\211\276\345\233\276/super_mario.jpg" create mode 100644 "app/src/main/assets/sample/\345\233\276\347\211\207\344\270\216\345\233\276\350\211\262\345\244\204\347\220\206/\346\211\276\345\233\276/\346\211\276\345\207\272\346\211\200\346\234\211\351\227\256\345\217\267\346\226\271\345\235\227.js" create mode 100644 "app/src/main/assets/sample/\345\233\276\347\211\207\344\270\216\345\233\276\350\211\262\345\244\204\347\220\206/\346\211\276\345\233\276/\346\211\276\345\207\272\351\227\256\345\217\267\346\226\271\345\235\227\345\271\266\347\224\273\345\207\272\344\275\215\347\275\256.js" create mode 100644 "app/src/main/assets/sample/\345\233\276\347\211\207\344\270\216\345\233\276\350\211\262\345\244\204\347\220\206/\346\211\276\345\233\276/\346\211\276\345\207\272\351\251\254\351\207\214\345\245\245.js" diff --git "a/app/src/main/assets/sample/\345\233\276\347\211\207\344\270\216\345\233\276\350\211\262\345\244\204\347\220\206/\346\211\276\345\233\276/block.png" "b/app/src/main/assets/sample/\345\233\276\347\211\207\344\270\216\345\233\276\350\211\262\345\244\204\347\220\206/\346\211\276\345\233\276/block.png" new file mode 100644 index 0000000000000000000000000000000000000000..c0944e12d05de2e9709b49674d9b1da422208dc6 GIT binary patch literal 917 zcmV;G18V$Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf11d>GK~y+T6_ZPB z6;&9=f9K5eK6`0SJoVnv`Woipp|b5EYGdQ{vQ_-Rp_JlZS4Z0{#dCek-6r#2f5m9E z#uxKbo~N7 zsaAncViK&N?+Ftfcs|xzbh*s%^fc%Gfz2CX`}z_rU!t*ikw5P^{%C3%tqy~cx$qy* zF-}N$0V+E+C+?*9#UiW1qcl_(TPxf+zrZhF9%b{`R$hH~o}1F#l_lh9ocTa(y^D$? zZku8BK$svZLY7f>1}mAcH!hPkZ{iK6#5F`6UU_+zD;GZD{11oG;%MMJ5FPWZht^(* z%dM1Yl+8tpzW8pqZ_5}@J~6|4?|(~2zRDD|X;O_vpn;=Kaw1xWB8PVJFjj*f$y>bE z1Hc;BZcD8pkgeIhL+pHD1eL6zC76CO!1;aefPzwdsk^q3D6oU(=h=g=!TyXcoJYBq29qqMV_2(j^OvjNU)V zGs9hnb`vzJAQ&ND&YG8K`hpqlzS&8n0e+|UYq+E zaZEGlYf@zJB&KR rYPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf1oKHmK~y+T9h7TO z)MXTh_e0Z6AJj@kr-%X}E$^8%I!qH|1}G&0DssPR7|KOJt|7bYE_?m& za%oxa7ZGt`1$7b>xdbAbh*uQ6J^k~;nK>Wc_jlfN-sk)zQX|N;Pbtygqh8TT(cwHA zqqC`wN~bD3orZ{POyM#rvfHWF4pFA+#h|@~%rHv6@DhdQC6fOWgK8LSwuKv!Sy)__ z)9=2Ru5}CEM7PTv+FX_}7?Hq0qLhIXIam^vn3esazzb9YNOClzm<_k6jnAQE{kL>_ zIMVMniJr9+=~**@?v-!T@8N*ic|JN+7zi(LH-xo#YZ+;E4CEHy%& zKNpQ&qy)apW#f8A>H~Pz6bda-WbU@5uQ-@HO?h0ZHqlyll_E_yI{gR=;W3h8(+%Ro z4^vy<$D@`2lKtP}nrQ=ftNeL!K9ccsp%lk_Nr!qXgO&Sv*nE;(XA7~K>L^uTLZur< zq7~Xmj18kfwvPwr50M`5K571wxFYl9Ws@j!HVm%BBgD<5CSwV&+vB)@A&2h9^VFOA z&>5Z}(V2UQjY}Xta6S3at9a6u$XM$Uo}CTlRbvELkCN&=i9ZiaCF_t4N&B6M^mWFh zx1iSCr9eG~q(Ik)R9S^yagu6T5aTT=jMYbqvxs4=E{IoRI|C&?Tr>O8W)9?n`45zN zX=rsfkZZ<}>c!tFG&~mv)J=&_NtN^<1IpbD6>Owe_C38?Pr9_5xvcl0y*dNyIWvtl z7EHw*D3!NRXvdKYuaGFzw<*?J$xVwSIdCcZz4jQlPr%?a8NuI1jOj@IXHhASz%0lx z=}OTl>nPIqq7g=r8pL+0Dy^g)3m_$C1+v(=lm^*T{)-Lg_uA3oV@ucG8B}@OkRRYg zX7p0h!@uG810GZsm!TCpIBgt7aw002)UcJDige^m_y^R4I8f#_feT(!>D>AuH#XVO z>iHh#09#aHcF3db$p~FUa^%nCW@(WZjfk8i1#=;16T-21=)-KO@tMZM=w%G;oXK_f zX>@J0g?KkE`Z!VHZ!ey4ph3Ekl5}56&zwP1G=yZ-BEsJq$94Gz%JzLkjr%*G4}`r- zxa)4mb>}Hi8qdw0^Jw<|gzC`QA}dFD(2_}8xqw>RgJiHy&huK4hq@@Jh@|Vg$=qHx zkw?xpJX$%Gr>=Gkt(d|;tEcliYArM$<#l~551LMi)Cvf~O;Mz+foF}`+)3TV)gR|F zyvBhis~s6~ox|X|g$%5k$*|k!+;;t#E{_?s|F&E#n8iSi97|;bg@uDiD$MP4m6y?f z^j9vqeI{Q1l)iO~Y4i2ta!3q)hk|Hc_qAvZj&%Jn8?)C+9#{QEyZIcYh7J@u5qqui zB9%%7mZ&H)NH2?qr07*qoM6N<$g8SKy$p8QV literal 0 HcmV?d00001 diff --git "a/app/src/main/assets/sample/\345\233\276\347\211\207\344\270\216\345\233\276\350\211\262\345\244\204\347\220\206/\346\211\276\345\233\276/super_mario.jpg" "b/app/src/main/assets/sample/\345\233\276\347\211\207\344\270\216\345\233\276\350\211\262\345\244\204\347\220\206/\346\211\276\345\233\276/super_mario.jpg" new file mode 100644 index 0000000000000000000000000000000000000000..373502ece880325202473aa6f60536a3d7cd1cfd GIT binary patch literal 56242 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
k=pWguSow$*tg^d!%BBnJ+hwk%9D_j~iC%YXEM zV1`BVMGu+bnp^;!%3CHA~TDZnV)k54k=ip-PGkBNcrE(?kP?}z|QL<2&Z3;+br zt0+N0cDc^~c4G==JkC_|!$j&emaON-RX%^_O$$oSJ6Z((nBsLoZ|PSL>6%AY?ch!a z_0}95Xp?W$}@_kl?nqGHXr+vx+GRi&Oyw%|6Jerh7FpY1dD&nP9Xbry+ z$tPv!DINrG)V}&Lc-C42a@cS)w0ZJxru?$)qEmdzP`!l^_}06JRN1iofJTTENp+;f zb{J98nW53Z)zkLvqnRnG^)iFY78Z36-NhZ^coBFfoPPBvj96kiTUGzwO$triwsQjuLc z#F2UNXlysq^GuJlimH?*L5M@nybCh=88kz4gQ4&4wakjVu?k5gz_WmP_~-kcPTR*e zTg7{E#Qhi1i?k=nWZ}H|`ir}9CewSCPoSfWI}Y8;iVsC6$-D}8qzYIQ13uO2kPHtK z1nyGa0A<-tig^VTcYVW@pO3xX*ed zu4sSbR+N-_PMriWamfHDH!y0|MId;CY#P5{s;y0C>_qWou7cxtR3$Av_h7eyGV6W= z@Dx2G3l6$4Bm79?249u;p}NzsC;`Z-UUqSW3<{&M)g89PbI%GO$@r^Dn_56^-DL~v zBElt$ZPR_p-^863MTGw@DlN#gLv^_W#M-N3;of6ubFR|?dA=s0#_j71i@xAt$B7=x z*>g!sBwmgU5M{Z1QH>lFU(=ftq)-OtTT9zh^$=XaG!!)LD4P(;mknb3^vz+s%7wcm z+sxL8)AgO3pO$P&H9YMkg~C?yvsW^|zw4rm_&p`N!VdzA2=lC|^wHQzU0qiSe0tBa z$MDVFUm{Rq@mp=}1ii@- z$YdP8MP=<9`Fola?cEb$HitqwSoVEI+=&jVbX-{lE8&7Gp;ihH_rNKM>8cX6*Aipi z&y-lC%D&mCdH}ArKYg*%sd73K{0r>-S&(IJ$ZT*uKz_3>!9S@c7|CmpC0^dk+mmOE zmU3$S<+}ALN}W{oR$0c)xOqBC1ny^mikR=235nq6wPf--ru_ z3bO9t>J{MG`9SFge+Ax_-d$F4u~Z>`R8|bNef|XKAL)A2L(9GUpSTxY;)kkJ6%C(A zKKp53u;mNUmz|VY%hDS?s{G^7+MW;dO_t-fNtMkO;+U{6)b@QeX1HT4T)z3SGcPIK zCgu0)Y2UI79fG+5J_B&4(n2QK2(cNJkO{J-S?kO%n2Rw;fL~SqC(q^1uA+lUdemi! zlys$35pV2LN`IKVs_X?bJZTsRLi)vgjjB(2oJSk;8!EMSYj?hpAR}e2edlZ2S}QPG zw)^KVZ28Dx`4Kww!ol#_)I=PwgJ40iAR?>*PJ2O*CxOlw?B?2B_U(Q{&(@lpMqwx8 z*&X6D;HH!#_EcrrMOPMm|La;t7xWTDWYFMRtJnUUI)H6lSM8H0H?Y)P$;^eT02?*&tv5701Ic2zQ^n3Qa-2IwN;g?%CZ&f9G_GA#5`vv3YUHCCDXa)3z*Ra%hr0QU2ue8wP zo^EWvV+|8*T)X+)w?2wm^~1RAgsg7$GYdlFZe1?f$g>ZYgX4S?L%F|7NK_~ z%0n_q7THueAUf_iVaUnnn)tiJ9~S&q;-3-edS0pGZxCu)ZRO>>Q`%i>Gff2P=C8`g z%vFaS2*qVngy`3daJYFYOP`unP4hhx-d9RDm6hKA0DndwjqwW>r2`4!tF)D zUAbSDHj|a3c9eb_ZEJqccoX3Vk0JOq@PK516PLEL)4NPG)p(P zwbO0_#bD6ez{(_(P`Qd%5HMdc*+b}jJMgZxrTC-8UNG?%jM^Tt;CUaxdPbUc3rqR* zol^TxNw4mnTRCO5n%;dEQSuZCWN7AMc1G*Geq(>ZQ9dqsv%=rDw~DmAFU0;K({#Ny z4L;V=&eu_z8+%w%$^}T{MPRCmpa7r%00394{A=;k~^#BNE$RU$fPudV?;n$oGK{j0Ir&uT|7+Xj)IIT)>5>RcaJ)4wz;h3YsZ-= zx4o}>@zc&L;Azv#Cn;2+Ma4=IYSM6NB%dwg2PCD)+|o(L_G;f<>3Rjvi~j&?p9JYP zJ~Gw38#TX!JY{{T+-Vwpj-{zSo;3Kp=#mS-Vjgm&h_W`^GMq3Vkz?XjkB+_xd@I(x zVXJ7q9r34zygdY$cl!5)wcBfJTWHrAPqFHAnv8EvBa}#RwZFsN zCtL9rxvXhghP4DYR(IF(+*{nCZc*cQD$0EbBDv$k_;rVd2NM-iG*PZxL|1BOs3ri*3^8mz6{o+Y=ji{ej+U`u%QIo2eMYBvfHC~O7C7{)PI{{U})h<+gWckuV% zPMP8Tb6C*y)$k3J!qZQ^lGXt7#*#?;5QW_C%*=6?W+dd3TK@oHI(4f$vW-t~B&{gu zly1_pl6oYPvyUylM=d@iRj}AqLK3C*Xt#LHb4pXRTW!UyTXL1-E^ED>r|CC?JT>B- zKjZ8l@RoRG{4T!>^y_~e&!6)z9)3wvvXqOO6r`+5`KFzE{1oFi!iM}Wp6p>gX z;CSjSN5wxH{tD^3e~CZg7V$5Lek}NDH0@G5cqh2CxNSy1^q8&Y202Vj;r6nW=onzv z$zQUEj&-ZA_#!XuQQ|2zjZ#k#Tk5(EoLZw@$k&lTHBC8$OE!0e-0XIPjIlW6*O!06 zC%k*Ec;EKf&@MHtYgX1SG)o)H-8xI#xh@{U;Z+LF335zw0;)qU2r4<^rk+PmjcPcW z50;)EntY$lC3!aF-Sx6sr(}&PaV2a`3{DRex$5G%Y5PqVEE-XYP)g60%2LtB?Y*}@ zN$h?T`1(6(r0~_gm+?zUg;k=G-&L^CHLX4^q=TtNsLN?+(@FDTbmzE@e5c-1bbI9R zUYgz=_$i~_f2`ELE5&2uy+U~MQdvvz4|wVjpG;|lS_(XWZ- zt4f=0Fr1atnzECcg68F1$zCn$o$i}|VtgU+UbW+mH{(XBqWntJv^yJb9%(jEX&RQ8 zw>k~Q`uKV;GHctbXlB2Nq-!i|9lEgdgkjV#n9HTCd@k`;zwraYUIp=|gi}rM{{W1h z?&DIrhr~K%?Z1e0Jv!O1^^0g0*5+Hgc`kJ5t|Nh`jt5toJ#J{um#SLRtx`r7w4F>86-eQpNBG|bEJWE&l-ae};TREy#1`+>bNt+E3WQ+7vCv+F7N~m9<%y@lW_!`RF&W7e)8pBP! zRMsr#cwOz}X|*d$8Dg3jm-lw=1d6Uz`L6-^V*AH`w6~9~^uHcW;S|xn7+XuKLvN>A z>Ir?n#5Q8y-t0(^Exo^-@XGH3`TknAz{G`blRx05zC71F5&r-L{{a1rX3=$>TSuE# z@UE$QeD+szTeal!No4X%AwoCE%*@4`B$gzcn)45WUOU$P6Lr5nRm}m&~xw?&M`xjH5SG;#qVb2wZ78 zPKyiZehTnClzK*$74-iA@(#0#StfBL&cv|u=D2VlcRekH$sUaf49iYA!1GlWs6dPF9L-Mmu(PU$I{Yei8WP{{UvMfwO7;G}HWN zeSh%tMYxZ{+U2Fbjd2aDLf>Yy((a;-EuEA1o@|<&@bDto>{-Cx_*G@%9Sh=jiM&VR zEe*UqseCL*G^-6Y^$Q(Jdp&biws(U2&9a(nX>I=ivPP)`A(e{DcMExYlYD=h{{Zk- z&x!se@GtFeHjkoshg{M0jXOxSwzRRazn0$G)+I6pjyTbRs)4{z02SzdDDmF8rGLS` zIxmPVb)8n*UevxZ*~NLOMRy`zU7~5)*hP|1ceM?~{s$8;3 z`@G5O*EOXiuDOzny`{bH!yMBQfT0|!QtMEQB67VO+xnziGzR{Gx4 zLb~x+?Pu_ZLel(Qec-)LQQ~W+zSFGjH4Q==IQ%cFwZMwn=op*LiDZX!j46{Kh5(Dc zEYQ4l@UP+azv7FH8%Fqp;Xe!5+-leQ&xbX;Ej-%VK@&?Pb6RS0+FeO@u_u_~(iveU zMM$08GOy=X{1em1+U~h)@uOb8*0pQRb4B=fs0}+&p7Kd9>;tPK`BIWzJ<9HfOFnDwq2E)Av2w;#%QP*YM^xkQ zH@a!U+dJrf%U^spz4#;HZ8yMol0$i}Y4c00_@eI6Gg|7}_1Z$WHwNgbJa3ZVeI5D8<+$2HOY zis{y`Qlz6lZq#ik`>~8~B&?*HvWkkcjkjA^7e-3GKc<)uPZxCr(l)Am0rPaNqs=+3k zb#Nn=En4$ToUD%!c&+9ca7=HN@uyYQJaOXR39<14=sqd&U&N0MHLj?(@JS>$viO3^ zLp)aU4=z?lCQmG>LKg&W$ghpRVP78Wx|jSCxAw}{?lrAi<6hHzKcZV&YEoUu*LJZ# zh_r(7$0s7zJlI3l#BeA%6 z=0N1_kr`E$h6pMMAd1iZU!_WPYvJE5JUesbwfUsI=J}g;x{PD0c1z@1;)>Pj;&8aQ z^VP*D()OAzNJ(;}qLrU3l%=DM+v&UgRMtKX{6;=I)@{5$CY$kcCB2n*{l8A|=Dh>? ztR74F?_{*o{&_cu*2Y?D+3o z_-FB-;I5hBy=PVM{+gc%w1!(vHttJE6r1f!BqU@me+rtsJ4$rwQ>DvJrA28RE5;I%zc(zBZfXg>U3pZKceCc^SASM~BJhT% zI3AzJu$+e*~DA!gcb&YvCLk$tF}9dO3i^Tiamw&@IU+%DTyE?#xqqztb1 zvG9B14~g~v01S99SMc_mrP=uM?d&1(3>yBOcctpq*7lQXH^M7;r+r2Rxzp^g787x6 z43WIi2|S0+-_AW_$9m_5{{Y~WS}v`oYdW@_s%zg7noUmf*6v7dH5N;2&5bmQLr7P9 z;ITN~*y?N2Kj4J^KG(c$`&0Pk^{s1G)!#|@XX1<77QMWZ;Mv>_He?e;yq%J4cU{Ya zhhdx(U0>L^X-=QFgk|h`V4a$6#>(!_&0k(tpKfNh`vo(D;L1X)G=7E%b{xAk(y%B^i>}Pql?Dtl@K$xudp<6f8>? zDp<1;Nh|Qwe0}lSj1L<4v=93W+<) { + canvas.drawRect(point.x, point.y, point.x + block.width, point.y + block.height, paint); +}); +var image = canvas.toImage(); +images.save(image, "/sdcard/tmp.png"); + +app.viewFile("/sdcard/tmp.png"); + +superMario.recycle(); +block.recycle(); +image.recycle(); diff --git "a/app/src/main/assets/sample/\345\233\276\347\211\207\344\270\216\345\233\276\350\211\262\345\244\204\347\220\206/\346\211\276\345\233\276/\346\211\276\345\207\272\351\251\254\351\207\214\345\245\245.js" "b/app/src/main/assets/sample/\345\233\276\347\211\207\344\270\216\345\233\276\350\211\262\345\244\204\347\220\206/\346\211\276\345\233\276/\346\211\276\345\207\272\351\251\254\351\207\214\345\245\245.js" new file mode 100644 index 000000000..6285cbef4 --- /dev/null +++ "b/app/src/main/assets/sample/\345\233\276\347\211\207\344\270\216\345\233\276\350\211\262\345\244\204\347\220\206/\346\211\276\345\233\276/\346\211\276\345\207\272\351\251\254\351\207\214\345\245\245.js" @@ -0,0 +1,8 @@ + +var superMario = images.read("./super_mario.jpg"); +var mario = images.read("./mario.png"); +var point = findImage(superMario, mario); +toastLog(point); + +superMario.recycle(); +mario.recycle(); \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/autojs/build/ApkBuilder.java b/app/src/main/java/org/autojs/autojs/autojs/build/ApkBuilder.java index 6060878a4..bd0837516 100644 --- a/app/src/main/java/org/autojs/autojs/autojs/build/ApkBuilder.java +++ b/app/src/main/java/org/autojs/autojs/autojs/build/ApkBuilder.java @@ -26,6 +26,7 @@ import java.io.InputStream; import java.util.ArrayList; import java.util.concurrent.Callable; +import java.util.regex.Pattern; import pxb.android.StringItem; import pxb.android.axml.AxmlWriter; @@ -201,7 +202,6 @@ public void copyDir(String relativePath, String path) throws IOException { private void encrypt(File toDir, File file) throws IOException { FileOutputStream fos = new FileOutputStream(new File(toDir, file.getName())); - EncryptedScriptFileHeader.INSTANCE.writeHeader(fos, (short) new JavaScriptFileSource(file).getExecutionMode()); encrypt(fos, file); } diff --git a/app/src/main/java/org/autojs/autojs/storage/database/Database.java b/app/src/main/java/org/autojs/autojs/storage/database/Database.java index d42fea788..ddf72f20f 100644 --- a/app/src/main/java/org/autojs/autojs/storage/database/Database.java +++ b/app/src/main/java/org/autojs/autojs/storage/database/Database.java @@ -58,6 +58,7 @@ public Observable delete(M model) { public Observable update(M model) { return exec(() -> { ContentValues values = asContentValues(model); + values.put("id", model.getId()); int update = mWritableSQLiteDatabase.update(mTable, values, "id = ?", arg(model.getId())); if (update >= 1) { mModelChange.onNext(new ModelChange<>(model, ModelChange.UPDATE)); diff --git a/app/src/main/java/org/autojs/autojs/storage/database/TimedTaskDatabase.java b/app/src/main/java/org/autojs/autojs/storage/database/TimedTaskDatabase.java index b6f343e5a..4354bb7ad 100644 --- a/app/src/main/java/org/autojs/autojs/storage/database/TimedTaskDatabase.java +++ b/app/src/main/java/org/autojs/autojs/storage/database/TimedTaskDatabase.java @@ -21,7 +21,6 @@ public TimedTaskDatabase(Context context) { @Override protected ContentValues asContentValues(TimedTask model) { ContentValues values = new ContentValues(); - values.put("id", model.getId()); values.put("time", model.getTimeFlag()); values.put("scheduled", model.isScheduled()); values.put("delay", model.getDelay()); diff --git a/autojs/src/main/assets/modules/__images__.js b/autojs/src/main/assets/modules/__images__.js index 587e10afd..1c35e4cb8 100644 --- a/autojs/src/main/assets/modules/__images__.js +++ b/autojs/src/main/assets/modules/__images__.js @@ -1,26 +1,123 @@ module.exports = function (runtime, scope) { const ResultAdapter = require("result_adapter"); - function images(){ + + var MatchingResult = (function () { + var comparators = { + "left": (l, r) => l.point.x - r.point.x, + "top": (l, r) => l.point.y - r.point.y, + "right": (l, r) => r.point.x - l.point.x, + "bottom": (l, r) => r.point.y - l.point.y + } + function MatchingResult(list) { + if (Array.isArray(list)) { + this.matches = list; + } else { + this.matches = runtime.bridges.bridges.toArray(list); + } + this.__defineGetter__("points", () => { + if (typeof (this.__points__) == 'undefined') { + this.__points__ = this.matches.map(m => m.point); + } + return this.__points__; + }); + } + MatchingResult.prototype.first = function () { + if (this.matches.length == 0) { + return null; + } + return this.matches[0]; + } + MatchingResult.prototype.last = function () { + if (this.matches.length == 0) { + return null; + } + return this.matches[this.matches.length - 1]; + } + MatchingResult.prototype.findMax = function (cmp) { + if (this.matches.length == 0) { + return null; + } + var target = this.matches[0]; + this.matches.forEach(m => { + if (cmp(target, m) > 0) { + target = m; + } + }); + return target; + } + MatchingResult.prototype.leftmost = function () { + return this.findMax(comparators.left); + } + MatchingResult.prototype.topmost = function () { + return this.findMax(comparators.top); + } + MatchingResult.prototype.rightmost = function () { + return this.findMax(comparators.right); + } + MatchingResult.prototype.bottommost = function () { + return this.findMax(comparators.bottom); + } + MatchingResult.prototype.worst = function () { + return this.findMax((l, r) => l.similarity - r.similarity); + } + MatchingResult.prototype.best = function () { + return this.findMax((l, r) => r.similarity - l.similarity); + } + MatchingResult.prototype.sortBy = function(cmp) { + var comparatorFn = null; + if(typeof(cmp) == 'string'){ + cmp.split("-").forEach(direction => { + var buildInFn = comparators[direction]; + if(!buildInFn){ + throw new Error("unknown direction '" + direction + "' in '" + cmp +"'"); + } + (function(fn){ + if(comparatorFn == null){ + comparatorFn = fn; + }else{ + comparatorFn = (function(comparatorFn, fn){ + return function(l, r){ + var cmpValue = comparatorFn(l, r); + if(cmpValue == 0){ + return fn(l, r); + } + return cmpValue; + } + })(comparatorFn, fn); + } + })(buildInFn); + }); + }else{ + comparatorFn = cmp; + } + var clone = this.matches.slice(); + clone.sort(comparatorFn); + return new MatchingResult(clone); + } + return MatchingResult; + })(); + + function images() { } - if(android.os.Build.VERSION.SDK_INT >= 21){ + if (android.os.Build.VERSION.SDK_INT >= 21) { util.__assignFunctions__(runtime.images, images, ['captureScreen', 'read', 'copy', 'load', 'clip', 'pixel']) } - images.opencvImporter = JavaImporter( - org.opencv.core.Point, - org.opencv.core.Point3, - org.opencv.core.Rect, - org.opencv.core.Algorithm, - org.opencv.core.Scalar, - org.opencv.core.Size, - org.opencv.core.Core, - org.opencv.core.CvException, - org.opencv.core.CvType, - org.opencv.core.TermCriteria, - org.opencv.core.RotatedRect, - org.opencv.core.Range, - org.opencv.imgproc.Imgproc, - com.stardust.autojs.core.opencv + images.opencvImporter = JavaImporter( + org.opencv.core.Point, + org.opencv.core.Point3, + org.opencv.core.Rect, + org.opencv.core.Algorithm, + org.opencv.core.Scalar, + org.opencv.core.Size, + org.opencv.core.Core, + org.opencv.core.CvException, + org.opencv.core.CvType, + org.opencv.core.TermCriteria, + org.opencv.core.RotatedRect, + org.opencv.core.Range, + org.opencv.imgproc.Imgproc, + com.stardust.autojs.core.opencv ); with (images.opencvImporter) { const defaultColorThreshold = 4; @@ -56,13 +153,13 @@ module.exports = function (runtime, scope) { var colorFinder = javaImages.colorFinder; - images.requestScreenCapture = function(landscape) { + images.requestScreenCapture = function (landscape) { let ScreenCapturer = com.stardust.autojs.core.image.capture.ScreenCapturer; var orientation = ScreenCapturer.ORIENTATION_AUTO; - if(landscape === true){ + if (landscape === true) { orientation = ScreenCapturer.ORIENTATION_LANDSCAPE; } - if(landscape === false){ + if (landscape === false) { orientation = ScreenCapturer.ORIENTATION_PORTRAIT; } return ResultAdapter.wait(javaImages.requestScreenCapture(orientation)); @@ -105,7 +202,7 @@ module.exports = function (runtime, scope) { colors.blue(color) - threshold, colors.alpha(color)); ub = new Scalar(colors.red(color) + threshold, colors.green(color) + threshold, colors.blue(color) + threshold, colors.alpha(color)); - }else{ + } else { throw new TypeError('lowerBound = ' + lowerBound, + 'upperBound = ' + upperBound); } } @@ -115,7 +212,7 @@ module.exports = function (runtime, scope) { } - images.adaptiveThreshold = function(img, maxValue, adaptiveMethod, thresholdType, blockSize, C){ + images.adaptiveThreshold = function (img, maxValue, adaptiveMethod, thresholdType, blockSize, C) { initIfNeeded(); var mat = new Mat(); adaptiveMethod = Imgproc["ADAPTIVE_THRESH_" + adaptiveMethod]; @@ -168,13 +265,13 @@ module.exports = function (runtime, scope) { return images.matToImage(mat); } - images.findCircles = function(grayImg, options) { + images.findCircles = function (grayImg, options) { initIfNeeded(); options = options || {}; var mat = options.region == undefined ? grayImg.mat : new Mat(grayImg.mat, buildRegion(options.region, grayImg)); var resultMat = new Mat() var dp = options.dp == undefined ? 1 : options.dp; - var minDst = options.minDst == undefined ? grayImg.height / 8 : options.minDst; + var minDst = options.minDst == undefined ? grayImg.height / 8 : options.minDst; var param1 = options.param1 == undefined ? 100 : options.param1; var param2 = options.param2 == undefined ? 100 : options.param2; var minRadius = options.minRadius == undefined ? 0 : options.minRadius; @@ -191,14 +288,14 @@ module.exports = function (runtime, scope) { }); } } - if(options.region != undefined){ + if (options.region != undefined) { mat.release(); } resultMat.release(); return result; } - images.resize = function(img, size, interpolation) { + images.resize = function (img, size, interpolation) { initIfNeeded(); var mat = new Mat(); interpolation = Imgproc["INTER_" + (interpolation || "LINEAR")]; @@ -206,7 +303,7 @@ module.exports = function (runtime, scope) { return images.matToImage(mat); } - images.scale = function(img, fx, fy, interpolation) { + images.scale = function (img, fx, fy, interpolation) { initIfNeeded(); var mat = new Mat(); interpolation = Imgproc["INTER_" + (interpolation || "LINEAR")]; @@ -214,18 +311,18 @@ module.exports = function (runtime, scope) { return images.matToImage(mat); } - images.rotate = function(img, degree, x, y) { + images.rotate = function (img, degree, x, y) { initIfNeeded(); - if(x == undefined){ + if (x == undefined) { x = img.width / 2; } - if(y == undefined){ + if (y == undefined) { y = img.height / 2; } return javaImages.rotate(img, x, y, degree); } - images.concat = function(img1, img2, direction, rect1, rect2) { + images.concat = function (img1, img2, direction, rect1, rect2) { initIfNeeded(); direction = direction || "right"; rect1 = buildRegion(rect1, img1); @@ -314,7 +411,7 @@ module.exports = function (runtime, scope) { if (typeof (options.level) == 'number') { maxLevel = options.level; } - var weakThreshold = options.weakThreshold || 0.7; + var weakThreshold = options.weakThreshold || 0.6; if (options.region) { return javaImages.findImage(img, template, weakThreshold, threshold, buildRegion(options.region, img), maxLevel); } else { @@ -322,6 +419,27 @@ module.exports = function (runtime, scope) { } } + images.matchTemplate = function (img, template, options) { + initIfNeeded(); + options = options || {}; + var threshold = options.threshold || 0.9; + var maxLevel = -1; + if (typeof (options.level) == 'number') { + maxLevel = options.level; + } + var max = options.max || 5; + var weakThreshold = options.weakThreshold || 0.6; + var result; + if (options.region) { + result = javaImages.matchTemplate(img, template, weakThreshold, threshold, buildRegion(options.region, img), maxLevel, max); + } else { + result = javaImages.matchTemplate(img, template, weakThreshold, threshold, null, maxLevel, max); + } + return new MatchingResult(result); + } + + + images.findImageInRegion = function (img, template, x, y, width, height, threshold) { return images.findImage(img, template, { region: [x, y, width, height], @@ -364,11 +482,15 @@ module.exports = function (runtime, scope) { }; } - images.matToImage = function(img){ + images.matToImage = function (img) { initIfNeeded(); return Image.ofMat(img); } + + + + function getColorDetector(color, algorithm, threshold) { switch (algorithm) { case "rgb": @@ -395,7 +517,7 @@ module.exports = function (runtime, scope) { } function buildRegion(region, img) { - if(region == undefined){ + if (region == undefined) { region = []; } var x = region[0] === undefined ? 0 : region[0]; @@ -403,6 +525,9 @@ module.exports = function (runtime, scope) { var width = region[2] === undefined ? img.getWidth() - x : region[2]; var height = region[3] === undefined ? (img.getHeight() - y) : region[3]; var r = new org.opencv.core.Rect(x, y, width, height); + if(x < 0 || y < 0 || x + width > img.width || y + height > img.height) { + throw new Error("out of region: region = [" + [x, y, width, height] + "], image.size = [" + [img.width, img.height] + "]"); + } return r; } @@ -412,7 +537,7 @@ module.exports = function (runtime, scope) { } return color; } - + function newSize(size) { if (!Array.isArray(size)) { size = [size, size]; @@ -423,14 +548,14 @@ module.exports = function (runtime, scope) { return new Size(size[0], size[1]); } - function initIfNeeded(){ + function initIfNeeded() { javaImages.initOpenCvIfNeeded(); } - + scope.__asGlobal__(images, ['requestScreenCapture', 'captureScreen', 'findImage', 'findImageInRegion', 'findColor', 'findColorInRegion', 'findColorEquals', 'findMultiColors']); - + scope.colors = colors; - + return images; } } \ No newline at end of file diff --git a/autojs/src/main/java/com/stardust/autojs/core/graphics/ScriptCanvas.java b/autojs/src/main/java/com/stardust/autojs/core/graphics/ScriptCanvas.java index d7d79df3a..a71e6aa10 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/graphics/ScriptCanvas.java +++ b/autojs/src/main/java/com/stardust/autojs/core/graphics/ScriptCanvas.java @@ -316,6 +316,7 @@ public void drawOval(@NonNull RectF oval, @NonNull Paint paint) { mCanvas.drawOval(oval, paint); } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) { mCanvas.drawOval(left, top, right, bottom, paint); } diff --git a/autojs/src/main/java/com/stardust/autojs/core/image/ColorFinder.java b/autojs/src/main/java/com/stardust/autojs/core/image/ColorFinder.java index cbba493c7..d5dba8655 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/image/ColorFinder.java +++ b/autojs/src/main/java/com/stardust/autojs/core/image/ColorFinder.java @@ -56,6 +56,7 @@ public Point findColor(ImageWrapper image, int color, int threshold, Rect rect) } public Point[] findAllPointsForColor(ImageWrapper image, int color, int threshold, Rect rect) { + MatOfPoint matOfPoint = findColorInner(image, color, threshold, rect); if (matOfPoint == null) { return new Point[0]; diff --git a/autojs/src/main/java/com/stardust/autojs/core/image/TemplateMatching.java b/autojs/src/main/java/com/stardust/autojs/core/image/TemplateMatching.java index ef9295c38..065f50a3f 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/image/TemplateMatching.java +++ b/autojs/src/main/java/com/stardust/autojs/core/image/TemplateMatching.java @@ -1,6 +1,5 @@ package com.stardust.autojs.core.image; -import android.util.Pair; import android.util.TimingLogger; import com.stardust.autojs.core.opencv.OpenCVHelper; @@ -8,12 +7,20 @@ import org.opencv.core.Core; import org.opencv.core.CvType; + import com.stardust.autojs.core.opencv.Mat; + import org.opencv.core.Point; import org.opencv.core.Rect; +import org.opencv.core.Scalar; import org.opencv.core.Size; import org.opencv.imgproc.Imgproc; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + /** * Created by Stardust on 2017/11/25. @@ -21,13 +28,35 @@ public class TemplateMatching { + public static class Match { + public final Point point; + public final double similarity; + + public Match(Point point, double similarity) { + this.point = point; + this.similarity = similarity; + } + + @Override + public String toString() { + return "Match{" + + "point=" + point + + ", similarity=" + similarity + + '}'; + } + } + private static final String LOG_TAG = "TemplateMatching"; public static final int MAX_LEVEL_AUTO = -1; public static final int MATCHING_METHOD_DEFAULT = Imgproc.TM_CCOEFF_NORMED; - public static Point fastTemplateMatching(Mat img, Mat template, float threshold) { - return fastTemplateMatching(img, template, MATCHING_METHOD_DEFAULT, 0.75f, threshold, MAX_LEVEL_AUTO); + public static Point fastTemplateMatching(Mat img, Mat template, int matchMethod, float weakThreshold, float strictThreshold, int maxLevel) { + List result = fastTemplateMatching(img, template, matchMethod, weakThreshold, strictThreshold, maxLevel, 1); + if (result.isEmpty()) { + return null; + } + return result.get(0).point; } /** @@ -41,7 +70,7 @@ public static Point fastTemplateMatching(Mat img, Mat template, float threshold) * @param maxLevel 图像金字塔的层数 * @return */ - public static Point fastTemplateMatching(Mat img, Mat template, int matchMethod, float weakThreshold, float strictThreshold, int maxLevel) { + public static List fastTemplateMatching(Mat img, Mat template, int matchMethod, float weakThreshold, float strictThreshold, int maxLevel, int limit) { TimingLogger logger = new TimingLogger(LOG_TAG, "fast_tm"); if (maxLevel == MAX_LEVEL_AUTO) { //自动选取金字塔层数 @@ -49,62 +78,64 @@ public static Point fastTemplateMatching(Mat img, Mat template, int matchMethod, logger.addSplit("selectPyramidLevel:" + maxLevel); } //保存每一轮匹配到模板图片在原图片的位置 - Point p = null; - Mat matchResult = null; - double similarity = 0; + List finalMatchResult = new ArrayList<>(); + List previousMatchResult = Collections.emptyList(); boolean isFirstMatching = true; for (int level = maxLevel; level >= 0; level--) { - //放缩图片 + // 放缩图片 + List currentMatchResult = new ArrayList<>(); Mat src = getPyramidDownAtLevel(img, level); Mat currentTemplate = getPyramidDownAtLevel(template, level); - //如果在上一轮中没有匹配到图片,则考虑是否退出匹配 - if (p == null) { - //如果不是第一次匹配,并且不满足shouldContinueMatching的条件,则直接退出匹配(返回null) + // 如果在上一轮中没有匹配到图片,则考虑是否退出匹配 + if (previousMatchResult.isEmpty()) { + // 如果不是第一次匹配,并且不满足shouldContinueMatching的条件,则直接退出匹配 if (!isFirstMatching && !shouldContinueMatching(level, maxLevel)) { break; } + Mat matchResult = matchTemplate(src, currentTemplate, matchMethod); + getBestMatched(matchResult, currentTemplate, matchMethod, weakThreshold, currentMatchResult, limit, null); OpenCVHelper.release(matchResult); - matchResult = matchTemplate(src, currentTemplate, matchMethod); - Pair bestMatched = getBestMatched(matchResult, matchMethod, weakThreshold); - p = bestMatched.first; - similarity = bestMatched.second; } else { - //根据上一轮的匹配点,计算本次匹配的区域 - Rect r = getROI(p, src, currentTemplate); - OpenCVHelper.release(matchResult); - Mat m = new Mat(src, r); - matchResult = matchTemplate(m, currentTemplate, matchMethod); - OpenCVHelper.release(m); - Pair bestMatched = getBestMatched(matchResult, matchMethod, weakThreshold); - //不满足弱阈值,返回null - if (bestMatched.second < weakThreshold) { - // p = null; - // break; + for (Match match : previousMatchResult) { + // 根据上一轮的匹配点,计算本次匹配的区域 + Rect r = getROI(match.point, src, currentTemplate); + Mat m = new Mat(src, r); + Mat matchResult = matchTemplate(m, currentTemplate, matchMethod); + getBestMatched(matchResult, currentTemplate, matchMethod, weakThreshold, currentMatchResult, limit, r); + OpenCVHelper.release(m); + OpenCVHelper.release(matchResult); } - p = bestMatched.first; - similarity = bestMatched.second; - p.x += r.x; - p.y += r.y; } + if (src != img) OpenCVHelper.release(src); if (currentTemplate != template) OpenCVHelper.release(currentTemplate); - //满足强阈值,返回当前结果 - if (similarity >= strictThreshold) { - pyrUp(p, level); - break; + + logger.addSplit("level:" + level + ", result:" + previousMatchResult); + + // 把满足强阈值的点找出来,加到最终结果列表 + if (!currentMatchResult.isEmpty()) { + Iterator iterator = currentMatchResult.iterator(); + while (iterator.hasNext()) { + Match match = iterator.next(); + if (match.similarity >= strictThreshold) { + pyrUp(match.point, level); + finalMatchResult.add(match); + iterator.remove(); + } + } + // 如果所有结果都满足强阈值,则退出循环,返回最终结果 + if (currentMatchResult.isEmpty()) { + break; + } } - logger.addSplit("level:" + level + " point:" + p); isFirstMatching = false; + previousMatchResult = currentMatchResult; } - logger.addSplit("result:" + p); + logger.addSplit("result:" + finalMatchResult); logger.dumpToLog(); - OpenCVHelper.release(matchResult); - if (similarity < strictThreshold) { - return null; - } - return p; + return finalMatchResult; } @@ -168,7 +199,7 @@ private static int selectPyramidLevel(Mat img, Mat template) { } - public static Mat matchTemplate(Mat img, Mat temp, int match_method) { + private static Mat matchTemplate(Mat img, Mat temp, int match_method) { int result_cols = img.cols() - temp.cols() + 1; int result_rows = img.rows() - temp.rows() + 1; Mat result = new Mat(result_rows, result_cols, CvType.CV_32FC1); @@ -176,10 +207,21 @@ public static Mat matchTemplate(Mat img, Mat temp, int match_method) { return result; } - public static Pair getBestMatched(Mat tmResult, int matchMethod, float threshold) { + private static void getBestMatched(Mat tmResult, Mat template, int matchMethod, float weakThreshold, List outResult, int limit, Rect rect) { + for (int i = 0; i < limit; i++) { + Match bestMatched = getBestMatched(tmResult, matchMethod, weakThreshold, rect); + if (bestMatched == null) { + break; + } + outResult.add(bestMatched); + Core.rectangle(tmResult, bestMatched.point, + new Point(bestMatched.point.x + template.cols(), bestMatched.point.y + template.rows()), + new Scalar(0, 255, 0), -1); + } + } + + private static Match getBestMatched(Mat tmResult, int matchMethod, float weakThreshold, Rect rect) { TimingLogger logger = new TimingLogger(LOG_TAG, "best_matched_point"); - // FIXME: 2017/11/26 正交化? - // Core.normalize(tmResult, tmResult, 0, 1, Core.NORM_MINMAX, -1, new Mat()); Core.MinMaxLocResult mmr = Core.minMaxLoc(tmResult); logger.addSplit("minMaxLoc"); double value; @@ -191,9 +233,15 @@ public static Pair getBestMatched(Mat tmResult, int matchMethod, pos = mmr.maxLoc; value = mmr.maxVal; } + if (value < weakThreshold) { + return null; + } + if (rect != null) { + pos.x += rect.x; + pos.y += rect.y; + } logger.addSplit("value:" + value); - logger.dumpToLog(); - return new Pair<>(pos, value); + return new Match(pos, value); } diff --git a/autojs/src/main/java/com/stardust/autojs/core/web/InjectableWebClient.java b/autojs/src/main/java/com/stardust/autojs/core/web/InjectableWebClient.java index 5099e301e..95eee69c4 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/web/InjectableWebClient.java +++ b/autojs/src/main/java/com/stardust/autojs/core/web/InjectableWebClient.java @@ -92,15 +92,12 @@ private class ScriptBridge { @JavascriptInterface public String eval(final String script) { result = null; - mWebView.post(new Runnable() { - @Override - public void run() { - Log.v(TAG, "ScriptBridge.eval: " + script); - result = mContext.evaluateString(mScriptable, script, "", 1, null); - Log.v(TAG, "ScriptBridge.eval = " + result); - synchronized (ScriptBridge.this) { - ScriptBridge.this.notify(); - } + mWebView.post(() -> { + Log.v(TAG, "ScriptBridge.eval: " + script); + result = mContext.evaluateString(mScriptable, script, "", 1, null); + Log.v(TAG, "ScriptBridge.eval = " + result); + synchronized (ScriptBridge.this) { + ScriptBridge.this.notify(); } }); synchronized (ScriptBridge.this) { diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/ScriptBridges.java b/autojs/src/main/java/com/stardust/autojs/runtime/ScriptBridges.java index c567d8b0f..072d9c2ce 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/ScriptBridges.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/ScriptBridges.java @@ -26,6 +26,10 @@ public void setBridges(Bridges bridges) { mBridges = bridges; } + public Bridges getBridges() { + return mBridges; + } + public Object callFunction(Object func, Object target, Object args) { checkBridges(); return mBridges.call(func, target, args); diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Images.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Images.java index 711a60383..53fb17f99 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Images.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Images.java @@ -43,6 +43,9 @@ import java.net.HttpURLConnection; import java.net.URL; import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; /** * Created by Stardust on 2017/5/20. @@ -303,6 +306,34 @@ public Point findImage(ImageWrapper image, ImageWrapper template, float weakThre return point; } + public List matchTemplate(ImageWrapper image, ImageWrapper template, float weakThreshold, float threshold, Rect rect, int maxLevel, int limit) { + initOpenCvIfNeeded(); + if (image == null) + throw new NullPointerException("image = null"); + if (template == null) + throw new NullPointerException("template = null"); + Mat src = image.getMat(); + if (rect != null) { + src = new Mat(src, rect); + } + List result = TemplateMatching.fastTemplateMatching(src, template.getMat(), TemplateMatching.MATCHING_METHOD_DEFAULT, + weakThreshold, threshold, maxLevel, limit); + for (TemplateMatching.Match match : result) { + Point point = match.point; + if (rect != null) { + point.x += rect.x; + point.y += rect.y; + } + point.x = mScreenMetrics.scaleX((int) point.x); + point.y = mScreenMetrics.scaleX((int) point.y); + } + if (src != image.getMat()) { + OpenCVHelper.release(src); + } + Collections.sort(result, (l, r) -> Double.compare(r.similarity, l.similarity)); + return result; + } + public Mat newMat() { return new Mat(); }