From 379dcf87d56b83723db09580d90004170b48d61f Mon Sep 17 00:00:00 2001 From: Oscar Deniz Suarez Date: Thu, 21 Feb 2013 17:17:34 +0100 Subject: [PATCH 01/33] Added smile detector --- data/haarcascades/haarcascade_smile.xml | 8353 +++++++++++++++++++++++ samples/c/smiledetect.cpp | 282 + 2 files changed, 8635 insertions(+) create mode 100644 data/haarcascades/haarcascade_smile.xml create mode 100644 samples/c/smiledetect.cpp diff --git a/data/haarcascades/haarcascade_smile.xml b/data/haarcascades/haarcascade_smile.xml new file mode 100644 index 0000000000..b7a6a3a765 --- /dev/null +++ b/data/haarcascades/haarcascade_smile.xml @@ -0,0 +1,8353 @@ + + + + + + + 36 18 + + <_> + + + <_> + + <_> + + + + <_> + 0 0 2 4 -1. + <_> + 0 2 2 2 2. + 0 + -4.8783610691316426e-004 + 0.5921934843063355 + -0.4416360855102539 + <_> + + <_> + + + + <_> + 34 10 2 8 -1. + <_> + 34 14 2 4 2. + 0 + -4.2209611274302006e-004 + 0.3031865060329437 + -0.3291291892528534 + <_> + + <_> + + + + <_> + 0 10 2 8 -1. + <_> + 0 14 2 4 2. + 0 + -4.9940118333324790e-004 + 0.4856331050395966 + -0.4292306005954742 + <_> + + <_> + + + + <_> + 15 0 18 10 -1. + <_> + 24 0 9 5 2. + <_> + 15 5 9 5 2. + 0 + 0.0372891984879971 + -0.2866730093955994 + 0.5997999906539917 + <_> + + <_> + + + + <_> + 7 0 4 4 -1. + <_> + 7 0 2 4 2. + 1 + 1.4334049774333835e-003 + -0.3489313125610352 + 0.4048275053501129 + <_> + + <_> + + + + <_> + 15 5 6 4 -1. + <_> + 15 6 6 2 2. + 0 + -7.7213020995259285e-003 + 0.7571418881416321 + -0.1222594976425171 + <_> + + <_> + + + + <_> + 13 6 8 3 -1. + <_> + 13 7 8 1 3. + 0 + 8.1067271530628204e-003 + -0.1665772050619125 + 0.7509614825248718 + <_> + + <_> + + + + <_> + 14 6 8 4 -1. + <_> + 14 7 8 2 2. + 0 + -7.7238711528480053e-003 + 0.6266279220581055 + -0.1912745982408524 + <_> + + <_> + + + + <_> + 0 10 2 8 -1. + <_> + 0 14 2 4 2. + 0 + 4.4225031160749495e-004 + -0.2394447028636932 + 0.4484061896800995 + <_> + + <_> + + + + <_> + 34 0 2 16 -1. + <_> + 35 0 1 8 2. + <_> + 34 8 1 8 2. + 0 + -1.6867710510268807e-003 + -0.1843906939029694 + 0.0917824134230614 + <_> + + <_> + + + + <_> + 1 0 4 7 -1. + <_> + 3 0 2 7 2. + 0 + 0.0146256200969219 + 0.1616805940866470 + -0.8150117993354797 + -1.2678639888763428 + -1 + -1 + <_> + + + <_> + + <_> + + + + <_> + 4 7 28 3 -1. + <_> + 11 7 14 3 2. + 0 + 0.0381411388516426 + -0.3327588140964508 + 0.7783334255218506 + <_> + + <_> + + + + <_> + 34 0 2 2 -1. + <_> + 34 1 2 1 2. + 0 + -1.3136120105627924e-004 + 0.3635309040546417 + -0.3204346895217896 + <_> + + <_> + + + + <_> + 0 12 4 6 -1. + <_> + 0 15 4 3 2. + 0 + -3.8757019210606813e-003 + 0.7135239243507385 + -0.3518598973751068 + <_> + + <_> + + + + <_> + 34 0 2 2 -1. + <_> + 34 1 2 1 2. + 0 + 1.4266290236264467e-003 + 0.0681008473038673 + -0.6172732710838318 + <_> + + <_> + + + + <_> + 0 0 2 2 -1. + <_> + 0 1 2 1 2. + 0 + -2.4605958606116474e-004 + 0.5727149844169617 + -0.3786099851131439 + <_> + + <_> + + + + <_> + 17 5 9 12 -1. + <_> + 20 5 3 12 3. + 0 + -0.0318226404488087 + -0.6348456144332886 + 0.1164183989167213 + <_> + + <_> + + + + <_> + 10 5 9 12 -1. + <_> + 13 5 3 12 3. + 0 + -0.0171309504657984 + -0.6279314756393433 + 0.3247947096824646 + <_> + + <_> + + + + <_> + 4 0 32 1 -1. + <_> + 4 0 16 1 2. + 0 + -9.3903783708810806e-003 + -0.2757895886898041 + 0.2233072966337204 + <_> + + <_> + + + + <_> + 0 0 3 3 -1. + <_> + 1 0 1 3 3. + 0 + 2.2802520543336868e-003 + 0.1897764056921005 + -0.6881762146949768 + <_> + + <_> + + + + <_> + 32 7 4 7 -1. + <_> + 33 8 2 7 2. + 1 + 2.6840099599212408e-003 + -0.2235050052404404 + 0.1372579932212830 + <_> + + <_> + + + + <_> + 7 0 8 6 -1. + <_> + 7 0 4 3 2. + <_> + 11 3 4 3 2. + 0 + 0.0106046395376325 + -0.2142623066902161 + 0.5620787143707275 + -1.5844069719314575 + 0 + -1 + <_> + + + <_> + + <_> + + + + <_> + 0 0 2 2 -1. + <_> + 0 1 2 1 2. + 0 + -3.1677199876867235e-004 + 0.4659548103809357 + -0.3742581903934479 + <_> + + <_> + + + + <_> + 27 1 8 9 -1. + <_> + 29 3 4 9 2. + 1 + -0.0551206283271313 + 0.5417978763580322 + -0.2265765070915222 + <_> + + <_> + + + + <_> + 1 10 1 8 -1. + <_> + 1 14 1 4 2. + 0 + -6.4742640824988484e-004 + 0.3770307004451752 + -0.3348644077777863 + <_> + + <_> + + + + <_> + 3 6 30 9 -1. + <_> + 13 9 10 3 9. + 0 + 0.3950783908367157 + -0.1814441978931427 + 0.8132591843605042 + <_> + + <_> + + + + <_> + 12 5 8 6 -1. + <_> + 12 7 8 2 3. + 0 + 0.0405094102025032 + -0.0953694134950638 + 0.8059561848640442 + <_> + + <_> + + + + <_> + 16 4 6 3 -1. + <_> + 16 5 6 1 3. + 0 + 4.8735421150922775e-003 + -0.1402366012334824 + 0.6164302825927734 + <_> + + <_> + + + + <_> + 0 0 2 18 -1. + <_> + 0 0 1 9 2. + <_> + 1 9 1 9 2. + 0 + 0.0105780400335789 + 0.1293267011642456 + -0.7482334971427918 + <_> + + <_> + + + + <_> + 34 2 2 14 -1. + <_> + 35 2 1 7 2. + <_> + 34 9 1 7 2. + 0 + 9.2986393719911575e-003 + 0.0589406006038189 + -0.4410730004310608 + <_> + + <_> + + + + <_> + 0 2 2 14 -1. + <_> + 0 2 1 7 2. + <_> + 1 9 1 7 2. + 0 + -5.0301607698202133e-003 + -0.6630973219871521 + 0.1810476928949356 + <_> + + <_> + + + + <_> + 35 0 1 4 -1. + <_> + 35 2 1 2 2. + 0 + -1.0947990085696802e-004 + 0.2211259007453919 + -0.2730903923511505 + <_> + + <_> + + + + <_> + 5 0 24 18 -1. + <_> + 5 0 12 9 2. + <_> + 17 9 12 9 2. + 0 + -0.1168550997972488 + -0.7720596790313721 + 0.1248165965080261 + <_> + + <_> + + + + <_> + 35 16 1 2 -1. + <_> + 35 17 1 1 2. + 0 + -4.3603649828583002e-005 + 0.1367060989141464 + -0.1612793952226639 + <_> + + <_> + + + + <_> + 0 16 1 2 -1. + <_> + 0 17 1 1 2. + 0 + -1.5056360280141234e-004 + 0.4486046135425568 + -0.2171128988265991 + <_> + + <_> + + + + <_> + 17 6 8 12 -1. + <_> + 19 6 4 12 2. + 0 + -0.0163946095854044 + -0.6582735180854797 + 0.1674550026655197 + <_> + + <_> + + + + <_> + 11 5 8 13 -1. + <_> + 13 5 4 13 2. + 0 + -0.0144828604534268 + -0.6834514737129211 + 0.1345615983009338 + <_> + + <_> + + + + <_> + 35 16 1 2 -1. + <_> + 35 17 1 1 2. + 0 + 3.9269471017178148e-005 + -0.1499813944101334 + 0.1601772010326386 + <_> + + <_> + + + + <_> + 10 9 12 3 -1. + <_> + 10 10 12 1 3. + 0 + 7.4323131702840328e-003 + -0.1684845983982086 + 0.5396398901939392 + -1.3820559978485107 + 1 + -1 + <_> + + + <_> + + <_> + + + + <_> + 0 10 1 8 -1. + <_> + 0 14 1 4 2. + 0 + -4.3472499237395823e-004 + 0.4394924044609070 + -0.4224875867366791 + <_> + + <_> + + + + <_> + 20 0 10 10 -1. + <_> + 25 0 5 5 2. + <_> + 20 5 5 5 2. + 0 + 0.0329953208565712 + -0.1979825049638748 + 0.5953487157821655 + <_> + + <_> + + + + <_> + 0 0 1 4 -1. + <_> + 0 2 1 2 2. + 0 + -4.1011828579939902e-004 + 0.4440306127071381 + -0.3074846863746643 + <_> + + <_> + + + + <_> + 19 0 13 18 -1. + <_> + 19 9 13 9 2. + 0 + -0.0819697380065918 + -0.5333436727523804 + 0.1671810001134872 + <_> + + <_> + + + + <_> + 4 0 14 6 -1. + <_> + 4 0 7 3 2. + <_> + 11 3 7 3 2. + 0 + 0.0177787002176046 + -0.2045017927885056 + 0.5144413113594055 + <_> + + <_> + + + + <_> + 16 5 6 6 -1. + <_> + 16 7 6 2 3. + 0 + 0.0228346996009350 + -0.1484607011079788 + 0.5624278783798218 + <_> + + <_> + + + + <_> + 13 7 7 8 -1. + <_> + 13 9 7 4 2. + 0 + 0.0386043414473534 + -0.1273147016763687 + 0.8149448037147522 + <_> + + <_> + + + + <_> + 33 0 3 1 -1. + <_> + 34 0 1 1 3. + 0 + -7.3286908445879817e-004 + -0.3719344139099121 + 0.0676164999604225 + <_> + + <_> + + + + <_> + 7 1 10 4 -1. + <_> + 6 2 10 2 2. + 1 + -0.0232290402054787 + 0.7123206257820129 + -0.1158939003944397 + <_> + + <_> + + + + <_> + 15 2 6 16 -1. + <_> + 18 2 3 8 2. + <_> + 15 10 3 8 2. + 0 + -0.0195753592997789 + -0.6899073123931885 + 0.1399950981140137 + <_> + + <_> + + + + <_> + 0 10 1 8 -1. + <_> + 0 14 1 4 2. + 0 + 4.1991271427832544e-004 + -0.1835464984178543 + 0.4943555891513825 + <_> + + <_> + + + + <_> + 27 4 6 6 -1. + <_> + 29 6 2 6 3. + 1 + -0.0570897497236729 + 0.6260784864425659 + -0.0785768479108810 + <_> + + <_> + + + + <_> + 14 5 8 8 -1. + <_> + 16 5 4 8 2. + 0 + 0.0256996992975473 + 0.1155714020133019 + -0.8193519115447998 + <_> + + <_> + + + + <_> + 27 5 6 6 -1. + <_> + 29 7 2 6 3. + 1 + 0.0325796194374561 + -0.1176773980259895 + 0.4277622103691101 + <_> + + <_> + + + + <_> + 9 5 6 6 -1. + <_> + 7 7 6 2 3. + 1 + -0.0205922499299049 + 0.4868524074554443 + -0.2131853997707367 + <_> + + <_> + + + + <_> + 12 5 12 9 -1. + <_> + 15 5 6 9 2. + 0 + -0.0174852795898914 + -0.5228734016418457 + 0.1339704990386963 + <_> + + <_> + + + + <_> + 0 0 3 1 -1. + <_> + 1 0 1 1 3. + 0 + 8.9153228327631950e-004 + 0.0963044911623001 + -0.6886307001113892 + <_> + + <_> + + + + <_> + 15 4 18 6 -1. + <_> + 15 6 18 2 3. + 0 + 0.0575339011847973 + -0.0870805233716965 + 0.4048064947128296 + -1.3879380226135254 + 2 + -1 + <_> + + + <_> + + <_> + + + + <_> + 0 10 1 6 -1. + <_> + 0 13 1 3 2. + 0 + -4.6606198884546757e-004 + 0.4277374148368835 + -0.3542076945304871 + <_> + + <_> + + + + <_> + 3 6 30 6 -1. + <_> + 13 8 10 2 9. + 0 + 0.3055455982685089 + -0.1639281064271927 + 0.8606523275375366 + <_> + + <_> + + + + <_> + 11 7 12 4 -1. + <_> + 11 8 12 2 2. + 0 + -0.0114494003355503 + 0.5972732901573181 + -0.2323434054851532 + <_> + + <_> + + + + <_> + 14 8 9 3 -1. + <_> + 14 9 9 1 3. + 0 + 6.3891541212797165e-003 + -0.1291541010141373 + 0.6105204224586487 + <_> + + <_> + + + + <_> + 14 8 7 4 -1. + <_> + 14 9 7 2 2. + 0 + -8.4334248676896095e-003 + 0.4792853891849518 + -0.1900272965431213 + <_> + + <_> + + + + <_> + 12 7 18 6 -1. + <_> + 12 9 18 2 3. + 0 + 0.0538089312613010 + -0.1149377003312111 + 0.5339453816413879 + <_> + + <_> + + + + <_> + 7 8 3 10 -1. + <_> + 7 13 3 5 2. + 0 + -4.7580219688825309e-004 + -0.3459854125976563 + 0.2548804879188538 + <_> + + <_> + + + + <_> + 35 10 1 6 -1. + <_> + 35 13 1 3 2. + 0 + -1.3450840197037905e-004 + 0.2241459041833878 + -0.1955007016658783 + <_> + + <_> + + + + <_> + 0 10 1 6 -1. + <_> + 0 13 1 3 2. + 0 + 5.0016911700367928e-004 + -0.1972054988145828 + 0.4967764019966126 + <_> + + <_> + + + + <_> + 18 13 9 5 -1. + <_> + 21 13 3 5 3. + 0 + 0.0150632699951530 + 0.1063077002763748 + -0.4113821089267731 + <_> + + <_> + + + + <_> + 15 9 6 4 -1. + <_> + 15 10 6 2 2. + 0 + 7.7588870190083981e-003 + -0.1537311971187592 + 0.4893161952495575 + <_> + + <_> + + + + <_> + 16 4 18 8 -1. + <_> + 16 6 18 4 2. + 0 + 0.0454101189970970 + -0.0735593065619469 + 0.2773792147636414 + <_> + + <_> + + + + <_> + 9 14 9 3 -1. + <_> + 12 14 3 3 3. + 0 + -0.0145996697247028 + -0.7096682786941528 + 0.0975155606865883 + <_> + + <_> + + + + <_> + 32 0 4 6 -1. + <_> + 32 0 2 6 2. + 0 + 0.0172360707074404 + 0.0168695393949747 + -0.5738832950592041 + <_> + + <_> + + + + <_> + 0 0 4 6 -1. + <_> + 2 0 2 6 2. + 0 + 0.0142307104542851 + 0.0947145000100136 + -0.7839525938034058 + <_> + + <_> + + + + <_> + 27 0 6 7 -1. + <_> + 29 2 2 7 3. + 1 + -0.0437068603932858 + 0.6097965240478516 + -0.1560188978910446 + <_> + + <_> + + + + <_> + 0 0 1 4 -1. + <_> + 0 2 1 2 2. + 0 + -6.2343222089111805e-004 + 0.3485119044780731 + -0.2170491069555283 + <_> + + <_> + + + + <_> + 27 8 6 4 -1. + <_> + 29 10 2 4 3. + 1 + 0.0192450508475304 + -0.1171097978949547 + 0.3070116043090820 + <_> + + <_> + + + + <_> + 4 9 27 6 -1. + <_> + 13 11 9 2 9. + 0 + 0.2703577876091003 + -0.0900964364409447 + 0.7665696144104004 + <_> + + <_> + + + + <_> + 31 14 2 3 -1. + <_> + 31 14 1 3 2. + 0 + -3.5394480801187456e-004 + -0.2002478986978531 + 0.1249336004257202 + <_> + + <_> + + + + <_> + 10 0 5 6 -1. + <_> + 8 2 5 2 3. + 1 + -0.0360139608383179 + 0.6702855825424194 + -0.1057187989354134 + <_> + + <_> + + + + <_> + 14 7 11 3 -1. + <_> + 14 8 11 1 3. + 0 + 9.2952791601419449e-003 + -0.1057471036911011 + 0.4509387910366058 + <_> + + <_> + + + + <_> + 0 12 2 6 -1. + <_> + 0 15 2 3 2. + 0 + -3.3304709359072149e-004 + 0.2793382108211517 + -0.2457676976919174 + <_> + + <_> + + + + <_> + 34 13 2 4 -1. + <_> + 34 15 2 2 2. + 0 + -2.9147620807634667e-005 + 0.0858138129115105 + -0.0954695865511894 + <_> + + <_> + + + + <_> + 0 13 2 4 -1. + <_> + 0 15 2 2 2. + 0 + 4.4382669148035347e-004 + -0.2022008001804352 + 0.5454357862472534 + -1.3538850545883179 + 3 + -1 + <_> + + + <_> + + <_> + + + + <_> + 3 6 4 12 -1. + <_> + 3 10 4 4 3. + 0 + 7.9610757529735565e-003 + -0.3672207891941071 + 0.4315434992313385 + <_> + + <_> + + + + <_> + 14 0 22 12 -1. + <_> + 25 0 11 6 2. + <_> + 14 6 11 6 2. + 0 + 0.0633948296308517 + -0.2073971033096314 + 0.5742601752281189 + <_> + + <_> + + + + <_> + 8 1 7 6 -1. + <_> + 6 3 7 2 3. + 1 + -0.0531933493912220 + 0.7255092263221741 + -0.1434202045202255 + <_> + + <_> + + + + <_> + 12 5 14 3 -1. + <_> + 12 6 14 1 3. + 0 + 0.0154607696458697 + -0.0960538163781166 + 0.7578523755073547 + <_> + + <_> + + + + <_> + 7 6 7 4 -1. + <_> + 6 7 7 2 2. + 1 + -0.0176431406289339 + 0.6681562066078186 + -0.1417672932147980 + <_> + + <_> + + + + <_> + 18 3 6 4 -1. + <_> + 18 4 6 2 2. + 0 + 9.5065636560320854e-003 + -0.0962597429752350 + 0.4699633121490479 + <_> + + <_> + + + + <_> + 4 5 5 6 -1. + <_> + 4 7 5 2 3. + 0 + 4.0446049533784389e-003 + -0.1973251998424530 + 0.4283801019191742 + <_> + + <_> + + + + <_> + 33 0 3 4 -1. + <_> + 34 0 1 4 3. + 0 + 3.2312041148543358e-003 + 0.1186169013381004 + -0.6103963255882263 + <_> + + <_> + + + + <_> + 9 0 6 18 -1. + <_> + 9 9 6 9 2. + 0 + -0.0401590503752232 + -0.4166434109210968 + 0.2167232930660248 + <_> + + <_> + + + + <_> + 6 6 24 6 -1. + <_> + 14 8 8 2 9. + 0 + 0.2852425873279572 + -0.1043575033545494 + 0.8573396801948547 + <_> + + <_> + + + + <_> + 16 8 4 4 -1. + <_> + 16 9 4 2 2. + 0 + -4.9264221452176571e-003 + 0.4706046879291534 + -0.1399745941162109 + <_> + + <_> + + + + <_> + 13 8 13 4 -1. + <_> + 13 9 13 2 2. + 0 + 0.0137817002832890 + -0.1271356940269470 + 0.4461891949176788 + <_> + + <_> + + + + <_> + 0 16 2 2 -1. + <_> + 0 17 2 1 2. + 0 + -4.9873598618432879e-004 + 0.4702663123607636 + -0.1548373997211456 + <_> + + <_> + + + + <_> + 35 14 1 4 -1. + <_> + 35 15 1 2 2. + 0 + -1.5621389320585877e-004 + 0.1885481029748917 + -0.0778397768735886 + <_> + + <_> + + + + <_> + 0 14 1 4 -1. + <_> + 0 15 1 2 2. + 0 + -3.7597760092467070e-004 + 0.5769770145416260 + -0.1335622072219849 + <_> + + <_> + + + + <_> + 15 6 9 7 -1. + <_> + 18 6 3 7 3. + 0 + -0.0106659103184938 + -0.4106529951095581 + 0.1556212007999420 + <_> + + <_> + + + + <_> + 0 0 3 4 -1. + <_> + 1 0 1 4 3. + 0 + -3.4135230816900730e-003 + -0.7636343240737915 + 0.1020964980125427 + <_> + + <_> + + + + <_> + 34 16 2 2 -1. + <_> + 35 16 1 1 2. + <_> + 34 17 1 1 2. + 0 + 5.6471868447260931e-005 + -0.1644393056631088 + 0.2290841937065125 + <_> + + <_> + + + + <_> + 0 16 2 2 -1. + <_> + 0 16 1 1 2. + <_> + 1 17 1 1 2. + 0 + 2.1611599368043244e-004 + -0.1629032939672470 + 0.4575636088848114 + <_> + + <_> + + + + <_> + 22 0 10 4 -1. + <_> + 22 0 5 4 2. + 1 + -0.0108227198943496 + -0.2446253001689911 + 0.1388894021511078 + <_> + + <_> + + + + <_> + 15 4 6 14 -1. + <_> + 15 4 3 7 2. + <_> + 18 11 3 7 2. + 0 + -0.0150849102064967 + -0.5781347751617432 + 0.1156411990523338 + <_> + + <_> + + + + <_> + 15 3 8 10 -1. + <_> + 17 3 4 10 2. + 0 + 0.0257159601897001 + 0.0396311990916729 + -0.6527001261711121 + <_> + + <_> + + + + <_> + 0 0 2 5 -1. + <_> + 1 0 1 5 2. + 0 + 2.6093570049852133e-003 + 0.1142188981175423 + -0.5680108070373535 + -1.3707510232925415 + 4 + -1 + <_> + + + <_> + + <_> + + + + <_> + 7 1 8 6 -1. + <_> + 5 3 8 2 3. + 1 + -0.0518619008362293 + 0.7043117284774780 + -0.2214370071887970 + <_> + + <_> + + + + <_> + 19 0 11 18 -1. + <_> + 19 9 11 9 2. + 0 + -0.0503416284918785 + -0.4639782905578613 + 0.2804746031761169 + <_> + + <_> + + + + <_> + 6 8 24 6 -1. + <_> + 14 10 8 2 9. + 0 + 0.2570973038673401 + -0.1312427967786789 + 0.8239594101905823 + <_> + + <_> + + + + <_> + 14 6 10 3 -1. + <_> + 14 7 10 1 3. + 0 + 0.0110318996012211 + -0.1425814032554627 + 0.6382390260696411 + <_> + + <_> + + + + <_> + 12 7 11 4 -1. + <_> + 12 8 11 2 2. + 0 + 0.0185650903731585 + -0.1512387990951538 + 0.5988119244575501 + <_> + + <_> + + + + <_> + 18 0 16 6 -1. + <_> + 26 0 8 3 2. + <_> + 18 3 8 3 2. + 0 + 0.0175023507326841 + -0.1261979937553406 + 0.3817803859710693 + <_> + + <_> + + + + <_> + 5 3 7 3 -1. + <_> + 4 4 7 1 3. + 1 + 7.2723729535937309e-003 + -0.1510328948497772 + 0.5812842249870300 + <_> + + <_> + + + + <_> + 18 4 4 4 -1. + <_> + 18 5 4 2 2. + 0 + 8.1504750996828079e-003 + -0.0654647573828697 + 0.5639755129814148 + <_> + + <_> + + + + <_> + 5 3 10 4 -1. + <_> + 4 4 10 2 2. + 1 + -0.0185527391731739 + 0.5315709710121155 + -0.1252657026052475 + <_> + + <_> + + + + <_> + 14 8 8 10 -1. + <_> + 18 8 4 5 2. + <_> + 14 13 4 5 2. + 0 + -0.0231014806777239 + -0.6794939041137695 + 0.1104625985026360 + <_> + + <_> + + + + <_> + 3 0 4 1 -1. + <_> + 5 0 2 1 2. + 0 + -1.8539339362177998e-004 + 0.3010003864765167 + -0.2120669931173325 + <_> + + <_> + + + + <_> + 20 0 10 8 -1. + <_> + 25 0 5 4 2. + <_> + 20 4 5 4 2. + 0 + 0.0173191204667091 + -0.0937381312251091 + 0.2100856006145477 + <_> + + <_> + + + + <_> + 13 0 10 8 -1. + <_> + 13 0 5 4 2. + <_> + 18 4 5 4 2. + 0 + 0.0143056204542518 + 0.1800594925880432 + -0.3977671861648560 + <_> + + <_> + + + + <_> + 21 5 6 13 -1. + <_> + 23 5 2 13 3. + 0 + 0.0257633402943611 + 8.7056998163461685e-003 + -0.6289495229721069 + <_> + + <_> + + + + <_> + 9 5 6 13 -1. + <_> + 11 5 2 13 3. + 0 + -0.0153833404183388 + -0.5341547131538391 + 0.1038073003292084 + <_> + + <_> + + + + <_> + 27 5 5 3 -1. + <_> + 27 6 5 1 3. + 0 + 1.0605469578877091e-003 + -0.0901285186409950 + 0.1679212003946304 + <_> + + <_> + + + + <_> + 10 0 3 6 -1. + <_> + 10 2 3 2 3. + 0 + 3.5230729263275862e-003 + -0.1711069047451019 + 0.3259654045104981 + <_> + + <_> + + + + <_> + 26 6 3 6 -1. + <_> + 26 8 3 2 3. + 0 + -0.0107892798259854 + 0.3610992133617401 + -0.0663391500711441 + <_> + + <_> + + + + <_> + 0 11 36 7 -1. + <_> + 18 11 18 7 2. + 0 + 0.2795093953609467 + -0.0746058970689774 + 0.7336987853050232 + <_> + + <_> + + + + <_> + 27 5 5 3 -1. + <_> + 27 6 5 1 3. + 0 + 3.8369540125131607e-003 + 0.0448735393583775 + -0.1860270053148270 + <_> + + <_> + + + + <_> + 4 5 5 3 -1. + <_> + 4 6 5 1 3. + 0 + 1.6195949865505099e-003 + -0.1392249017953873 + 0.4343700110912323 + <_> + + <_> + + + + <_> + 28 6 4 4 -1. + <_> + 29 7 2 4 2. + 1 + 0.0116479499265552 + -0.0743575915694237 + 0.5420144200325012 + <_> + + <_> + + + + <_> + 14 15 8 2 -1. + <_> + 16 15 4 2 2. + 0 + -5.9066400863230228e-003 + -0.7055758833885193 + 0.0864336192607880 + <_> + + <_> + + + + <_> + 3 5 30 6 -1. + <_> + 13 7 10 2 9. + 0 + 0.3968684077262878 + -0.0748983696103096 + 0.9406285881996155 + <_> + + <_> + + + + <_> + 6 7 16 6 -1. + <_> + 6 9 16 2 3. + 0 + 0.0576637797057629 + -0.0965584069490433 + 0.5418242812156677 + <_> + + <_> + + + + <_> + 14 10 12 6 -1. + <_> + 14 12 12 2 3. + 0 + 0.0603195689618587 + -0.0665010735392571 + 0.6402354836463928 + -1.3303329944610596 + 5 + -1 + <_> + + + <_> + + <_> + + + + <_> + 6 0 12 10 -1. + <_> + 6 0 6 5 2. + <_> + 12 5 6 5 2. + 0 + 0.0190502498298883 + -0.4443340897560120 + 0.4394856989383698 + <_> + + <_> + + + + <_> + 25 2 7 16 -1. + <_> + 25 10 7 8 2. + 0 + -0.0201983004808426 + -0.3170621991157532 + 0.1043293029069901 + <_> + + <_> + + + + <_> + 9 6 18 7 -1. + <_> + 15 6 6 7 3. + 0 + 0.0214780308306217 + -0.3502483963966370 + 0.2635537087917328 + <_> + + <_> + + + + <_> + 5 0 26 18 -1. + <_> + 18 0 13 9 2. + <_> + 5 9 13 9 2. + 0 + -0.1018775999546051 + -0.5988957881927490 + 0.1768579930067062 + <_> + + <_> + + + + <_> + 10 6 10 3 -1. + <_> + 10 7 10 1 3. + 0 + 0.0109741603955626 + -0.1489523947238922 + 0.6011521816253662 + <_> + + <_> + + + + <_> + 17 6 6 4 -1. + <_> + 17 7 6 2 2. + 0 + -0.0114767104387283 + 0.4066570997238159 + -0.1240468993782997 + <_> + + <_> + + + + <_> + 15 6 6 7 -1. + <_> + 18 6 3 7 2. + 0 + -0.0234311502426863 + -0.7148783206939697 + 0.1427811980247498 + <_> + + <_> + + + + <_> + 26 6 5 4 -1. + <_> + 26 7 5 2 2. + 0 + 1.4963559806346893e-003 + -0.1704585999250412 + 0.1719308048486710 + <_> + + <_> + + + + <_> + 0 12 1 6 -1. + <_> + 0 15 1 3 2. + 0 + -5.4855772759765387e-004 + 0.3155323863029480 + -0.2144445031881332 + <_> + + <_> + + + + <_> + 9 4 18 14 -1. + <_> + 18 4 9 7 2. + <_> + 9 11 9 7 2. + 0 + 0.0749126300215721 + 0.0912405624985695 + -0.6395121216773987 + <_> + + <_> + + + + <_> + 7 5 6 3 -1. + <_> + 6 6 6 1 3. + 1 + 6.8816398270428181e-003 + -0.1490440964698792 + 0.4795236885547638 + <_> + + <_> + + + + <_> + 27 5 6 3 -1. + <_> + 29 7 2 3 3. + 1 + -0.0382125787436962 + 0.5288773775100708 + -0.0618947297334671 + <_> + + <_> + + + + <_> + 7 8 3 3 -1. + <_> + 6 9 3 1 3. + 1 + 4.4051730073988438e-003 + -0.1193412989377976 + 0.5061342120170593 + <_> + + <_> + + + + <_> + 28 5 6 5 -1. + <_> + 30 7 2 5 3. + 1 + 0.0239668991416693 + -0.0897205099463463 + 0.3315277993679047 + <_> + + <_> + + + + <_> + 8 5 5 6 -1. + <_> + 6 7 5 2 3. + 1 + -0.0341629907488823 + 0.5313478112220764 + -0.1466650068759918 + <_> + + <_> + + + + <_> + 31 0 4 1 -1. + <_> + 31 0 2 1 2. + 0 + 1.9642219413071871e-003 + 0.0907835885882378 + -0.4303255975246429 + <_> + + <_> + + + + <_> + 1 0 4 1 -1. + <_> + 3 0 2 1 2. + 0 + 9.6757910796441138e-005 + 0.2255253940820694 + -0.2822071015834808 + <_> + + <_> + + + + <_> + 17 11 4 3 -1. + <_> + 17 12 4 1 3. + 0 + -3.2862399239093065e-003 + 0.4051502048969269 + -0.1177619993686676 + <_> + + <_> + + + + <_> + 12 3 7 4 -1. + <_> + 12 4 7 2 2. + 0 + 0.0116883097216487 + -0.0918571278452873 + 0.6283488869667053 + <_> + + <_> + + + + <_> + 14 9 9 3 -1. + <_> + 14 10 9 1 3. + 0 + -6.0287420637905598e-003 + 0.3926180899143219 + -0.1228715032339096 + <_> + + <_> + + + + <_> + 1 17 21 1 -1. + <_> + 8 17 7 1 3. + 0 + -0.0137213403359056 + -0.5529879927635193 + 0.0910412818193436 + <_> + + <_> + + + + <_> + 12 9 20 4 -1. + <_> + 12 9 10 4 2. + 0 + 0.0756266415119171 + -0.0449295900762081 + 0.1744275987148285 + <_> + + <_> + + + + <_> + 3 9 22 4 -1. + <_> + 14 9 11 4 2. + 0 + 0.0934344828128815 + -0.0845939517021179 + 0.6013116240501404 + <_> + + <_> + + + + <_> + 25 0 3 3 -1. + <_> + 26 1 1 3 3. + 1 + 5.8748829178512096e-003 + -0.0441314987838268 + 0.3956570923328400 + <_> + + <_> + + + + <_> + 14 9 4 3 -1. + <_> + 14 10 4 1 3. + 0 + 4.0064537897706032e-003 + -0.1141439974308014 + 0.3792538046836853 + <_> + + <_> + + + + <_> + 19 4 9 3 -1. + <_> + 22 4 3 3 3. + 0 + 0.0229454599320889 + 0.0246731899678707 + -0.4152199923992157 + <_> + + <_> + + + + <_> + 8 4 9 3 -1. + <_> + 11 4 3 3 3. + 0 + -0.0128104602918029 + -0.5155742764472961 + 0.0913196131587029 + <_> + + <_> + + + + <_> + 0 15 36 3 -1. + <_> + 12 16 12 1 9. + 0 + 0.2042552977800369 + -0.0659275427460670 + 0.7594249248504639 + <_> + + <_> + + + + <_> + 2 0 4 2 -1. + <_> + 2 0 4 1 2. + 1 + 4.9796327948570251e-003 + 0.1080627962946892 + -0.5001627206802368 + <_> + + <_> + + + + <_> + 19 9 2 9 -1. + <_> + 19 12 2 3 3. + 0 + 0.0283976309001446 + -0.0371529608964920 + 0.5401064753532410 + <_> + + <_> + + + + <_> + 13 7 8 3 -1. + <_> + 13 8 8 1 3. + 0 + 6.0867150314152241e-003 + -0.1197860985994339 + 0.3569226861000061 + <_> + + <_> + + + + <_> + 30 4 2 2 -1. + <_> + 31 4 1 1 2. + <_> + 30 5 1 1 2. + 0 + -2.1456899412441999e-004 + 0.1874015033245087 + -0.0884172022342682 + <_> + + <_> + + + + <_> + 4 4 2 2 -1. + <_> + 4 4 1 1 2. + <_> + 5 5 1 1 2. + 0 + 2.8941858909092844e-004 + -0.1259797960519791 + 0.3998227119445801 + <_> + + <_> + + + + <_> + 18 7 4 3 -1. + <_> + 18 8 4 1 3. + 0 + -1.3047619722783566e-003 + 0.1549997031688690 + -0.0753860473632813 + <_> + + <_> + + + + <_> + 9 0 1 8 -1. + <_> + 9 0 1 4 2. + 1 + -0.0129750100895762 + -0.5534411072731018 + 0.0823542475700378 + <_> + + <_> + + + + <_> + 25 6 10 3 -1. + <_> + 25 7 10 1 3. + 0 + 7.7442410401999950e-003 + 0.0276998002082109 + -0.3483599126338959 + <_> + + <_> + + + + <_> + 1 6 10 3 -1. + <_> + 1 7 10 1 3. + 0 + 2.4850629270076752e-003 + -0.1297612935304642 + 0.3790883123874664 + -1.5300060510635376 + 6 + -1 + <_> + + + <_> + + <_> + + + + <_> + 6 6 14 12 -1. + <_> + 6 6 7 6 2. + <_> + 13 12 7 6 2. + 0 + -0.0403868816792965 + 0.5960354804992676 + -0.3574176132678986 + <_> + + <_> + + + + <_> + 31 14 3 4 -1. + <_> + 31 16 3 2 2. + 0 + -6.6068649175576866e-005 + 0.4462898075580597 + -0.3595947027206421 + <_> + + <_> + + + + <_> + 1 12 2 4 -1. + <_> + 1 14 2 2 2. + 0 + 3.7622239906340837e-003 + 0.1794701963663101 + -0.7563151121139526 + <_> + + <_> + + + + <_> + 15 0 12 5 -1. + <_> + 19 0 4 5 3. + 0 + -0.0309677198529243 + -0.2884705066680908 + 0.0768705308437347 + <_> + + <_> + + + + <_> + 10 0 8 14 -1. + <_> + 12 0 4 14 2. + 0 + 0.0305665601044893 + 0.1400360018014908 + -0.7175536751747131 + <_> + + <_> + + + + <_> + 28 1 8 7 -1. + <_> + 30 3 4 7 2. + 1 + 9.9054910242557526e-004 + 0.0829155892133713 + -0.2919717133045197 + <_> + + <_> + + + + <_> + 8 14 20 4 -1. + <_> + 8 14 10 2 2. + <_> + 18 16 10 2 2. + 0 + 0.0125777004286647 + 0.1538071930408478 + -0.4688293039798737 + <_> + + <_> + + + + <_> + 6 11 24 3 -1. + <_> + 14 12 8 1 9. + 0 + 0.1239292025566101 + -0.0908238589763641 + 0.7383757233619690 + <_> + + <_> + + + + <_> + 4 5 27 6 -1. + <_> + 13 7 9 2 9. + 0 + 0.3773748874664307 + -0.0542329512536526 + 0.9229121804237366 + <_> + + <_> + + + + <_> + 7 0 22 18 -1. + <_> + 18 0 11 9 2. + <_> + 7 9 11 9 2. + 0 + 0.1099637001752853 + 0.0915962681174278 + -0.6597716808319092 + <_> + + <_> + + + + <_> + 16 0 3 2 -1. + <_> + 16 1 3 1 2. + 0 + -1.2721329694613814e-003 + 0.3347575068473816 + -0.1829068958759308 + <_> + + <_> + + + + <_> + 0 17 36 1 -1. + <_> + 9 17 18 1 2. + 0 + 0.0469062514603138 + -0.0839710533618927 + 0.6984758973121643 + <_> + + <_> + + + + <_> + 5 5 12 1 -1. + <_> + 5 5 6 1 2. + 1 + 3.2869930146262050e-004 + 0.1879463046789169 + -0.2929005920886993 + <_> + + <_> + + + + <_> + 34 15 2 1 -1. + <_> + 34 15 1 1 2. + 1 + 1.7333080177195370e-004 + -0.2696416079998016 + 0.3494757115840912 + <_> + + <_> + + + + <_> + 7 8 16 4 -1. + <_> + 7 9 16 2 2. + 0 + 0.0198009591549635 + -0.1467922925949097 + 0.4399561882019043 + <_> + + <_> + + + + <_> + 35 10 1 6 -1. + <_> + 35 12 1 2 3. + 0 + 2.0056760695297271e-004 + -0.1372741013765335 + 0.2221331000328064 + <_> + + <_> + + + + <_> + 13 8 3 4 -1. + <_> + 13 9 3 2 2. + 0 + -1.4923149719834328e-003 + 0.3473525941371918 + -0.1594821065664291 + <_> + + <_> + + + + <_> + 35 10 1 6 -1. + <_> + 35 12 1 2 3. + 0 + -4.2736999603221193e-005 + 0.3152787089347839 + -0.2306694984436035 + <_> + + <_> + + + + <_> + 12 0 1 4 -1. + <_> + 11 1 1 2 2. + 1 + 6.6625140607357025e-004 + -0.2013110071420670 + 0.2869189083576202 + <_> + + <_> + + + + <_> + 35 10 1 6 -1. + <_> + 35 12 1 2 3. + 0 + 1.3850460163666867e-005 + -0.2021923959255219 + 0.2307330965995789 + <_> + + <_> + + + + <_> + 18 0 1 14 -1. + <_> + 18 0 1 7 2. + 1 + 0.0409726314246655 + 0.0795431807637215 + -0.8079563975334168 + -1.4114329814910889 + 7 + -1 + <_> + + + <_> + + <_> + + + + <_> + 5 6 16 12 -1. + <_> + 5 6 8 6 2. + <_> + 13 12 8 6 2. + 0 + -0.0469829291105270 + 0.7082253098487854 + -0.3703424036502838 + <_> + + <_> + + + + <_> + 18 1 7 8 -1. + <_> + 16 3 7 4 2. + 1 + -7.5753079727292061e-004 + -0.1255030930042267 + 0.1394442021846771 + <_> + + <_> + + + + <_> + 14 4 8 10 -1. + <_> + 14 4 4 5 2. + <_> + 18 9 4 5 2. + 0 + 0.0153272999450564 + 0.2161353975534439 + -0.5629395246505737 + <_> + + <_> + + + + <_> + 22 0 9 3 -1. + <_> + 25 0 3 3 3. + 0 + 0.0181470401585102 + -0.0320796482264996 + 0.3234755992889404 + <_> + + <_> + + + + <_> + 0 10 26 8 -1. + <_> + 0 10 13 4 2. + <_> + 13 14 13 4 2. + 0 + 0.0473471917212009 + -0.1738158017396927 + 0.5758044719696045 + <_> + + <_> + + + + <_> + 15 10 16 8 -1. + <_> + 23 10 8 4 2. + <_> + 15 14 8 4 2. + 0 + -0.0598379410803318 + 0.4779787063598633 + -0.1026028022170067 + <_> + + <_> + + + + <_> + 6 0 24 18 -1. + <_> + 6 0 12 9 2. + <_> + 18 9 12 9 2. + 0 + -0.0527967996895313 + -0.4798848927021027 + 0.1878775954246521 + <_> + + <_> + + + + <_> + 18 0 9 6 -1. + <_> + 21 0 3 6 3. + 0 + -0.0243854299187660 + -0.3084166944026947 + 8.7605630978941917e-003 + <_> + + <_> + + + + <_> + 9 0 9 6 -1. + <_> + 12 0 3 6 3. + 0 + 0.0252883005887270 + 0.1391403973102570 + -0.7109494209289551 + <_> + + <_> + + + + <_> + 30 1 5 14 -1. + <_> + 30 8 5 7 2. + 0 + -0.0216124504804611 + -0.2328253984451294 + 0.0809946805238724 + <_> + + <_> + + + + <_> + 1 1 5 14 -1. + <_> + 1 8 5 7 2. + 0 + 3.4023479092866182e-003 + -0.2298990041017532 + 0.3788951039314270 + <_> + + <_> + + + + <_> + 10 8 26 6 -1. + <_> + 23 8 13 3 2. + <_> + 10 11 13 3 2. + 0 + 0.1127460002899170 + -0.0154747096821666 + 0.5703054070472717 + <_> + + <_> + + + + <_> + 0 8 28 6 -1. + <_> + 0 8 14 3 2. + <_> + 14 11 14 3 2. + 0 + 0.0345168709754944 + -0.1230008006095886 + 0.5677536725997925 + <_> + + <_> + + + + <_> + 12 0 24 12 -1. + <_> + 24 0 12 6 2. + <_> + 12 6 12 6 2. + 0 + 0.0789848119020462 + -0.1424216926097870 + 0.4694185853004456 + <_> + + <_> + + + + <_> + 3 1 14 2 -1. + <_> + 3 1 14 1 2. + 1 + -0.0153778595849872 + 0.6394686102867127 + -0.1123619005084038 + <_> + + <_> + + + + <_> + 33 16 3 2 -1. + <_> + 33 17 3 1 2. + 0 + -2.2373620595317334e-004 + 0.5558329820632935 + -0.2724758088588715 + <_> + + <_> + + + + <_> + 12 0 9 14 -1. + <_> + 15 0 3 14 3. + 0 + -0.0247623901814222 + -0.5040485858917236 + 0.1407779008150101 + <_> + + <_> + + + + <_> + 28 16 8 2 -1. + <_> + 32 16 4 1 2. + <_> + 28 17 4 1 2. + 0 + -9.4061157142277807e-005 + 0.3719528019428253 + -0.2250299006700516 + <_> + + <_> + + + + <_> + 15 8 6 6 -1. + <_> + 15 10 6 2 3. + 0 + -0.0202563591301441 + 0.5105100870132446 + -0.1429875940084457 + <_> + + <_> + + + + <_> + 13 6 22 6 -1. + <_> + 24 6 11 3 2. + <_> + 13 9 11 3 2. + 0 + 0.0481228791177273 + -0.0669795125722885 + 0.3662230968475342 + <_> + + <_> + + + + <_> + 0 10 26 4 -1. + <_> + 0 10 13 2 2. + <_> + 13 12 13 2 2. + 0 + -0.0237878002226353 + 0.5081325173377991 + -0.1290815025568008 + <_> + + <_> + + + + <_> + 24 16 4 2 -1. + <_> + 24 17 4 1 2. + 0 + -1.0520319920033216e-003 + -0.1560467034578323 + 0.0662133172154427 + <_> + + <_> + + + + <_> + 9 16 3 2 -1. + <_> + 9 17 3 1 2. + 0 + -2.6640200521796942e-003 + -0.7254558205604553 + 0.0823654532432556 + -1.3777890205383301 + 8 + -1 + <_> + + + <_> + + <_> + + + + <_> + 3 7 18 8 -1. + <_> + 3 7 9 4 2. + <_> + 12 11 9 4 2. + 0 + -0.0502246208488941 + 0.7084565758705139 + -0.2558549940586090 + <_> + + <_> + + + + <_> + 23 0 8 4 -1. + <_> + 23 0 4 4 2. + 0 + 0.0140728699043393 + 0.0630331784486771 + -0.0598385296761990 + <_> + + <_> + + + + <_> + 5 0 8 4 -1. + <_> + 9 0 4 4 2. + 0 + 0.0178040098398924 + 0.1941471993923187 + -0.5844426751136780 + <_> + + <_> + + + + <_> + 6 10 24 3 -1. + <_> + 14 11 8 1 9. + 0 + 0.1304673999547958 + -0.1151698008179665 + 0.8504030108451843 + <_> + + <_> + + + + <_> + 7 5 5 6 -1. + <_> + 5 7 5 2 3. + 1 + 0.0175068005919456 + -0.2071896940469742 + 0.4643828868865967 + <_> + + <_> + + + + <_> + 5 16 26 2 -1. + <_> + 18 16 13 1 2. + <_> + 5 17 13 1 2. + 0 + -7.4240020476281643e-003 + -0.6656516790390015 + 0.1403498947620392 + <_> + + <_> + + + + <_> + 0 7 24 4 -1. + <_> + 0 7 12 2 2. + <_> + 12 9 12 2 2. + 0 + -0.0345711186528206 + 0.6511297821998596 + -0.1490191966295242 + <_> + + <_> + + + + <_> + 23 14 13 4 -1. + <_> + 23 15 13 2 2. + 0 + 4.2270249687135220e-003 + -1.6027219826355577e-003 + 0.3895606100559235 + <_> + + <_> + + + + <_> + 2 10 18 8 -1. + <_> + 2 10 9 4 2. + <_> + 11 14 9 4 2. + 0 + -0.0506620407104492 + 0.5803576707839966 + -0.1514143943786621 + <_> + + <_> + + + + <_> + 15 10 6 4 -1. + <_> + 15 11 6 2 2. + 0 + -7.0715770125389099e-003 + 0.5300896763801575 + -0.1449830979108810 + <_> + + <_> + + + + <_> + 0 6 24 2 -1. + <_> + 0 6 12 1 2. + <_> + 12 7 12 1 2. + 0 + -0.0118635101243854 + 0.6729742288589478 + -0.1106354966759682 + <_> + + <_> + + + + <_> + 17 0 18 18 -1. + <_> + 17 9 18 9 2. + 0 + -0.0605200305581093 + -0.3316448926925659 + 0.2119556069374085 + <_> + + <_> + + + + <_> + 1 0 11 2 -1. + <_> + 1 1 11 1 2. + 0 + -7.7340779826045036e-003 + -0.6941440105438232 + 0.0727053135633469 + <_> + + <_> + + + + <_> + 15 6 8 12 -1. + <_> + 19 6 4 6 2. + <_> + 15 12 4 6 2. + 0 + -0.0324861407279968 + -0.5185081958770752 + 0.0592126213014126 + <_> + + <_> + + + + <_> + 2 1 32 12 -1. + <_> + 2 1 16 6 2. + <_> + 18 7 16 6 2. + 0 + 0.0832797065377235 + 0.1206794008612633 + -0.5309563279151917 + <_> + + <_> + + + + <_> + 29 10 7 8 -1. + <_> + 29 12 7 4 2. + 0 + 7.8782817581668496e-004 + -0.2737655937671661 + 0.2716251909732819 + <_> + + <_> + + + + <_> + 12 2 8 10 -1. + <_> + 12 2 4 5 2. + <_> + 16 7 4 5 2. + 0 + -0.0175391808152199 + -0.5690230131149292 + 0.1228737011551857 + <_> + + <_> + + + + <_> + 15 12 6 4 -1. + <_> + 15 13 6 2 2. + 0 + -5.8226347900927067e-003 + 0.4386585950851440 + -0.1493742018938065 + <_> + + <_> + + + + <_> + 0 12 8 6 -1. + <_> + 0 14 8 2 3. + 0 + -0.0100575601682067 + -0.6616886258125305 + 0.1144542992115021 + <_> + + <_> + + + + <_> + 10 9 26 8 -1. + <_> + 23 9 13 4 2. + <_> + 10 13 13 4 2. + 0 + 0.0903454273939133 + -0.0666652470827103 + 0.2870647907257080 + <_> + + <_> + + + + <_> + 7 8 22 10 -1. + <_> + 7 8 11 5 2. + <_> + 18 13 11 5 2. + 0 + -0.0675872936844826 + -0.5363761186599731 + 0.1123751997947693 + <_> + + <_> + + + + <_> + 14 9 8 3 -1. + <_> + 14 10 8 1 3. + 0 + -8.1747528165578842e-003 + 0.4434241950511932 + -0.1297765970230103 + <_> + + <_> + + + + <_> + 11 3 4 9 -1. + <_> + 11 6 4 3 3. + 0 + -0.0115505503490567 + 0.3273158073425293 + -0.1700761020183563 + <_> + + <_> + + + + <_> + 29 14 2 2 -1. + <_> + 29 14 2 1 2. + 1 + -1.7406829283572733e-004 + 0.1327867954969406 + -0.1081293970346451 + <_> + + <_> + + + + <_> + 14 13 8 3 -1. + <_> + 14 14 8 1 3. + 0 + 4.6040047891438007e-003 + -0.1226582005620003 + 0.4412580132484436 + -1.3266400098800659 + 9 + -1 + <_> + + + <_> + + <_> + + + + <_> + 11 3 7 8 -1. + <_> + 9 5 7 4 2. + 1 + -0.0469432808458805 + 0.6094344258308411 + -0.2637800872325897 + <_> + + <_> + + + + <_> + 28 13 1 4 -1. + <_> + 28 13 1 2 2. + 1 + -1.6899159527383745e-004 + 0.1665875017642975 + -0.1254196017980576 + <_> + + <_> + + + + <_> + 8 13 4 1 -1. + <_> + 8 13 2 1 2. + 1 + 2.7983370237052441e-003 + 0.1905744969844818 + -0.6568077206611633 + <_> + + <_> + + + + <_> + 16 9 4 3 -1. + <_> + 16 10 4 1 3. + 0 + 4.0413960814476013e-003 + -0.1731746941804886 + 0.6362075209617615 + <_> + + <_> + + + + <_> + 13 8 10 4 -1. + <_> + 13 9 10 2 2. + 0 + -8.6033362895250320e-003 + 0.6025841832160950 + -0.2316936999559403 + <_> + + <_> + + + + <_> + 14 8 8 3 -1. + <_> + 14 9 8 1 3. + 0 + 8.8247945532202721e-003 + -0.1756583005189896 + 0.7104166746139526 + <_> + + <_> + + + + <_> + 2 10 6 2 -1. + <_> + 4 12 2 2 3. + 1 + -9.2786159366369247e-003 + -0.6890857219696045 + 0.1789650022983551 + <_> + + <_> + + + + <_> + 16 10 6 3 -1. + <_> + 16 11 6 1 3. + 0 + 6.0826768167316914e-003 + -0.1706372052431107 + 0.5375748276710510 + <_> + + <_> + + + + <_> + 8 5 8 13 -1. + <_> + 12 5 4 13 2. + 0 + -0.0390073694288731 + -0.6834635734558106 + 0.1441708058118820 + <_> + + <_> + + + + <_> + 0 0 36 8 -1. + <_> + 18 0 18 4 2. + <_> + 0 4 18 4 2. + 0 + -0.0703379511833191 + -0.6508566737174988 + 0.1008547991514206 + <_> + + <_> + + + + <_> + 1 5 8 12 -1. + <_> + 1 5 4 6 2. + <_> + 5 11 4 6 2. + 0 + 0.0331666991114616 + -0.1932571977376938 + 0.4779865145683289 + <_> + + <_> + + + + <_> + 18 8 18 10 -1. + <_> + 27 8 9 5 2. + <_> + 18 13 9 5 2. + 0 + 0.0752889066934586 + -0.0695677325129509 + 0.4125064909458160 + <_> + + <_> + + + + <_> + 0 8 18 10 -1. + <_> + 0 8 9 5 2. + <_> + 9 13 9 5 2. + 0 + -0.0705017298460007 + 0.7157300710678101 + -0.1022270023822784 + <_> + + <_> + + + + <_> + 11 5 14 3 -1. + <_> + 11 6 14 1 3. + 0 + 0.0122494902461767 + -0.1061242967844009 + 0.6295958161354065 + <_> + + <_> + + + + <_> + 10 6 16 6 -1. + <_> + 10 8 16 2 3. + 0 + 0.0706446766853333 + -0.0973746329545975 + 0.6762204170227051 + <_> + + <_> + + + + <_> + 7 2 24 16 -1. + <_> + 19 2 12 8 2. + <_> + 7 10 12 8 2. + 0 + 0.1624888032674789 + 0.0527133606374264 + -0.8494657278060913 + <_> + + <_> + + + + <_> + 0 1 18 15 -1. + <_> + 6 6 6 5 9. + 0 + 0.1380825042724609 + 0.1406479030847549 + -0.4764721095561981 + -1.4497200250625610 + 10 + -1 + <_> + + + <_> + + <_> + + + + <_> + 4 5 16 6 -1. + <_> + 12 5 8 6 2. + 0 + -0.0418823398649693 + -0.8077452778816223 + 0.2640967071056366 + <_> + + <_> + + + + <_> + 29 0 6 11 -1. + <_> + 31 2 2 11 3. + 1 + -0.0536229908466339 + 0.5580704212188721 + -0.2498968988656998 + <_> + + <_> + + + + <_> + 2 8 9 1 -1. + <_> + 5 11 3 1 3. + 1 + 9.3709938228130341e-003 + 0.2650170028209686 + -0.5990694761276245 + <_> + + <_> + + + + <_> + 10 6 17 3 -1. + <_> + 10 7 17 1 3. + 0 + 0.0139097301289439 + -0.1470918059349060 + 0.7354667186737061 + <_> + + <_> + + + + <_> + 18 6 6 2 -1. + <_> + 20 8 2 2 3. + 1 + 0.0190035700798035 + -0.1887511014938355 + 0.7487422227859497 + <_> + + <_> + + + + <_> + 13 11 12 3 -1. + <_> + 13 12 12 1 3. + 0 + 5.9199850074946880e-003 + -0.1599563956260681 + 0.5673577785491943 + <_> + + <_> + + + + <_> + 2 3 8 8 -1. + <_> + 2 3 4 4 2. + <_> + 6 7 4 4 2. + 0 + -0.0247051399201155 + 0.7556992173194885 + -0.1235088035464287 + <_> + + <_> + + + + <_> + 18 12 18 4 -1. + <_> + 27 12 9 2 2. + <_> + 18 14 9 2 2. + 0 + 0.0160583592951298 + -0.1282460987567902 + 0.5129454731941223 + <_> + + <_> + + + + <_> + 11 5 11 3 -1. + <_> + 11 6 11 1 3. + 0 + 8.8288700208067894e-003 + -0.1686663925647736 + 0.6152185201644898 + <_> + + <_> + + + + <_> + 14 7 14 4 -1. + <_> + 14 8 14 2 2. + 0 + 0.0175563395023346 + -0.1090169996023178 + 0.5803176164627075 + <_> + + <_> + + + + <_> + 9 8 16 10 -1. + <_> + 9 8 8 5 2. + <_> + 17 13 8 5 2. + 0 + 0.0421881191432476 + 0.1486624032258987 + -0.6922233104705811 + <_> + + <_> + + + + <_> + 18 17 2 1 -1. + <_> + 18 17 1 1 2. + 0 + 5.0687207840383053e-004 + 0.0315808691084385 + -0.3700995147228241 + <_> + + <_> + + + + <_> + 13 10 5 3 -1. + <_> + 13 11 5 1 3. + 0 + 2.7651190757751465e-003 + -0.2133754044771195 + 0.4704301059246063 + <_> + + <_> + + + + <_> + 18 17 2 1 -1. + <_> + 18 17 1 1 2. + 0 + -1.2231520377099514e-003 + -0.7818967103958130 + 0.0209542606025934 + <_> + + <_> + + + + <_> + 7 5 8 3 -1. + <_> + 6 6 8 1 3. + 1 + 8.5432287305593491e-003 + -0.1455352008342743 + 0.6789504289627075 + <_> + + <_> + + + + <_> + 18 17 2 1 -1. + <_> + 18 17 1 1 2. + 0 + -2.0657219283748418e-004 + 0.2437624037265778 + -0.0675588026642799 + <_> + + <_> + + + + <_> + 10 5 5 3 -1. + <_> + 10 6 5 1 3. + 0 + -4.6798270195722580e-003 + 0.6684169769287109 + -0.1388788074254990 + <_> + + <_> + + + + <_> + 2 5 34 10 -1. + <_> + 19 5 17 5 2. + <_> + 2 10 17 5 2. + 0 + 0.1220175996422768 + 0.1102816015481949 + -0.7530742287635803 + <_> + + <_> + + + + <_> + 3 2 12 3 -1. + <_> + 6 5 6 3 2. + 1 + 0.0204043406993151 + 0.1645383983850479 + -0.5223162174224854 + <_> + + <_> + + + + <_> + 35 6 1 6 -1. + <_> + 35 8 1 2 3. + 0 + 8.0343370791524649e-004 + -0.1301285028457642 + 0.2635852992534638 + -1.4622910022735596 + 11 + -1 + <_> + + + <_> + + <_> + + + + <_> + 10 6 13 6 -1. + <_> + 10 8 13 2 3. + 0 + 0.0727917104959488 + -0.1372790038585663 + 0.8291574716567993 + <_> + + <_> + + + + <_> + 15 5 6 4 -1. + <_> + 15 6 6 2 2. + 0 + 7.5939209200441837e-003 + -0.1678012013435364 + 0.5683972239494324 + <_> + + <_> + + + + <_> + 5 2 11 4 -1. + <_> + 4 3 11 2 2. + 1 + -0.0235623903572559 + 0.6500560045242310 + -0.1424535065889359 + <_> + + <_> + + + + <_> + 26 6 10 6 -1. + <_> + 31 6 5 3 2. + <_> + 26 9 5 3 2. + 0 + 0.0173929501324892 + -0.1529144942760468 + 0.3425354063510895 + <_> + + <_> + + + + <_> + 10 7 11 8 -1. + <_> + 10 9 11 4 2. + 0 + 0.0718258023262024 + -0.0991311371326447 + 0.8279678821563721 + <_> + + <_> + + + + <_> + 28 2 4 9 -1. + <_> + 29 3 2 9 2. + 1 + 0.0136738000437617 + -0.0417872704565525 + 0.5078148245811462 + <_> + + <_> + + + + <_> + 8 2 10 4 -1. + <_> + 7 3 10 2 2. + 1 + -0.0285859592258930 + 0.7011532187461853 + -0.1314471065998077 + <_> + + <_> + + + + <_> + 31 0 5 2 -1. + <_> + 31 1 5 1 2. + 0 + -4.1845720261335373e-004 + 0.2845467031002045 + -0.3123202919960022 + <_> + + <_> + + + + <_> + 10 6 16 12 -1. + <_> + 10 10 16 4 3. + 0 + -0.0520956814289093 + 0.4181294143199921 + -0.1699313074350357 + <_> + + <_> + + + + <_> + 18 4 4 3 -1. + <_> + 18 5 4 1 3. + 0 + 3.2256329432129860e-003 + -0.0904662087559700 + 0.3008623123168945 + <_> + + <_> + + + + <_> + 11 10 6 6 -1. + <_> + 11 12 6 2 3. + 0 + 0.0347716398537159 + -0.0842167884111404 + 0.7801663875579834 + <_> + + <_> + + + + <_> + 35 8 1 10 -1. + <_> + 35 13 1 5 2. + 0 + -1.3356630224734545e-003 + 0.3316453099250794 + -0.1696092039346695 + <_> + + <_> + + + + <_> + 0 10 36 8 -1. + <_> + 18 10 18 8 2. + 0 + 0.2510198056697846 + -0.1392046958208084 + 0.6633893251419067 + <_> + + <_> + + + + <_> + 16 7 6 8 -1. + <_> + 19 7 3 4 2. + <_> + 16 11 3 4 2. + 0 + -9.9689997732639313e-003 + -0.3713817000389099 + 0.1290012001991272 + <_> + + <_> + + + + <_> + 7 6 8 4 -1. + <_> + 7 6 4 4 2. + 1 + 0.0143037298694253 + 0.1572919934988022 + -0.5093821287155151 + <_> + + <_> + + + + <_> + 21 11 4 3 -1. + <_> + 21 12 4 1 3. + 0 + -7.0856059901416302e-003 + 0.4656791090965271 + -0.0662708207964897 + <_> + + <_> + + + + <_> + 0 9 1 8 -1. + <_> + 0 13 1 4 2. + 0 + -4.6260809176601470e-004 + 0.2933731079101563 + -0.2333986014127731 + <_> + + <_> + + + + <_> + 27 7 6 4 -1. + <_> + 29 9 2 4 3. + 1 + -0.0344354808330536 + 0.7002474069595337 + -0.1013351008296013 + <_> + + <_> + + + + <_> + 10 14 8 4 -1. + <_> + 12 14 4 4 2. + 0 + -7.2570890188217163e-003 + -0.5628641247749329 + 0.1314862072467804 + <_> + + <_> + + + + <_> + 18 17 2 1 -1. + <_> + 18 17 1 1 2. + 0 + 4.8352940939366817e-004 + 0.0262274891138077 + -0.2605080008506775 + <_> + + <_> + + + + <_> + 10 4 11 4 -1. + <_> + 10 5 11 2 2. + 0 + -0.0129999397322536 + 0.5311700105667114 + -0.1202305033802986 + <_> + + <_> + + + + <_> + 17 12 2 4 -1. + <_> + 17 13 2 2 2. + 0 + -1.0009329998865724e-003 + 0.3964129984378815 + -0.1599515974521637 + <_> + + <_> + + + + <_> + 13 4 5 3 -1. + <_> + 13 5 5 1 3. + 0 + 4.1314200498163700e-003 + -0.1492992043495178 + 0.4295912086963654 + <_> + + <_> + + + + <_> + 13 12 11 2 -1. + <_> + 13 13 11 1 2. + 0 + 8.7364455685019493e-003 + -0.1127102002501488 + 0.4945647120475769 + <_> + + <_> + + + + <_> + 1 16 2 2 -1. + <_> + 1 16 1 1 2. + <_> + 2 17 1 1 2. + 0 + 2.6352869463153183e-004 + -0.1212491989135742 + 0.4943937957286835 + <_> + + <_> + + + + <_> + 27 7 6 4 -1. + <_> + 29 9 2 4 3. + 1 + -0.0538859590888023 + 0.7035598754882813 + -0.0132305501028895 + <_> + + <_> + + + + <_> + 4 7 6 6 -1. + <_> + 4 9 6 2 3. + 0 + 4.2885672301054001e-003 + -0.1754055023193359 + 0.3567946851253510 + <_> + + <_> + + + + <_> + 30 6 4 5 -1. + <_> + 31 7 2 5 2. + 1 + 7.9539399594068527e-003 + -0.0998840034008026 + 0.3137167096138001 + -1.3885619640350342 + 12 + -1 + <_> + + + <_> + + <_> + + + + <_> + 8 5 20 7 -1. + <_> + 13 5 10 7 2. + 0 + 0.0567523688077927 + -0.3257648050785065 + 0.3737593889236450 + <_> + + <_> + + + + <_> + 30 2 3 12 -1. + <_> + 30 8 3 6 2. + 0 + 7.0906039327383041e-003 + -0.1391862928867340 + 0.1503984034061432 + <_> + + <_> + + + + <_> + 4 2 12 4 -1. + <_> + 4 2 12 2 2. + 1 + -0.0412988215684891 + 0.4702607989311218 + -0.1617936044931412 + <_> + + <_> + + + + <_> + 0 8 36 6 -1. + <_> + 12 10 12 2 9. + 0 + 0.4775018990039825 + -0.1006157994270325 + 0.7635074257850647 + <_> + + <_> + + + + <_> + 3 5 30 6 -1. + <_> + 13 7 10 2 9. + 0 + 0.4226649105548859 + -0.0351909101009369 + 0.8303126096725464 + <_> + + <_> + + + + <_> + 14 4 12 9 -1. + <_> + 18 4 4 9 3. + 0 + -0.0330318994820118 + -0.3750554919242859 + 0.0489026196300983 + <_> + + <_> + + + + <_> + 0 17 6 1 -1. + <_> + 3 17 3 1 2. + 0 + 1.1923770216526464e-004 + -0.2661466896533966 + 0.2234652042388916 + <_> + + <_> + + + + <_> + 34 0 1 2 -1. + <_> + 34 0 1 1 2. + 1 + 4.2101400904357433e-003 + 8.7575968354940414e-003 + -0.5938351750373840 + <_> + + <_> + + + + <_> + 2 0 2 1 -1. + <_> + 2 0 1 1 2. + 1 + 3.3337279455736279e-004 + -0.2122765928506851 + 0.2473503947257996 + <_> + + <_> + + + + <_> + 31 3 3 8 -1. + <_> + 32 4 1 8 3. + 1 + 0.0117938900366426 + -0.0689979493618011 + 0.5898082852363586 + <_> + + <_> + + + + <_> + 5 6 26 12 -1. + <_> + 5 6 13 6 2. + <_> + 18 12 13 6 2. + 0 + -0.1143207997083664 + -0.7733368277549744 + 0.0628622919321060 + <_> + + <_> + + + + <_> + 14 4 12 9 -1. + <_> + 18 4 4 9 3. + 0 + 0.0824010074138641 + 0.0168252792209387 + -0.6170011758804321 + <_> + + <_> + + + + <_> + 13 7 10 10 -1. + <_> + 13 7 5 5 2. + <_> + 18 12 5 5 2. + 0 + 0.0181261505931616 + 0.0995334684848785 + -0.3830915987491608 + <_> + + <_> + + + + <_> + 30 5 4 6 -1. + <_> + 31 6 2 6 2. + 1 + 8.9282449334859848e-003 + -0.1010973975062370 + 0.2948305010795593 + <_> + + <_> + + + + <_> + 6 5 6 4 -1. + <_> + 5 6 6 2 2. + 1 + -0.0174371004104614 + 0.4614987075328827 + -0.1050636023283005 + <_> + + <_> + + + + <_> + 29 5 4 5 -1. + <_> + 30 6 2 5 2. + 1 + -0.0112803103402257 + 0.4561164975166321 + -0.1013116016983986 + <_> + + <_> + + + + <_> + 7 5 5 4 -1. + <_> + 6 6 5 2 2. + 1 + 7.0190089754760265e-003 + -0.1368626952171326 + 0.4173265993595123 + <_> + + <_> + + + + <_> + 0 0 36 1 -1. + <_> + 12 0 12 1 3. + 0 + -3.2439709175378084e-003 + 0.2321648001670837 + -0.1791536957025528 + <_> + + <_> + + + + <_> + 6 3 24 6 -1. + <_> + 14 5 8 2 9. + 0 + 0.3561589121818543 + -0.0486268103122711 + 0.9537345767021179 + <_> + + <_> + + + + <_> + 15 12 6 3 -1. + <_> + 15 13 6 1 3. + 0 + 3.8440749049186707e-003 + -0.1028828024864197 + 0.3671778142452240 + <_> + + <_> + + + + <_> + 11 1 9 17 -1. + <_> + 14 1 3 17 3. + 0 + 0.0609500296413898 + 0.0561417415738106 + -0.6458569765090942 + <_> + + <_> + + + + <_> + 18 1 18 10 -1. + <_> + 18 1 9 10 2. + 0 + 0.1814922988414764 + 0.0308063905686140 + -0.4604896008968353 + <_> + + <_> + + + + <_> + 0 1 18 10 -1. + <_> + 9 1 9 10 2. + 0 + -0.0923592597246170 + -0.4524821043014526 + 0.0881522372364998 + <_> + + <_> + + + + <_> + 30 7 4 5 -1. + <_> + 31 8 2 5 2. + 1 + 7.6072998344898224e-003 + -0.0971223264932632 + 0.2155224978923798 + <_> + + <_> + + + + <_> + 0 10 1 3 -1. + <_> + 0 11 1 1 3. + 0 + -4.6946710790507495e-004 + -0.4089371860027313 + 0.0800421908497810 + <_> + + <_> + + + + <_> + 33 16 2 2 -1. + <_> + 34 16 1 1 2. + <_> + 33 17 1 1 2. + 0 + 1.0301820293534547e-004 + -0.1153035983443260 + 0.2795535027980804 + <_> + + <_> + + + + <_> + 1 16 2 2 -1. + <_> + 1 16 1 1 2. + <_> + 2 17 1 1 2. + 0 + 2.7936851256527007e-004 + -0.1139610037207604 + 0.2931660115718842 + <_> + + <_> + + + + <_> + 0 8 36 3 -1. + <_> + 12 9 12 1 9. + 0 + 0.2467595934867859 + -0.0385956317186356 + 0.8264998197555542 + <_> + + <_> + + + + <_> + 14 7 8 4 -1. + <_> + 14 8 8 2 2. + 0 + -8.4232958033680916e-003 + 0.3299596905708313 + -0.1164536997675896 + <_> + + <_> + + + + <_> + 17 9 5 3 -1. + <_> + 17 10 5 1 3. + 0 + -4.2311567813158035e-003 + 0.2714211940765381 + -0.1081148013472557 + <_> + + <_> + + + + <_> + 4 0 1 2 -1. + <_> + 4 0 1 1 2. + 1 + 1.5653009759262204e-003 + 0.0782537832856178 + -0.5209766030311585 + <_> + + <_> + + + + <_> + 31 0 3 2 -1. + <_> + 31 0 3 1 2. + 1 + -5.0341398455202579e-003 + 0.2948805987834930 + -0.0469605103135109 + <_> + + <_> + + + + <_> + 5 0 2 3 -1. + <_> + 5 0 1 3 2. + 1 + 1.4283140189945698e-003 + -0.1379459947347641 + 0.2432370930910111 + <_> + + <_> + + + + <_> + 0 13 36 5 -1. + <_> + 0 13 18 5 2. + 0 + 0.1903136968612671 + -0.0520935095846653 + 0.6870803236961365 + <_> + + <_> + + + + <_> + 6 3 4 3 -1. + <_> + 5 4 4 1 3. + 1 + 8.1368777900934219e-003 + -0.0533115193247795 + 0.5827271938323975 + <_> + + <_> + + + + <_> + 28 7 6 3 -1. + <_> + 30 9 2 3 3. + 1 + -0.0467283688485622 + 0.3552536070346832 + -0.0178062599152327 + <_> + + <_> + + + + <_> + 8 7 3 6 -1. + <_> + 6 9 3 2 3. + 1 + 0.0143171697854996 + -0.1262664049863815 + 0.2696101069450378 + <_> + + <_> + + + + <_> + 14 5 18 10 -1. + <_> + 23 5 9 5 2. + <_> + 14 10 9 5 2. + 0 + -0.0961097329854965 + 0.3411748111248016 + -0.0392176099121571 + <_> + + <_> + + + + <_> + 4 5 18 10 -1. + <_> + 4 5 9 5 2. + <_> + 13 10 9 5 2. + 0 + 0.0748788118362427 + -0.0648199021816254 + 0.5671138167381287 + <_> + + <_> + + + + <_> + 32 17 3 1 -1. + <_> + 33 17 1 1 3. + 0 + -5.1972299843328074e-005 + 0.2874209880828857 + -0.1642889976501465 + <_> + + <_> + + + + <_> + 1 17 3 1 -1. + <_> + 2 17 1 1 3. + 0 + -2.0099039829801768e-004 + 0.2659021019935608 + -0.1299035996198654 + <_> + + <_> + + + + <_> + 5 0 26 2 -1. + <_> + 18 0 13 1 2. + <_> + 5 1 13 1 2. + 0 + 0.0155834900215268 + 0.0363226197659969 + -0.8874331712722778 + <_> + + <_> + + + + <_> + 0 3 27 9 -1. + <_> + 9 6 9 3 9. + 0 + 6.7313341423869133e-003 + 0.1628185957670212 + -0.1971620023250580 + <_> + + <_> + + + + <_> + 13 0 18 12 -1. + <_> + 13 6 18 6 2. + 0 + -0.0452514104545116 + -0.2031500935554504 + 0.1573408991098404 + <_> + + <_> + + + + <_> + 0 17 4 1 -1. + <_> + 1 17 2 1 2. + 0 + 2.8729529003612697e-004 + -0.1244959011673927 + 0.2565822899341583 + <_> + + <_> + + + + <_> + 29 13 1 3 -1. + <_> + 28 14 1 1 3. + 1 + -2.1028579212725163e-003 + -0.5088729262351990 + 0.0340831801295280 + <_> + + <_> + + + + <_> + 0 12 8 6 -1. + <_> + 0 14 8 2 3. + 0 + -3.9328099228441715e-003 + -0.3393375873565674 + 0.0930555686354637 + <_> + + <_> + + + + <_> + 23 7 3 3 -1. + <_> + 24 7 1 3 3. + 0 + 3.1205590348690748e-003 + -0.0227940604090691 + 0.2379353046417236 + <_> + + <_> + + + + <_> + 11 1 12 6 -1. + <_> + 11 3 12 2 3. + 0 + 0.0780286788940430 + -0.0445036217570305 + 0.6776394248008728 + <_> + + <_> + + + + <_> + 5 10 26 8 -1. + <_> + 18 10 13 4 2. + <_> + 5 14 13 4 2. + 0 + 0.0424769781529903 + 0.0925821065902710 + -0.3536301851272583 + <_> + + <_> + + + + <_> + 11 12 9 6 -1. + <_> + 14 12 3 6 3. + 0 + -0.0257683005183935 + -0.9091991186141968 + 0.0266928393393755 + <_> + + <_> + + + + <_> + 14 12 12 3 -1. + <_> + 18 13 4 1 9. + 0 + 0.0614446699619293 + -0.0249543990939856 + 0.7212049961090088 + <_> + + <_> + + + + <_> + 10 12 12 3 -1. + <_> + 14 13 4 1 9. + 0 + 3.5776318982243538e-003 + 0.1772899031639099 + -0.1972344964742661 + -1.2766569852828979 + 13 + -1 + <_> + + + <_> + + <_> + + + + <_> + 4 6 27 6 -1. + <_> + 13 8 9 2 9. + 0 + 0.2858596146106720 + -0.1539604961872101 + 0.6624677181243897 + <_> + + <_> + + + + <_> + 17 9 5 4 -1. + <_> + 17 10 5 2 2. + 0 + 9.2271259054541588e-003 + -0.1074633970856667 + 0.4311806857585907 + <_> + + <_> + + + + <_> + 0 0 16 2 -1. + <_> + 0 0 8 1 2. + <_> + 8 1 8 1 2. + 0 + 2.2924109362065792e-003 + -0.1983013004064560 + 0.3842228949069977 + <_> + + <_> + + + + <_> + 22 0 8 8 -1. + <_> + 26 0 4 4 2. + <_> + 22 4 4 4 2. + 0 + 0.0140045098960400 + -0.1924948990345001 + 0.3442491888999939 + <_> + + <_> + + + + <_> + 1 0 32 12 -1. + <_> + 1 0 16 6 2. + <_> + 17 6 16 6 2. + 0 + 0.0960232019424438 + 0.1299059987068176 + -0.6065304875373840 + <_> + + <_> + + + + <_> + 28 7 6 10 -1. + <_> + 31 7 3 5 2. + <_> + 28 12 3 5 2. + 0 + 6.1803720891475677e-003 + -0.1904646009206772 + 0.1891862004995346 + <_> + + <_> + + + + <_> + 2 7 6 10 -1. + <_> + 2 7 3 5 2. + <_> + 5 12 3 5 2. + 0 + 8.2172285765409470e-003 + -0.2518267929553986 + 0.2664459049701691 + <_> + + <_> + + + + <_> + 20 10 3 3 -1. + <_> + 20 11 3 1 3. + 0 + -1.4542760327458382e-003 + 0.2710269093513489 + -0.1204148977994919 + <_> + + <_> + + + + <_> + 13 10 3 3 -1. + <_> + 13 11 3 1 3. + 0 + 3.0185449868440628e-003 + -0.1353860944509506 + 0.4733603000640869 + <_> + + <_> + + + + <_> + 17 16 6 2 -1. + <_> + 19 16 2 2 3. + 0 + -3.4214779734611511e-003 + -0.5049971938133240 + 0.1042480990290642 + <_> + + <_> + + + + <_> + 13 11 7 3 -1. + <_> + 13 12 7 1 3. + 0 + 9.5980763435363770e-003 + -0.1034729033708572 + 0.5837283730506897 + <_> + + <_> + + + + <_> + 25 13 3 2 -1. + <_> + 25 13 3 1 2. + 1 + 4.1849957779049873e-003 + 0.0588967092335224 + -0.4623228907585144 + <_> + + <_> + + + + <_> + 13 10 4 4 -1. + <_> + 13 11 4 2 2. + 0 + -4.6107750385999680e-003 + 0.3783561885356903 + -0.1259022951126099 + <_> + + <_> + + + + <_> + 17 16 18 2 -1. + <_> + 26 16 9 1 2. + <_> + 17 17 9 1 2. + 0 + 2.8978679329156876e-003 + -0.1369954943656921 + 0.2595148086547852 + <_> + + <_> + + + + <_> + 9 13 4 1 -1. + <_> + 9 13 2 1 2. + 1 + 4.2606070637702942e-003 + 0.0882339626550674 + -0.6390284895896912 + <_> + + <_> + + + + <_> + 34 1 2 1 -1. + <_> + 34 1 1 1 2. + 1 + -4.2996238917112350e-003 + -0.7953972816467285 + 0.0170935597270727 + <_> + + <_> + + + + <_> + 5 4 24 6 -1. + <_> + 13 6 8 2 9. + 0 + 0.3542361855506897 + -0.0593450404703617 + 0.8557919859886169 + <_> + + <_> + + + + <_> + 33 16 3 2 -1. + <_> + 33 17 3 1 2. + 0 + -3.0245838570408523e-004 + 0.3147065043449402 + -0.1448609977960587 + <_> + + <_> + + + + <_> + 0 17 36 1 -1. + <_> + 18 17 18 1 2. + 0 + 0.0271694902330637 + -0.1249295026063919 + 0.4280903935432434 + <_> + + <_> + + + + <_> + 34 1 2 1 -1. + <_> + 34 1 1 1 2. + 1 + 3.4571529831737280e-003 + 0.0397093296051025 + -0.7089157104492188 + <_> + + <_> + + + + <_> + 2 1 1 2 -1. + <_> + 2 1 1 1 2. + 1 + 2.1742798853665590e-003 + 0.0658724531531334 + -0.6949694156646729 + <_> + + <_> + + + + <_> + 22 0 8 10 -1. + <_> + 24 2 4 10 2. + 1 + 0.0252638105303049 + -0.1169395968317986 + 0.1904976963996887 + <_> + + <_> + + + + <_> + 12 4 8 12 -1. + <_> + 12 4 4 6 2. + <_> + 16 10 4 6 2. + 0 + -0.0247209891676903 + -0.4965795874595642 + 0.1017538011074066 + <_> + + <_> + + + + <_> + 26 6 6 6 -1. + <_> + 29 6 3 3 2. + <_> + 26 9 3 3 2. + 0 + 0.0103848800063133 + -0.1148673966526985 + 0.3374153077602387 + <_> + + <_> + + + + <_> + 5 6 4 6 -1. + <_> + 5 6 2 3 2. + <_> + 7 9 2 3 2. + 0 + 5.0045028328895569e-003 + -0.1096355020999908 + 0.3925519883632660 + <_> + + <_> + + + + <_> + 29 5 2 4 -1. + <_> + 29 5 1 4 2. + 1 + 7.1279620751738548e-003 + -0.0649081915616989 + 0.4042040109634399 + <_> + + <_> + + + + <_> + 7 4 18 3 -1. + <_> + 7 5 18 1 3. + 0 + 0.0197004191577435 + -0.0793758779764175 + 0.5308234095573425 + <_> + + <_> + + + + <_> + 29 13 2 3 -1. + <_> + 28 14 2 1 3. + 1 + 4.2097331024706364e-003 + 0.0407970212399960 + -0.6044098734855652 + <_> + + <_> + + + + <_> + 9 5 3 3 -1. + <_> + 8 6 3 1 3. + 1 + 4.4459570199251175e-003 + -0.1038623005151749 + 0.4093598127365112 + <_> + + <_> + + + + <_> + 7 16 22 2 -1. + <_> + 18 16 11 1 2. + <_> + 7 17 11 1 2. + 0 + -5.9610428288578987e-003 + -0.5291494727134705 + 0.0805394500494003 + <_> + + <_> + + + + <_> + 0 2 1 3 -1. + <_> + 0 3 1 1 3. + 0 + 5.7519221445545554e-004 + 0.0638044029474258 + -0.5863661766052246 + <_> + + <_> + + + + <_> + 16 3 20 6 -1. + <_> + 26 3 10 3 2. + <_> + 16 6 10 3 2. + 0 + 0.0605248510837555 + -0.0337128005921841 + 0.2631115913391113 + <_> + + <_> + + + + <_> + 10 5 8 6 -1. + <_> + 12 5 4 6 2. + 0 + -0.0103538101539016 + -0.4792002141475678 + 0.0800439566373825 + <_> + + <_> + + + + <_> + 1 8 34 8 -1. + <_> + 18 8 17 4 2. + <_> + 1 12 17 4 2. + 0 + -0.0227775108069181 + -0.3116275072097778 + 0.1189998015761375 + <_> + + <_> + + + + <_> + 14 9 8 8 -1. + <_> + 14 9 4 4 2. + <_> + 18 13 4 4 2. + 0 + -0.0224688798189163 + -0.6608346104621887 + 0.0522344894707203 + <_> + + <_> + + + + <_> + 35 0 1 3 -1. + <_> + 35 1 1 1 3. + 0 + 5.8432162040844560e-004 + 0.0546303391456604 + -0.4639565944671631 + <_> + + <_> + + + + <_> + 15 8 3 5 -1. + <_> + 16 8 1 5 3. + 0 + -3.6177870351821184e-003 + 0.6744704246520996 + -0.0587895289063454 + <_> + + <_> + + + + <_> + 19 0 10 1 -1. + <_> + 19 0 5 1 2. + 1 + 0.0300888605415821 + 0.0331335216760635 + -0.4646137058734894 + -1.4061349630355835 + 14 + -1 + <_> + + + <_> + + <_> + + + + <_> + 9 3 9 6 -1. + <_> + 7 5 9 2 3. + 1 + -0.0726009905338287 + 0.6390709280967712 + -0.1512455046176910 + <_> + + <_> + + + + <_> + 6 6 24 6 -1. + <_> + 14 8 8 2 9. + 0 + 0.3471255898475647 + -0.0790246576070786 + 0.7955042123794556 + <_> + + <_> + + + + <_> + 4 8 27 6 -1. + <_> + 13 10 9 2 9. + 0 + 0.3429723083972931 + -0.1230095997452736 + 0.6572809815406799 + <_> + + <_> + + + + <_> + 5 4 27 6 -1. + <_> + 14 6 9 2 9. + 0 + 0.3561694025993347 + -0.0537334382534027 + 0.8285108208656311 + <_> + + <_> + + + + <_> + 5 6 5 6 -1. + <_> + 5 8 5 2 3. + 0 + 6.0840700753033161e-003 + -0.1284721046686173 + 0.3382267951965332 + <_> + + <_> + + + + <_> + 35 0 1 2 -1. + <_> + 35 1 1 1 2. + 0 + -1.6281309945043176e-004 + 0.3035660982131958 + -0.2518202960491180 + <_> + + <_> + + + + <_> + 4 3 10 3 -1. + <_> + 3 4 10 1 3. + 1 + 0.0112819001078606 + -0.0839143469929695 + 0.4347592890262604 + <_> + + <_> + + + + <_> + 29 5 2 4 -1. + <_> + 29 5 1 4 2. + 1 + 7.4357059784233570e-003 + -0.0670880377292633 + 0.3722797930240631 + <_> + + <_> + + + + <_> + 3 0 28 16 -1. + <_> + 3 0 14 8 2. + <_> + 17 8 14 8 2. + 0 + -0.0905762165784836 + -0.5831961035728455 + 0.0801467597484589 + <_> + + <_> + + + + <_> + 31 0 4 2 -1. + <_> + 31 0 2 2 2. + 1 + 8.8247694075107574e-003 + 0.1290193051099777 + -0.4760313034057617 + <_> + + <_> + + + + <_> + 4 9 3 9 -1. + <_> + 4 12 3 3 3. + 0 + -2.6147770695388317e-003 + -0.4000220894813538 + 0.1124631017446518 + <_> + + <_> + + + + <_> + 32 16 4 2 -1. + <_> + 32 17 4 1 2. + 0 + -2.5541300419718027e-004 + 0.3238615989685059 + -0.2333187013864517 + <_> + + <_> + + + + <_> + 17 0 1 10 -1. + <_> + 17 0 1 5 2. + 1 + 0.0265476293861866 + 0.0723338723182678 + -0.5837839841842651 + <_> + + <_> + + + + <_> + 17 4 14 8 -1. + <_> + 17 4 7 8 2. + 0 + -0.0513831414282322 + -0.2244618982076645 + 0.0409497395157814 + <_> + + <_> + + + + <_> + 6 0 11 4 -1. + <_> + 6 2 11 2 2. + 0 + 3.3701129723340273e-003 + -0.1671708971261978 + 0.2552697062492371 + <_> + + <_> + + + + <_> + 35 0 1 2 -1. + <_> + 35 1 1 1 2. + 0 + -2.2581920493394136e-003 + -0.9207922816276550 + 3.4371060319244862e-003 + <_> + + <_> + + + + <_> + 0 0 1 2 -1. + <_> + 0 1 1 1 2. + 0 + -1.3282749569043517e-004 + 0.1857322007417679 + -0.2249896973371506 + <_> + + <_> + + + + <_> + 33 0 2 1 -1. + <_> + 33 0 1 1 2. + 1 + -2.8032590635120869e-003 + -0.8589754104614258 + 0.0463845208287239 + <_> + + <_> + + + + <_> + 3 0 1 2 -1. + <_> + 3 0 1 1 2. + 1 + 1.3141379458829761e-003 + 0.0796270668506622 + -0.4610596895217896 + <_> + + <_> + + + + <_> + 0 17 36 1 -1. + <_> + 9 17 18 1 2. + 0 + 0.0638845413923264 + -0.0534401498734951 + 0.8104500174522400 + <_> + + <_> + + + + <_> + 7 13 3 1 -1. + <_> + 8 14 1 1 3. + 1 + -1.9811019301414490e-003 + -0.6382514834403992 + 0.0766435563564301 + <_> + + <_> + + + + <_> + 17 4 14 8 -1. + <_> + 17 4 7 8 2. + 0 + 0.0133598595857620 + -0.0950375497341156 + 0.0625333487987518 + <_> + + <_> + + + + <_> + 0 16 4 2 -1. + <_> + 0 17 4 1 2. + 0 + -1.0935300088021904e-004 + 0.1747954040765762 + -0.2287603020668030 + <_> + + <_> + + + + <_> + 13 12 10 3 -1. + <_> + 13 13 10 1 3. + 0 + 0.0119106303900480 + -0.0770419836044312 + 0.5045837759971619 + <_> + + <_> + + + + <_> + 0 12 36 6 -1. + <_> + 18 12 18 6 2. + 0 + 0.2395170032978058 + -0.0651228874921799 + 0.5042074918746948 + <_> + + <_> + + + + <_> + 5 3 27 6 -1. + <_> + 14 5 9 2 9. + 0 + 0.3983140885829926 + -0.0299998205155134 + 0.7968547940254211 + <_> + + <_> + + + + <_> + 9 5 5 3 -1. + <_> + 8 6 5 1 3. + 1 + 6.1875800602138042e-003 + -0.0853391736745834 + 0.3945176899433136 + <_> + + <_> + + + + <_> + 12 7 12 4 -1. + <_> + 15 7 6 4 2. + 0 + -9.4047123566269875e-003 + -0.4344133138656616 + 0.0826191008090973 + <_> + + <_> + + + + <_> + 13 5 8 4 -1. + <_> + 15 5 4 4 2. + 0 + 0.0117366304621100 + 0.0694831609725952 + -0.4870649874210358 + <_> + + <_> + + + + <_> + 16 14 6 4 -1. + <_> + 16 14 3 4 2. + 0 + -0.0151767702773213 + -0.5854120850563049 + 0.0328795611858368 + <_> + + <_> + + + + <_> + 14 10 5 3 -1. + <_> + 14 11 5 1 3. + 0 + 3.0744259711354971e-003 + -0.1314608007669449 + 0.2546674013137817 + <_> + + <_> + + + + <_> + 25 3 6 4 -1. + <_> + 25 4 6 2 2. + 0 + 2.9391339048743248e-003 + -0.1086023002862930 + 0.2783496081829071 + <_> + + <_> + + + + <_> + 3 6 6 8 -1. + <_> + 3 8 6 4 2. + 0 + 2.1510310471057892e-003 + -0.1575057953596115 + 0.2087786048650742 + <_> + + <_> + + + + <_> + 27 4 5 6 -1. + <_> + 27 6 5 2 3. + 0 + 5.3775361739099026e-003 + -0.1320703029632568 + 0.3767293989658356 + <_> + + <_> + + + + <_> + 4 1 6 9 -1. + <_> + 4 4 6 3 3. + 0 + 0.0221741795539856 + -0.0901802927255630 + 0.4157527089118958 + <_> + + <_> + + + + <_> + 21 9 2 4 -1. + <_> + 21 10 2 2 2. + 0 + -1.9948610570281744e-003 + 0.2560858130455017 + -0.0990849286317825 + <_> + + <_> + + + + <_> + 1 10 34 4 -1. + <_> + 1 10 17 2 2. + <_> + 18 12 17 2 2. + 0 + 0.0315575599670410 + 0.0741889998316765 + -0.5494022965431213 + <_> + + <_> + + + + <_> + 34 15 2 3 -1. + <_> + 34 16 2 1 3. + 0 + -4.3111158447572961e-005 + 0.3032462894916534 + -0.1778181046247482 + <_> + + <_> + + + + <_> + 3 0 2 2 -1. + <_> + 3 0 2 1 2. + 1 + -3.2675920519977808e-003 + -0.6721243262290955 + 0.0591883286833763 + <_> + + <_> + + + + <_> + 33 0 1 2 -1. + <_> + 33 0 1 1 2. + 1 + 4.2293380829505622e-004 + -0.1103409975767136 + 0.1257317960262299 + -1.3384460210800171 + 15 + -1 + <_> + + + <_> + + <_> + + + + <_> + 8 0 10 8 -1. + <_> + 6 2 10 4 2. + 1 + -0.0425620190799236 + 0.3334665894508362 + -0.2986198067665100 + <_> + + <_> + + + + <_> + 3 6 30 6 -1. + <_> + 13 8 10 2 9. + 0 + 0.4182719886302948 + -0.0951386988162994 + 0.7570992112159729 + <_> + + <_> + + + + <_> + 13 7 10 4 -1. + <_> + 13 8 10 2 2. + 0 + -0.0202563796192408 + 0.4778389036655426 + -0.1459210067987442 + <_> + + <_> + + + + <_> + 16 5 6 12 -1. + <_> + 19 5 3 6 2. + <_> + 16 11 3 6 2. + 0 + -0.0189483091235161 + -0.3872750103473663 + 0.0524798892438412 + <_> + + <_> + + + + <_> + 10 1 4 6 -1. + <_> + 8 3 4 2 3. + 1 + -0.0405505895614624 + 0.5464624762535095 + -0.0813998579978943 + <_> + + <_> + + + + <_> + 2 7 33 6 -1. + <_> + 13 9 11 2 9. + 0 + 0.5187274813652039 + -0.0279305391013622 + 0.8458098173141480 + <_> + + <_> + + + + <_> + 3 6 30 3 -1. + <_> + 13 7 10 1 9. + 0 + 0.2071361988782883 + -0.0588508695363998 + 0.7960156202316284 + <_> + + <_> + + + + <_> + 15 11 6 3 -1. + <_> + 15 12 6 1 3. + 0 + 8.1972572952508926e-003 + -0.0999663695693016 + 0.4983156025409699 + <_> + + <_> + + + + <_> + 14 5 6 12 -1. + <_> + 14 5 3 6 2. + <_> + 17 11 3 6 2. + 0 + 0.0174453891813755 + 0.0680409595370293 + -0.5669981837272644 + <_> + + <_> + + + + <_> + 5 12 26 6 -1. + <_> + 18 12 13 3 2. + <_> + 5 15 13 3 2. + 0 + -0.0563102811574936 + -0.6862804293632507 + 0.0742225572466850 + <_> + + <_> + + + + <_> + 4 12 27 3 -1. + <_> + 13 13 9 1 9. + 0 + 0.1809556037187576 + -0.0528081282973289 + 0.8448318243026733 + <_> + + <_> + + + + <_> + 16 11 4 3 -1. + <_> + 16 12 4 1 3. + 0 + -2.3450690787285566e-003 + 0.2839694023132324 + -0.1112336963415146 + <_> + + <_> + + + + <_> + 5 12 4 2 -1. + <_> + 6 13 2 2 2. + 1 + 3.8937770295888186e-003 + 0.0654993131756783 + -0.5792096257209778 + <_> + + <_> + + + + <_> + 34 17 2 1 -1. + <_> + 34 17 1 1 2. + 0 + 3.9383721741614863e-005 + -0.3093047142028809 + 0.4223710894584656 + <_> + + <_> + + + + <_> + 16 0 1 12 -1. + <_> + 16 0 1 6 2. + 1 + 0.0338991582393646 + 0.0307075399905443 + -0.7229980826377869 + <_> + + <_> + + + + <_> + 2 17 34 1 -1. + <_> + 2 17 17 1 2. + 0 + -0.0336443893611431 + 0.4266444146633148 + -0.0720057785511017 + <_> + + <_> + + + + <_> + 5 3 18 4 -1. + <_> + 5 4 18 2 2. + 0 + 0.0388077609241009 + -0.0417135208845139 + 0.6599556803703308 + <_> + + <_> + + + + <_> + 34 17 2 1 -1. + <_> + 34 17 1 1 2. + 0 + -3.9149548683781177e-005 + 0.4933550059795380 + -0.2426010966300964 + <_> + + <_> + + + + <_> + 0 0 2 2 -1. + <_> + 0 1 2 1 2. + 0 + -2.7580570895224810e-004 + 0.1791010946035385 + -0.2192519009113312 + <_> + + <_> + + + + <_> + 15 5 16 3 -1. + <_> + 15 6 16 1 3. + 0 + 0.0126366596668959 + -0.0712336227297783 + 0.2534261941909790 + <_> + + <_> + + + + <_> + 13 9 3 3 -1. + <_> + 13 10 3 1 3. + 0 + -3.3681739587336779e-003 + 0.3310086131095886 + -0.1020777970552445 + <_> + + <_> + + + + <_> + 20 4 8 14 -1. + <_> + 22 4 4 14 2. + 0 + -0.0411845296621323 + -0.4787198901176453 + 0.0274448096752167 + <_> + + <_> + + + + <_> + 7 5 20 6 -1. + <_> + 12 5 10 6 2. + 0 + 0.0172852799296379 + -0.2373382002115250 + 0.1541430056095123 + <_> + + <_> + + + + <_> + 26 3 6 6 -1. + <_> + 28 5 2 6 3. + 1 + -0.0583733208477497 + 0.3635525107383728 + -0.0629119277000427 + <_> + + <_> + + + + <_> + 10 3 6 6 -1. + <_> + 8 5 6 2 3. + 1 + 0.0252293199300766 + -0.0943458229303360 + 0.4322442114353180 + <_> + + <_> + + + + <_> + 34 0 2 3 -1. + <_> + 34 0 1 3 2. + 1 + 4.7925519756972790e-003 + 0.0486642718315125 + -0.4704689085483551 + <_> + + <_> + + + + <_> + 0 16 2 2 -1. + <_> + 0 17 2 1 2. + 0 + -1.3549529830925167e-004 + 0.1936188042163849 + -0.1933847069740295 + <_> + + <_> + + + + <_> + 30 6 4 8 -1. + <_> + 31 7 2 8 2. + 1 + -0.0179694108664989 + 0.2900086045265198 + -0.0545452795922756 + <_> + + <_> + + + + <_> + 6 6 7 4 -1. + <_> + 5 7 7 2 2. + 1 + 0.0111410403624177 + -0.1080225035548210 + 0.3332796096801758 + <_> + + <_> + + + + <_> + 20 4 8 14 -1. + <_> + 22 4 4 14 2. + 0 + 0.0397595092654228 + 0.0192408692091703 + -0.4889996051788330 + <_> + + <_> + + + + <_> + 8 4 8 14 -1. + <_> + 10 4 4 14 2. + 0 + -0.0226527098566294 + -0.5036928057670593 + 0.0807737335562706 + <_> + + <_> + + + + <_> + 17 17 6 1 -1. + <_> + 19 17 2 1 3. + 0 + 1.0915650054812431e-003 + 0.0655540525913239 + -0.2444387972354889 + <_> + + <_> + + + + <_> + 0 0 20 6 -1. + <_> + 10 0 10 6 2. + 0 + 0.0687547475099564 + 0.0891968086361885 + -0.3565390110015869 + <_> + + <_> + + + + <_> + 8 0 22 18 -1. + <_> + 8 0 11 18 2. + 0 + -0.3307105898857117 + 0.4649569988250732 + -0.0581836998462677 + <_> + + <_> + + + + <_> + 13 2 8 12 -1. + <_> + 13 2 4 6 2. + <_> + 17 8 4 6 2. + 0 + -0.0193072296679020 + -0.4415718019008637 + 0.0830501168966293 + <_> + + <_> + + + + <_> + 11 10 14 8 -1. + <_> + 18 10 7 4 2. + <_> + 11 14 7 4 2. + 0 + 0.0348087586462498 + 0.0534805804491043 + -0.5037739872932434 + <_> + + <_> + + + + <_> + 1 16 2 2 -1. + <_> + 1 16 1 1 2. + <_> + 2 17 1 1 2. + 0 + -3.8908151327632368e-004 + 0.3427126109600067 + -0.0899231806397438 + <_> + + <_> + + + + <_> + 34 0 2 1 -1. + <_> + 34 0 1 1 2. + 1 + -2.1421869751065969e-003 + -0.6064280271530151 + 0.0555892400443554 + <_> + + <_> + + + + <_> + 6 3 24 4 -1. + <_> + 12 3 12 4 2. + 0 + 0.1101581007242203 + -0.0547747202217579 + 0.6878091096878052 + <_> + + <_> + + + + <_> + 19 1 2 3 -1. + <_> + 19 2 2 1 3. + 0 + 3.0875208904035389e-004 + -0.0558342188596725 + 0.0931682363152504 + <_> + + <_> + + + + <_> + 2 0 1 2 -1. + <_> + 2 0 1 1 2. + 1 + 2.1960400044918060e-003 + 0.0539557486772537 + -0.6050305962562561 + <_> + + <_> + + + + <_> + 15 3 6 8 -1. + <_> + 18 3 3 4 2. + <_> + 15 7 3 4 2. + 0 + -0.0126062501221895 + -0.4686402976512909 + 0.0599438697099686 + <_> + + <_> + + + + <_> + 14 5 4 2 -1. + <_> + 14 6 4 1 2. + 0 + -2.7497899718582630e-003 + 0.2894253134727478 + -0.1129785031080246 + <_> + + <_> + + + + <_> + 3 7 30 9 -1. + <_> + 13 10 10 3 9. + 0 + 0.6096264123916626 + -0.0478859916329384 + 0.5946549177169800 + <_> + + <_> + + + + <_> + 9 8 12 9 -1. + <_> + 12 8 6 9 2. + 0 + 0.0450232513248920 + 0.0638310685753822 + -0.5295680165290833 + -1.2722699642181396 + 16 + -1 + <_> + + + <_> + + <_> + + + + <_> + 10 8 16 5 -1. + <_> + 14 8 8 5 2. + 0 + 0.0159072801470757 + -0.3819232881069183 + 0.2941176891326904 + <_> + + <_> + + + + <_> + 30 1 4 10 -1. + <_> + 31 2 2 10 2. + 1 + -0.0304830092936754 + 0.6401454806327820 + -0.1133823990821838 + <_> + + <_> + + + + <_> + 13 0 10 8 -1. + <_> + 11 2 10 4 2. + 1 + 0.0258412398397923 + -0.1765469014644623 + 0.2556340098381043 + <_> + + <_> + + + + <_> + 32 2 2 14 -1. + <_> + 32 2 1 14 2. + 1 + 0.0121606197208166 + -0.0494619905948639 + 0.3473398983478546 + <_> + + <_> + + + + <_> + 4 2 14 2 -1. + <_> + 4 2 14 1 2. + 1 + -0.0159101597964764 + 0.4796676933765411 + -0.1300950944423676 + <_> + + <_> + + + + <_> + 30 14 6 4 -1. + <_> + 30 14 3 4 2. + 0 + 3.5282061435282230e-004 + -0.3418492972850800 + 0.2309112995862961 + <_> + + <_> + + + + <_> + 11 13 1 4 -1. + <_> + 11 15 1 2 2. + 0 + 6.7633582511916757e-004 + -0.1543250977993012 + 0.2668730020523071 + <_> + + <_> + + + + <_> + 11 0 14 18 -1. + <_> + 18 0 7 9 2. + <_> + 11 9 7 9 2. + 0 + -0.0599361397325993 + -0.4880258142948151 + 0.0933274477720261 + <_> + + <_> + + + + <_> + 0 1 20 9 -1. + <_> + 10 1 10 9 2. + 0 + -0.1134240999817848 + -0.6577144265174866 + 0.0591668188571930 + <_> + + <_> + + + + <_> + 21 3 8 3 -1. + <_> + 23 3 4 3 2. + 0 + -4.3361280113458633e-003 + -0.1593652069568634 + 0.0502370409667492 + <_> + + <_> + + + + <_> + 13 9 2 4 -1. + <_> + 13 10 2 2 2. + 0 + -1.8627740209922194e-003 + 0.3073025941848755 + -0.1254066973924637 + <_> + + <_> + + + + <_> + 14 9 11 2 -1. + <_> + 14 10 11 1 2. + 0 + 0.0126530099660158 + -0.1004493013024330 + 0.3749617934226990 + <_> + + <_> + + + + <_> + 0 2 36 9 -1. + <_> + 12 5 12 3 9. + 0 + 0.6911857724189758 + -0.0471464097499847 + 0.8321244120597839 + <_> + + <_> + + + + <_> + 34 12 2 6 -1. + <_> + 34 15 2 3 2. + 0 + -2.6093868655152619e-004 + 0.3198773860931397 + -0.2718330919742584 + <_> + + <_> + + + + <_> + 11 4 14 6 -1. + <_> + 11 6 14 2 3. + 0 + -0.0763450562953949 + 0.4309130012989044 + -0.0908882692456245 + <_> + + <_> + + + + <_> + 31 0 4 1 -1. + <_> + 31 0 2 1 2. + 0 + 2.8098300099372864e-003 + 0.0587311200797558 + -0.6199675202369690 + <_> + + <_> + + + + <_> + 1 0 4 1 -1. + <_> + 3 0 2 1 2. + 0 + -1.3322039740160108e-004 + 0.2000005990266800 + -0.2012010961771011 + <_> + + <_> + + + + <_> + 19 14 6 4 -1. + <_> + 21 14 2 4 3. + 0 + -0.0137176299467683 + -0.7309545278549194 + 0.0271785296499729 + <_> + + <_> + + + + <_> + 11 14 6 4 -1. + <_> + 13 14 2 4 3. + 0 + -6.2303808517754078e-003 + -0.5478098988533020 + 0.0687499493360519 + <_> + + <_> + + + + <_> + 0 14 36 1 -1. + <_> + 9 14 18 1 2. + 0 + 0.0499227195978165 + -0.0473043099045753 + 0.8242310285568237 + <_> + + <_> + + + + <_> + 5 0 2 2 -1. + <_> + 5 0 2 1 2. + 1 + -1.9126719562336802e-003 + -0.5394017100334168 + 0.0774475932121277 + <_> + + <_> + + + + <_> + 26 3 5 3 -1. + <_> + 26 4 5 1 3. + 0 + 1.1384560493752360e-003 + -0.0965376868844032 + 0.1548569053411484 + <_> + + <_> + + + + <_> + 16 8 1 3 -1. + <_> + 15 9 1 1 3. + 1 + -2.4732090532779694e-003 + 0.3559078872203827 + -0.0931698307394981 + <_> + + <_> + + + + <_> + 21 11 2 3 -1. + <_> + 21 12 2 1 3. + 0 + -7.1464257780462503e-004 + 0.1452019065618515 + -0.0741942077875137 + <_> + + <_> + + + + <_> + 9 5 6 4 -1. + <_> + 8 6 6 2 2. + 1 + -0.0204371493309736 + 0.4416376948356628 + -0.0809424370527267 + <_> + + <_> + + + + <_> + 31 0 2 2 -1. + <_> + 31 0 1 2 2. + 1 + -4.0483791381120682e-003 + -0.5999277830123901 + 0.0330253802239895 + <_> + + <_> + + + + <_> + 6 4 3 9 -1. + <_> + 6 7 3 3 3. + 0 + 0.0111480504274368 + -0.1135832965373993 + 0.3264499902725220 + <_> + + <_> + + + + <_> + 19 0 11 2 -1. + <_> + 19 0 11 1 2. + 1 + 9.8842009902000427e-003 + 0.0554044805467129 + -0.3273097872734070 + <_> + + <_> + + + + <_> + 5 0 2 2 -1. + <_> + 5 0 2 1 2. + 1 + 3.1296359375119209e-003 + 0.0774086564779282 + -0.4595307111740112 + <_> + + <_> + + + + <_> + 22 0 14 4 -1. + <_> + 29 0 7 2 2. + <_> + 22 2 7 2 2. + 0 + 2.9721839819103479e-003 + -0.1291726976633072 + 0.1552311033010483 + <_> + + <_> + + + + <_> + 15 1 4 13 -1. + <_> + 15 1 2 13 2. + 1 + 0.0205544792115688 + 0.0876004695892334 + -0.4577418863773346 + <_> + + <_> + + + + <_> + 21 3 8 4 -1. + <_> + 23 3 4 4 2. + 0 + -0.0230272803455591 + 0.3548808991909027 + -0.0205669198185205 + <_> + + <_> + + + + <_> + 7 3 8 4 -1. + <_> + 9 3 4 4 2. + 0 + -8.3903772756457329e-003 + -0.4324072897434235 + 0.0920679792761803 + <_> + + <_> + + + + <_> + 32 14 2 2 -1. + <_> + 33 14 1 1 2. + <_> + 32 15 1 1 2. + 0 + -1.1431539896875620e-003 + 0.3959133923053742 + -0.0231928899884224 + <_> + + <_> + + + + <_> + 2 14 2 2 -1. + <_> + 2 14 1 1 2. + <_> + 3 15 1 1 2. + 0 + -4.9133709399029613e-004 + 0.4274964034557343 + -0.0855242162942886 + <_> + + <_> + + + + <_> + 35 5 1 12 -1. + <_> + 35 9 1 4 3. + 0 + 5.1292928401380777e-004 + -0.1619673967361450 + 0.1961497068405151 + <_> + + <_> + + + + <_> + 0 7 1 9 -1. + <_> + 0 10 1 3 3. + 0 + -5.8478871360421181e-003 + -0.5911636948585510 + 0.0624482408165932 + <_> + + <_> + + + + <_> + 12 2 15 6 -1. + <_> + 12 4 15 2 3. + 0 + -0.0941330492496490 + 0.4770160913467407 + -0.0567101612687111 + <_> + + <_> + + + + <_> + 0 17 2 1 -1. + <_> + 1 17 1 1 2. + 0 + 1.0079269850393757e-004 + -0.1625709980726242 + 0.2140229046344757 + <_> + + <_> + + + + <_> + 34 17 2 1 -1. + <_> + 34 17 1 1 2. + 0 + 3.2930231100181118e-005 + -0.1859605014324188 + 0.1964769065380096 + <_> + + <_> + + + + <_> + 0 17 2 1 -1. + <_> + 1 17 1 1 2. + 0 + -1.1743210052372888e-004 + 0.3182134926319122 + -0.1328738033771515 + <_> + + <_> + + + + <_> + 11 0 16 10 -1. + <_> + 15 0 8 10 2. + 0 + 0.1275181025266647 + 0.0301400795578957 + -0.7411035895347595 + <_> + + <_> + + + + <_> + 5 10 24 8 -1. + <_> + 5 10 12 4 2. + <_> + 17 14 12 4 2. + 0 + 0.0803262963891029 + 0.0415550395846367 + -0.8263683915138245 + <_> + + <_> + + + + <_> + 27 4 3 3 -1. + <_> + 27 5 3 1 3. + 0 + 1.6904190415516496e-003 + -0.1029061973094940 + 0.2972418069839478 + -1.3022350072860718 + 17 + -1 + <_> + + + <_> + + <_> + + + + <_> + 6 6 14 12 -1. + <_> + 6 6 7 6 2. + <_> + 13 12 7 6 2. + 0 + -0.0461227893829346 + 0.4425258934497833 + -0.2991319894790649 + <_> + + <_> + + + + <_> + 6 5 24 6 -1. + <_> + 14 7 8 2 9. + 0 + 0.3672331869602203 + -0.0630117505788803 + 0.7712538242340088 + <_> + + <_> + + + + <_> + 12 6 3 4 -1. + <_> + 12 7 3 2 2. + 0 + -3.0962929595261812e-003 + 0.3514241874217987 + -0.1730643957853317 + <_> + + <_> + + + + <_> + 30 7 6 10 -1. + <_> + 33 7 3 5 2. + <_> + 30 12 3 5 2. + 0 + 9.2647131532430649e-003 + -0.1607280969619751 + 0.1853290945291519 + <_> + + <_> + + + + <_> + 3 12 6 6 -1. + <_> + 3 12 3 3 2. + <_> + 6 15 3 3 2. + 0 + 3.1748649198561907e-003 + -0.1968899965286255 + 0.2409728020429611 + <_> + + <_> + + + + <_> + 20 0 13 2 -1. + <_> + 20 0 13 1 2. + 1 + 8.0439839512109756e-003 + 0.0898629724979401 + -0.3655225932598114 + <_> + + <_> + + + + <_> + 6 10 24 6 -1. + <_> + 14 12 8 2 9. + 0 + 0.3275249004364014 + -0.0568796806037426 + 0.7749336957931519 + <_> + + <_> + + + + <_> + 15 4 8 8 -1. + <_> + 19 4 4 4 2. + <_> + 15 8 4 4 2. + 0 + -0.0190744306892157 + -0.2895380854606628 + 0.0622916705906391 + <_> + + <_> + + + + <_> + 13 4 8 8 -1. + <_> + 13 4 4 4 2. + <_> + 17 8 4 4 2. + 0 + -0.0205017495900393 + -0.6262530088424683 + 0.0682769715785980 + <_> + + <_> + + + + <_> + 34 16 2 2 -1. + <_> + 34 16 1 2 2. + 0 + 5.3187010053079575e-005 + -0.2514955997467041 + 0.2613196074962616 + <_> + + <_> + + + + <_> + 12 6 3 3 -1. + <_> + 12 7 3 1 3. + 0 + 3.3275580499321222e-003 + -0.1199077963829041 + 0.3651930093765259 + <_> + + <_> + + + + <_> + 21 7 4 4 -1. + <_> + 21 8 4 2 2. + 0 + 5.8408430777490139e-003 + -0.0827485173940659 + 0.2365082055330277 + <_> + + <_> + + + + <_> + 2 8 30 4 -1. + <_> + 2 8 15 2 2. + <_> + 17 10 15 2 2. + 0 + -0.0464623309671879 + -0.6928564906120300 + 0.0781976729631424 + <_> + + <_> + + + + <_> + 27 4 3 4 -1. + <_> + 27 5 3 2 2. + 0 + -3.7785700988024473e-003 + 0.3437257111072540 + -0.1027545034885407 + <_> + + <_> + + + + <_> + 5 4 3 4 -1. + <_> + 5 5 3 2 2. + 0 + 1.6655459767207503e-003 + -0.1160527989268303 + 0.3716202974319458 + <_> + + <_> + + + + <_> + 34 16 2 2 -1. + <_> + 34 16 1 2 2. + 0 + -5.7107670727418736e-005 + 0.4589366912841797 + -0.2123643010854721 + <_> + + <_> + + + + <_> + 0 16 34 2 -1. + <_> + 0 16 17 1 2. + <_> + 17 17 17 1 2. + 0 + -9.0066380798816681e-003 + -0.5953341126441956 + 0.0808764025568962 + <_> + + <_> + + + + <_> + 12 5 15 12 -1. + <_> + 12 9 15 4 3. + 0 + -0.1378971040248871 + 0.3957067131996155 + -0.0898853763937950 + <_> + + <_> + + + + <_> + 0 8 36 6 -1. + <_> + 12 10 12 2 9. + 0 + 0.5759987235069275 + -0.0538108199834824 + 0.8170394897460938 + <_> + + <_> + + + + <_> + 25 4 6 2 -1. + <_> + 25 5 6 1 2. + 0 + -2.3918158840388060e-003 + 0.1393374055624008 + -0.0421559289097786 + <_> + + <_> + + + + <_> + 0 17 2 1 -1. + <_> + 1 17 1 1 2. + 0 + 2.4896071408875287e-004 + -0.1485866010189056 + 0.2626332938671112 + <_> + + <_> + + + + <_> + 16 0 9 9 -1. + <_> + 19 0 3 9 3. + 0 + 0.0330624915659428 + 0.0306599102914333 + -0.3231860101222992 + <_> + + <_> + + + + <_> + 11 0 9 9 -1. + <_> + 14 0 3 9 3. + 0 + 0.0443218797445297 + 0.0478538200259209 + -0.7813590168952942 + <_> + + <_> + + + + <_> + 20 5 16 5 -1. + <_> + 24 5 8 5 2. + 0 + -0.0187181904911995 + 0.1201262027025223 + -0.1121146976947784 + <_> + + <_> + + + + <_> + 0 3 16 9 -1. + <_> + 4 3 8 9 2. + 0 + 0.0923093706369400 + 0.0424630790948868 + -0.8009700179100037 + <_> + + <_> + + + + <_> + 7 6 26 12 -1. + <_> + 20 6 13 6 2. + <_> + 7 12 13 6 2. + 0 + 0.0906654372811317 + -0.0223045293241739 + 0.1284797936677933 + <_> + + <_> + + + + <_> + 5 6 24 12 -1. + <_> + 5 6 12 6 2. + <_> + 17 12 12 6 2. + 0 + -0.0582949295639992 + -0.3936854004859924 + 0.0954821407794952 + <_> + + <_> + + + + <_> + 17 4 3 12 -1. + <_> + 18 4 1 12 3. + 0 + 4.6649780124425888e-003 + -0.0656419470906258 + 0.3640717864036560 + <_> + + <_> + + + + <_> + 1 11 6 1 -1. + <_> + 3 13 2 1 3. + 1 + 5.2480432204902172e-003 + 0.0687657818198204 + -0.5050830245018005 + <_> + + <_> + + + + <_> + 21 12 14 2 -1. + <_> + 28 12 7 1 2. + <_> + 21 13 7 1 2. + 0 + 2.5315659586340189e-003 + -0.0933471694588661 + 0.1649612933397293 + <_> + + <_> + + + + <_> + 1 13 2 3 -1. + <_> + 2 13 1 3 2. + 0 + 2.4391160695813596e-004 + -0.1888543963432312 + 0.1695670038461685 + <_> + + <_> + + + + <_> + 26 8 3 2 -1. + <_> + 27 9 1 2 3. + 1 + -6.3037211075425148e-003 + 0.3826352953910828 + -0.0590420998632908 + <_> + + <_> + + + + <_> + 10 8 2 3 -1. + <_> + 9 9 2 1 3. + 1 + 2.2754059173166752e-003 + -0.1224882006645203 + 0.2828365862369537 + <_> + + <_> + + + + <_> + 12 0 18 18 -1. + <_> + 12 0 9 18 2. + 0 + -0.2769486904144287 + 0.4851497113704681 + -0.0404825396835804 + <_> + + <_> + + + + <_> + 8 9 3 3 -1. + <_> + 7 10 3 1 3. + 1 + 5.8051547966897488e-003 + -0.0835584178566933 + 0.4215149879455566 + <_> + + <_> + + + + <_> + 28 5 5 6 -1. + <_> + 28 7 5 2 3. + 0 + 2.4654529988765717e-003 + -0.1281685978174210 + 0.2077662944793701 + <_> + + <_> + + + + <_> + 9 1 9 8 -1. + <_> + 9 1 9 4 2. + 1 + 7.8863510861992836e-003 + -0.1719754040241242 + 0.2079081982374191 + <_> + + <_> + + + + <_> + 0 0 36 2 -1. + <_> + 18 0 18 1 2. + <_> + 0 1 18 1 2. + 0 + -0.0118171302601695 + -0.5788066983222961 + 0.0589591413736343 + <_> + + <_> + + + + <_> + 5 0 26 6 -1. + <_> + 5 0 13 3 2. + <_> + 18 3 13 3 2. + 0 + -0.0641399174928665 + -0.6368926167488098 + 0.0417975001037121 + <_> + + <_> + + + + <_> + 28 3 3 3 -1. + <_> + 28 4 3 1 3. + 0 + -1.2179970508441329e-003 + 0.2356870025396347 + -0.0805152580142021 + <_> + + <_> + + + + <_> + 5 3 5 3 -1. + <_> + 5 4 5 1 3. + 0 + 2.8652620967477560e-003 + -0.0931371971964836 + 0.3902595043182373 + <_> + + <_> + + + + <_> + 14 12 8 2 -1. + <_> + 16 12 4 2 2. + 0 + -5.7746102102100849e-003 + -0.5753986835479736 + 0.0596776902675629 + <_> + + <_> + + + + <_> + 13 0 9 14 -1. + <_> + 16 0 3 14 3. + 0 + 0.0653770864009857 + 0.0341660715639591 + -0.7425342202186585 + <_> + + <_> + + + + <_> + 23 0 10 1 -1. + <_> + 23 0 5 1 2. + 1 + 0.0162657108157873 + 0.0536542609333992 + -0.2365860939025879 + <_> + + <_> + + + + <_> + 8 14 2 2 -1. + <_> + 8 14 1 2 2. + 1 + 2.2717609535902739e-003 + 0.0533591099083424 + -0.5494074225425720 + <_> + + <_> + + + + <_> + 0 12 36 3 -1. + <_> + 12 13 12 1 9. + 0 + 0.2262602001428604 + -0.0420460589230061 + 0.7791252136230469 + <_> + + <_> + + + + <_> + 0 13 34 4 -1. + <_> + 0 13 17 2 2. + <_> + 17 15 17 2 2. + 0 + -0.0293774604797363 + -0.5947058796882629 + 0.0548178702592850 + -1.1933319568634033 + 18 + -1 + diff --git a/samples/c/smiledetect.cpp b/samples/c/smiledetect.cpp new file mode 100644 index 0000000000..dd2b03edf4 --- /dev/null +++ b/samples/c/smiledetect.cpp @@ -0,0 +1,282 @@ +#include "opencv2/objdetect/objdetect.hpp" +#include "opencv2/highgui/highgui.hpp" +#include "opencv2/imgproc/imgproc.hpp" + +#include +#include +#include + +using namespace std; +using namespace cv; + +static void help() +{ + cout << "\nThis program demonstrates the smile detector.\n" + "Usage:\n" + "./smiledetect [--cascade= this is the frontal face classifier]\n" + " [--smile-cascade[=smile_cascade_path]]\n" + " [--scale=]\n" + " [--try-flip]\n" + " [filename|camera_index]\n\n" + "Example:\n" + "./smiledetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --smile-cascade=\"../../data/haarcascades/haarcascade_smile.xml\" --scale=1.3\n\n" + "During execution:\n\tHit any key to quit.\n" + "\tUsing OpenCV version " << CV_VERSION << "\n" << endl; +} + +void detectAndDraw( Mat& img, CascadeClassifier& cascade, + CascadeClassifier& nestedCascade, + double scale, bool tryflip ); + +string cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml"; +string nestedCascadeName = "../../data/haarcascades/haarcascade_smile.xml"; + +// The number of detected neighbors depends on image size, these are for performing an approximate mapping to a maximum number of neighbors +const float coef1 = 0.3190; +const float coef2 = -48.7187; + + +int main( int argc, const char** argv ) +{ + CvCapture* capture = 0; + Mat frame, frameCopy, image; + const string scaleOpt = "--scale="; + size_t scaleOptLen = scaleOpt.length(); + const string cascadeOpt = "--cascade="; + size_t cascadeOptLen = cascadeOpt.length(); + const string nestedCascadeOpt = "--smile-cascade"; + size_t nestedCascadeOptLen = nestedCascadeOpt.length(); + const string tryFlipOpt = "--try-flip"; + size_t tryFlipOptLen = tryFlipOpt.length(); + string inputName; + bool tryflip = false; + + help(); + + CascadeClassifier cascade, nestedCascade; + double scale = 1; + + for( int i = 1; i < argc; i++ ) + { + cout << "Processing " << i << " " << argv[i] << endl; + if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 ) + { + cascadeName.assign( argv[i] + cascadeOptLen ); + cout << " from which we have cascadeName= " << cascadeName << endl; + } + else if( nestedCascadeOpt.compare( 0, nestedCascadeOptLen, argv[i], nestedCascadeOptLen ) == 0 ) + { + if( argv[i][nestedCascadeOpt.length()] == '=' ) + nestedCascadeName.assign( argv[i] + nestedCascadeOpt.length() + 1 ); + if( !nestedCascade.load( nestedCascadeName ) ) + cerr << "WARNING: Could not load classifier cascade for nested objects" << endl; + } + else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 ) + { + if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale < 1 ) + scale = 1; + cout << " from which we read scale = " << scale << endl; + } + else if( tryFlipOpt.compare( 0, tryFlipOptLen, argv[i], tryFlipOptLen ) == 0 ) + { + tryflip = true; + cout << " will try to flip image horizontally to detect assymetric objects\n"; + } + else if( argv[i][0] == '-' ) + { + cerr << "WARNING: Unknown option " << argv[i] << endl; + } + else + inputName.assign( argv[i] ); + } + + if( !cascade.load( cascadeName ) ) + { + cerr << "ERROR: Could not load classifier cascade" << endl; + help(); + return -1; + } + + if( inputName.empty() || (isdigit(inputName.c_str()[0]) && inputName.c_str()[1] == '\0') ) + { + capture = cvCaptureFromCAM( inputName.empty() ? 0 : inputName.c_str()[0] - '0' ); + int c = inputName.empty() ? 0 : inputName.c_str()[0] - '0' ; + if(!capture) cout << "Capture from CAM " << c << " didn't work" << endl; + } + else if( inputName.size() ) + { + image = imread( inputName, 1 ); + if( image.empty() ) + { + capture = cvCaptureFromAVI( inputName.c_str() ); + if(!capture) cout << "Capture from AVI didn't work" << endl; + } + } + else + { + image = imread( "lena.jpg", 1 ); + if(image.empty()) cout << "Couldn't read lena.jpg" << endl; + } + + cvNamedWindow( "result", 1 ); + + if( capture ) + { + cout << "In capture ..." << endl; + for(;;) + { + IplImage* iplImg = cvQueryFrame( capture ); + frame = iplImg; + if( frame.empty() ) + break; + if( iplImg->origin == IPL_ORIGIN_TL ) + frame.copyTo( frameCopy ); + else + flip( frame, frameCopy, 0 ); + + detectAndDraw( frameCopy, cascade, nestedCascade, scale, tryflip ); + + if( waitKey( 10 ) >= 0 ) + goto _cleanup_; + } + + waitKey(0); + +_cleanup_: + cvReleaseCapture( &capture ); + } + else + { + cout << "In image read" << endl; + if( !image.empty() ) + { + detectAndDraw( image, cascade, nestedCascade, scale, tryflip ); + waitKey(0); + } + else if( !inputName.empty() ) + { + /* assume it is a text file containing the + list of the image filenames to be processed - one per line */ + FILE* f = fopen( inputName.c_str(), "rt" ); + if( f ) + { + char buf[1000+1]; + while( fgets( buf, 1000, f ) ) + { + int len = (int)strlen(buf), c; + while( len > 0 && isspace(buf[len-1]) ) + len--; + buf[len] = '\0'; + cout << "file " << buf << endl; + image = imread( buf, 1 ); + if( !image.empty() ) + { + detectAndDraw( image, cascade, nestedCascade, scale, tryflip ); + c = waitKey(0); + if( c == 27 || c == 'q' || c == 'Q' ) + break; + } + else + { + cerr << "Aw snap, couldn't read image " << buf << endl; + } + } + fclose(f); + } + } + } + + cvDestroyWindow("result"); + return 0; +} + +void detectAndDraw( Mat& img, CascadeClassifier& cascade, + CascadeClassifier& nestedCascade, + double scale, bool tryflip) +{ + int i = 0; + vector faces, faces2; + const static Scalar colors[] = { CV_RGB(0,0,255), + CV_RGB(0,128,255), + CV_RGB(0,255,255), + CV_RGB(0,255,0), + CV_RGB(255,128,0), + CV_RGB(255,255,0), + CV_RGB(255,0,0), + CV_RGB(255,0,255)} ; + Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 ); + + const int max_neighbors = MAX(0, cvRound((float)coef1*smallImg.cols + coef2)); + + cvtColor( img, gray, CV_BGR2GRAY ); + resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR ); + equalizeHist( smallImg, smallImg ); + + cascade.detectMultiScale( smallImg, faces, + 1.1, 2, 0 + //|CV_HAAR_FIND_BIGGEST_OBJECT + //|CV_HAAR_DO_ROUGH_SEARCH + |CV_HAAR_SCALE_IMAGE + , + Size(30, 30) ); + if( tryflip ) + { + flip(smallImg, smallImg, 1); + cascade.detectMultiScale( smallImg, faces2, + 1.1, 2, 0 + //|CV_HAAR_FIND_BIGGEST_OBJECT + //|CV_HAAR_DO_ROUGH_SEARCH + |CV_HAAR_SCALE_IMAGE + , + Size(30, 30) ); + for( vector::const_iterator r = faces2.begin(); r != faces2.end(); r++ ) + { + faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height)); + } + } + for( vector::iterator r = faces.begin(); r != faces.end(); r++, i++ ) + { + Mat smallImgROI; + vector nestedObjects; + Point center; + Scalar color = colors[i%8]; + int radius; + + double aspect_ratio = (double)r->width/r->height; + if( 0.75 < aspect_ratio && aspect_ratio < 1.3 ) + { + center.x = cvRound((r->x + r->width*0.5)*scale); + center.y = cvRound((r->y + r->height*0.5)*scale); + radius = cvRound((r->width + r->height)*0.25*scale); + circle( img, center, radius, color, 3, 8, 0 ); + } + else + rectangle( img, cvPoint(cvRound(r->x*scale), cvRound(r->y*scale)), + cvPoint(cvRound((r->x + r->width-1)*scale), cvRound((r->y + r->height-1)*scale)), + color, 3, 8, 0); + if( nestedCascade.empty() ) + continue; + + const int half_height=cvRound((float)r->height/2); + r->y=r->y + half_height; + r->height = half_height; + smallImgROI = smallImg(*r); + nestedCascade.detectMultiScale( smallImgROI, nestedObjects, + 1.1, 0, 0 + //|CV_HAAR_FIND_BIGGEST_OBJECT + //|CV_HAAR_DO_ROUGH_SEARCH + //|CV_HAAR_DO_CANNY_PRUNING + |CV_HAAR_SCALE_IMAGE + , + Size(30, 30) ); + + // Draw rectangle reflecting confidence + const int smile_neighbors = nestedObjects.size(); + cout << "Detected " << smile_neighbors << " smile neighbors" << endl; + const int rect_height = cvRound((float)img.rows * smile_neighbors / max_neighbors); + CvScalar col = CV_RGB((float)255 * smile_neighbors / max_neighbors, 0, 0); + rectangle(img, cvPoint(0, img.rows), cvPoint(img.cols/10, img.rows - rect_height), col, -1); + } + + cv::imshow( "result", img ); +} From 8cfba6456bc099e08279b6a880505233b06c6cd5 Mon Sep 17 00:00:00 2001 From: Oscar Deniz Suarez Date: Thu, 21 Feb 2013 22:55:28 +0100 Subject: [PATCH 02/33] Update samples/c/smiledetect.cpp - Changed to floating neighbor maximum mode - Fixed some previous errors. --- samples/c/smiledetect.cpp | 104 +++++++++++++------------------------- 1 file changed, 34 insertions(+), 70 deletions(-) diff --git a/samples/c/smiledetect.cpp b/samples/c/smiledetect.cpp index dd2b03edf4..63254dca8c 100644 --- a/samples/c/smiledetect.cpp +++ b/samples/c/smiledetect.cpp @@ -14,12 +14,12 @@ static void help() cout << "\nThis program demonstrates the smile detector.\n" "Usage:\n" "./smiledetect [--cascade= this is the frontal face classifier]\n" - " [--smile-cascade[=smile_cascade_path]]\n" - " [--scale=]\n" + " [--smile-cascade=[]]\n" + " [--scale=]\n" " [--try-flip]\n" - " [filename|camera_index]\n\n" + " [video_filename|camera_index]\n\n" "Example:\n" - "./smiledetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --smile-cascade=\"../../data/haarcascades/haarcascade_smile.xml\" --scale=1.3\n\n" + "./smiledetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --smile-cascade=\"../../data/haarcascades/haarcascade_smile.xml\" --scale=2.0\n\n" "During execution:\n\tHit any key to quit.\n" "\tUsing OpenCV version " << CV_VERSION << "\n" << endl; } @@ -31,10 +31,6 @@ void detectAndDraw( Mat& img, CascadeClassifier& cascade, string cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml"; string nestedCascadeName = "../../data/haarcascades/haarcascade_smile.xml"; -// The number of detected neighbors depends on image size, these are for performing an approximate mapping to a maximum number of neighbors -const float coef1 = 0.3190; -const float coef2 = -48.7187; - int main( int argc, const char** argv ) { @@ -68,8 +64,6 @@ int main( int argc, const char** argv ) { if( argv[i][nestedCascadeOpt.length()] == '=' ) nestedCascadeName.assign( argv[i] + nestedCascadeOpt.length() + 1 ); - if( !nestedCascade.load( nestedCascadeName ) ) - cerr << "WARNING: Could not load classifier cascade for nested objects" << endl; } else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 ) { @@ -92,7 +86,13 @@ int main( int argc, const char** argv ) if( !cascade.load( cascadeName ) ) { - cerr << "ERROR: Could not load classifier cascade" << endl; + cerr << "ERROR: Could not load face cascade" << endl; + help(); + return -1; + } + if( !nestedCascade.load( nestedCascadeName ) ) + { + cerr << "ERROR: Could not load smile cascade" << endl; help(); return -1; } @@ -105,17 +105,8 @@ int main( int argc, const char** argv ) } else if( inputName.size() ) { - image = imread( inputName, 1 ); - if( image.empty() ) - { - capture = cvCaptureFromAVI( inputName.c_str() ); - if(!capture) cout << "Capture from AVI didn't work" << endl; - } - } - else - { - image = imread( "lena.jpg", 1 ); - if(image.empty()) cout << "Couldn't read lena.jpg" << endl; + capture = cvCaptureFromAVI( inputName.c_str() ); + if(!capture) cout << "Capture from AVI didn't work" << endl; } cvNamedWindow( "result", 1 ); @@ -123,6 +114,8 @@ int main( int argc, const char** argv ) if( capture ) { cout << "In capture ..." << endl; + cout << endl << "NOTE: Smile intensity will only be valid after a first smile has been detected" << endl; + for(;;) { IplImage* iplImg = cvQueryFrame( capture ); @@ -147,43 +140,9 @@ _cleanup_: } else { - cout << "In image read" << endl; - if( !image.empty() ) - { - detectAndDraw( image, cascade, nestedCascade, scale, tryflip ); - waitKey(0); - } - else if( !inputName.empty() ) - { - /* assume it is a text file containing the - list of the image filenames to be processed - one per line */ - FILE* f = fopen( inputName.c_str(), "rt" ); - if( f ) - { - char buf[1000+1]; - while( fgets( buf, 1000, f ) ) - { - int len = (int)strlen(buf), c; - while( len > 0 && isspace(buf[len-1]) ) - len--; - buf[len] = '\0'; - cout << "file " << buf << endl; - image = imread( buf, 1 ); - if( !image.empty() ) - { - detectAndDraw( image, cascade, nestedCascade, scale, tryflip ); - c = waitKey(0); - if( c == 27 || c == 'q' || c == 'Q' ) - break; - } - else - { - cerr << "Aw snap, couldn't read image " << buf << endl; - } - } - fclose(f); - } - } + cerr << "ERROR: Could not initiate capture" << endl; + help(); + return -1; } cvDestroyWindow("result"); @@ -206,8 +165,6 @@ void detectAndDraw( Mat& img, CascadeClassifier& cascade, CV_RGB(255,0,255)} ; Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 ); - const int max_neighbors = MAX(0, cvRound((float)coef1*smallImg.cols + coef2)); - cvtColor( img, gray, CV_BGR2GRAY ); resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR ); equalizeHist( smallImg, smallImg ); @@ -234,6 +191,7 @@ void detectAndDraw( Mat& img, CascadeClassifier& cascade, faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height)); } } + for( vector::iterator r = faces.begin(); r != faces.end(); r++, i++ ) { Mat smallImgROI; @@ -254,8 +212,6 @@ void detectAndDraw( Mat& img, CascadeClassifier& cascade, rectangle( img, cvPoint(cvRound(r->x*scale), cvRound(r->y*scale)), cvPoint(cvRound((r->x + r->width-1)*scale), cvRound((r->y + r->height-1)*scale)), color, 3, 8, 0); - if( nestedCascade.empty() ) - continue; const int half_height=cvRound((float)r->height/2); r->y=r->y + half_height; @@ -270,13 +226,21 @@ void detectAndDraw( Mat& img, CascadeClassifier& cascade, , Size(30, 30) ); - // Draw rectangle reflecting confidence + // The number of detected neighbors depends on image size (and also illumination, etc.). The + // following steps use a floating minimum and maximum of neighbors. Intensity thus estimated will be + //accurate only after a first smile has been displayed by the user. const int smile_neighbors = nestedObjects.size(); - cout << "Detected " << smile_neighbors << " smile neighbors" << endl; - const int rect_height = cvRound((float)img.rows * smile_neighbors / max_neighbors); - CvScalar col = CV_RGB((float)255 * smile_neighbors / max_neighbors, 0, 0); - rectangle(img, cvPoint(0, img.rows), cvPoint(img.cols/10, img.rows - rect_height), col, -1); - } + static int max_neighbors=-1; + static int min_neighbors=-1; + if (min_neighbors == -1) min_neighbors = smile_neighbors; + max_neighbors = MAX(max_neighbors, smile_neighbors); - cv::imshow( "result", img ); + // Draw rectangle on the left side of the image reflecting smile intensity + float intensityZeroOne = ((float)smile_neighbors - min_neighbors) / (max_neighbors - min_neighbors + 1); + int rect_height = cvRound((float)img.rows * intensityZeroOne); + CvScalar col = CV_RGB((float)255 * intensityZeroOne, 0, 0); + rectangle(img, cvPoint(0, img.rows), cvPoint(img.cols/10, img.rows - rect_height), col, -1); + } + + cv::imshow( "result", img ); } From 07ea88b8c6177d34b5d2fe2fe694501fd32735e1 Mon Sep 17 00:00:00 2001 From: Oscar Deniz Suarez Date: Fri, 22 Feb 2013 16:23:42 +0100 Subject: [PATCH 03/33] Update samples/c/smiledetect.cpp Fixed isdigit() Android build error --- samples/c/smiledetect.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/c/smiledetect.cpp b/samples/c/smiledetect.cpp index 63254dca8c..ff032e4791 100644 --- a/samples/c/smiledetect.cpp +++ b/samples/c/smiledetect.cpp @@ -2,6 +2,7 @@ #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" +#include #include #include #include From a138e12a26df8e6335b50e85844e4e8e0e717e1a Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 26 Feb 2013 13:49:35 +0400 Subject: [PATCH 04/33] refactored gpu perf tests and fixed sanity tests --- modules/gpu/perf/perf_calib3d.cpp | 219 ++-- modules/gpu/perf/perf_core.cpp | 1330 +++++++++++---------- modules/gpu/perf/perf_denoising.cpp | 172 ++- modules/gpu/perf/perf_features2d.cpp | 328 +++--- modules/gpu/perf/perf_filters.cpp | 263 ++--- modules/gpu/perf/perf_imgproc.cpp | 1591 +++++++++++--------------- modules/gpu/perf/perf_labeling.cpp | 57 +- modules/gpu/perf/perf_main.cpp | 6 +- modules/gpu/perf/perf_matop.cpp | 159 ++- modules/gpu/perf/perf_objdetect.cpp | 147 +-- modules/gpu/perf/perf_video.cpp | 766 ++++++------- modules/gpu/perf/utility.cpp | 9 +- modules/gpu/perf/utility.hpp | 49 +- modules/gpu/src/graphcuts.cpp | 8 +- modules/gpu/src/imgproc.cpp | 1 + modules/gpu/src/mssegmentation.cpp | 1 + modules/gpu/src/pyrlk.cpp | 2 + modules/gpu/src/warp.cpp | 12 +- 18 files changed, 2366 insertions(+), 2754 deletions(-) diff --git a/modules/gpu/perf/perf_calib3d.cpp b/modules/gpu/perf/perf_calib3d.cpp index 906024f640..b174d9a12e 100644 --- a/modules/gpu/perf/perf_calib3d.cpp +++ b/modules/gpu/perf/perf_calib3d.cpp @@ -3,15 +3,14 @@ using namespace std; using namespace testing; -namespace { - ////////////////////////////////////////////////////////////////////// // StereoBM typedef std::tr1::tuple pair_string; DEF_PARAM_TEST_1(ImagePair, pair_string); -PERF_TEST_P(ImagePair, Calib3D_StereoBM, Values(pair_string("gpu/perf/aloe.png", "gpu/perf/aloeR.png"))) +PERF_TEST_P(ImagePair, Calib3D_StereoBM, + Values(pair_string("gpu/perf/aloe.png", "gpu/perf/aloeR.png"))) { declare.time(5.0); @@ -28,18 +27,13 @@ PERF_TEST_P(ImagePair, Calib3D_StereoBM, Values(pair_string("gpu/perf/aloe.png", { cv::gpu::StereoBM_GPU d_bm(preset, ndisp); - cv::gpu::GpuMat d_imgLeft(imgLeft); - cv::gpu::GpuMat d_imgRight(imgRight); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_imgLeft(imgLeft); + const cv::gpu::GpuMat d_imgRight(imgRight); + cv::gpu::GpuMat dst; - d_bm(d_imgLeft, d_imgRight, d_dst); + TEST_CYCLE() d_bm(d_imgLeft, d_imgRight, dst); - TEST_CYCLE() - { - d_bm(d_imgLeft, d_imgRight, d_dst); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { @@ -47,12 +41,7 @@ PERF_TEST_P(ImagePair, Calib3D_StereoBM, Values(pair_string("gpu/perf/aloe.png", cv::Mat dst; - bm(imgLeft, imgRight, dst); - - TEST_CYCLE() - { - bm(imgLeft, imgRight, dst); - } + TEST_CYCLE() bm(imgLeft, imgRight, dst); CPU_SANITY_CHECK(dst); } @@ -61,7 +50,8 @@ PERF_TEST_P(ImagePair, Calib3D_StereoBM, Values(pair_string("gpu/perf/aloe.png", ////////////////////////////////////////////////////////////////////// // StereoBeliefPropagation -PERF_TEST_P(ImagePair, Calib3D_StereoBeliefPropagation, Values(pair_string("gpu/stereobp/aloe-L.png", "gpu/stereobp/aloe-R.png"))) +PERF_TEST_P(ImagePair, Calib3D_StereoBeliefPropagation, + Values(pair_string("gpu/stereobp/aloe-L.png", "gpu/stereobp/aloe-R.png"))) { declare.time(10.0); @@ -77,29 +67,25 @@ PERF_TEST_P(ImagePair, Calib3D_StereoBeliefPropagation, Values(pair_string("gpu/ { cv::gpu::StereoBeliefPropagation d_bp(ndisp); - cv::gpu::GpuMat d_imgLeft(imgLeft); - cv::gpu::GpuMat d_imgRight(imgRight); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_imgLeft(imgLeft); + const cv::gpu::GpuMat d_imgRight(imgRight); + cv::gpu::GpuMat dst; - d_bp(d_imgLeft, d_imgRight, d_dst); + TEST_CYCLE() d_bp(d_imgLeft, d_imgRight, dst); - TEST_CYCLE() - { - d_bp(d_imgLeft, d_imgRight, d_dst); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy."; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // StereoConstantSpaceBP -PERF_TEST_P(ImagePair, Calib3D_StereoConstantSpaceBP, Values(pair_string("gpu/stereobm/aloe-L.png", "gpu/stereobm/aloe-R.png"))) +PERF_TEST_P(ImagePair, Calib3D_StereoConstantSpaceBP, + Values(pair_string("gpu/stereobm/aloe-L.png", "gpu/stereobm/aloe-R.png"))) { declare.time(10.0); @@ -115,29 +101,25 @@ PERF_TEST_P(ImagePair, Calib3D_StereoConstantSpaceBP, Values(pair_string("gpu/st { cv::gpu::StereoConstantSpaceBP d_csbp(ndisp); - cv::gpu::GpuMat d_imgLeft(imgLeft); - cv::gpu::GpuMat d_imgRight(imgRight); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_imgLeft(imgLeft); + const cv::gpu::GpuMat d_imgRight(imgRight); + cv::gpu::GpuMat dst; - d_csbp(d_imgLeft, d_imgRight, d_dst); + TEST_CYCLE() d_csbp(d_imgLeft, d_imgRight, dst); - TEST_CYCLE() - { - d_csbp(d_imgLeft, d_imgRight, d_dst); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy."; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // DisparityBilateralFilter -PERF_TEST_P(ImagePair, Calib3D_DisparityBilateralFilter, Values(pair_string("gpu/stereobm/aloe-L.png", "gpu/stereobm/aloe-disp.png"))) +PERF_TEST_P(ImagePair, Calib3D_DisparityBilateralFilter, + Values(pair_string("gpu/stereobm/aloe-L.png", "gpu/stereobm/aloe-disp.png"))) { const cv::Mat img = readImage(GET_PARAM(0), cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); @@ -151,22 +133,17 @@ PERF_TEST_P(ImagePair, Calib3D_DisparityBilateralFilter, Values(pair_string("gpu { cv::gpu::DisparityBilateralFilter d_filter(ndisp); - cv::gpu::GpuMat d_img(img); - cv::gpu::GpuMat d_disp(disp); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_img(img); + const cv::gpu::GpuMat d_disp(disp); + cv::gpu::GpuMat dst; - d_filter(d_disp, d_img, d_dst); + TEST_CYCLE() d_filter(d_disp, d_img, dst); - TEST_CYCLE() - { - d_filter(d_disp, d_img, d_dst); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy."; + FAIL_NO_CPU(); } } @@ -175,45 +152,42 @@ PERF_TEST_P(ImagePair, Calib3D_DisparityBilateralFilter, Values(pair_string("gpu DEF_PARAM_TEST_1(Count, int); -PERF_TEST_P(Count, Calib3D_TransformPoints, Values(5000, 10000, 20000)) +PERF_TEST_P(Count, Calib3D_TransformPoints, + Values(5000, 10000, 20000)) { const int count = GetParam(); cv::Mat src(1, count, CV_32FC3); - fillRandom(src, -100, 100); + declare.in(src, WARMUP_RNG); const cv::Mat rvec = cv::Mat::ones(1, 3, CV_32FC1); const cv::Mat tvec = cv::Mat::ones(1, 3, CV_32FC1); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::transformPoints(d_src, rvec, tvec, d_dst); + TEST_CYCLE() cv::gpu::transformPoints(d_src, rvec, tvec, dst); - TEST_CYCLE() - { - cv::gpu::transformPoints(d_src, rvec, tvec, d_dst); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy."; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // ProjectPoints -PERF_TEST_P(Count, Calib3D_ProjectPoints, Values(5000, 10000, 20000)) +PERF_TEST_P(Count, Calib3D_ProjectPoints, + Values(5000, 10000, 20000)) { const int count = GetParam(); cv::Mat src(1, count, CV_32FC3); - fillRandom(src, -100, 100); + declare.in(src, WARMUP_RNG); const cv::Mat rvec = cv::Mat::ones(1, 3, CV_32FC1); const cv::Mat tvec = cv::Mat::ones(1, 3, CV_32FC1); @@ -221,28 +195,18 @@ PERF_TEST_P(Count, Calib3D_ProjectPoints, Values(5000, 10000, 20000)) if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::projectPoints(d_src, rvec, tvec, camera_mat, cv::Mat(), d_dst); + TEST_CYCLE() cv::gpu::projectPoints(d_src, rvec, tvec, camera_mat, cv::Mat(), dst); - TEST_CYCLE() - { - cv::gpu::projectPoints(d_src, rvec, tvec, camera_mat, cv::Mat(), d_dst); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::projectPoints(src, rvec, tvec, camera_mat, cv::noArray(), dst); - - TEST_CYCLE() - { - cv::projectPoints(src, rvec, tvec, camera_mat, cv::noArray(), dst); - } + TEST_CYCLE() cv::projectPoints(src, rvec, tvec, camera_mat, cv::noArray(), dst); CPU_SANITY_CHECK(dst); } @@ -251,17 +215,18 @@ PERF_TEST_P(Count, Calib3D_ProjectPoints, Values(5000, 10000, 20000)) ////////////////////////////////////////////////////////////////////// // SolvePnPRansac -PERF_TEST_P(Count, Calib3D_SolvePnPRansac, Values(5000, 10000, 20000)) +PERF_TEST_P(Count, Calib3D_SolvePnPRansac, + Values(5000, 10000, 20000)) { declare.time(10.0); const int count = GetParam(); cv::Mat object(1, count, CV_32FC3); - fillRandom(object, -100, 100); + declare.in(object, WARMUP_RNG); cv::Mat camera_mat(3, 3, CV_32FC1); - fillRandom(camera_mat, 0.5, 1); + cv::randu(camera_mat, 0.5, 1); camera_mat.at(0, 1) = 0.f; camera_mat.at(1, 0) = 0.f; camera_mat.at(2, 0) = 0.f; @@ -269,79 +234,66 @@ PERF_TEST_P(Count, Calib3D_SolvePnPRansac, Values(5000, 10000, 20000)) const cv::Mat dist_coef(1, 8, CV_32F, cv::Scalar::all(0)); - std::vector image_vec; cv::Mat rvec_gold(1, 3, CV_32FC1); - fillRandom(rvec_gold, 0, 1); + cv::randu(rvec_gold, 0, 1); + cv::Mat tvec_gold(1, 3, CV_32FC1); - fillRandom(tvec_gold, 0, 1); + cv::randu(tvec_gold, 0, 1); + + std::vector image_vec; cv::projectPoints(object, rvec_gold, tvec_gold, camera_mat, dist_coef, image_vec); - cv::Mat image(1, count, CV_32FC2, &image_vec[0]); + const cv::Mat image(1, count, CV_32FC2, &image_vec[0]); cv::Mat rvec; cv::Mat tvec; if (PERF_RUN_GPU()) { - cv::gpu::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); + TEST_CYCLE() cv::gpu::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); - TEST_CYCLE() - { - cv::gpu::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); - } + GPU_SANITY_CHECK(rvec, 1e-3); + GPU_SANITY_CHECK(tvec, 1e-3); } else { - cv::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); + TEST_CYCLE() cv::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); - TEST_CYCLE() - { - cv::solvePnPRansac(object, image, camera_mat, dist_coef, rvec, tvec); - } + CPU_SANITY_CHECK(rvec, 1e-6); + CPU_SANITY_CHECK(tvec, 1e-6); } - - CPU_SANITY_CHECK(rvec); - CPU_SANITY_CHECK(tvec); } ////////////////////////////////////////////////////////////////////// // ReprojectImageTo3D -PERF_TEST_P(Sz_Depth, Calib3D_ReprojectImageTo3D, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S))) +PERF_TEST_P(Sz_Depth, Calib3D_ReprojectImageTo3D, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16S))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src, 5.0, 30.0); + declare.in(src, WARMUP_RNG); cv::Mat Q(4, 4, CV_32FC1); - fillRandom(Q, 0.1, 1.0); + cv::randu(Q, 0.1, 1.0); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::reprojectImageTo3D(d_src, d_dst, Q); + TEST_CYCLE() cv::gpu::reprojectImageTo3D(d_src, dst, Q); - TEST_CYCLE() - { - cv::gpu::reprojectImageTo3D(d_src, d_dst, Q); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::reprojectImageTo3D(src, dst, Q); - - TEST_CYCLE() - { - cv::reprojectImageTo3D(src, dst, Q); - } + TEST_CYCLE() cv::reprojectImageTo3D(src, dst, Q); CPU_SANITY_CHECK(dst); } @@ -350,32 +302,27 @@ PERF_TEST_P(Sz_Depth, Calib3D_ReprojectImageTo3D, Combine(GPU_TYPICAL_MAT_SIZES, ////////////////////////////////////////////////////////////////////// // DrawColorDisp -PERF_TEST_P(Sz_Depth, Calib3D_DrawColorDisp, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S))) +PERF_TEST_P(Sz_Depth, Calib3D_DrawColorDisp, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16S))) { const cv::Size size = GET_PARAM(0); const int type = GET_PARAM(1); cv::Mat src(size, type); - fillRandom(src, 0, 255); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::drawColorDisp(d_src, d_dst, 255); + TEST_CYCLE() cv::gpu::drawColorDisp(d_src, dst, 255); - TEST_CYCLE() - { - cv::gpu::drawColorDisp(d_src, d_dst, 255); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy."; + FAIL_NO_CPU(); } } - -} // namespace diff --git a/modules/gpu/perf/perf_core.cpp b/modules/gpu/perf/perf_core.cpp index b97c4999cd..d0529e80a4 100644 --- a/modules/gpu/perf/perf_core.cpp +++ b/modules/gpu/perf/perf_core.cpp @@ -2,15 +2,17 @@ using namespace std; using namespace testing; - -namespace { +using namespace perf; #define ARITHM_MAT_DEPTH Values(CV_8U, CV_16U, CV_32F, CV_64F) ////////////////////////////////////////////////////////////////////// // Merge -PERF_TEST_P(Sz_Depth_Cn, Core_Merge, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH, Values(2, 3, 4))) +PERF_TEST_P(Sz_Depth_Cn, Core_Merge, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH, + Values(2, 3, 4))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); @@ -18,7 +20,10 @@ PERF_TEST_P(Sz_Depth_Cn, Core_Merge, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_D std::vector src(channels); for (int i = 0; i < channels; ++i) - src[i] = cv::Mat(size, depth, cv::Scalar::all(i)); + { + src[i].create(size, depth); + declare.in(src[i], WARMUP_RNG); + } if (PERF_RUN_GPU()) { @@ -26,11 +31,11 @@ PERF_TEST_P(Sz_Depth_Cn, Core_Merge, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_D for (int i = 0; i < channels; ++i) d_src[i].upload(src[i]); - cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::merge(d_src, d_dst); + TEST_CYCLE() cv::gpu::merge(d_src, dst); - GPU_SANITY_CHECK(d_dst, 1e-12); + GPU_SANITY_CHECK(dst); } else { @@ -38,31 +43,37 @@ PERF_TEST_P(Sz_Depth_Cn, Core_Merge, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_D TEST_CYCLE() cv::merge(src, dst); - CPU_SANITY_CHECK(dst, 1e-12); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // Split -PERF_TEST_P(Sz_Depth_Cn, Core_Split, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH, Values(2, 3, 4))) +PERF_TEST_P(Sz_Depth_Cn, Core_Split, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH, + Values(2, 3, 4))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); const int channels = GET_PARAM(2); - cv::Mat src(size, CV_MAKE_TYPE(depth, channels), cv::Scalar(1, 2, 3, 4)); + cv::Mat src(size, CV_MAKE_TYPE(depth, channels)); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_src(src); + std::vector dst; - std::vector d_dst; + TEST_CYCLE() cv::gpu::split(d_src, dst); - TEST_CYCLE() cv::gpu::split(d_src, d_dst); + const cv::gpu::GpuMat& dst0 = dst[0]; + const cv::gpu::GpuMat& dst1 = dst[1]; - cv::gpu::GpuMat first = d_dst[0]; - GPU_SANITY_CHECK(first, 1e-12); + GPU_SANITY_CHECK(dst0); + GPU_SANITY_CHECK(dst1); } else { @@ -70,33 +81,39 @@ PERF_TEST_P(Sz_Depth_Cn, Core_Split, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_D TEST_CYCLE() cv::split(src, dst); - CPU_SANITY_CHECK(dst, 1e-12); + const cv::Mat& dst0 = dst[0]; + const cv::Mat& dst1 = dst[1]; + + CPU_SANITY_CHECK(dst0); + CPU_SANITY_CHECK(dst1); } } ////////////////////////////////////////////////////////////////////// // AddMat -PERF_TEST_P(Sz_Depth, Core_AddMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) +PERF_TEST_P(Sz_Depth, Core_AddMat, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src1(size, depth); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, depth); - fillRandom(src2); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::add(d_src1, d_src2, d_dst); + TEST_CYCLE() cv::gpu::add(d_src1, d_src2, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -104,31 +121,34 @@ PERF_TEST_P(Sz_Depth, Core_AddMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEP TEST_CYCLE() cv::add(src1, src2, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // AddScalar -PERF_TEST_P(Sz_Depth, Core_AddScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) +PERF_TEST_P(Sz_Depth, Core_AddScalar, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Scalar s(1, 2, 3, 4); + cv::Scalar s; + declare.in(s, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::add(d_src, s, d_dst); + TEST_CYCLE() cv::gpu::add(d_src, s, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -136,33 +156,35 @@ PERF_TEST_P(Sz_Depth, Core_AddScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_ TEST_CYCLE() cv::add(src, s, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // SubtractMat -PERF_TEST_P(Sz_Depth, Core_SubtractMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) +PERF_TEST_P(Sz_Depth, Core_SubtractMat, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src1(size, depth); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, depth); - fillRandom(src2); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::subtract(d_src1, d_src2, d_dst); + TEST_CYCLE() cv::gpu::subtract(d_src1, d_src2, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -170,31 +192,34 @@ PERF_TEST_P(Sz_Depth, Core_SubtractMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MA TEST_CYCLE() cv::subtract(src1, src2, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // SubtractScalar -PERF_TEST_P(Sz_Depth, Core_SubtractScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) +PERF_TEST_P(Sz_Depth, Core_SubtractScalar, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Scalar s(1, 2, 3, 4); + cv::Scalar s; + declare.in(s, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::subtract(d_src, s, d_dst); + TEST_CYCLE() cv::gpu::subtract(d_src, s, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -202,33 +227,35 @@ PERF_TEST_P(Sz_Depth, Core_SubtractScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM TEST_CYCLE() cv::subtract(src, s, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // MultiplyMat -PERF_TEST_P(Sz_Depth, Core_MultiplyMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) +PERF_TEST_P(Sz_Depth, Core_MultiplyMat, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src1(size, depth); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, depth); - fillRandom(src2); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::multiply(d_src1, d_src2, d_dst); + TEST_CYCLE() cv::gpu::multiply(d_src1, d_src2, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -236,33 +263,34 @@ PERF_TEST_P(Sz_Depth, Core_MultiplyMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MA TEST_CYCLE() cv::multiply(src1, src2, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // MultiplyScalar -PERF_TEST_P(Sz_Depth, Core_MultiplyScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) +PERF_TEST_P(Sz_Depth, Core_MultiplyScalar, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Scalar s(1, 2, 3, 4); + cv::Scalar s; + declare.in(s, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::multiply(d_src, s, d_dst); + TEST_CYCLE() cv::gpu::multiply(d_src, s, dst); - TEST_CYCLE() cv::gpu::multiply(d_src, s, d_dst); - - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -270,33 +298,35 @@ PERF_TEST_P(Sz_Depth, Core_MultiplyScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM TEST_CYCLE() cv::multiply(src, s, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // DivideMat -PERF_TEST_P(Sz_Depth, Core_DivideMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) +PERF_TEST_P(Sz_Depth, Core_DivideMat, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src1(size, depth); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, depth); - fillRandom(src2); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::divide(d_src1, d_src2, d_dst); + TEST_CYCLE() cv::gpu::divide(d_src1, d_src2, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -304,31 +334,34 @@ PERF_TEST_P(Sz_Depth, Core_DivideMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_ TEST_CYCLE() cv::divide(src1, src2, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // DivideScalar -PERF_TEST_P(Sz_Depth, Core_DivideScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) +PERF_TEST_P(Sz_Depth, Core_DivideScalar, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Scalar s(1, 2, 3, 4); + cv::Scalar s; + declare.in(s, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::divide(d_src, s, d_dst); + TEST_CYCLE() cv::gpu::divide(d_src, s, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -336,31 +369,34 @@ PERF_TEST_P(Sz_Depth, Core_DivideScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_M TEST_CYCLE() cv::divide(src, s, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // DivideScalarInv -PERF_TEST_P(Sz_Depth, Core_DivideScalarInv, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) +PERF_TEST_P(Sz_Depth, Core_DivideScalarInv, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); - double s = 100.0; + cv::Scalar s; + declare.in(s, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::divide(s, d_src, d_dst); + TEST_CYCLE() cv::gpu::divide(s[0], d_src, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -368,33 +404,35 @@ PERF_TEST_P(Sz_Depth, Core_DivideScalarInv, Combine(GPU_TYPICAL_MAT_SIZES, ARITH TEST_CYCLE() cv::divide(s, src, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // AbsDiffMat -PERF_TEST_P(Sz_Depth, Core_AbsDiffMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) +PERF_TEST_P(Sz_Depth, Core_AbsDiffMat, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src1(size, depth); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, depth); - fillRandom(src2); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::absdiff(d_src1, d_src2, d_dst); + TEST_CYCLE() cv::gpu::absdiff(d_src1, d_src2, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -402,31 +440,34 @@ PERF_TEST_P(Sz_Depth, Core_AbsDiffMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT TEST_CYCLE() cv::absdiff(src1, src2, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // AbsDiffScalar -PERF_TEST_P(Sz_Depth, Core_AbsDiffScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH)) +PERF_TEST_P(Sz_Depth, Core_AbsDiffScalar, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Scalar s(1, 2, 3, 4); + cv::Scalar s; + declare.in(s, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::absdiff(d_src, s, d_dst); + TEST_CYCLE() cv::gpu::absdiff(d_src, s, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -434,75 +475,87 @@ PERF_TEST_P(Sz_Depth, Core_AbsDiffScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_ TEST_CYCLE() cv::absdiff(src, s, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // Abs -PERF_TEST_P(Sz_Depth, Core_Abs, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_16S, CV_32F))) +PERF_TEST_P(Sz_Depth, Core_Abs, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_16S, CV_32F))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::abs(d_src, d_dst); + TEST_CYCLE() cv::gpu::abs(d_src, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); + } + else + { + FAIL_NO_CPU(); } - else FAIL_NO_CPU(); } ////////////////////////////////////////////////////////////////////// // Sqr -PERF_TEST_P(Sz_Depth, Core_Sqr, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F))) +PERF_TEST_P(Sz_Depth, Core_Sqr, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16S, CV_32F))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::sqr(d_src, d_dst); + TEST_CYCLE() cv::gpu::sqr(d_src, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); + } + else + { + FAIL_NO_CPU(); } - else FAIL_NO_CPU(); } ////////////////////////////////////////////////////////////////////// // Sqrt -PERF_TEST_P(Sz_Depth, Core_Sqrt, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F))) +PERF_TEST_P(Sz_Depth, Core_Sqrt, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16S, CV_32F))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); + cv::randu(src, 0, 100000); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::sqrt(d_src, d_dst); + TEST_CYCLE() cv::gpu::sqrt(d_src, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -510,29 +563,31 @@ PERF_TEST_P(Sz_Depth, Core_Sqrt, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV TEST_CYCLE() cv::sqrt(src, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // Log -PERF_TEST_P(Sz_Depth, Core_Log, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F))) +PERF_TEST_P(Sz_Depth, Core_Log, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16S, CV_32F))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src, 1.0, 255.0); + cv::randu(src, 0, 100000); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::log(d_src, d_dst); + TEST_CYCLE() cv::gpu::log(d_src, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -540,37 +595,39 @@ PERF_TEST_P(Sz_Depth, Core_Log, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_ TEST_CYCLE() cv::log(src, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // Exp -PERF_TEST_P(Sz_Depth, Core_Exp, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F))) +PERF_TEST_P(Sz_Depth, Core_Exp, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16S, CV_32F))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src, 1.0, 10.0); + cv::randu(src, 0, 10); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::exp(d_src, d_dst); + TEST_CYCLE() cv::gpu::exp(d_src, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() TEST_CYCLE() cv::exp(src, dst); + TEST_CYCLE() cv::exp(src, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } @@ -579,31 +636,34 @@ PERF_TEST_P(Sz_Depth, Core_Exp, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_ DEF_PARAM_TEST(Sz_Depth_Power, cv::Size, MatDepth, double); -PERF_TEST_P(Sz_Depth_Power, Core_Pow, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16S, CV_32F), Values(0.3, 2.0, 2.4))) +PERF_TEST_P(Sz_Depth_Power, Core_Pow, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16S, CV_32F), + Values(0.3, 2.0, 2.4))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); const double power = GET_PARAM(2); cv::Mat src(size, depth); - fillRandom(src, 1.0, 10.0); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::pow(d_src, power, d_dst); + TEST_CYCLE() cv::gpu::pow(d_src, power, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() cv::pow(src, power,dst); + TEST_CYCLE() cv::pow(src, power, dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } @@ -615,27 +675,30 @@ CV_ENUM(CmpCode, cv::CMP_EQ, cv::CMP_GT, cv::CMP_GE, cv::CMP_LT, cv::CMP_LE, cv: DEF_PARAM_TEST(Sz_Depth_Code, cv::Size, MatDepth, CmpCode); -PERF_TEST_P(Sz_Depth_Code, Core_CompareMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH, ALL_CMP_CODES)) +PERF_TEST_P(Sz_Depth_Code, Core_CompareMat, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH, + ALL_CMP_CODES)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); const int cmp_code = GET_PARAM(2); cv::Mat src1(size, depth); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, depth); - fillRandom(src2); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::compare(d_src1, d_src2, d_dst, cmp_code); + TEST_CYCLE() cv::gpu::compare(d_src1, d_src2, dst, cmp_code); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { @@ -650,25 +713,29 @@ PERF_TEST_P(Sz_Depth_Code, Core_CompareMat, Combine(GPU_TYPICAL_MAT_SIZES, ARITH ////////////////////////////////////////////////////////////////////// // CompareScalar -PERF_TEST_P(Sz_Depth_Code, Core_CompareScalar, Combine(GPU_TYPICAL_MAT_SIZES, ARITHM_MAT_DEPTH, ALL_CMP_CODES)) +PERF_TEST_P(Sz_Depth_Code, Core_CompareScalar, + Combine(GPU_TYPICAL_MAT_SIZES, + ARITHM_MAT_DEPTH, + ALL_CMP_CODES)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); const int cmp_code = GET_PARAM(2); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Scalar s = cv::Scalar::all(100); + cv::Scalar s; + declare.in(s, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::compare(d_src, s, d_dst, cmp_code); + TEST_CYCLE() cv::gpu::compare(d_src, s, dst, cmp_code); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { @@ -683,28 +750,30 @@ PERF_TEST_P(Sz_Depth_Code, Core_CompareScalar, Combine(GPU_TYPICAL_MAT_SIZES, AR ////////////////////////////////////////////////////////////////////// // BitwiseNot -PERF_TEST_P(Sz_Depth, Core_BitwiseNot, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S))) +PERF_TEST_P(Sz_Depth, Core_BitwiseNot, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32S))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::bitwise_not(d_src,d_dst); + TEST_CYCLE() cv::gpu::bitwise_not(d_src, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() cv::bitwise_not(src,dst); + TEST_CYCLE() cv::bitwise_not(src, dst); CPU_SANITY_CHECK(dst); } @@ -713,39 +782,46 @@ PERF_TEST_P(Sz_Depth, Core_BitwiseNot, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_ ////////////////////////////////////////////////////////////////////// // BitwiseAndMat -PERF_TEST_P(Sz_Depth, Core_BitwiseAndMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S))) +PERF_TEST_P(Sz_Depth, Core_BitwiseAndMat, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32S))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src1(size, depth); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, depth); - fillRandom(src2); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::bitwise_and(d_src1, d_src2,d_dst); + TEST_CYCLE() cv::gpu::bitwise_and(d_src1, d_src2, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() cv::bitwise_and(src1, src2,dst); + TEST_CYCLE() cv::bitwise_and(src1, src2, dst); + + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // BitwiseAndScalar -PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseAndScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseAndScalar, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32S), + GPU_CHANNELS_1_3_4)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); @@ -754,24 +830,26 @@ PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseAndScalar, Combine(GPU_TYPICAL_MAT_SIZES, V const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Scalar s = cv::Scalar::all(100); + cv::Scalar s; + declare.in(s, WARMUP_RNG); + cv::Scalar_ is = s; if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::bitwise_and(d_src, s,d_dst); + TEST_CYCLE() cv::gpu::bitwise_and(d_src, is, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() cv::bitwise_and(src, s,dst); + TEST_CYCLE() cv::bitwise_and(src, is, dst); CPU_SANITY_CHECK(dst); } @@ -780,32 +858,34 @@ PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseAndScalar, Combine(GPU_TYPICAL_MAT_SIZES, V ////////////////////////////////////////////////////////////////////// // BitwiseOrMat -PERF_TEST_P(Sz_Depth, Core_BitwiseOrMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S))) +PERF_TEST_P(Sz_Depth, Core_BitwiseOrMat, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32S))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src1(size, depth); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, depth); - fillRandom(src2); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::bitwise_or(d_src1, d_src2,d_dst); + TEST_CYCLE() cv::gpu::bitwise_or(d_src1, d_src2, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() cv::bitwise_or(src1, src2,dst); + TEST_CYCLE() cv::bitwise_or(src1, src2, dst); CPU_SANITY_CHECK(dst); } @@ -814,7 +894,10 @@ PERF_TEST_P(Sz_Depth, Core_BitwiseOrMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(C ////////////////////////////////////////////////////////////////////// // BitwiseOrScalar -PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseOrScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseOrScalar, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32S), + GPU_CHANNELS_1_3_4)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); @@ -823,24 +906,26 @@ PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseOrScalar, Combine(GPU_TYPICAL_MAT_SIZES, Va const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Scalar s = cv::Scalar::all(100); + cv::Scalar s; + declare.in(s, WARMUP_RNG); + cv::Scalar_ is = s; if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::bitwise_or(d_src, s,d_dst); + TEST_CYCLE() cv::gpu::bitwise_or(d_src, is, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() cv::bitwise_or(src, s,dst); + TEST_CYCLE() cv::bitwise_or(src, is, dst); CPU_SANITY_CHECK(dst); } @@ -849,39 +934,46 @@ PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseOrScalar, Combine(GPU_TYPICAL_MAT_SIZES, Va ////////////////////////////////////////////////////////////////////// // BitwiseXorMat -PERF_TEST_P(Sz_Depth, Core_BitwiseXorMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S))) +PERF_TEST_P(Sz_Depth, Core_BitwiseXorMat, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32S))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src1(size, depth); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, depth); - fillRandom(src2); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::bitwise_xor(d_src1, d_src2,d_dst); + TEST_CYCLE() cv::gpu::bitwise_xor(d_src1, d_src2, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() cv::bitwise_xor(src1, src2,dst); + TEST_CYCLE() cv::bitwise_xor(src1, src2, dst); + + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // BitwiseXorScalar -PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseXorScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseXorScalar, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32S), + GPU_CHANNELS_1_3_4)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); @@ -890,24 +982,26 @@ PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseXorScalar, Combine(GPU_TYPICAL_MAT_SIZES, V const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Scalar s = cv::Scalar::all(100); + cv::Scalar s; + declare.in(s, WARMUP_RNG); + cv::Scalar_ is = s; if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::bitwise_xor(d_src, s,d_dst); + TEST_CYCLE() cv::gpu::bitwise_xor(d_src, is, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() cv::bitwise_xor(src, s,dst); + TEST_CYCLE() cv::bitwise_xor(src, is, dst); CPU_SANITY_CHECK(dst); } @@ -916,7 +1010,10 @@ PERF_TEST_P(Sz_Depth_Cn, Core_BitwiseXorScalar, Combine(GPU_TYPICAL_MAT_SIZES, V ////////////////////////////////////////////////////////////////////// // RShift -PERF_TEST_P(Sz_Depth_Cn, Core_RShift, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, Core_RShift, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32S), + GPU_CHANNELS_1_3_4)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); @@ -925,18 +1022,18 @@ PERF_TEST_P(Sz_Depth_Cn, Core_RShift, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8 const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); const cv::Scalar_ val = cv::Scalar_::all(4); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::rshift(d_src, val,d_dst); + TEST_CYCLE() cv::gpu::rshift(d_src, val, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { @@ -947,7 +1044,10 @@ PERF_TEST_P(Sz_Depth_Cn, Core_RShift, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8 ////////////////////////////////////////////////////////////////////// // LShift -PERF_TEST_P(Sz_Depth_Cn, Core_LShift, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32S), GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, Core_LShift, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32S), + GPU_CHANNELS_1_3_4)) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); @@ -956,18 +1056,18 @@ PERF_TEST_P(Sz_Depth_Cn, Core_LShift, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8 const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); const cv::Scalar_ val = cv::Scalar_::all(4); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::lshift(d_src, val,d_dst); + TEST_CYCLE() cv::gpu::lshift(d_src, val, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { @@ -978,32 +1078,34 @@ PERF_TEST_P(Sz_Depth_Cn, Core_LShift, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8 ////////////////////////////////////////////////////////////////////// // MinMat -PERF_TEST_P(Sz_Depth, Core_MinMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F))) +PERF_TEST_P(Sz_Depth, Core_MinMat, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src1(size, depth); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, depth); - fillRandom(src2); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::min(d_src1, d_src2,d_dst); + TEST_CYCLE() cv::gpu::min(d_src1, d_src2, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() cv::min(src1, src2,dst); + TEST_CYCLE() cv::min(src1, src2, dst); CPU_SANITY_CHECK(dst); } @@ -1012,30 +1114,33 @@ PERF_TEST_P(Sz_Depth, Core_MinMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, ////////////////////////////////////////////////////////////////////// // MinScalar -PERF_TEST_P(Sz_Depth, Core_MinScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F))) +PERF_TEST_P(Sz_Depth, Core_MinScalar, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); - const double val = 50.0; + cv::Scalar val; + declare.in(val, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::min(d_src, val,d_dst); + TEST_CYCLE() cv::gpu::min(d_src, val[0], dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() cv::min(src, val,dst); + TEST_CYCLE() cv::min(src, val[0], dst); CPU_SANITY_CHECK(dst); } @@ -1044,32 +1149,34 @@ PERF_TEST_P(Sz_Depth, Core_MinScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8 ////////////////////////////////////////////////////////////////////// // MaxMat -PERF_TEST_P(Sz_Depth, Core_MaxMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F))) +PERF_TEST_P(Sz_Depth, Core_MaxMat, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src1(size, depth); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, depth); - fillRandom(src2); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::max(d_src1, d_src2,d_dst); + TEST_CYCLE() cv::gpu::max(d_src1, d_src2, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() cv::max(src1, src2,dst); + TEST_CYCLE() cv::max(src1, src2, dst); CPU_SANITY_CHECK(dst); } @@ -1078,30 +1185,33 @@ PERF_TEST_P(Sz_Depth, Core_MaxMat, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, ////////////////////////////////////////////////////////////////////// // MaxScalar -PERF_TEST_P(Sz_Depth, Core_MaxScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F))) +PERF_TEST_P(Sz_Depth, Core_MaxScalar, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F))) { const cv::Size size = GET_PARAM(0); const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); - const double val = 50.0; + cv::Scalar val; + declare.in(val, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::max(d_src, val,d_dst); + TEST_CYCLE() cv::gpu::max(d_src, val[0], dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() cv::max(src, val,dst); + TEST_CYCLE() cv::max(src, val[0], dst); CPU_SANITY_CHECK(dst); } @@ -1112,11 +1222,11 @@ PERF_TEST_P(Sz_Depth, Core_MaxScalar, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8 DEF_PARAM_TEST(Sz_3Depth, cv::Size, MatDepth, MatDepth, MatDepth); -PERF_TEST_P(Sz_3Depth, Core_AddWeighted, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F, CV_64F), - Values(CV_8U, CV_16U, CV_32F, CV_64F), - Values(CV_8U, CV_16U, CV_32F, CV_64F))) +PERF_TEST_P(Sz_3Depth, Core_AddWeighted, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F), + Values(CV_8U, CV_16U, CV_32F, CV_64F), + Values(CV_8U, CV_16U, CV_32F, CV_64F))) { const cv::Size size = GET_PARAM(0); const int depth1 = GET_PARAM(1); @@ -1124,20 +1234,20 @@ PERF_TEST_P(Sz_3Depth, Core_AddWeighted, Combine( const int dst_depth = GET_PARAM(3); cv::Mat src1(size, depth1); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, depth2); - fillRandom(src2); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::addWeighted(d_src1, 0.5, d_src2, 0.5, 10.0, d_dst, dst_depth); + TEST_CYCLE() cv::gpu::addWeighted(d_src1, 0.5, d_src2, 0.5, 10.0, dst, dst_depth); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { @@ -1157,76 +1267,76 @@ CV_FLAGS(GemmFlags, 0, cv::GEMM_1_T, cv::GEMM_2_T, cv::GEMM_3_T) DEF_PARAM_TEST(Sz_Type_Flags, cv::Size, MatType, GemmFlags); -PERF_TEST_P(Sz_Type_Flags, Core_GEMM, Combine( - Values(cv::Size(512, 512), cv::Size(1024, 1024)), - Values(CV_32FC1, CV_32FC2, CV_64FC1, CV_64FC2), - ALL_GEMM_FLAGS)) +PERF_TEST_P(Sz_Type_Flags, Core_GEMM, + Combine(Values(cv::Size(512, 512), cv::Size(1024, 1024)), + Values(CV_32FC1, CV_32FC2, CV_64FC1), + ALL_GEMM_FLAGS)) { - declare.time(5.0); - const cv::Size size = GET_PARAM(0); const int type = GET_PARAM(1); const int flags = GET_PARAM(2); cv::Mat src1(size, type); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, type); - fillRandom(src2); + declare.in(src2, WARMUP_RNG); cv::Mat src3(size, type); - fillRandom(src3); + declare.in(src3, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_src3(src3); - cv::gpu::GpuMat d_dst; + declare.time(5.0); - TEST_CYCLE() cv::gpu::gemm(d_src1, d_src2, 1.0, d_src3, 1.0, d_dst, flags); + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + const cv::gpu::GpuMat d_src3(src3); + cv::gpu::GpuMat dst; - GPU_SANITY_CHECK(d_dst, 1e-8); + TEST_CYCLE() cv::gpu::gemm(d_src1, d_src2, 1.0, d_src3, 1.0, dst, flags); + + GPU_SANITY_CHECK(dst); } else { - cv::Mat dst; - declare.time(50.0); + cv::Mat dst; + TEST_CYCLE() cv::gemm(src1, src2, 1.0, src3, 1.0, dst, flags); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // Transpose -PERF_TEST_P(Sz_Type, Core_Transpose, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8UC1, CV_8UC4, CV_16UC2, CV_16SC2, CV_32SC1, CV_32SC2, CV_64FC1))) +PERF_TEST_P(Sz_Type, Core_Transpose, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8UC1, CV_8UC4, CV_16UC2, CV_16SC2, CV_32SC1, CV_32SC2, CV_64FC1))) { - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::transpose(d_src,d_dst); + TEST_CYCLE() cv::gpu::transpose(d_src, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - TEST_CYCLE() cv::transpose(src,dst); + TEST_CYCLE() cv::transpose(src, dst); CPU_SANITY_CHECK(dst); } @@ -1241,30 +1351,30 @@ CV_ENUM(FlipCode, FLIP_BOTH, FLIP_X, FLIP_Y) DEF_PARAM_TEST(Sz_Depth_Cn_Code, cv::Size, MatDepth, MatCn, FlipCode); -PERF_TEST_P(Sz_Depth_Cn_Code, Core_Flip, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - GPU_CHANNELS_1_3_4, - ALL_FLIP_CODES)) +PERF_TEST_P(Sz_Depth_Cn_Code, Core_Flip, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4, + ALL_FLIP_CODES)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); - int flipCode = GET_PARAM(3); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); + const int flipCode = GET_PARAM(3); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::flip(d_src, d_dst, flipCode); + TEST_CYCLE() cv::gpu::flip(d_src, dst, flipCode); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { @@ -1279,27 +1389,27 @@ PERF_TEST_P(Sz_Depth_Cn_Code, Core_Flip, Combine( ////////////////////////////////////////////////////////////////////// // LutOneChannel -PERF_TEST_P(Sz_Type, Core_LutOneChannel, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8UC1, CV_8UC3))) +PERF_TEST_P(Sz_Type, Core_LutOneChannel, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8UC1, CV_8UC3))) { - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); cv::Mat lut(1, 256, CV_8UC1); - fillRandom(lut); + declare.in(lut, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::LUT(d_src, lut,d_dst); + TEST_CYCLE() cv::gpu::LUT(d_src, lut, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { @@ -1314,27 +1424,27 @@ PERF_TEST_P(Sz_Type, Core_LutOneChannel, Combine( ////////////////////////////////////////////////////////////////////// // LutMultiChannel -PERF_TEST_P(Sz_Type, Core_LutMultiChannel, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8UC3))) +PERF_TEST_P(Sz_Type, Core_LutMultiChannel, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8UC3))) { - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); cv::Mat lut(1, 256, CV_MAKE_TYPE(CV_8U, src.channels())); - fillRandom(lut); + declare.in(lut, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::LUT(d_src, lut,d_dst); + TEST_CYCLE() cv::gpu::LUT(d_src, lut, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { @@ -1349,21 +1459,22 @@ PERF_TEST_P(Sz_Type, Core_LutMultiChannel, Combine( ////////////////////////////////////////////////////////////////////// // MagnitudeComplex -PERF_TEST_P(Sz, Core_MagnitudeComplex, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, Core_MagnitudeComplex, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); cv::Mat src(size, CV_32FC2); - fillRandom(src, -100.0, 100.0); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::magnitude(d_src,d_dst); + TEST_CYCLE() cv::gpu::magnitude(d_src, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -1374,28 +1485,29 @@ PERF_TEST_P(Sz, Core_MagnitudeComplex, GPU_TYPICAL_MAT_SIZES) TEST_CYCLE() cv::magnitude(xy[0], xy[1], dst); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // MagnitudeSqrComplex -PERF_TEST_P(Sz, Core_MagnitudeSqrComplex, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, Core_MagnitudeSqrComplex, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); cv::Mat src(size, CV_32FC2); - fillRandom(src, -100.0, 100.0); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::magnitudeSqr(d_src, d_dst); + TEST_CYCLE() cv::gpu::magnitudeSqr(d_src, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { @@ -1406,25 +1518,26 @@ PERF_TEST_P(Sz, Core_MagnitudeSqrComplex, GPU_TYPICAL_MAT_SIZES) ////////////////////////////////////////////////////////////////////// // Magnitude -PERF_TEST_P(Sz, Core_Magnitude, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, Core_Magnitude, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); cv::Mat src1(size, CV_32FC1); - fillRandom(src1, -100.0, 100.0); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, CV_32FC1); - fillRandom(src2, -100.0, 100.0); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::magnitude(d_src1, d_src2, d_dst); + TEST_CYCLE() cv::gpu::magnitude(d_src1, d_src2, dst); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -1432,33 +1545,33 @@ PERF_TEST_P(Sz, Core_Magnitude, GPU_TYPICAL_MAT_SIZES) TEST_CYCLE() cv::magnitude(src1, src2, dst); - CPU_SANITY_CHECK(dst, 1e-8); - + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // MagnitudeSqr -PERF_TEST_P(Sz, Core_MagnitudeSqr, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, Core_MagnitudeSqr, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); cv::Mat src1(size, CV_32FC1); - fillRandom(src1, -100.0, 100.0); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, CV_32FC1); - fillRandom(src2, -100.0, 100.0); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::magnitudeSqr(d_src1, d_src2, d_dst); + TEST_CYCLE() cv::gpu::magnitudeSqr(d_src1, d_src2, dst); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { @@ -1471,26 +1584,28 @@ PERF_TEST_P(Sz, Core_MagnitudeSqr, GPU_TYPICAL_MAT_SIZES) DEF_PARAM_TEST(Sz_AngleInDegrees, cv::Size, bool); -PERF_TEST_P(Sz_AngleInDegrees, Core_Phase, Combine(GPU_TYPICAL_MAT_SIZES, Bool())) +PERF_TEST_P(Sz_AngleInDegrees, Core_Phase, + Combine(GPU_TYPICAL_MAT_SIZES, + Bool())) { - cv::Size size = GET_PARAM(0); - bool angleInDegrees = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const bool angleInDegrees = GET_PARAM(1); cv::Mat src1(size, CV_32FC1); - fillRandom(src1, -100.0, 100.0); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, CV_32FC1); - fillRandom(src2, -100.0, 100.0); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::phase(d_src1, d_src2, d_dst, angleInDegrees); + TEST_CYCLE() cv::gpu::phase(d_src1, d_src2, dst, angleInDegrees); - GPU_SANITY_CHECK(d_dst, 1e-8); + GPU_SANITY_CHECK(dst); } else { @@ -1498,36 +1613,37 @@ PERF_TEST_P(Sz_AngleInDegrees, Core_Phase, Combine(GPU_TYPICAL_MAT_SIZES, Bool() TEST_CYCLE() cv::phase(src1, src2, dst, angleInDegrees); - CPU_SANITY_CHECK(dst, 1e-8); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // CartToPolar -PERF_TEST_P(Sz_AngleInDegrees, Core_CartToPolar, Combine(GPU_TYPICAL_MAT_SIZES, Bool())) +PERF_TEST_P(Sz_AngleInDegrees, Core_CartToPolar, + Combine(GPU_TYPICAL_MAT_SIZES, + Bool())) { - cv::Size size = GET_PARAM(0); - bool angleInDegrees = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const bool angleInDegrees = GET_PARAM(1); cv::Mat src1(size, CV_32FC1); - fillRandom(src1, -100.0, 100.0); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, CV_32FC1); - fillRandom(src2, -100.0, 100.0); + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_magnitude; - cv::gpu::GpuMat d_angle; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat magnitude; + cv::gpu::GpuMat angle; - TEST_CYCLE() cv::gpu::cartToPolar(d_src1, d_src2, d_magnitude, d_angle, angleInDegrees); - - GPU_SANITY_CHECK(d_magnitude, 1e-8); - GPU_SANITY_CHECK(d_angle, 1e-8); + TEST_CYCLE() cv::gpu::cartToPolar(d_src1, d_src2, magnitude, angle, angleInDegrees); + GPU_SANITY_CHECK(magnitude); + GPU_SANITY_CHECK(angle); } else { @@ -1536,36 +1652,38 @@ PERF_TEST_P(Sz_AngleInDegrees, Core_CartToPolar, Combine(GPU_TYPICAL_MAT_SIZES, TEST_CYCLE() cv::cartToPolar(src1, src2, magnitude, angle, angleInDegrees); - CPU_SANITY_CHECK(magnitude, 1e-8); - CPU_SANITY_CHECK(angle, 1e-8); + CPU_SANITY_CHECK(magnitude); + CPU_SANITY_CHECK(angle); } } ////////////////////////////////////////////////////////////////////// // PolarToCart -PERF_TEST_P(Sz_AngleInDegrees, Core_PolarToCart, Combine(GPU_TYPICAL_MAT_SIZES, Bool())) +PERF_TEST_P(Sz_AngleInDegrees, Core_PolarToCart, + Combine(GPU_TYPICAL_MAT_SIZES, + Bool())) { - cv::Size size = GET_PARAM(0); - bool angleInDegrees = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const bool angleInDegrees = GET_PARAM(1); cv::Mat magnitude(size, CV_32FC1); - fillRandom(magnitude, 0.0, 100.0); + declare.in(magnitude, WARMUP_RNG); cv::Mat angle(size, CV_32FC1); - fillRandom(angle, 0.0, angleInDegrees ? 360.0 : 2 * CV_PI); + declare.in(angle, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_magnitude(magnitude); - cv::gpu::GpuMat d_angle(angle); - cv::gpu::GpuMat d_x; - cv::gpu::GpuMat d_y; + const cv::gpu::GpuMat d_magnitude(magnitude); + const cv::gpu::GpuMat d_angle(angle); + cv::gpu::GpuMat x; + cv::gpu::GpuMat y; - TEST_CYCLE() cv::gpu::polarToCart(d_magnitude, d_angle, d_x, d_y, angleInDegrees); + TEST_CYCLE() cv::gpu::polarToCart(d_magnitude, d_angle, x, y, angleInDegrees); - GPU_SANITY_CHECK(d_x, 1e-8); - GPU_SANITY_CHECK(d_y, 1e-8); + GPU_SANITY_CHECK(x); + GPU_SANITY_CHECK(y); } else { @@ -1574,37 +1692,45 @@ PERF_TEST_P(Sz_AngleInDegrees, Core_PolarToCart, Combine(GPU_TYPICAL_MAT_SIZES, TEST_CYCLE() cv::polarToCart(magnitude, angle, x, y, angleInDegrees); - CPU_SANITY_CHECK(x, 1e-8); - CPU_SANITY_CHECK(y, 1e-8); + CPU_SANITY_CHECK(x); + CPU_SANITY_CHECK(y); } } ////////////////////////////////////////////////////////////////////// // MeanStdDev -PERF_TEST_P(Sz, Core_MeanStdDev, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, Core_MeanStdDev, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); cv::Mat src(size, CV_8UC1); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Scalar mean; - cv::Scalar stddev; if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_buf; + cv::Scalar gpu_mean; + cv::Scalar gpu_stddev; - TEST_CYCLE() cv::gpu::meanStdDev(d_src, mean, stddev, d_buf); + TEST_CYCLE() cv::gpu::meanStdDev(d_src, gpu_mean, gpu_stddev, d_buf); + + SANITY_CHECK(gpu_mean); + SANITY_CHECK(gpu_stddev); } else { - TEST_CYCLE() cv::meanStdDev(src, mean, stddev); - } + cv::Scalar cpu_mean; + cv::Scalar cpu_stddev; - GPU_SANITY_CHECK(stddev, 1e-6); + TEST_CYCLE() cv::meanStdDev(src, cpu_mean, cpu_stddev); + + SANITY_CHECK(cpu_mean); + SANITY_CHECK(cpu_stddev); + } } ////////////////////////////////////////////////////////////////////// @@ -1612,33 +1738,36 @@ PERF_TEST_P(Sz, Core_MeanStdDev, GPU_TYPICAL_MAT_SIZES) DEF_PARAM_TEST(Sz_Depth_Norm, cv::Size, MatDepth, NormType); -PERF_TEST_P(Sz_Depth_Norm, Core_Norm, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32S, CV_32F), - Values(NormType(cv::NORM_INF), NormType(cv::NORM_L1), NormType(cv::NORM_L2)))) +PERF_TEST_P(Sz_Depth_Norm, Core_Norm, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32S, CV_32F), + Values(NormType(cv::NORM_INF), NormType(cv::NORM_L1), NormType(cv::NORM_L2)))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int normType = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int normType = GET_PARAM(2); cv::Mat src(size, depth); - fillRandom(src); - - double dst; + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_buf; + double gpu_dst; - TEST_CYCLE() dst = cv::gpu::norm(d_src, normType, cv::gpu::GpuMat(), d_buf); + TEST_CYCLE() gpu_dst = cv::gpu::norm(d_src, normType, d_buf); + + SANITY_CHECK(gpu_dst, 1e-6, ERROR_RELATIVE); } else { - TEST_CYCLE() dst = cv::norm(src, normType); - } + double cpu_dst; - SANITY_CHECK(dst, 1e-6); + TEST_CYCLE() cpu_dst = cv::norm(src, normType); + + SANITY_CHECK(cpu_dst, 1e-6, ERROR_RELATIVE); + } } ////////////////////////////////////////////////////////////////////// @@ -1646,99 +1775,103 @@ PERF_TEST_P(Sz_Depth_Norm, Core_Norm, Combine( DEF_PARAM_TEST(Sz_Norm, cv::Size, NormType); -PERF_TEST_P(Sz_Norm, Core_NormDiff, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(NormType(cv::NORM_INF), NormType(cv::NORM_L1), NormType(cv::NORM_L2)))) +PERF_TEST_P(Sz_Norm, Core_NormDiff, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(NormType(cv::NORM_INF), NormType(cv::NORM_L1), NormType(cv::NORM_L2)))) { - cv::Size size = GET_PARAM(0); - int normType = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int normType = GET_PARAM(1); cv::Mat src1(size, CV_8UC1); - fillRandom(src1); + declare.in(src1, WARMUP_RNG); cv::Mat src2(size, CV_8UC1); - fillRandom(src2); - - double dst; + declare.in(src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + double gpu_dst; - TEST_CYCLE() dst = cv::gpu::norm(d_src1, d_src2, normType); + TEST_CYCLE() gpu_dst = cv::gpu::norm(d_src1, d_src2, normType); + + SANITY_CHECK(gpu_dst); } else { - TEST_CYCLE() dst = cv::norm(src1, src2, normType); - } + double cpu_dst; - SANITY_CHECK(dst, 1e-6); + TEST_CYCLE() cpu_dst = cv::norm(src1, src2, normType); + + SANITY_CHECK(cpu_dst); + } } ////////////////////////////////////////////////////////////////////// // Sum -PERF_TEST_P(Sz_Depth_Cn, Core_Sum, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, Core_Sum, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); - - cv::Scalar dst; + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_buf; + cv::Scalar gpu_dst; - TEST_CYCLE() dst = cv::gpu::sum(d_src, cv::gpu::GpuMat(), d_buf); + TEST_CYCLE() gpu_dst = cv::gpu::sum(d_src, d_buf); + + SANITY_CHECK(gpu_dst, 1e-5, ERROR_RELATIVE); } else { - TEST_CYCLE() dst = cv::sum(src); - } + cv::Scalar cpu_dst; - double error = (depth == CV_32F) ? 3e+1 : 1e-6; - SANITY_CHECK(dst, error); + TEST_CYCLE() cpu_dst = cv::sum(src); + + SANITY_CHECK(cpu_dst, 1e-6, ERROR_RELATIVE); + } } ////////////////////////////////////////////////////////////////////// // SumAbs -PERF_TEST_P(Sz_Depth_Cn, Core_SumAbs, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, Core_SumAbs, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); - - cv::Scalar dst; + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_buf; + cv::Scalar gpu_dst; - TEST_CYCLE() dst = cv::gpu::absSum(d_src, cv::gpu::GpuMat(), d_buf); + TEST_CYCLE() gpu_dst = cv::gpu::absSum(d_src, d_buf); - SANITY_CHECK(dst, 1e-6); + SANITY_CHECK(gpu_dst, 1e-6, ERROR_RELATIVE); } else { @@ -1749,30 +1882,29 @@ PERF_TEST_P(Sz_Depth_Cn, Core_SumAbs, Combine( ////////////////////////////////////////////////////////////////////// // SumSqr -PERF_TEST_P(Sz_Depth_Cn, Core_SumSqr, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, Core_SumSqr, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); - - cv::Scalar dst; + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_buf; + cv::Scalar gpu_dst; - TEST_CYCLE() dst = cv::gpu::sqrSum(d_src, cv::gpu::GpuMat(), d_buf); + TEST_CYCLE() gpu_dst = cv::gpu::sqrSum(d_src, d_buf); - SANITY_CHECK(dst, 1e-6); + SANITY_CHECK(gpu_dst, 1e-6, ERROR_RELATIVE); } else { @@ -1783,98 +1915,106 @@ PERF_TEST_P(Sz_Depth_Cn, Core_SumSqr, Combine( ////////////////////////////////////////////////////////////////////// // MinMax -PERF_TEST_P(Sz_Depth, Core_MinMax, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F, CV_64F))) +PERF_TEST_P(Sz_Depth, Core_MinMax, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); - - double minVal, maxVal; + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_buf; + double gpu_minVal, gpu_maxVal; - TEST_CYCLE() cv::gpu::minMax(d_src, &minVal, &maxVal, cv::gpu::GpuMat(), d_buf); + TEST_CYCLE() cv::gpu::minMax(d_src, &gpu_minVal, &gpu_maxVal, cv::gpu::GpuMat(), d_buf); - SANITY_CHECK(minVal); - SANITY_CHECK(maxVal); + SANITY_CHECK(gpu_minVal); + SANITY_CHECK(gpu_maxVal); } else { - FAIL_NO_CPU(); + double cpu_minVal, cpu_maxVal; + + TEST_CYCLE() cv::minMaxLoc(src, &cpu_minVal, &cpu_maxVal); + + SANITY_CHECK(cpu_minVal); + SANITY_CHECK(cpu_maxVal); } } ////////////////////////////////////////////////////////////////////// // MinMaxLoc -PERF_TEST_P(Sz_Depth, Core_MinMaxLoc, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F, CV_64F))) +PERF_TEST_P(Sz_Depth, Core_MinMaxLoc, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); - - double minVal, maxVal; - cv::Point minLoc, maxLoc; + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_valbuf, d_locbuf; + double gpu_minVal, gpu_maxVal; + cv::Point gpu_minLoc, gpu_maxLoc; - TEST_CYCLE() cv::gpu::minMaxLoc(d_src, &minVal, &maxVal, &minLoc, &maxLoc, cv::gpu::GpuMat(), d_valbuf, d_locbuf); + TEST_CYCLE() cv::gpu::minMaxLoc(d_src, &gpu_minVal, &gpu_maxVal, &gpu_minLoc, &gpu_maxLoc, cv::gpu::GpuMat(), d_valbuf, d_locbuf); + + SANITY_CHECK(gpu_minVal); + SANITY_CHECK(gpu_maxVal); } else { - TEST_CYCLE() cv::minMaxLoc(src, &minVal, &maxVal, &minLoc, &maxLoc); + double cpu_minVal, cpu_maxVal; + cv::Point cpu_minLoc, cpu_maxLoc; + + TEST_CYCLE() cv::minMaxLoc(src, &cpu_minVal, &cpu_maxVal, &cpu_minLoc, &cpu_maxLoc); + + SANITY_CHECK(cpu_minVal); + SANITY_CHECK(cpu_maxVal); } - - SANITY_CHECK(minVal, 1e-12); - SANITY_CHECK(maxVal, 1e-12); - - // unsupported by peft system - //SANITY_CHECK(minLoc); - //SANITY_CHECK(maxLoc); } ////////////////////////////////////////////////////////////////////// // CountNonZero -PERF_TEST_P(Sz_Depth, Core_CountNonZero, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F, CV_64F))) +PERF_TEST_P(Sz_Depth, Core_CountNonZero, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); - - int dst = 0; + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_buf; + int gpu_dst = 0; - TEST_CYCLE() dst = cv::gpu::countNonZero(d_src, d_buf); + TEST_CYCLE() gpu_dst = cv::gpu::countNonZero(d_src, d_buf); + + SANITY_CHECK(gpu_dst); } else { - TEST_CYCLE() dst = cv::countNonZero(src); - } + int cpu_dst = 0; - SANITY_CHECK(dst); + TEST_CYCLE() cpu_dst = cv::countNonZero(src); + + SANITY_CHECK(cpu_dst); + } } ////////////////////////////////////////////////////////////////////// @@ -1889,32 +2029,32 @@ CV_ENUM(ReduceDim, Rows, Cols) DEF_PARAM_TEST(Sz_Depth_Cn_Code_Dim, cv::Size, MatDepth, MatCn, ReduceCode, ReduceDim); -PERF_TEST_P(Sz_Depth_Cn_Code_Dim, Core_Reduce, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_16S, CV_32F), - Values(1, 2, 3, 4), - ALL_REDUCE_CODES, - ALL_REDUCE_DIMS)) +PERF_TEST_P(Sz_Depth_Cn_Code_Dim, Core_Reduce, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_16S, CV_32F), + Values(1, 2, 3, 4), + ALL_REDUCE_CODES, + ALL_REDUCE_DIMS)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); - int reduceOp = GET_PARAM(3); - int dim = GET_PARAM(4); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); + const int reduceOp = GET_PARAM(3); + const int dim = GET_PARAM(4); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() cv::gpu::reduce(d_src, d_dst, dim, reduceOp); + TEST_CYCLE() cv::gpu::reduce(d_src, dst, dim, reduceOp); - GPU_SANITY_CHECK(d_dst, 1); + GPU_SANITY_CHECK(dst); } else { @@ -1922,43 +2062,41 @@ PERF_TEST_P(Sz_Depth_Cn_Code_Dim, Core_Reduce, Combine( TEST_CYCLE() cv::reduce(src, dst, dim, reduceOp); - CPU_SANITY_CHECK(dst, 1); + CPU_SANITY_CHECK(dst); } } - ////////////////////////////////////////////////////////////////////// // Normalize DEF_PARAM_TEST(Sz_Depth_NormType, cv::Size, MatDepth, NormType); -PERF_TEST_P(Sz_Depth_NormType, Core_Normalize, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F, CV_64F), - Values(NormType(cv::NORM_INF), - NormType(cv::NORM_L1), - NormType(cv::NORM_L2), - NormType(cv::NORM_MINMAX)) - )) +PERF_TEST_P(Sz_Depth_NormType, Core_Normalize, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F), + Values(NormType(cv::NORM_INF), + NormType(cv::NORM_L1), + NormType(cv::NORM_L2), + NormType(cv::NORM_MINMAX)))) { - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); - int norm_type = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); + const int norm_type = GET_PARAM(2); - double alpha = 1; - double beta = 0; + const double alpha = 1; + const double beta = 0; cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; cv::gpu::GpuMat d_norm_buf, d_cvt_buf; - TEST_CYCLE() cv::gpu::normalize(d_src, d_dst, alpha, beta, norm_type, type, cv::gpu::GpuMat(), d_norm_buf, d_cvt_buf); + TEST_CYCLE() cv::gpu::normalize(d_src, dst, alpha, beta, norm_type, type, cv::gpu::GpuMat(), d_norm_buf, d_cvt_buf); - GPU_SANITY_CHECK(d_dst, 1); + GPU_SANITY_CHECK(dst, 1e-6); } else { @@ -1966,8 +2104,6 @@ PERF_TEST_P(Sz_Depth_NormType, Core_Normalize, Combine( TEST_CYCLE() cv::normalize(src, dst, alpha, beta, norm_type, type); - CPU_SANITY_CHECK(dst, 1); + CPU_SANITY_CHECK(dst); } } - -} // namespace diff --git a/modules/gpu/perf/perf_denoising.cpp b/modules/gpu/perf/perf_denoising.cpp index ed63177ddb..6f03994bd9 100644 --- a/modules/gpu/perf/perf_denoising.cpp +++ b/modules/gpu/perf/perf_denoising.cpp @@ -3,8 +3,7 @@ using namespace std; using namespace testing; -#define GPU_DENOISING_IMAGE_SIZES testing::Values(perf::szVGA, perf::szXGA, perf::sz720p, perf::sz1080p) - +#define GPU_DENOISING_IMAGE_SIZES testing::Values(perf::szVGA, perf::sz720p) ////////////////////////////////////////////////////////////////////// // BilateralFilter @@ -12,96 +11,86 @@ using namespace testing; DEF_PARAM_TEST(Sz_Depth_Cn_KernelSz, cv::Size, MatDepth, MatCn, int); PERF_TEST_P(Sz_Depth_Cn_KernelSz, Denoising_BilateralFilter, - Combine(GPU_DENOISING_IMAGE_SIZES, Values(CV_8U, CV_32F), GPU_CHANNELS_1_3, Values(3, 5, 9))) + Combine(GPU_DENOISING_IMAGE_SIZES, + Values(CV_8U, CV_32F), + GPU_CHANNELS_1_3, + Values(3, 5, 9))) { declare.time(60.0); - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); - int kernel_size = GET_PARAM(3); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); + const int kernel_size = GET_PARAM(3); - float sigma_color = 7; - float sigma_spatial = 5; - int borderMode = cv::BORDER_REFLECT101; + const float sigma_color = 7; + const float sigma_spatial = 5; + const int borderMode = cv::BORDER_REFLECT101; - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); - if (PERF_RUN_GPU()) + if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::bilateralFilter(d_src, d_dst, kernel_size, sigma_color, sigma_spatial, borderMode); + TEST_CYCLE() cv::gpu::bilateralFilter(d_src, dst, kernel_size, sigma_color, sigma_spatial, borderMode); - TEST_CYCLE() - { - cv::gpu::bilateralFilter(d_src, d_dst, kernel_size, sigma_color, sigma_spatial, borderMode); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::bilateralFilter(src, dst, kernel_size, sigma_color, sigma_spatial, borderMode); - - TEST_CYCLE() - { - cv::bilateralFilter(src, dst, kernel_size, sigma_color, sigma_spatial, borderMode); - } + TEST_CYCLE() cv::bilateralFilter(src, dst, kernel_size, sigma_color, sigma_spatial, borderMode); CPU_SANITY_CHECK(dst); } } - ////////////////////////////////////////////////////////////////////// // nonLocalMeans DEF_PARAM_TEST(Sz_Depth_Cn_WinSz_BlockSz, cv::Size, MatDepth, MatCn, int, int); PERF_TEST_P(Sz_Depth_Cn_WinSz_BlockSz, Denoising_NonLocalMeans, - Combine(GPU_DENOISING_IMAGE_SIZES, Values(CV_8U), GPU_CHANNELS_1_3, Values(21), Values(5, 7))) + Combine(GPU_DENOISING_IMAGE_SIZES, + Values(CV_8U), + GPU_CHANNELS_1_3, + Values(21), + Values(5))) { declare.time(60.0); - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); + const int search_widow_size = GET_PARAM(3); + const int block_size = GET_PARAM(4); - int search_widow_size = GET_PARAM(3); - int block_size = GET_PARAM(4); + const float h = 10; + const int borderMode = cv::BORDER_REFLECT101; - float h = 10; - int borderMode = cv::BORDER_REFLECT101; - - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::nonLocalMeans(d_src, d_dst, h, search_widow_size, block_size, borderMode); + TEST_CYCLE() cv::gpu::nonLocalMeans(d_src, dst, h, search_widow_size, block_size, borderMode); - TEST_CYCLE() - { - cv::gpu::nonLocalMeans(d_src, d_dst, h, search_widow_size, block_size, borderMode); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } @@ -112,46 +101,41 @@ PERF_TEST_P(Sz_Depth_Cn_WinSz_BlockSz, Denoising_NonLocalMeans, DEF_PARAM_TEST(Sz_Depth_Cn_WinSz_BlockSz, cv::Size, MatDepth, MatCn, int, int); PERF_TEST_P(Sz_Depth_Cn_WinSz_BlockSz, Denoising_FastNonLocalMeans, - Combine(GPU_DENOISING_IMAGE_SIZES, Values(CV_8U), GPU_CHANNELS_1_3, Values(21), Values(7))) + Combine(GPU_DENOISING_IMAGE_SIZES, + Values(CV_8U), + GPU_CHANNELS_1_3, + Values(21), + Values(7))) { - declare.time(150.0); + declare.time(60.0); - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int search_widow_size = GET_PARAM(2); + const int block_size = GET_PARAM(3); - int search_widow_size = GET_PARAM(2); - int block_size = GET_PARAM(3); - - float h = 10; - int type = CV_MAKE_TYPE(depth, 1); + const float h = 10; + const int type = CV_MAKE_TYPE(depth, 1); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; cv::gpu::FastNonLocalMeansDenoising fnlmd; - fnlmd.simpleMethod(d_src, d_dst, h, search_widow_size, block_size); + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() - { - fnlmd.simpleMethod(d_src, d_dst, h, search_widow_size, block_size); - } + TEST_CYCLE() fnlmd.simpleMethod(d_src, dst, h, search_widow_size, block_size); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::fastNlMeansDenoising(src, dst, h, block_size, search_widow_size); - TEST_CYCLE() - { - cv::fastNlMeansDenoising(src, dst, h, block_size, search_widow_size); - } + TEST_CYCLE() cv::fastNlMeansDenoising(src, dst, h, block_size, search_widow_size); CPU_SANITY_CHECK(dst); } @@ -163,47 +147,41 @@ PERF_TEST_P(Sz_Depth_Cn_WinSz_BlockSz, Denoising_FastNonLocalMeans, DEF_PARAM_TEST(Sz_Depth_WinSz_BlockSz, cv::Size, MatDepth, int, int); PERF_TEST_P(Sz_Depth_WinSz_BlockSz, Denoising_FastNonLocalMeansColored, - Combine(GPU_DENOISING_IMAGE_SIZES, Values(CV_8U), Values(21), Values(7))) + Combine(GPU_DENOISING_IMAGE_SIZES, + Values(CV_8U), + Values(21), + Values(7))) { - declare.time(350.0); + declare.time(60.0); - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int search_widow_size = GET_PARAM(2); + const int block_size = GET_PARAM(3); - int search_widow_size = GET_PARAM(2); - int block_size = GET_PARAM(3); - - float h = 10; - int type = CV_MAKE_TYPE(depth, 3); + const float h = 10; + const int type = CV_MAKE_TYPE(depth, 3); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; cv::gpu::FastNonLocalMeansDenoising fnlmd; - fnlmd.labMethod(d_src, d_dst, h, h, search_widow_size, block_size); + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - TEST_CYCLE() - { - fnlmd.labMethod(d_src, d_dst, h, h, search_widow_size, block_size); - } + TEST_CYCLE() fnlmd.labMethod(d_src, dst, h, h, search_widow_size, block_size); - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::fastNlMeansDenoisingColored(src, dst, h, h, block_size, search_widow_size); - TEST_CYCLE() - { - cv::fastNlMeansDenoisingColored(src, dst, h, h, block_size, search_widow_size); - } + TEST_CYCLE() cv::fastNlMeansDenoisingColored(src, dst, h, h, block_size, search_widow_size); CPU_SANITY_CHECK(dst); } -} \ No newline at end of file +} diff --git a/modules/gpu/perf/perf_features2d.cpp b/modules/gpu/perf/perf_features2d.cpp index a93cef9b33..67de9a1eac 100644 --- a/modules/gpu/perf/perf_features2d.cpp +++ b/modules/gpu/perf/perf_features2d.cpp @@ -3,139 +3,194 @@ using namespace std; using namespace testing; -namespace { +struct KeypointIdxCompare +{ + std::vector* keypoints; + + explicit KeypointIdxCompare(std::vector* _keypoints) : keypoints(_keypoints) {} + + bool operator ()(size_t i1, size_t i2) const + { + cv::KeyPoint kp1 = (*keypoints)[i1]; + cv::KeyPoint kp2 = (*keypoints)[i2]; + if (kp1.pt.x != kp2.pt.x) + return kp1.pt.x < kp2.pt.x; + if (kp1.pt.y != kp2.pt.y) + return kp1.pt.y < kp2.pt.y; + if (kp1.response != kp2.response) + return kp1.response < kp2.response; + return kp1.octave < kp2.octave; + } +}; + +static void sortKeyPoints(std::vector& keypoints, cv::InputOutputArray _descriptors = cv::noArray()) +{ + std::vector indexies(keypoints.size()); + for (size_t i = 0; i < indexies.size(); ++i) + indexies[i] = i; + + std::sort(indexies.begin(), indexies.end(), KeypointIdxCompare(&keypoints)); + + std::vector new_keypoints; + cv::Mat new_descriptors; + + new_keypoints.resize(keypoints.size()); + + cv::Mat descriptors; + if (_descriptors.needed()) + { + descriptors = _descriptors.getMat(); + new_descriptors.create(descriptors.size(), descriptors.type()); + } + + for (size_t i = 0; i < indexies.size(); ++i) + { + size_t new_idx = indexies[i]; + new_keypoints[i] = keypoints[new_idx]; + if (!new_descriptors.empty()) + descriptors.row((int) new_idx).copyTo(new_descriptors.row((int) i)); + } + + keypoints.swap(new_keypoints); + if (_descriptors.needed()) + new_descriptors.copyTo(_descriptors); +} ////////////////////////////////////////////////////////////////////// // SURF DEF_PARAM_TEST_1(Image, string); -PERF_TEST_P(Image, Features2D_SURF, Values("gpu/perf/aloe.png")) +PERF_TEST_P(Image, Features2D_SURF, + Values("gpu/perf/aloe.png")) { declare.time(50.0); - cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); + const cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); if (PERF_RUN_GPU()) { cv::gpu::SURF_GPU d_surf; - cv::gpu::GpuMat d_img(img); + const cv::gpu::GpuMat d_img(img); cv::gpu::GpuMat d_keypoints, d_descriptors; - d_surf(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); + TEST_CYCLE() d_surf(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); - TEST_CYCLE() - { - d_surf(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); - } + std::vector gpu_keypoints; + d_surf.downloadKeypoints(d_keypoints, gpu_keypoints); - GPU_SANITY_CHECK(d_descriptors, 1e-4); - GPU_SANITY_CHECK_KEYPOINTS(SURF, d_keypoints); + cv::Mat gpu_descriptors(d_descriptors); + + sortKeyPoints(gpu_keypoints, gpu_descriptors); + + SANITY_CHECK_KEYPOINTS(gpu_keypoints); + SANITY_CHECK(gpu_descriptors); } else { cv::SURF surf; - std::vector keypoints; - cv::Mat descriptors; + std::vector cpu_keypoints; + cv::Mat cpu_descriptors; - surf(img, cv::noArray(), keypoints, descriptors); + TEST_CYCLE() surf(img, cv::noArray(), cpu_keypoints, cpu_descriptors); - TEST_CYCLE() - { - keypoints.clear(); - surf(img, cv::noArray(), keypoints, descriptors); - } - - SANITY_CHECK_KEYPOINTS(keypoints); - SANITY_CHECK(descriptors, 1e-4); + SANITY_CHECK_KEYPOINTS(cpu_keypoints); + SANITY_CHECK(cpu_descriptors); } } ////////////////////////////////////////////////////////////////////// // FAST -PERF_TEST_P(Image, Features2D_FAST, Values("gpu/perf/aloe.png")) +DEF_PARAM_TEST(Image_Threshold_NonMaxSupression, string, int, bool); + +PERF_TEST_P(Image_Threshold_NonMaxSupression, Features2D_FAST, + Combine(Values("gpu/perf/aloe.png"), + Values(20), + Bool())) { - cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); + const cv::Mat img = readImage(GET_PARAM(0), cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); + const int threshold = GET_PARAM(1); + const bool nonMaxSuppersion = GET_PARAM(2); + if (PERF_RUN_GPU()) { - cv::gpu::FAST_GPU d_fast(20); + cv::gpu::FAST_GPU d_fast(threshold, nonMaxSuppersion, 0.5); - cv::gpu::GpuMat d_img(img); + const cv::gpu::GpuMat d_img(img); cv::gpu::GpuMat d_keypoints; - d_fast(d_img, cv::gpu::GpuMat(), d_keypoints); + TEST_CYCLE() d_fast(d_img, cv::gpu::GpuMat(), d_keypoints); - TEST_CYCLE() - { - d_fast(d_img, cv::gpu::GpuMat(), d_keypoints); - } + std::vector gpu_keypoints; + d_fast.downloadKeypoints(d_keypoints, gpu_keypoints); - GPU_SANITY_CHECK_RESPONSE(FAST, d_keypoints); + sortKeyPoints(gpu_keypoints); + + SANITY_CHECK_KEYPOINTS(gpu_keypoints); } else { - std::vector keypoints; + std::vector cpu_keypoints; - cv::FAST(img, keypoints, 20); + TEST_CYCLE() cv::FAST(img, cpu_keypoints, threshold, nonMaxSuppersion); - TEST_CYCLE() - { - keypoints.clear(); - cv::FAST(img, keypoints, 20); - } - - SANITY_CHECK_KEYPOINTS(keypoints); + SANITY_CHECK_KEYPOINTS(cpu_keypoints); } } ////////////////////////////////////////////////////////////////////// // ORB -PERF_TEST_P(Image, Features2D_ORB, Values("gpu/perf/aloe.png")) +DEF_PARAM_TEST(Image_NFeatures, string, int); + +PERF_TEST_P(Image_NFeatures, Features2D_ORB, + Combine(Values("gpu/perf/aloe.png"), + Values(4000))) { - cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); + const cv::Mat img = readImage(GET_PARAM(0), cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); + const int nFeatures = GET_PARAM(1); + if (PERF_RUN_GPU()) { - cv::gpu::ORB_GPU d_orb(4000); + cv::gpu::ORB_GPU d_orb(nFeatures); - cv::gpu::GpuMat d_img(img); + const cv::gpu::GpuMat d_img(img); cv::gpu::GpuMat d_keypoints, d_descriptors; - d_orb(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); + TEST_CYCLE() d_orb(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); - TEST_CYCLE() - { - d_orb(d_img, cv::gpu::GpuMat(), d_keypoints, d_descriptors); - } + std::vector gpu_keypoints; + d_orb.downloadKeyPoints(d_keypoints, gpu_keypoints); - GPU_SANITY_CHECK_KEYPOINTS(ORB, d_keypoints); - GPU_SANITY_CHECK(d_descriptors); + cv::Mat gpu_descriptors(d_descriptors); + + gpu_keypoints.resize(10); + gpu_descriptors = gpu_descriptors.rowRange(0, 10); + + sortKeyPoints(gpu_keypoints, gpu_descriptors); + + SANITY_CHECK_KEYPOINTS(gpu_keypoints); + SANITY_CHECK(gpu_descriptors); } else { - cv::ORB orb(4000); + cv::ORB orb(nFeatures); - std::vector keypoints; - cv::Mat descriptors; + std::vector cpu_keypoints; + cv::Mat cpu_descriptors; - orb(img, cv::noArray(), keypoints, descriptors); + TEST_CYCLE() orb(img, cv::noArray(), cpu_keypoints, cpu_descriptors); - TEST_CYCLE() - { - keypoints.clear(); - orb(img, cv::noArray(), keypoints, descriptors); - } - - SANITY_CHECK_KEYPOINTS(keypoints); - SANITY_CHECK(descriptors); + SANITY_CHECK_KEYPOINTS(cpu_keypoints); + SANITY_CHECK(cpu_descriptors); } } @@ -144,166 +199,165 @@ PERF_TEST_P(Image, Features2D_ORB, Values("gpu/perf/aloe.png")) DEF_PARAM_TEST(DescSize_Norm, int, NormType); -PERF_TEST_P(DescSize_Norm, Features2D_BFMatch, Combine(Values(64, 128, 256), Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))) +PERF_TEST_P(DescSize_Norm, Features2D_BFMatch, + Combine(Values(64, 128, 256), + Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))) { declare.time(20.0); - int desc_size = GET_PARAM(0); - int normType = GET_PARAM(1); + const int desc_size = GET_PARAM(0); + const int normType = GET_PARAM(1); - int type = normType == cv::NORM_HAMMING ? CV_8U : CV_32F; + const int type = normType == cv::NORM_HAMMING ? CV_8U : CV_32F; cv::Mat query(3000, desc_size, type); - fillRandom(query); + declare.in(query, WARMUP_RNG); cv::Mat train(3000, desc_size, type); - fillRandom(train); + declare.in(train, WARMUP_RNG); if (PERF_RUN_GPU()) { cv::gpu::BFMatcher_GPU d_matcher(normType); - cv::gpu::GpuMat d_query(query); - cv::gpu::GpuMat d_train(train); + const cv::gpu::GpuMat d_query(query); + const cv::gpu::GpuMat d_train(train); cv::gpu::GpuMat d_trainIdx, d_distance; - d_matcher.matchSingle(d_query, d_train, d_trainIdx, d_distance); + TEST_CYCLE() d_matcher.matchSingle(d_query, d_train, d_trainIdx, d_distance); - TEST_CYCLE() - { - d_matcher.matchSingle(d_query, d_train, d_trainIdx, d_distance); - } + std::vector gpu_matches; + d_matcher.matchDownload(d_trainIdx, d_distance, gpu_matches); - GPU_SANITY_CHECK(d_trainIdx); - GPU_SANITY_CHECK(d_distance); + SANITY_CHECK_MATCHES(gpu_matches); } else { cv::BFMatcher matcher(normType); - std::vector matches; + std::vector cpu_matches; - matcher.match(query, train, matches); + TEST_CYCLE() matcher.match(query, train, cpu_matches); - TEST_CYCLE() - { - matcher.match(query, train, matches); - } - - SANITY_CHECK(matches); + SANITY_CHECK_MATCHES(cpu_matches); } } ////////////////////////////////////////////////////////////////////// // BFKnnMatch +static void toOneRowMatches(const std::vector< std::vector >& src, std::vector& dst) +{ + dst.clear(); + for (size_t i = 0; i < src.size(); ++i) + for (size_t j = 0; j < src[i].size(); ++j) + dst.push_back(src[i][j]); +} + DEF_PARAM_TEST(DescSize_K_Norm, int, int, NormType); -PERF_TEST_P(DescSize_K_Norm, Features2D_BFKnnMatch, Combine( - Values(64, 128, 256), - Values(2, 3), - Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))) +PERF_TEST_P(DescSize_K_Norm, Features2D_BFKnnMatch, + Combine(Values(64, 128, 256), + Values(2, 3), + Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2)))) { declare.time(30.0); - int desc_size = GET_PARAM(0); - int k = GET_PARAM(1); - int normType = GET_PARAM(2); + const int desc_size = GET_PARAM(0); + const int k = GET_PARAM(1); + const int normType = GET_PARAM(2); - int type = normType == cv::NORM_HAMMING ? CV_8U : CV_32F; + const int type = normType == cv::NORM_HAMMING ? CV_8U : CV_32F; cv::Mat query(3000, desc_size, type); - fillRandom(query); + declare.in(query, WARMUP_RNG); cv::Mat train(3000, desc_size, type); - fillRandom(train); + declare.in(train, WARMUP_RNG); if (PERF_RUN_GPU()) { cv::gpu::BFMatcher_GPU d_matcher(normType); - cv::gpu::GpuMat d_query(query); - cv::gpu::GpuMat d_train(train); + const cv::gpu::GpuMat d_query(query); + const cv::gpu::GpuMat d_train(train); cv::gpu::GpuMat d_trainIdx, d_distance, d_allDist; - d_matcher.knnMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_allDist, k); + TEST_CYCLE() d_matcher.knnMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_allDist, k); - TEST_CYCLE() - { - d_matcher.knnMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_allDist, k); - } + std::vector< std::vector > matchesTbl; + d_matcher.knnMatchDownload(d_trainIdx, d_distance, matchesTbl); - GPU_SANITY_CHECK(d_trainIdx); - GPU_SANITY_CHECK(d_distance); + std::vector gpu_matches; + toOneRowMatches(matchesTbl, gpu_matches); + + SANITY_CHECK_MATCHES(gpu_matches); } else { cv::BFMatcher matcher(normType); - std::vector< std::vector > matches; + std::vector< std::vector > matchesTbl; - matcher.knnMatch(query, train, matches, k); + TEST_CYCLE() matcher.knnMatch(query, train, matchesTbl, k); - TEST_CYCLE() - { - matcher.knnMatch(query, train, matches, k); - } + std::vector cpu_matches; + toOneRowMatches(matchesTbl, cpu_matches); - SANITY_CHECK(matches); + SANITY_CHECK_MATCHES(cpu_matches); } } ////////////////////////////////////////////////////////////////////// // BFRadiusMatch -PERF_TEST_P(DescSize_Norm, Features2D_BFRadiusMatch, Combine(Values(64, 128, 256), Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2), NormType(cv::NORM_HAMMING)))) +PERF_TEST_P(DescSize_Norm, Features2D_BFRadiusMatch, + Combine(Values(64, 128, 256), + Values(NormType(cv::NORM_L1), NormType(cv::NORM_L2)))) { declare.time(30.0); - int desc_size = GET_PARAM(0); - int normType = GET_PARAM(1); + const int desc_size = GET_PARAM(0); + const int normType = GET_PARAM(1); - int type = normType == cv::NORM_HAMMING ? CV_8U : CV_32F; + const int type = normType == cv::NORM_HAMMING ? CV_8U : CV_32F; + const float maxDistance = 10000; cv::Mat query(3000, desc_size, type); - fillRandom(query, 0.0, 1.0); + declare.in(query, WARMUP_RNG); cv::Mat train(3000, desc_size, type); - fillRandom(train, 0.0, 1.0); + declare.in(train, WARMUP_RNG); if (PERF_RUN_GPU()) { cv::gpu::BFMatcher_GPU d_matcher(normType); - cv::gpu::GpuMat d_query(query); - cv::gpu::GpuMat d_train(train); + const cv::gpu::GpuMat d_query(query); + const cv::gpu::GpuMat d_train(train); cv::gpu::GpuMat d_trainIdx, d_nMatches, d_distance; - d_matcher.radiusMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_nMatches, 2.0); + TEST_CYCLE() d_matcher.radiusMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_nMatches, maxDistance); - TEST_CYCLE() - { - d_matcher.radiusMatchSingle(d_query, d_train, d_trainIdx, d_distance, d_nMatches, 2.0); - } + std::vector< std::vector > matchesTbl; + d_matcher.radiusMatchDownload(d_trainIdx, d_distance, d_nMatches, matchesTbl); - GPU_SANITY_CHECK(d_trainIdx); - GPU_SANITY_CHECK(d_distance); + std::vector gpu_matches; + toOneRowMatches(matchesTbl, gpu_matches); + + SANITY_CHECK_MATCHES(gpu_matches); } else { cv::BFMatcher matcher(normType); - std::vector< std::vector > matches; + std::vector< std::vector > matchesTbl; - matcher.radiusMatch(query, train, matches, 2.0); + TEST_CYCLE() matcher.radiusMatch(query, train, matchesTbl, maxDistance); - TEST_CYCLE() - { - matcher.radiusMatch(query, train, matches, 2.0); - } + std::vector cpu_matches; + toOneRowMatches(matchesTbl, cpu_matches); - SANITY_CHECK(matches); + SANITY_CHECK_MATCHES(cpu_matches); } } - -} // namespace diff --git a/modules/gpu/perf/perf_filters.cpp b/modules/gpu/perf/perf_filters.cpp index 7faf93e979..3516954a6c 100644 --- a/modules/gpu/perf/perf_filters.cpp +++ b/modules/gpu/perf/perf_filters.cpp @@ -3,48 +3,39 @@ using namespace std; using namespace testing; -namespace { - ////////////////////////////////////////////////////////////////////// // Blur DEF_PARAM_TEST(Sz_Type_KernelSz, cv::Size, MatType, int); -PERF_TEST_P(Sz_Type_KernelSz, Filters_Blur, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC1, CV_8UC4), Values(3, 5, 7))) +PERF_TEST_P(Sz_Type_KernelSz, Filters_Blur, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8UC1, CV_8UC4), + Values(3, 5, 7))) { declare.time(20.0); - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); - int ksize = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); + const int ksize = GET_PARAM(2); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::blur(d_src, d_dst, cv::Size(ksize, ksize)); + TEST_CYCLE() cv::gpu::blur(d_src, dst, cv::Size(ksize, ksize)); - TEST_CYCLE() - { - cv::gpu::blur(d_src, d_dst, cv::Size(ksize, ksize)); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::blur(src, dst, cv::Size(ksize, ksize)); - - TEST_CYCLE() - { - cv::blur(src, dst, cv::Size(ksize, ksize)); - } + TEST_CYCLE() cv::blur(src, dst, cv::Size(ksize, ksize)); CPU_SANITY_CHECK(dst); } @@ -57,38 +48,28 @@ PERF_TEST_P(Sz_Type_KernelSz, Filters_Sobel, Combine(GPU_TYPICAL_MAT_SIZES, Valu { declare.time(20.0); - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); - int ksize = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); + const int ksize = GET_PARAM(2); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; cv::gpu::GpuMat d_buf; - cv::gpu::Sobel(d_src, d_dst, -1, 1, 1, d_buf, ksize); + TEST_CYCLE() cv::gpu::Sobel(d_src, dst, -1, 1, 1, d_buf, ksize); - TEST_CYCLE() - { - cv::gpu::Sobel(d_src, d_dst, -1, 1, 1, d_buf, ksize); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::Sobel(src, dst, -1, 1, 1, ksize); - - TEST_CYCLE() - { - cv::Sobel(src, dst, -1, 1, 1, ksize); - } + TEST_CYCLE() cv::Sobel(src, dst, -1, 1, 1, ksize); CPU_SANITY_CHECK(dst); } @@ -101,37 +82,27 @@ PERF_TEST_P(Sz_Type, Filters_Scharr, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U { declare.time(20.0); - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; cv::gpu::GpuMat d_buf; - cv::gpu::Scharr(d_src, d_dst, -1, 1, 0, d_buf); + TEST_CYCLE() cv::gpu::Scharr(d_src, dst, -1, 1, 0, d_buf); - TEST_CYCLE() - { - cv::gpu::Scharr(d_src, d_dst, -1, 1, 0, d_buf); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::Scharr(src, dst, -1, 1, 0); - - TEST_CYCLE() - { - cv::Scharr(src, dst, -1, 1, 0); - } + TEST_CYCLE() cv::Scharr(src, dst, -1, 1, 0); CPU_SANITY_CHECK(dst); } @@ -144,38 +115,28 @@ PERF_TEST_P(Sz_Type_KernelSz, Filters_GaussianBlur, Combine(GPU_TYPICAL_MAT_SIZE { declare.time(20.0); - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); - int ksize = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); + const int ksize = GET_PARAM(2); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; cv::gpu::GpuMat d_buf; - cv::gpu::GaussianBlur(d_src, d_dst, cv::Size(ksize, ksize), d_buf, 0.5); + TEST_CYCLE() cv::gpu::GaussianBlur(d_src, dst, cv::Size(ksize, ksize), d_buf, 0.5); - TEST_CYCLE() - { - cv::gpu::GaussianBlur(d_src, d_dst, cv::Size(ksize, ksize), d_buf, 0.5); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::GaussianBlur(src, dst, cv::Size(ksize, ksize), 0.5); - - TEST_CYCLE() - { - cv::GaussianBlur(src, dst, cv::Size(ksize, ksize), 0.5); - } + TEST_CYCLE() cv::GaussianBlur(src, dst, cv::Size(ksize, ksize), 0.5); CPU_SANITY_CHECK(dst); } @@ -188,37 +149,27 @@ PERF_TEST_P(Sz_Type_KernelSz, Filters_Laplacian, Combine(GPU_TYPICAL_MAT_SIZES, { declare.time(20.0); - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); - int ksize = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); + const int ksize = GET_PARAM(2); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::Laplacian(d_src, d_dst, -1, ksize); + TEST_CYCLE() cv::gpu::Laplacian(d_src, dst, -1, ksize); - TEST_CYCLE() - { - cv::gpu::Laplacian(d_src, d_dst, -1, ksize); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::Laplacian(src, dst, -1, ksize); - - TEST_CYCLE() - { - cv::Laplacian(src, dst, -1, ksize); - } + TEST_CYCLE() cv::Laplacian(src, dst, -1, ksize); CPU_SANITY_CHECK(dst); } @@ -231,39 +182,29 @@ PERF_TEST_P(Sz_Type, Filters_Erode, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC { declare.time(20.0); - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); + const cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; cv::gpu::GpuMat d_buf; - cv::gpu::erode(d_src, d_dst, ker, d_buf); + TEST_CYCLE() cv::gpu::erode(d_src, dst, ker, d_buf); - TEST_CYCLE() - { - cv::gpu::erode(d_src, d_dst, ker, d_buf); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::erode(src, dst, ker); - - TEST_CYCLE() - { - cv::erode(src, dst, ker); - } + TEST_CYCLE() cv::erode(src, dst, ker); CPU_SANITY_CHECK(dst); } @@ -276,39 +217,29 @@ PERF_TEST_P(Sz_Type, Filters_Dilate, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U { declare.time(20.0); - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); + const cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; cv::gpu::GpuMat d_buf; - cv::gpu::dilate(d_src, d_dst, ker, d_buf); + TEST_CYCLE() cv::gpu::dilate(d_src, dst, ker, d_buf); - TEST_CYCLE() - { - cv::gpu::dilate(d_src, d_dst, ker, d_buf); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::dilate(src, dst, ker); - - TEST_CYCLE() - { - cv::dilate(src, dst, ker); - } + TEST_CYCLE() cv::dilate(src, dst, ker); CPU_SANITY_CHECK(dst); } @@ -326,41 +257,31 @@ PERF_TEST_P(Sz_Type_Op, Filters_MorphologyEx, Combine(GPU_TYPICAL_MAT_SIZES, Val { declare.time(20.0); - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); - int morphOp = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); + const int morphOp = GET_PARAM(2); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); + const cv::Mat ker = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; cv::gpu::GpuMat d_buf1; cv::gpu::GpuMat d_buf2; - cv::gpu::morphologyEx(d_src, d_dst, morphOp, ker, d_buf1, d_buf2); + TEST_CYCLE() cv::gpu::morphologyEx(d_src, dst, morphOp, ker, d_buf1, d_buf2); - TEST_CYCLE() - { - cv::gpu::morphologyEx(d_src, d_dst, morphOp, ker, d_buf1, d_buf2); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::morphologyEx(src, dst, morphOp, ker); - - TEST_CYCLE() - { - cv::morphologyEx(src, dst, morphOp, ker); - } + TEST_CYCLE() cv::morphologyEx(src, dst, morphOp, ker); CPU_SANITY_CHECK(dst); } @@ -373,43 +294,31 @@ PERF_TEST_P(Sz_Type_KernelSz, Filters_Filter2D, Combine(GPU_TYPICAL_MAT_SIZES, V { declare.time(20.0); - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); - int ksize = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); + const int ksize = GET_PARAM(2); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); cv::Mat kernel(ksize, ksize, CV_32FC1); - fillRandom(kernel, 0.0, 1.0); + declare.in(kernel, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::filter2D(d_src, d_dst, -1, kernel); + TEST_CYCLE() cv::gpu::filter2D(d_src, dst, -1, kernel); - TEST_CYCLE() - { - cv::gpu::filter2D(d_src, d_dst, -1, kernel); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::filter2D(src, dst, -1, kernel); - - TEST_CYCLE() - { - cv::filter2D(src, dst, -1, kernel); - } + TEST_CYCLE() cv::filter2D(src, dst, -1, kernel); CPU_SANITY_CHECK(dst); } } - -} // namespace diff --git a/modules/gpu/perf/perf_imgproc.cpp b/modules/gpu/perf/perf_imgproc.cpp index e3d488ec94..62915c85ce 100644 --- a/modules/gpu/perf/perf_imgproc.cpp +++ b/modules/gpu/perf/perf_imgproc.cpp @@ -2,13 +2,12 @@ using namespace std; using namespace testing; - -namespace { +using namespace perf; ////////////////////////////////////////////////////////////////////// // Remap -enum{HALF_SIZE=0, UPSIDE_DOWN, REFLECTION_X, REFLECTION_BOTH}; +enum { HALF_SIZE=0, UPSIDE_DOWN, REFLECTION_X, REFLECTION_BOTH }; CV_ENUM(RemapMode, HALF_SIZE, UPSIDE_DOWN, REFLECTION_X, REFLECTION_BOTH); #define ALL_REMAP_MODES ValuesIn(RemapMode::all()) @@ -51,59 +50,50 @@ void generateMap(cv::Mat& map_x, cv::Mat& map_y, int remapMode) DEF_PARAM_TEST(Sz_Depth_Cn_Inter_Border_Mode, cv::Size, MatDepth, MatCn, Interpolation, BorderMode, RemapMode); -PERF_TEST_P(Sz_Depth_Cn_Inter_Border_Mode, ImgProc_Remap, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - GPU_CHANNELS_1_3_4, - Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), - ALL_BORDER_MODES, - ALL_REMAP_MODES)) +PERF_TEST_P(Sz_Depth_Cn_Inter_Border_Mode, ImgProc_Remap, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4, + Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), + ALL_BORDER_MODES, + ALL_REMAP_MODES)) { declare.time(20.0); - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); - int interpolation = GET_PARAM(3); - int borderMode = GET_PARAM(4); - int remapMode = GET_PARAM(5); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); + const int interpolation = GET_PARAM(3); + const int borderMode = GET_PARAM(4); + const int remapMode = GET_PARAM(5); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); cv::Mat xmap(size, CV_32FC1); cv::Mat ymap(size, CV_32FC1); - generateMap(xmap, ymap, remapMode); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_xmap(xmap); - cv::gpu::GpuMat d_ymap(ymap); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_xmap(xmap); + const cv::gpu::GpuMat d_ymap(ymap); + cv::gpu::GpuMat dst; - cv::gpu::remap(d_src, d_dst, d_xmap, d_ymap, interpolation, borderMode); + TEST_CYCLE() cv::gpu::remap(d_src, dst, d_xmap, d_ymap, interpolation, borderMode); - TEST_CYCLE() - { - cv::gpu::remap(d_src, d_dst, d_xmap, d_ymap, interpolation, borderMode); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::remap(src, dst, xmap, ymap, interpolation, borderMode); + TEST_CYCLE() cv::remap(src, dst, xmap, ymap, interpolation, borderMode); - TEST_CYCLE() - { - cv::remap(src, dst, xmap, ymap, interpolation, borderMode); - } + CPU_SANITY_CHECK(dst); } } @@ -112,50 +102,42 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Border_Mode, ImgProc_Remap, Combine( DEF_PARAM_TEST(Sz_Depth_Cn_Inter_Scale, cv::Size, MatDepth, MatCn, Interpolation, double); -PERF_TEST_P(Sz_Depth_Cn_Inter_Scale, ImgProc_Resize, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - GPU_CHANNELS_1_3_4, - ALL_INTERPOLATIONS, - Values(0.5, 0.3, 2.0))) +PERF_TEST_P(Sz_Depth_Cn_Inter_Scale, ImgProc_Resize, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4, + ALL_INTERPOLATIONS, + Values(0.5, 0.3, 2.0))) { declare.time(20.0); - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); - int interpolation = GET_PARAM(3); - double f = GET_PARAM(4); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); + const int interpolation = GET_PARAM(3); + const double f = GET_PARAM(4); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); + TEST_CYCLE() cv::gpu::resize(d_src, dst, cv::Size(), f, f, interpolation); - TEST_CYCLE() - { - cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::resize(src, dst, cv::Size(), f, f, interpolation); + TEST_CYCLE() cv::resize(src, dst, cv::Size(), f, f, interpolation); - TEST_CYCLE() - { - cv::resize(src, dst, cv::Size(), f, f, interpolation); - } + CPU_SANITY_CHECK(dst); } } @@ -164,49 +146,41 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Scale, ImgProc_Resize, Combine( DEF_PARAM_TEST(Sz_Depth_Cn_Scale, cv::Size, MatDepth, MatCn, double); -PERF_TEST_P(Sz_Depth_Cn_Scale, ImgProc_ResizeArea, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - GPU_CHANNELS_1_3_4, - Values(0.2, 0.1, 0.05))) +PERF_TEST_P(Sz_Depth_Cn_Scale, ImgProc_ResizeArea, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4, + Values(0.2, 0.1, 0.05))) { declare.time(1.0); - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); - int interpolation = cv::INTER_AREA; - double f = GET_PARAM(3); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); + const int interpolation = cv::INTER_AREA; + const double f = GET_PARAM(3); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); + TEST_CYCLE() cv::gpu::resize(d_src, dst, cv::Size(), f, f, interpolation); - TEST_CYCLE() - { - cv::gpu::resize(d_src, d_dst, cv::Size(), f, f, interpolation); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::resize(src, dst, cv::Size(), f, f, interpolation); + TEST_CYCLE() cv::resize(src, dst, cv::Size(), f, f, interpolation); - TEST_CYCLE() - { - cv::resize(src, dst, cv::Size(), f, f, interpolation); - } + CPU_SANITY_CHECK(dst); } } @@ -215,111 +189,98 @@ PERF_TEST_P(Sz_Depth_Cn_Scale, ImgProc_ResizeArea, Combine( DEF_PARAM_TEST(Sz_Depth_Cn_Inter_Border, cv::Size, MatDepth, MatCn, Interpolation, BorderMode); -PERF_TEST_P(Sz_Depth_Cn_Inter_Border, ImgProc_WarpAffine, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - GPU_CHANNELS_1_3_4, - Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), - ALL_BORDER_MODES)) +PERF_TEST_P(Sz_Depth_Cn_Inter_Border, ImgProc_WarpAffine, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4, + Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), + ALL_BORDER_MODES)) { declare.time(20.0); - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); - int interpolation = GET_PARAM(3); - int borderMode = GET_PARAM(4); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); + const int interpolation = GET_PARAM(3); + const int borderMode = GET_PARAM(4); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); const double aplha = CV_PI / 4; - double mat[2][3] = { {std::cos(aplha), -std::sin(aplha), src.cols / 2}, - {std::sin(aplha), std::cos(aplha), 0}}; - cv::Mat M(2, 3, CV_64F, (void*) mat); + const double mat[2 * 3] = + { + std::cos(aplha), -std::sin(aplha), src.cols / 2, + std::sin(aplha), std::cos(aplha), 0 + }; + const cv::Mat M(2, 3, CV_64F, (void*) mat); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::warpAffine(d_src, d_dst, M, size, interpolation, borderMode); + TEST_CYCLE() cv::gpu::warpAffine(d_src, dst, M, size, interpolation, borderMode); - TEST_CYCLE() - { - cv::gpu::warpAffine(d_src, d_dst, M, size, interpolation, borderMode); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::warpAffine(src, dst, M, size, interpolation, borderMode); + TEST_CYCLE() cv::warpAffine(src, dst, M, size, interpolation, borderMode); - TEST_CYCLE() - { - cv::warpAffine(src, dst, M, size, interpolation, borderMode); - } + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // WarpPerspective -PERF_TEST_P(Sz_Depth_Cn_Inter_Border, ImgProc_WarpPerspective, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - GPU_CHANNELS_1_3_4, - Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), - ALL_BORDER_MODES)) +PERF_TEST_P(Sz_Depth_Cn_Inter_Border, ImgProc_WarpPerspective, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4, + Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), + ALL_BORDER_MODES)) { declare.time(20.0); - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); - int interpolation = GET_PARAM(3); - int borderMode = GET_PARAM(4); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); + const int interpolation = GET_PARAM(3); + const int borderMode = GET_PARAM(4); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); const double aplha = CV_PI / 4; double mat[3][3] = { {std::cos(aplha), -std::sin(aplha), src.cols / 2}, {std::sin(aplha), std::cos(aplha), 0}, {0.0, 0.0, 1.0}}; - cv::Mat M(3, 3, CV_64F, (void*) mat); + const cv::Mat M(3, 3, CV_64F, (void*) mat); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::warpPerspective(d_src, d_dst, M, size, interpolation, borderMode); + TEST_CYCLE() cv::gpu::warpPerspective(d_src, dst, M, size, interpolation, borderMode); - TEST_CYCLE() - { - cv::gpu::warpPerspective(d_src, d_dst, M, size, interpolation, borderMode); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::warpPerspective(src, dst, M, size, interpolation, borderMode); + TEST_CYCLE() cv::warpPerspective(src, dst, M, size, interpolation, borderMode); - TEST_CYCLE() - { - cv::warpPerspective(src, dst, M, size, interpolation, borderMode); - } + CPU_SANITY_CHECK(dst); } } @@ -328,46 +289,38 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Border, ImgProc_WarpPerspective, Combine( DEF_PARAM_TEST(Sz_Depth_Cn_Border, cv::Size, MatDepth, MatCn, BorderMode); -PERF_TEST_P(Sz_Depth_Cn_Border, ImgProc_CopyMakeBorder, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - GPU_CHANNELS_1_3_4, - ALL_BORDER_MODES)) +PERF_TEST_P(Sz_Depth_Cn_Border, ImgProc_CopyMakeBorder, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4, + ALL_BORDER_MODES)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); - int borderMode = GET_PARAM(3); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); + const int borderMode = GET_PARAM(3); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::copyMakeBorder(d_src, d_dst, 5, 5, 5, 5, borderMode); + TEST_CYCLE() cv::gpu::copyMakeBorder(d_src, dst, 5, 5, 5, 5, borderMode); - TEST_CYCLE() - { - cv::gpu::copyMakeBorder(d_src, d_dst, 5, 5, 5, 5, borderMode); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::copyMakeBorder(src, dst, 5, 5, 5, 5, borderMode); + TEST_CYCLE() cv::copyMakeBorder(src, dst, 5, 5, 5, 5, borderMode); - TEST_CYCLE() - { - cv::copyMakeBorder(src, dst, 5, 5, 5, 5, borderMode); - } + CPU_SANITY_CHECK(dst); } } @@ -379,168 +332,145 @@ CV_ENUM(ThreshOp, cv::THRESH_BINARY, cv::THRESH_BINARY_INV, cv::THRESH_TRUNC, cv DEF_PARAM_TEST(Sz_Depth_Op, cv::Size, MatDepth, ThreshOp); -PERF_TEST_P(Sz_Depth_Op, ImgProc_Threshold, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F, CV_64F), - ALL_THRESH_OPS)) +PERF_TEST_P(Sz_Depth_Op, ImgProc_Threshold, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F), + ALL_THRESH_OPS)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int threshOp = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int threshOp = GET_PARAM(2); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::threshold(d_src, d_dst, 100.0, 255.0, threshOp); + TEST_CYCLE() cv::gpu::threshold(d_src, dst, 100.0, 255.0, threshOp); - TEST_CYCLE() - { - cv::gpu::threshold(d_src, d_dst, 100.0, 255.0, threshOp); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::threshold(src, dst, 100.0, 255.0, threshOp); + TEST_CYCLE() cv::threshold(src, dst, 100.0, 255.0, threshOp); - TEST_CYCLE() - { - cv::threshold(src, dst, 100.0, 255.0, threshOp); - } + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // Integral -PERF_TEST_P(Sz, ImgProc_Integral, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, ImgProc_Integral, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); cv::Mat src(size, CV_8UC1); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; cv::gpu::GpuMat d_buf; - cv::gpu::integralBuffered(d_src, d_dst, d_buf); + TEST_CYCLE() cv::gpu::integralBuffered(d_src, dst, d_buf); - TEST_CYCLE() - { - cv::gpu::integralBuffered(d_src, d_dst, d_buf); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::integral(src, dst); + TEST_CYCLE() cv::integral(src, dst); - TEST_CYCLE() - { - cv::integral(src, dst); - } + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // IntegralSqr -PERF_TEST_P(Sz, ImgProc_IntegralSqr, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, ImgProc_IntegralSqr, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); cv::Mat src(size, CV_8UC1); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::sqrIntegral(d_src, d_dst); + TEST_CYCLE() cv::gpu::sqrIntegral(d_src, dst); - TEST_CYCLE() - { - cv::gpu::sqrIntegral(d_src, d_dst); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // HistEvenC1 -PERF_TEST_P(Sz_Depth, ImgProc_HistEvenC1, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_16S))) +PERF_TEST_P(Sz_Depth, ImgProc_HistEvenC1, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_16S))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, depth); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_hist; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; cv::gpu::GpuMat d_buf; - cv::gpu::histEven(d_src, d_hist, d_buf, 30, 0, 180); + TEST_CYCLE() cv::gpu::histEven(d_src, dst, d_buf, 30, 0, 180); - TEST_CYCLE() - { - cv::gpu::histEven(d_src, d_hist, d_buf, 30, 0, 180); - } - - GPU_SANITY_CHECK(d_hist); + GPU_SANITY_CHECK(dst); } else { - int hbins = 30; - float hranges[] = {0.0f, 180.0f}; - int histSize[] = {hbins}; + const int hbins = 30; + const float hranges[] = {0.0f, 180.0f}; + const int histSize[] = {hbins}; const float* ranges[] = {hranges}; - int channels[] = {0}; + const int channels[] = {0}; - cv::Mat hist; + cv::Mat dst; - cv::calcHist(&src, 1, channels, cv::Mat(), hist, 1, histSize, ranges); + TEST_CYCLE() cv::calcHist(&src, 1, channels, cv::Mat(), dst, 1, histSize, ranges); - TEST_CYCLE() - { - cv::calcHist(&src, 1, channels, cv::Mat(), hist, 1, histSize, ranges); - } + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // HistEvenC4 -PERF_TEST_P(Sz_Depth, ImgProc_HistEvenC4, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_16S))) +PERF_TEST_P(Sz_Depth, ImgProc_HistEvenC4, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_16S))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); cv::Mat src(size, CV_MAKE_TYPE(depth, 4)); - fillRandom(src); + declare.in(src, WARMUP_RNG); int histSize[] = {30, 30, 30, 30}; int lowerLevel[] = {0, 0, 0, 0}; @@ -548,121 +478,109 @@ PERF_TEST_P(Sz_Depth, ImgProc_HistEvenC4, Combine(GPU_TYPICAL_MAT_SIZES, Values( if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_hist[4]; - cv::gpu::GpuMat d_buf, d_hist0; + cv::gpu::GpuMat d_buf; - cv::gpu::histEven(d_src, d_hist, d_buf, histSize, lowerLevel, upperLevel); + TEST_CYCLE() cv::gpu::histEven(d_src, d_hist, d_buf, histSize, lowerLevel, upperLevel); - TEST_CYCLE() - { - cv::gpu::histEven(d_src, d_hist, d_buf, histSize, lowerLevel, upperLevel); - } - - GPU_SANITY_CHECK(d_hist0); + cv::Mat cpu_hist0, cpu_hist1, cpu_hist2, cpu_hist3; + d_hist[0].download(cpu_hist0); + d_hist[1].download(cpu_hist1); + d_hist[2].download(cpu_hist2); + d_hist[3].download(cpu_hist3); + SANITY_CHECK(cpu_hist0); + SANITY_CHECK(cpu_hist1); + SANITY_CHECK(cpu_hist2); + SANITY_CHECK(cpu_hist3); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // CalcHist -PERF_TEST_P(Sz, ImgProc_CalcHist, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, ImgProc_CalcHist, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); cv::Mat src(size, CV_8UC1); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_hist; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::calcHist(d_src, d_hist); + TEST_CYCLE() cv::gpu::calcHist(d_src, dst); - TEST_CYCLE() - { - cv::gpu::calcHist(d_src, d_hist); - } - - GPU_SANITY_CHECK(d_hist); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // EqualizeHist -PERF_TEST_P(Sz, ImgProc_EqualizeHist, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, ImgProc_EqualizeHist, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); cv::Mat src(size, CV_8UC1); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; cv::gpu::GpuMat d_hist; cv::gpu::GpuMat d_buf; - cv::gpu::equalizeHist(d_src, d_dst, d_hist, d_buf); + TEST_CYCLE() cv::gpu::equalizeHist(d_src, dst, d_hist, d_buf); - TEST_CYCLE() - { - cv::gpu::equalizeHist(d_src, d_dst, d_hist, d_buf); - } - - GPU_SANITY_CHECK(d_hist); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::equalizeHist(src, dst); + TEST_CYCLE() cv::equalizeHist(src, dst); - TEST_CYCLE() - { - cv::equalizeHist(src, dst); - } + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // ColumnSum -PERF_TEST_P(Sz, ImgProc_ColumnSum, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, ImgProc_ColumnSum, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); cv::Mat src(size, CV_32FC1); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::columnSum(d_src, d_dst); + TEST_CYCLE() cv::gpu::columnSum(d_src, dst); - TEST_CYCLE() - { - cv::gpu::columnSum(d_src, d_dst); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } @@ -671,43 +589,38 @@ PERF_TEST_P(Sz, ImgProc_ColumnSum, GPU_TYPICAL_MAT_SIZES) DEF_PARAM_TEST(Image_AppertureSz_L2gradient, string, int, bool); -PERF_TEST_P(Image_AppertureSz_L2gradient, ImgProc_Canny, Combine( - Values("perf/800x600.png", "perf/1280x1024.png", "perf/1680x1050.png"), - Values(3, 5), - Bool())) +PERF_TEST_P(Image_AppertureSz_L2gradient, ImgProc_Canny, + Combine(Values("perf/800x600.png", "perf/1280x1024.png", "perf/1680x1050.png"), + Values(3, 5), + Bool())) { - string fileName = GET_PARAM(0); - int apperture_size = GET_PARAM(1); - bool useL2gradient = GET_PARAM(2); + const string fileName = GET_PARAM(0); + const int apperture_size = GET_PARAM(1); + const bool useL2gradient = GET_PARAM(2); - cv::Mat image = readImage(fileName, cv::IMREAD_GRAYSCALE); + const cv::Mat image = readImage(fileName, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(image.empty()); + const double low_thresh = 50.0; + const double high_thresh = 100.0; + if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_image(image); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_image(image); + cv::gpu::GpuMat dst; cv::gpu::CannyBuf d_buf; - cv::gpu::Canny(d_image, d_buf, d_dst, 50.0, 100.0, apperture_size, useL2gradient); + TEST_CYCLE() cv::gpu::Canny(d_image, d_buf, dst, low_thresh, high_thresh, apperture_size, useL2gradient); - TEST_CYCLE() - { - cv::gpu::Canny(d_image, d_buf, d_dst, 50.0, 100.0, apperture_size, useL2gradient); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::Canny(image, dst, 50.0, 100.0, apperture_size, useL2gradient); + TEST_CYCLE() cv::Canny(image, dst, low_thresh, high_thresh, apperture_size, useL2gradient); - TEST_CYCLE() - { - cv::Canny(image, dst, 50.0, 100.0, apperture_size, useL2gradient); - } + CPU_SANITY_CHECK(dst); } } @@ -716,148 +629,142 @@ PERF_TEST_P(Image_AppertureSz_L2gradient, ImgProc_Canny, Combine( DEF_PARAM_TEST_1(Image, string); -PERF_TEST_P(Image, ImgProc_MeanShiftFiltering, Values("gpu/meanshift/cones.png")) +PERF_TEST_P(Image, ImgProc_MeanShiftFiltering, + Values("gpu/meanshift/cones.png")) { declare.time(15.0); - cv::Mat img = readImage(GetParam()); + const cv::Mat img = readImage(GetParam()); ASSERT_FALSE(img.empty()); cv::Mat rgba; cv::cvtColor(img, rgba, cv::COLOR_BGR2BGRA); + const int sp = 50; + const int sr = 50; + if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(rgba); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(rgba); + cv::gpu::GpuMat dst; - cv::gpu::meanShiftFiltering(d_src, d_dst, 50, 50); + TEST_CYCLE() cv::gpu::meanShiftFiltering(d_src, dst, sp, sr); - TEST_CYCLE() - { - cv::gpu::meanShiftFiltering(d_src, d_dst, 50, 50); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::pyrMeanShiftFiltering(img, dst, 50, 50); + TEST_CYCLE() cv::pyrMeanShiftFiltering(img, dst, sp, sr); - TEST_CYCLE() - { - cv::pyrMeanShiftFiltering(img, dst, 50, 50); - } + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // MeanShiftProc -PERF_TEST_P(Image, ImgProc_MeanShiftProc, Values("gpu/meanshift/cones.png")) +PERF_TEST_P(Image, ImgProc_MeanShiftProc, + Values("gpu/meanshift/cones.png")) { declare.time(5.0); - cv::Mat img = readImage(GetParam()); + const cv::Mat img = readImage(GetParam()); ASSERT_FALSE(img.empty()); cv::Mat rgba; cv::cvtColor(img, rgba, cv::COLOR_BGR2BGRA); + const int sp = 50; + const int sr = 50; + if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(rgba); - cv::gpu::GpuMat d_dstr; - cv::gpu::GpuMat d_dstsp; + const cv::gpu::GpuMat d_src(rgba); + cv::gpu::GpuMat dstr; + cv::gpu::GpuMat dstsp; - cv::gpu::meanShiftProc(d_src, d_dstr, d_dstsp, 50, 50); + TEST_CYCLE() cv::gpu::meanShiftProc(d_src, dstr, dstsp, sp, sr); - TEST_CYCLE() - { - cv::gpu::meanShiftProc(d_src, d_dstr, d_dstsp, 50, 50); - } - - GPU_SANITY_CHECK(d_dstr); + GPU_SANITY_CHECK(dstr); + GPU_SANITY_CHECK(dstsp); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // MeanShiftSegmentation -PERF_TEST_P(Image, ImgProc_MeanShiftSegmentation, Values("gpu/meanshift/cones.png")) +PERF_TEST_P(Image, ImgProc_MeanShiftSegmentation, + Values("gpu/meanshift/cones.png")) { declare.time(5.0); - cv::Mat img = readImage(GetParam()); + const cv::Mat img = readImage(GetParam()); ASSERT_FALSE(img.empty()); cv::Mat rgba; cv::cvtColor(img, rgba, cv::COLOR_BGR2BGRA); - cv::Mat dst; + const int sp = 10; + const int sr = 10; + const int minsize = 20; if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(rgba); + const cv::gpu::GpuMat d_src(rgba); + cv::Mat dst; - cv::gpu::meanShiftSegmentation(d_src, dst, 10, 10, 20); - - TEST_CYCLE() - { - cv::gpu::meanShiftSegmentation(d_src, dst, 10, 10, 20); - } + TEST_CYCLE() cv::gpu::meanShiftSegmentation(d_src, dst, sp, sr, minsize); GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // BlendLinear -PERF_TEST_P(Sz_Depth_Cn, ImgProc_BlendLinear, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_32F), GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, ImgProc_BlendLinear, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_32F), + GPU_CHANNELS_1_3_4)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat img1(size, type); - fillRandom(img1); - cv::Mat img2(size, type); - fillRandom(img2); + declare.in(img1, img2, WARMUP_RNG); + + const cv::Mat weights1(size, CV_32FC1, cv::Scalar::all(0.5)); + const cv::Mat weights2(size, CV_32FC1, cv::Scalar::all(0.5)); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_img1(img1); - cv::gpu::GpuMat d_img2(img2); - cv::gpu::GpuMat d_weights1(size, CV_32FC1, cv::Scalar::all(0.5)); - cv::gpu::GpuMat d_weights2(size, CV_32FC1, cv::Scalar::all(0.5)); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_img1(img1); + const cv::gpu::GpuMat d_img2(img2); + const cv::gpu::GpuMat d_weights1(weights1); + const cv::gpu::GpuMat d_weights2(weights2); + cv::gpu::GpuMat dst; - cv::gpu::blendLinear(d_img1, d_img2, d_weights1, d_weights2, d_dst); + TEST_CYCLE() cv::gpu::blendLinear(d_img1, d_img2, d_weights1, d_weights2, dst); - TEST_CYCLE() - { - cv::gpu::blendLinear(d_img1, d_img2, d_weights1, d_weights2, d_dst); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } @@ -866,19 +773,20 @@ PERF_TEST_P(Sz_Depth_Cn, ImgProc_BlendLinear, Combine(GPU_TYPICAL_MAT_SIZES, Val DEF_PARAM_TEST(Sz_KernelSz_Ccorr, cv::Size, int, bool); -PERF_TEST_P(Sz_KernelSz_Ccorr, ImgProc_Convolve, Combine(GPU_TYPICAL_MAT_SIZES, Values(17, 27, 32, 64), Bool())) +PERF_TEST_P(Sz_KernelSz_Ccorr, ImgProc_Convolve, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(17, 27, 32, 64), + Bool())) { declare.time(10.0); - cv::Size size = GET_PARAM(0); - int templ_size = GET_PARAM(1); - bool ccorr = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int templ_size = GET_PARAM(1); + const bool ccorr = GET_PARAM(2); - cv::Mat image(size, CV_32FC1); - image.setTo(1.0); - - cv::Mat templ(templ_size, templ_size, CV_32FC1); - templ.setTo(1.0); + const cv::Mat image(size, CV_32FC1); + const cv::Mat templ(templ_size, templ_size, CV_32FC1); + declare.in(image, templ, WARMUP_RNG); if (PERF_RUN_GPU()) { @@ -888,30 +796,21 @@ PERF_TEST_P(Sz_KernelSz_Ccorr, ImgProc_Convolve, Combine(GPU_TYPICAL_MAT_SIZES, cv::gpu::GpuMat d_templ = cv::gpu::createContinuous(templ_size, templ_size, CV_32FC1); d_templ.upload(templ); - cv::gpu::GpuMat d_dst; + cv::gpu::GpuMat dst; cv::gpu::ConvolveBuf d_buf; - cv::gpu::convolve(d_image, d_templ, d_dst, ccorr, d_buf); + TEST_CYCLE() cv::gpu::convolve(d_image, d_templ, dst, ccorr, d_buf); - TEST_CYCLE() - { - cv::gpu::convolve(d_image, d_templ, d_dst, ccorr, d_buf); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - ASSERT_FALSE(ccorr); + if (ccorr) + FAIL_NO_CPU(); cv::Mat dst; - cv::filter2D(image, dst, image.depth(), templ); - - TEST_CYCLE() - { - cv::filter2D(image, dst, image.depth(), templ); - } + TEST_CYCLE() cv::filter2D(image, dst, image.depth(), templ); CPU_SANITY_CHECK(dst); } @@ -925,48 +824,36 @@ CV_ENUM(TemplateMethod, cv::TM_SQDIFF, cv::TM_SQDIFF_NORMED, cv::TM_CCORR, cv::T DEF_PARAM_TEST(Sz_TemplateSz_Cn_Method, cv::Size, cv::Size, MatCn, TemplateMethod); -PERF_TEST_P(Sz_TemplateSz_Cn_Method, ImgProc_MatchTemplate8U, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(cv::Size(5, 5), cv::Size(16, 16), cv::Size(30, 30)), - GPU_CHANNELS_1_3_4, - ALL_TEMPLATE_METHODS)) +PERF_TEST_P(Sz_TemplateSz_Cn_Method, ImgProc_MatchTemplate8U, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(cv::Size(5, 5), cv::Size(16, 16), cv::Size(30, 30)), + GPU_CHANNELS_1_3_4, + ALL_TEMPLATE_METHODS)) { - cv::Size size = GET_PARAM(0); - cv::Size templ_size = GET_PARAM(1); - int cn = GET_PARAM(2); - int method = GET_PARAM(3); + const cv::Size size = GET_PARAM(0); + const cv::Size templ_size = GET_PARAM(1); + const int cn = GET_PARAM(2); + const int method = GET_PARAM(3); cv::Mat image(size, CV_MAKE_TYPE(CV_8U, cn)); - fillRandom(image); - cv::Mat templ(templ_size, CV_MAKE_TYPE(CV_8U, cn)); - fillRandom(templ); + declare.in(image, templ, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_image(image); - cv::gpu::GpuMat d_templ(templ); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_image(image); + const cv::gpu::GpuMat d_templ(templ); + cv::gpu::GpuMat dst; - cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); + TEST_CYCLE() cv::gpu::matchTemplate(d_image, d_templ, dst, method); - TEST_CYCLE() - { - cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst, 1e-5, ERROR_RELATIVE); } else { cv::Mat dst; - cv::matchTemplate(image, templ, dst, method); - - TEST_CYCLE() - { - cv::matchTemplate(image, templ, dst, method); - } + TEST_CYCLE() cv::matchTemplate(image, templ, dst, method); CPU_SANITY_CHECK(dst); } @@ -975,48 +862,36 @@ PERF_TEST_P(Sz_TemplateSz_Cn_Method, ImgProc_MatchTemplate8U, Combine( //////////////////////////////////////////////////////////////////////////////// // MatchTemplate32F -PERF_TEST_P(Sz_TemplateSz_Cn_Method, ImgProc_MatchTemplate32F, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(cv::Size(5, 5), cv::Size(16, 16), cv::Size(30, 30)), - GPU_CHANNELS_1_3_4, - Values(TemplateMethod(cv::TM_SQDIFF), TemplateMethod(cv::TM_CCORR)))) +PERF_TEST_P(Sz_TemplateSz_Cn_Method, ImgProc_MatchTemplate32F, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(cv::Size(5, 5), cv::Size(16, 16), cv::Size(30, 30)), + GPU_CHANNELS_1_3_4, + Values(TemplateMethod(cv::TM_SQDIFF), TemplateMethod(cv::TM_CCORR)))) { - cv::Size size = GET_PARAM(0); - cv::Size templ_size = GET_PARAM(1); - int cn = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const cv::Size templ_size = GET_PARAM(1); + const int cn = GET_PARAM(2); int method = GET_PARAM(3); cv::Mat image(size, CV_MAKE_TYPE(CV_32F, cn)); - fillRandom(image); - cv::Mat templ(templ_size, CV_MAKE_TYPE(CV_32F, cn)); - fillRandom(templ); + declare.in(image, templ, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_image(image); - cv::gpu::GpuMat d_templ(templ); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_image(image); + const cv::gpu::GpuMat d_templ(templ); + cv::gpu::GpuMat dst; - cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); + TEST_CYCLE() cv::gpu::matchTemplate(d_image, d_templ, dst, method); - TEST_CYCLE() - { - cv::gpu::matchTemplate(d_image, d_templ, d_dst, method); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE); } else { cv::Mat dst; - cv::matchTemplate(image, templ, dst, method); - - TEST_CYCLE() - { - cv::matchTemplate(image, templ, dst, method); - } + TEST_CYCLE() cv::matchTemplate(image, templ, dst, method); CPU_SANITY_CHECK(dst); } @@ -1029,44 +904,32 @@ CV_FLAGS(DftFlags, 0, cv::DFT_INVERSE, cv::DFT_SCALE, cv::DFT_ROWS, cv::DFT_COMP DEF_PARAM_TEST(Sz_Flags, cv::Size, DftFlags); -PERF_TEST_P(Sz_Flags, ImgProc_MulSpectrums, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(0, DftFlags(cv::DFT_ROWS)))) +PERF_TEST_P(Sz_Flags, ImgProc_MulSpectrums, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(0, DftFlags(cv::DFT_ROWS)))) { - cv::Size size = GET_PARAM(0); - int flag = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int flag = GET_PARAM(1); cv::Mat a(size, CV_32FC2); - fillRandom(a, 0, 100); - cv::Mat b(size, CV_32FC2); - fillRandom(b, 0, 100); + declare.in(a, b, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_a(a); - cv::gpu::GpuMat d_b(b); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_a(a); + const cv::gpu::GpuMat d_b(b); + cv::gpu::GpuMat dst; - cv::gpu::mulSpectrums(d_a, d_b, d_dst, flag); + TEST_CYCLE() cv::gpu::mulSpectrums(d_a, d_b, dst, flag); - TEST_CYCLE() - { - cv::gpu::mulSpectrums(d_a, d_b, d_dst, flag); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::mulSpectrums(a, b, dst, flag); - - TEST_CYCLE() - { - cv::mulSpectrums(a, b, dst, flag); - } + TEST_CYCLE() cv::mulSpectrums(a, b, dst, flag); CPU_SANITY_CHECK(dst); } @@ -1075,78 +938,62 @@ PERF_TEST_P(Sz_Flags, ImgProc_MulSpectrums, Combine( ////////////////////////////////////////////////////////////////////// // MulAndScaleSpectrums -PERF_TEST_P(Sz, ImgProc_MulAndScaleSpectrums, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, ImgProc_MulAndScaleSpectrums, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); - float scale = 1.f / size.area(); + const float scale = 1.f / size.area(); cv::Mat src1(size, CV_32FC2); - fillRandom(src1, 0, 100); - cv::Mat src2(size, CV_32FC2); - fillRandom(src2, 0, 100); + declare.in(src1,src2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src1(src1); - cv::gpu::GpuMat d_src2(src2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src1(src1); + const cv::gpu::GpuMat d_src2(src2); + cv::gpu::GpuMat dst; - cv::gpu::mulAndScaleSpectrums(d_src1, d_src2, d_dst, cv::DFT_ROWS, scale, false); + TEST_CYCLE() cv::gpu::mulAndScaleSpectrums(d_src1, d_src2, dst, cv::DFT_ROWS, scale, false); - TEST_CYCLE() - { - cv::gpu::mulAndScaleSpectrums(d_src1, d_src2, d_dst, cv::DFT_ROWS, scale, false); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // Dft -PERF_TEST_P(Sz_Flags, ImgProc_Dft, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(0, DftFlags(cv::DFT_ROWS), DftFlags(cv::DFT_INVERSE)))) +PERF_TEST_P(Sz_Flags, ImgProc_Dft, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(0, DftFlags(cv::DFT_ROWS), DftFlags(cv::DFT_INVERSE)))) { declare.time(10.0); - cv::Size size = GET_PARAM(0); - int flag = GET_PARAM(1); + const cv::Size size = GET_PARAM(0); + const int flag = GET_PARAM(1); cv::Mat src(size, CV_32FC2); - fillRandom(src, 0, 100); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::dft(d_src, d_dst, size, flag); + TEST_CYCLE() cv::gpu::dft(d_src, dst, size, flag); - TEST_CYCLE() - { - cv::gpu::dft(d_src, d_dst, size, flag); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE); } else { cv::Mat dst; - cv::dft(src, dst, flag); - - TEST_CYCLE() - { - cv::dft(src, dst, flag); - } + TEST_CYCLE() cv::dft(src, dst, flag); CPU_SANITY_CHECK(dst); } @@ -1157,52 +1004,43 @@ PERF_TEST_P(Sz_Flags, ImgProc_Dft, Combine( DEF_PARAM_TEST(Image_Type_Border_BlockSz_ApertureSz, string, MatType, BorderMode, int, int); -PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, ImgProc_CornerHarris, Combine( - Values("gpu/stereobm/aloe-L.png"), - Values(CV_8UC1, CV_32FC1), - Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_REFLECT)), - Values(3, 5, 7), - Values(0, 3, 5, 7))) +PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, ImgProc_CornerHarris, + Combine(Values("gpu/stereobm/aloe-L.png"), + Values(CV_8UC1, CV_32FC1), + Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_REFLECT)), + Values(3, 5, 7), + Values(0, 3, 5, 7))) { - string fileName = GET_PARAM(0); - int type = GET_PARAM(1); - int borderMode = GET_PARAM(2); - int blockSize = GET_PARAM(3); - int apertureSize = GET_PARAM(4); + const string fileName = GET_PARAM(0); + const int type = GET_PARAM(1); + const int borderMode = GET_PARAM(2); + const int blockSize = GET_PARAM(3); + const int apertureSize = GET_PARAM(4); cv::Mat img = readImage(fileName, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); + img.convertTo(img, type, type == CV_32F ? 1.0 / 255.0 : 1.0); - double k = 0.5; + const double k = 0.5; if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_img(img); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat dst; cv::gpu::GpuMat d_Dx; cv::gpu::GpuMat d_Dy; cv::gpu::GpuMat d_buf; - cv::gpu::cornerHarris(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, k, borderMode); + TEST_CYCLE() cv::gpu::cornerHarris(d_img, dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, k, borderMode); - TEST_CYCLE() - { - cv::gpu::cornerHarris(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, k, borderMode); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::cornerHarris(img, dst, blockSize, apertureSize, k, borderMode); - - TEST_CYCLE() - { - cv::cornerHarris(img, dst, blockSize, apertureSize, k, borderMode); - } + TEST_CYCLE() cv::cornerHarris(img, dst, blockSize, apertureSize, k, borderMode); CPU_SANITY_CHECK(dst); } @@ -1211,18 +1049,18 @@ PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, ImgProc_CornerHarris, Combine( ////////////////////////////////////////////////////////////////////// // CornerMinEigenVal -PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, ImgProc_CornerMinEigenVal, Combine( - Values("gpu/stereobm/aloe-L.png"), - Values(CV_8UC1, CV_32FC1), - Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_REFLECT)), - Values(3, 5, 7), - Values(0, 3, 5, 7))) +PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, ImgProc_CornerMinEigenVal, + Combine(Values("gpu/stereobm/aloe-L.png"), + Values(CV_8UC1, CV_32FC1), + Values(BorderMode(cv::BORDER_REFLECT101), BorderMode(cv::BORDER_REPLICATE), BorderMode(cv::BORDER_REFLECT)), + Values(3, 5, 7), + Values(0, 3, 5, 7))) { - string fileName = GET_PARAM(0); - int type = GET_PARAM(1); - int borderMode = GET_PARAM(2); - int blockSize = GET_PARAM(3); - int apertureSize = GET_PARAM(4); + const string fileName = GET_PARAM(0); + const int type = GET_PARAM(1); + const int borderMode = GET_PARAM(2); + const int blockSize = GET_PARAM(3); + const int apertureSize = GET_PARAM(4); cv::Mat img = readImage(fileName, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); @@ -1231,31 +1069,21 @@ PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, ImgProc_CornerMinEigenVal, Com if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_img(img); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat dst; cv::gpu::GpuMat d_Dx; cv::gpu::GpuMat d_Dy; cv::gpu::GpuMat d_buf; - cv::gpu::cornerMinEigenVal(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, borderMode); + TEST_CYCLE() cv::gpu::cornerMinEigenVal(d_img, dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, borderMode); - TEST_CYCLE() - { - cv::gpu::cornerMinEigenVal(d_img, d_dst, d_Dx, d_Dy, d_buf, blockSize, apertureSize, borderMode); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::cornerMinEigenVal(img, dst, blockSize, apertureSize, borderMode); - - TEST_CYCLE() - { - cv::cornerMinEigenVal(img, dst, blockSize, apertureSize, borderMode); - } + TEST_CYCLE() cv::cornerMinEigenVal(img, dst, blockSize, apertureSize, borderMode); CPU_SANITY_CHECK(dst); } @@ -1264,95 +1092,82 @@ PERF_TEST_P(Image_Type_Border_BlockSz_ApertureSz, ImgProc_CornerMinEigenVal, Com ////////////////////////////////////////////////////////////////////// // BuildWarpPlaneMaps -PERF_TEST_P(Sz, ImgProc_BuildWarpPlaneMaps, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, ImgProc_BuildWarpPlaneMaps, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); - cv::Mat K = cv::Mat::eye(3, 3, CV_32FC1); - cv::Mat R = cv::Mat::ones(3, 3, CV_32FC1); - cv::Mat T = cv::Mat::zeros(1, 3, CV_32F); + const cv::Mat K = cv::Mat::eye(3, 3, CV_32FC1); + const cv::Mat R = cv::Mat::ones(3, 3, CV_32FC1); + const cv::Mat T = cv::Mat::zeros(1, 3, CV_32F); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_map_x; - cv::gpu::GpuMat d_map_y; + cv::gpu::GpuMat map_x; + cv::gpu::GpuMat map_y; - cv::gpu::buildWarpPlaneMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, T, 1.0, d_map_x, d_map_y); + TEST_CYCLE() cv::gpu::buildWarpPlaneMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, T, 1.0, map_x, map_y); - TEST_CYCLE() - { - cv::gpu::buildWarpPlaneMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, T, 1.0, d_map_x, d_map_y); - } - - GPU_SANITY_CHECK(d_map_x); - GPU_SANITY_CHECK(d_map_y); + GPU_SANITY_CHECK(map_x); + GPU_SANITY_CHECK(map_y); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // BuildWarpCylindricalMaps -PERF_TEST_P(Sz, ImgProc_BuildWarpCylindricalMaps, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, ImgProc_BuildWarpCylindricalMaps, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); - cv::Mat K = cv::Mat::eye(3, 3, CV_32FC1); - cv::Mat R = cv::Mat::ones(3, 3, CV_32FC1); + const cv::Mat K = cv::Mat::eye(3, 3, CV_32FC1); + const cv::Mat R = cv::Mat::ones(3, 3, CV_32FC1); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_map_x; - cv::gpu::GpuMat d_map_y; + cv::gpu::GpuMat map_x; + cv::gpu::GpuMat map_y; - cv::gpu::buildWarpCylindricalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); + TEST_CYCLE() cv::gpu::buildWarpCylindricalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, map_x, map_y); - TEST_CYCLE() - { - cv::gpu::buildWarpCylindricalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); - } - - GPU_SANITY_CHECK(d_map_x); - GPU_SANITY_CHECK(d_map_y); + GPU_SANITY_CHECK(map_x); + GPU_SANITY_CHECK(map_y); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // BuildWarpSphericalMaps -PERF_TEST_P(Sz, ImgProc_BuildWarpSphericalMaps, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, ImgProc_BuildWarpSphericalMaps, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); - cv::Mat K = cv::Mat::eye(3, 3, CV_32FC1); - cv::Mat R = cv::Mat::ones(3, 3, CV_32FC1); + const cv::Mat K = cv::Mat::eye(3, 3, CV_32FC1); + const cv::Mat R = cv::Mat::ones(3, 3, CV_32FC1); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_map_x; - cv::gpu::GpuMat d_map_y; + cv::gpu::GpuMat map_x; + cv::gpu::GpuMat map_y; - cv::gpu::buildWarpSphericalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); - - TEST_CYCLE() - { - cv::gpu::buildWarpSphericalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, d_map_x, d_map_y); - } - - GPU_SANITY_CHECK(d_map_x); - GPU_SANITY_CHECK(d_map_y); + TEST_CYCLE() cv::gpu::buildWarpSphericalMaps(size, cv::Rect(0, 0, size.width, size.height), K, R, 1.0, map_x, map_y); + GPU_SANITY_CHECK(map_x); + GPU_SANITY_CHECK(map_y); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } @@ -1361,83 +1176,68 @@ PERF_TEST_P(Sz, ImgProc_BuildWarpSphericalMaps, GPU_TYPICAL_MAT_SIZES) DEF_PARAM_TEST(Sz_Depth_Cn_Inter, cv::Size, MatDepth, MatCn, Interpolation); -PERF_TEST_P(Sz_Depth_Cn_Inter, ImgProc_Rotate, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - GPU_CHANNELS_1_3_4, - Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)))) +PERF_TEST_P(Sz_Depth_Cn_Inter, ImgProc_Rotate, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4, + Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); - int interpolation = GET_PARAM(3); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); + const int interpolation = GET_PARAM(3); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::rotate(d_src, d_dst, size, 30.0, 0, 0, interpolation); + TEST_CYCLE() cv::gpu::rotate(d_src, dst, size, 30.0, 0, 0, interpolation); - TEST_CYCLE() - { - cv::gpu::rotate(d_src, d_dst, size, 30.0, 0, 0, interpolation); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // PyrDown -PERF_TEST_P(Sz_Depth_Cn, ImgProc_PyrDown, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, ImgProc_PyrDown, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::pyrDown(d_src, d_dst); + TEST_CYCLE() cv::gpu::pyrDown(d_src, dst); - TEST_CYCLE() - { - cv::gpu::pyrDown(d_src, d_dst); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::pyrDown(src, dst); - - TEST_CYCLE() - { - cv::pyrDown(src, dst); - } + TEST_CYCLE() cv::pyrDown(src, dst); CPU_SANITY_CHECK(dst); } @@ -1446,44 +1246,34 @@ PERF_TEST_P(Sz_Depth_Cn, ImgProc_PyrDown, Combine( ////////////////////////////////////////////////////////////////////// // PyrUp -PERF_TEST_P(Sz_Depth_Cn, ImgProc_PyrUp, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, ImgProc_PyrUp, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::pyrUp(d_src, d_dst); + TEST_CYCLE() cv::gpu::pyrUp(d_src, dst); - TEST_CYCLE() - { - cv::gpu::pyrUp(d_src, d_dst); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - cv::pyrUp(src, dst); - - TEST_CYCLE() - { - cv::pyrUp(src, dst); - } + TEST_CYCLE() cv::pyrUp(src, dst); CPU_SANITY_CHECK(dst); } @@ -1494,67 +1284,86 @@ PERF_TEST_P(Sz_Depth_Cn, ImgProc_PyrUp, Combine( DEF_PARAM_TEST(Sz_Depth_Code, cv::Size, MatDepth, CvtColorInfo); -PERF_TEST_P(Sz_Depth_Code, ImgProc_CvtColor, Combine( - GPU_TYPICAL_MAT_SIZES, - Values(CV_8U, CV_16U, CV_32F), - Values(CvtColorInfo(4, 4, cv::COLOR_RGBA2BGRA), - CvtColorInfo(4, 1, cv::COLOR_BGRA2GRAY), - CvtColorInfo(1, 4, cv::COLOR_GRAY2BGRA), - CvtColorInfo(3, 3, cv::COLOR_BGR2XYZ), - CvtColorInfo(3, 3, cv::COLOR_XYZ2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2YCrCb), - CvtColorInfo(3, 3, cv::COLOR_YCrCb2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2YUV), - CvtColorInfo(3, 3, cv::COLOR_YUV2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2HSV), - CvtColorInfo(3, 3, cv::COLOR_HSV2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2HLS), - CvtColorInfo(3, 3, cv::COLOR_HLS2BGR), - CvtColorInfo(3, 3, cv::COLOR_BGR2Lab), - CvtColorInfo(3, 3, cv::COLOR_LBGR2Lab), - CvtColorInfo(3, 3, cv::COLOR_BGR2Luv), - CvtColorInfo(3, 3, cv::COLOR_LBGR2Luv), - CvtColorInfo(3, 3, cv::COLOR_Lab2BGR), - CvtColorInfo(3, 3, cv::COLOR_Lab2LBGR), - CvtColorInfo(3, 3, cv::COLOR_Luv2RGB), - CvtColorInfo(3, 3, cv::COLOR_Luv2LRGB), - CvtColorInfo(1, 3, cv::COLOR_BayerBG2BGR), - CvtColorInfo(1, 3, cv::COLOR_BayerGB2BGR), - CvtColorInfo(1, 3, cv::COLOR_BayerRG2BGR), - CvtColorInfo(1, 3, cv::COLOR_BayerGR2BGR), - CvtColorInfo(4, 4, cv::COLOR_RGBA2mRGBA)))) +PERF_TEST_P(Sz_Depth_Code, ImgProc_CvtColor, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_32F), + Values(CvtColorInfo(4, 4, cv::COLOR_RGBA2BGRA), + CvtColorInfo(4, 1, cv::COLOR_BGRA2GRAY), + CvtColorInfo(1, 4, cv::COLOR_GRAY2BGRA), + CvtColorInfo(3, 3, cv::COLOR_BGR2XYZ), + CvtColorInfo(3, 3, cv::COLOR_XYZ2BGR), + CvtColorInfo(3, 3, cv::COLOR_BGR2YCrCb), + CvtColorInfo(3, 3, cv::COLOR_YCrCb2BGR), + CvtColorInfo(3, 3, cv::COLOR_BGR2YUV), + CvtColorInfo(3, 3, cv::COLOR_YUV2BGR), + CvtColorInfo(3, 3, cv::COLOR_BGR2HSV), + CvtColorInfo(3, 3, cv::COLOR_HSV2BGR), + CvtColorInfo(3, 3, cv::COLOR_BGR2HLS), + CvtColorInfo(3, 3, cv::COLOR_HLS2BGR), + CvtColorInfo(3, 3, cv::COLOR_BGR2Lab), + CvtColorInfo(3, 3, cv::COLOR_LBGR2Lab), + CvtColorInfo(3, 3, cv::COLOR_BGR2Luv), + CvtColorInfo(3, 3, cv::COLOR_LBGR2Luv), + CvtColorInfo(3, 3, cv::COLOR_Lab2BGR), + CvtColorInfo(3, 3, cv::COLOR_Lab2LBGR), + CvtColorInfo(3, 3, cv::COLOR_Luv2RGB), + CvtColorInfo(3, 3, cv::COLOR_Luv2LRGB)))) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - CvtColorInfo info = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const CvtColorInfo info = GET_PARAM(2); cv::Mat src(size, CV_MAKETYPE(depth, info.scn)); - fillRandom(src); + cv::randu(src, 0, depth == CV_8U ? 255.0 : 1.0); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::cvtColor(d_src, d_dst, info.code, info.dcn); + TEST_CYCLE() cv::gpu::cvtColor(d_src, dst, info.code, info.dcn); - TEST_CYCLE() - { - cv::gpu::cvtColor(d_src, d_dst, info.code, info.dcn); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst, 1e-4); } else { cv::Mat dst; - cv::cvtColor(src, dst, info.code, info.dcn); + TEST_CYCLE() cv::cvtColor(src, dst, info.code, info.dcn); - TEST_CYCLE() - { - cv::cvtColor(src, dst, info.code, info.dcn); - } + CPU_SANITY_CHECK(dst); + } +} + +PERF_TEST_P(Sz_Depth_Code, ImgProc_CvtColorBayer, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U), + Values(CvtColorInfo(1, 3, cv::COLOR_BayerBG2BGR), + CvtColorInfo(1, 3, cv::COLOR_BayerGB2BGR), + CvtColorInfo(1, 3, cv::COLOR_BayerRG2BGR), + CvtColorInfo(1, 3, cv::COLOR_BayerGR2BGR)))) +{ + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const CvtColorInfo info = GET_PARAM(2); + + cv::Mat src(size, CV_MAKETYPE(depth, info.scn)); + declare.in(src, WARMUP_RNG); + + if (PERF_RUN_GPU()) + { + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; + + TEST_CYCLE() cv::gpu::cvtColor(d_src, dst, info.code, info.dcn); + + GPU_SANITY_CHECK(dst); + } + else + { + cv::Mat dst; + + TEST_CYCLE() cv::cvtColor(src, dst, info.code, info.dcn); CPU_SANITY_CHECK(dst); } @@ -1563,31 +1372,27 @@ PERF_TEST_P(Sz_Depth_Code, ImgProc_CvtColor, Combine( ////////////////////////////////////////////////////////////////////// // SwapChannels -PERF_TEST_P(Sz, ImgProc_SwapChannels, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, ImgProc_SwapChannels, + GPU_TYPICAL_MAT_SIZES) { - cv::Size size = GetParam(); + const cv::Size size = GetParam(); cv::Mat src(size, CV_8UC4); - fillRandom(src); + declare.in(src, WARMUP_RNG); const int dstOrder[] = {2, 1, 0, 3}; if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst(src); - cv::gpu::swapChannels(d_src, dstOrder); + TEST_CYCLE() cv::gpu::swapChannels(dst, dstOrder); - TEST_CYCLE() - { - cv::gpu::swapChannels(d_src, dstOrder); - } - - GPU_SANITY_CHECK(d_src); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } @@ -1599,113 +1404,116 @@ CV_ENUM(AlphaOp, cv::gpu::ALPHA_OVER, cv::gpu::ALPHA_IN, cv::gpu::ALPHA_OUT, cv: DEF_PARAM_TEST(Sz_Type_Op, cv::Size, MatType, AlphaOp); -PERF_TEST_P(Sz_Type_Op, ImgProc_AlphaComp, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8UC4, CV_16UC4, CV_32SC4, CV_32FC4), ALL_ALPHA_OPS)) +PERF_TEST_P(Sz_Type_Op, ImgProc_AlphaComp, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8UC4, CV_16UC4, CV_32SC4, CV_32FC4), + ALL_ALPHA_OPS)) { - cv::Size size = GET_PARAM(0); - int type = GET_PARAM(1); - int alpha_op = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int type = GET_PARAM(1); + const int alpha_op = GET_PARAM(2); cv::Mat img1(size, type); - fillRandom(img1); - cv::Mat img2(size, type); - fillRandom(img2); + declare.in(img1, img2, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_img1(img1); - cv::gpu::GpuMat d_img2(img2); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_img1(img1); + const cv::gpu::GpuMat d_img2(img2); + cv::gpu::GpuMat dst; - cv::gpu::alphaComp(d_img1, d_img2, d_dst, alpha_op); + TEST_CYCLE() cv::gpu::alphaComp(d_img1, d_img2, dst, alpha_op); - TEST_CYCLE() - { - cv::gpu::alphaComp(d_img1, d_img2, d_dst, alpha_op); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // ImagePyramidBuild -PERF_TEST_P(Sz_Depth_Cn, ImgProc_ImagePyramidBuild, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F), GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, ImgProc_ImagePyramidBuild, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); + + const int nLayers = 5; + const cv::Size dstSize(size.width / 2 + 10, size.height / 2 + 10); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_src(src); cv::gpu::ImagePyramid d_pyr; - d_pyr.build(d_src, 5); + TEST_CYCLE() d_pyr.build(d_src, nLayers); - TEST_CYCLE() - { - d_pyr.build(d_src, 5); - } + cv::gpu::GpuMat dst; + d_pyr.getLayer(dst, dstSize); - GPU_SANITY_CHECK(d_src); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } ////////////////////////////////////////////////////////////////////// // ImagePyramidGetLayer -PERF_TEST_P(Sz_Depth_Cn, ImgProc_ImagePyramidGetLayer, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F), GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, ImgProc_ImagePyramidGetLayer, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F), + GPU_CHANNELS_1_3_4)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); + declare.in(src, WARMUP_RNG); - cv::Size dstSize(size.width / 2 + 10, size.height / 2 + 10); + const int nLayers = 3; + const cv::Size dstSize(size.width / 2 + 10, size.height / 2 + 10); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - cv::gpu::ImagePyramid d_pyr(d_src, 3); + cv::gpu::ImagePyramid d_pyr(d_src, nLayers); - d_pyr.getLayer(d_dst, dstSize); + TEST_CYCLE() d_pyr.getLayer(dst, dstSize); - TEST_CYCLE() - { - d_pyr.getLayer(d_dst, dstSize); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } -namespace { +////////////////////////////////////////////////////////////////////// +// HoughLines + +namespace +{ struct Vec4iComparator { bool operator()(const cv::Vec4i& a, const cv::Vec4i b) const @@ -1735,10 +1543,8 @@ namespace { }; } -////////////////////////////////////////////////////////////////////// -// HoughLines - -PERF_TEST_P(Sz, ImgProc_HoughLines, GPU_TYPICAL_MAT_SIZES) +PERF_TEST_P(Sz, ImgProc_HoughLines, + GPU_TYPICAL_MAT_SIZES) { declare.time(30.0); @@ -1748,49 +1554,35 @@ PERF_TEST_P(Sz, ImgProc_HoughLines, GPU_TYPICAL_MAT_SIZES) const float theta = static_cast(CV_PI / 180.0); const int threshold = 300; - cv::RNG rng(123456789); - cv::Mat src(size, CV_8UC1, cv::Scalar::all(0)); - - const int numLines = rng.uniform(100, 300); - for (int i = 0; i < numLines; ++i) - { - cv::Point p1(rng.uniform(0, src.cols), rng.uniform(0, src.rows)); - cv::Point p2(rng.uniform(0, src.cols), rng.uniform(0, src.rows)); - cv::line(src, p1, p2, cv::Scalar::all(255), 2); - } + cv::line(src, cv::Point(0, 100), cv::Point(src.cols, 100), cv::Scalar::all(255), 1); + cv::line(src, cv::Point(0, 200), cv::Point(src.cols, 200), cv::Scalar::all(255), 1); + cv::line(src, cv::Point(0, 400), cv::Point(src.cols, 400), cv::Scalar::all(255), 1); + cv::line(src, cv::Point(100, 0), cv::Point(100, src.rows), cv::Scalar::all(255), 1); + cv::line(src, cv::Point(200, 0), cv::Point(200, src.rows), cv::Scalar::all(255), 1); + cv::line(src, cv::Point(400, 0), cv::Point(400, src.rows), cv::Scalar::all(255), 1); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_lines; cv::gpu::HoughLinesBuf d_buf; - cv::gpu::HoughLines(d_src, d_lines, d_buf, rho, theta, threshold); + TEST_CYCLE() cv::gpu::HoughLines(d_src, d_lines, d_buf, rho, theta, threshold); - TEST_CYCLE() - { - cv::gpu::HoughLines(d_src, d_lines, d_buf, rho, theta, threshold); - } - - cv::Mat h_lines(d_lines); - cv::Vec2f* begin = (cv::Vec2f*)(h_lines.ptr(0)); - cv::Vec2f* end = (cv::Vec2f*)(h_lines.ptr(0) + (h_lines.cols) * 2 * sizeof(float)); + cv::Mat gpu_lines(d_lines.row(0)); + cv::Vec2f* begin = gpu_lines.ptr(0); + cv::Vec2f* end = begin + gpu_lines.cols; std::sort(begin, end, Vec2fComparator()); - SANITY_CHECK(h_lines); + SANITY_CHECK(gpu_lines); } else { - std::vector lines; - cv::HoughLines(src, lines, rho, theta, threshold); + std::vector cpu_lines; - TEST_CYCLE() - { - cv::HoughLines(src, lines, rho, theta, threshold); - } + TEST_CYCLE() cv::HoughLines(src, cpu_lines, rho, theta, threshold); - std::sort(lines.begin(), lines.end(), Vec2fComparator()); - SANITY_CHECK(lines); + SANITY_CHECK(cpu_lines); } } @@ -1799,11 +1591,12 @@ PERF_TEST_P(Sz, ImgProc_HoughLines, GPU_TYPICAL_MAT_SIZES) DEF_PARAM_TEST_1(Image, std::string); -PERF_TEST_P(Image, ImgProc_HoughLinesP, testing::Values("cv/shared/pic5.png", "stitching/a1.png")) +PERF_TEST_P(Image, ImgProc_HoughLinesP, + testing::Values("cv/shared/pic5.png", "stitching/a1.png")) { declare.time(30.0); - std::string fileName = getDataPath(GetParam()); + const std::string fileName = getDataPath(GetParam()); const float rho = 1.0f; const float theta = static_cast(CV_PI / 180.0); @@ -1811,42 +1604,33 @@ PERF_TEST_P(Image, ImgProc_HoughLinesP, testing::Values("cv/shared/pic5.png", "s const int minLineLenght = 50; const int maxLineGap = 5; - cv::Mat image = cv::imread(fileName, cv::IMREAD_GRAYSCALE); + const cv::Mat image = cv::imread(fileName, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(image.empty()); cv::Mat mask; cv::Canny(image, mask, 50, 100); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_mask(mask); + const cv::gpu::GpuMat d_mask(mask); cv::gpu::GpuMat d_lines; cv::gpu::HoughLinesBuf d_buf; - cv::gpu::HoughLinesP(d_mask, d_lines, d_buf, rho, theta, minLineLenght, maxLineGap); + TEST_CYCLE() cv::gpu::HoughLinesP(d_mask, d_lines, d_buf, rho, theta, minLineLenght, maxLineGap); - TEST_CYCLE() - { - cv::gpu::HoughLinesP(d_mask, d_lines, d_buf, rho, theta, minLineLenght, maxLineGap); - } - - cv::Mat h_lines(d_lines); - cv::Vec4i* begin = h_lines.ptr(); - cv::Vec4i* end = h_lines.ptr() + h_lines.cols; + cv::Mat gpu_lines(d_lines); + cv::Vec4i* begin = gpu_lines.ptr(); + cv::Vec4i* end = begin + gpu_lines.cols; std::sort(begin, end, Vec4iComparator()); - SANITY_CHECK(h_lines); + SANITY_CHECK(gpu_lines); } else { - std::vector lines; - cv::HoughLinesP(mask, lines, rho, theta, threshold, minLineLenght, maxLineGap); + std::vector cpu_lines; - TEST_CYCLE() - { - cv::HoughLinesP(mask, lines, rho, theta, threshold, minLineLenght, maxLineGap); - } + TEST_CYCLE() cv::HoughLinesP(mask, cpu_lines, rho, theta, threshold, minLineLenght, maxLineGap); - std::sort(lines.begin(), lines.end(), Vec4iComparator()); - SANITY_CHECK(lines); + SANITY_CHECK(cpu_lines); } } @@ -1855,7 +1639,10 @@ PERF_TEST_P(Image, ImgProc_HoughLinesP, testing::Values("cv/shared/pic5.png", "s DEF_PARAM_TEST(Sz_Dp_MinDist, cv::Size, float, float); -PERF_TEST_P(Sz_Dp_MinDist, ImgProc_HoughCircles, Combine(GPU_TYPICAL_MAT_SIZES, Values(1.0f, 2.0f, 4.0f), Values(1.0f, 10.0f))) +PERF_TEST_P(Sz_Dp_MinDist, ImgProc_HoughCircles, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(1.0f, 2.0f, 4.0f), + Values(1.0f))) { declare.time(30.0); @@ -1868,51 +1655,32 @@ PERF_TEST_P(Sz_Dp_MinDist, ImgProc_HoughCircles, Combine(GPU_TYPICAL_MAT_SIZES, const int cannyThreshold = 100; const int votesThreshold = 15; - cv::RNG rng(123456789); - cv::Mat src(size, CV_8UC1, cv::Scalar::all(0)); - - const int numCircles = rng.uniform(50, 100); - for (int i = 0; i < numCircles; ++i) - { - cv::Point center(rng.uniform(0, src.cols), rng.uniform(0, src.rows)); - const int radius = rng.uniform(minRadius, maxRadius + 1); - - cv::circle(src, center, radius, cv::Scalar::all(255), -1); - } + cv::circle(src, cv::Point(100, 100), 20, cv::Scalar::all(255), -1); + cv::circle(src, cv::Point(200, 200), 25, cv::Scalar::all(255), -1); + cv::circle(src, cv::Point(200, 100), 25, cv::Scalar::all(255), -1); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_src(src); cv::gpu::GpuMat d_circles; cv::gpu::HoughCirclesBuf d_buf; - cv::gpu::HoughCircles(d_src, d_circles, d_buf, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); + TEST_CYCLE() cv::gpu::HoughCircles(d_src, d_circles, d_buf, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); - TEST_CYCLE() - { - cv::gpu::HoughCircles(d_src, d_circles, d_buf, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); - } - - cv::Mat h_circles(d_circles); - cv::Vec3f* begin = (cv::Vec3f*)(h_circles.ptr(0)); - cv::Vec3f* end = (cv::Vec3f*)(h_circles.ptr(0) + (h_circles.cols) * 3 * sizeof(float)); + cv::Mat gpu_circles(d_circles); + cv::Vec3f* begin = gpu_circles.ptr(0); + cv::Vec3f* end = begin + gpu_circles.cols; std::sort(begin, end, Vec3fComparator()); - SANITY_CHECK(h_circles); + SANITY_CHECK(gpu_circles); } else { - std::vector circles; + std::vector cpu_circles; - cv::HoughCircles(src, circles, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); + TEST_CYCLE() cv::HoughCircles(src, cpu_circles, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); - TEST_CYCLE() - { - cv::HoughCircles(src, circles, CV_HOUGH_GRADIENT, dp, minDist, cannyThreshold, votesThreshold, minRadius, maxRadius); - } - - std::sort(circles.begin(), circles.end(), Vec3fComparator()); - SANITY_CHECK(circles); + SANITY_CHECK(cpu_circles); } } @@ -1923,9 +1691,9 @@ CV_FLAGS(GHMethod, cv::GHT_POSITION, cv::GHT_SCALE, cv::GHT_ROTATION); DEF_PARAM_TEST(Method_Sz, GHMethod, cv::Size); -PERF_TEST_P(Method_Sz, ImgProc_GeneralizedHough, Combine( - Values(GHMethod(cv::GHT_POSITION), GHMethod(cv::GHT_POSITION | cv::GHT_SCALE), GHMethod(cv::GHT_POSITION | cv::GHT_ROTATION), GHMethod(cv::GHT_POSITION | cv::GHT_SCALE | cv::GHT_ROTATION)), - GPU_TYPICAL_MAT_SIZES)) +PERF_TEST_P(Method_Sz, ImgProc_GeneralizedHough, + Combine(Values(GHMethod(cv::GHT_POSITION), GHMethod(cv::GHT_POSITION | cv::GHT_SCALE), GHMethod(cv::GHT_POSITION | cv::GHT_ROTATION), GHMethod(cv::GHT_POSITION | cv::GHT_SCALE | cv::GHT_ROTATION)), + GPU_TYPICAL_MAT_SIZES)) { declare.time(10); @@ -1936,6 +1704,7 @@ PERF_TEST_P(Method_Sz, ImgProc_GeneralizedHough, Combine( ASSERT_FALSE(templ.empty()); cv::Mat image(imageSize, CV_8UC1, cv::Scalar::all(0)); + templ.copyTo(image(cv::Rect(50, 50, templ.cols, templ.rows))); cv::RNG rng(123456789); const int objCount = rng.uniform(5, 15); @@ -1967,10 +1736,10 @@ PERF_TEST_P(Method_Sz, ImgProc_GeneralizedHough, Combine( if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_edges(edges); - cv::gpu::GpuMat d_dx(dx); - cv::gpu::GpuMat d_dy(dy); - cv::gpu::GpuMat d_position; + const cv::gpu::GpuMat d_edges(edges); + const cv::gpu::GpuMat d_dx(dx); + const cv::gpu::GpuMat d_dy(dy); + cv::gpu::GpuMat posAndVotes; cv::Ptr d_hough = cv::gpu::GeneralizedHough_GPU::create(method); if (method & cv::GHT_ROTATION) @@ -1981,14 +1750,10 @@ PERF_TEST_P(Method_Sz, ImgProc_GeneralizedHough, Combine( d_hough->setTemplate(cv::gpu::GpuMat(templ)); - d_hough->detect(d_edges, d_dx, d_dy, d_position); + TEST_CYCLE() d_hough->detect(d_edges, d_dx, d_dy, posAndVotes); - TEST_CYCLE() - { - d_hough->detect(d_edges, d_dx, d_dy, d_position); - } - - GPU_SANITY_CHECK(d_position); + const cv::gpu::GpuMat positions(1, posAndVotes.cols, CV_32FC4, posAndVotes.data); + GPU_SANITY_CHECK(positions); } else { @@ -2003,16 +1768,8 @@ PERF_TEST_P(Method_Sz, ImgProc_GeneralizedHough, Combine( hough->setTemplate(templ); - hough->detect(edges, dx, dy, positions); + TEST_CYCLE() hough->detect(edges, dx, dy, positions); - TEST_CYCLE() - { - hough->detect(edges, dx, dy, positions); - } - - CPU_SANITY_CHECK(dx); - CPU_SANITY_CHECK(dy); + CPU_SANITY_CHECK(positions); } } - -} // namespace diff --git a/modules/gpu/perf/perf_labeling.cpp b/modules/gpu/perf/perf_labeling.cpp index 3b10ba3bef..15d286bafe 100644 --- a/modules/gpu/perf/perf_labeling.cpp +++ b/modules/gpu/perf/perf_labeling.cpp @@ -3,8 +3,6 @@ using namespace std; using namespace testing; -namespace { - DEF_PARAM_TEST_1(Image, string); struct GreedyLabeling @@ -100,28 +98,45 @@ struct GreedyLabeling dot* stack; }; -PERF_TEST_P(Image, Labeling_ConnectedComponents, Values("gpu/labeling/aloe-disp.png")) +PERF_TEST_P(Image, Labeling_ConnectivityMask, + Values("gpu/labeling/aloe-disp.png")) { declare.time(1.0); - cv::Mat image = readImage(GetParam(), cv::IMREAD_GRAYSCALE); + const cv::Mat image = readImage(GetParam(), cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(image.empty()); if (PERF_RUN_GPU()) { + cv::gpu::GpuMat d_image(image); cv::gpu::GpuMat mask; - mask.create(image.rows, image.cols, CV_8UC1); + + TEST_CYCLE() cv::gpu::connectivityMask(d_image, mask, cv::Scalar::all(0), cv::Scalar::all(2)); + + GPU_SANITY_CHECK(mask); + } + else + { + FAIL_NO_CPU(); + } +} + +PERF_TEST_P(Image, Labeling_ConnectedComponents, + Values("gpu/labeling/aloe-disp.png")) +{ + declare.time(1.0); + + const cv::Mat image = readImage(GetParam(), cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(image.empty()); + + if (PERF_RUN_GPU()) + { + cv::gpu::GpuMat d_mask; + cv::gpu::connectivityMask(cv::gpu::GpuMat(image), d_mask, cv::Scalar::all(0), cv::Scalar::all(2)); cv::gpu::GpuMat components; - components.create(image.rows, image.cols, CV_32SC1); - cv::gpu::connectivityMask(cv::gpu::GpuMat(image), mask, cv::Scalar::all(0), cv::Scalar::all(2)); - - ASSERT_NO_THROW(cv::gpu::labelComponents(mask, components)); - - TEST_CYCLE() - { - cv::gpu::labelComponents(mask, components); - } + TEST_CYCLE() cv::gpu::labelComponents(d_mask, components); GPU_SANITY_CHECK(components); } @@ -129,17 +144,9 @@ PERF_TEST_P(Image, Labeling_ConnectedComponents, Values("gpu/labeling/al { GreedyLabeling host(image); - host(host._labels); + TEST_CYCLE() host(host._labels); - declare.time(1.0); - - TEST_CYCLE() - { - host(host._labels); - } - - CPU_SANITY_CHECK(host._labels); + cv::Mat components = host._labels; + CPU_SANITY_CHECK(components); } } - -} // namespace diff --git a/modules/gpu/perf/perf_main.cpp b/modules/gpu/perf/perf_main.cpp index f8eb23d098..312b744482 100644 --- a/modules/gpu/perf/perf_main.cpp +++ b/modules/gpu/perf/perf_main.cpp @@ -1,7 +1,5 @@ #include "perf_precomp.hpp" -namespace{ - static void printOsInfo() { #if defined _WIN32 @@ -69,6 +67,4 @@ static void printCudaInfo() #endif } -} - -CV_PERF_TEST_MAIN(gpu, printCudaInfo()) \ No newline at end of file +CV_PERF_TEST_MAIN(gpu, printCudaInfo()) diff --git a/modules/gpu/perf/perf_matop.cpp b/modules/gpu/perf/perf_matop.cpp index b6d4a110f9..aeea1b5181 100644 --- a/modules/gpu/perf/perf_matop.cpp +++ b/modules/gpu/perf/perf_matop.cpp @@ -3,137 +3,112 @@ using namespace std; using namespace testing; -namespace { - ////////////////////////////////////////////////////////////////////// // SetTo -PERF_TEST_P(Sz_Depth_Cn, MatOp_SetTo, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F, CV_64F), GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, MatOp_SetTo, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F), + GPU_CHANNELS_1_3_4)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); - cv::Scalar val(1, 2, 3, 4); + const cv::Scalar val(1, 2, 3, 4); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(size, type); + cv::gpu::GpuMat dst(size, type); - d_src.setTo(val); + TEST_CYCLE() dst.setTo(val); - TEST_CYCLE() - { - d_src.setTo(val); - } - - GPU_SANITY_CHECK(d_src); + GPU_SANITY_CHECK(dst); } else { - cv::Mat src(size, type); + cv::Mat dst(size, type); - src.setTo(val); + TEST_CYCLE() dst.setTo(val); - TEST_CYCLE() - { - src.setTo(val); - } - - CPU_SANITY_CHECK(src); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // SetToMasked -PERF_TEST_P(Sz_Depth_Cn, MatOp_SetToMasked, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F, CV_64F), GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, MatOp_SetToMasked, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F), + GPU_CHANNELS_1_3_4)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); - cv::Mat mask(size, CV_8UC1); - fillRandom(mask, 0, 2); + declare.in(src, mask, WARMUP_RNG); - cv::Scalar val(1, 2, 3, 4); + const cv::Scalar val(1, 2, 3, 4); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_mask(mask); + cv::gpu::GpuMat dst(src); + const cv::gpu::GpuMat d_mask(mask); - d_src.setTo(val, d_mask); + TEST_CYCLE() dst.setTo(val, d_mask); - TEST_CYCLE() - { - d_src.setTo(val, d_mask); - } - - GPU_SANITY_CHECK(d_src); + GPU_SANITY_CHECK(dst); } else { - src.setTo(val, mask); + cv::Mat dst = src; - TEST_CYCLE() - { - src.setTo(val, mask); - } + TEST_CYCLE() dst.setTo(val, mask); - CPU_SANITY_CHECK(src); + CPU_SANITY_CHECK(dst); } } ////////////////////////////////////////////////////////////////////// // CopyToMasked -PERF_TEST_P(Sz_Depth_Cn, MatOp_CopyToMasked, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F, CV_64F), GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Sz_Depth_Cn, MatOp_CopyToMasked, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F), + GPU_CHANNELS_1_3_4)) { - cv::Size size = GET_PARAM(0); - int depth = GET_PARAM(1); - int channels = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth = GET_PARAM(1); + const int channels = GET_PARAM(2); - int type = CV_MAKE_TYPE(depth, channels); + const int type = CV_MAKE_TYPE(depth, channels); cv::Mat src(size, type); - fillRandom(src); - cv::Mat mask(size, CV_8UC1); - fillRandom(mask, 0, 2); + declare.in(src, mask, WARMUP_RNG); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_mask(mask); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + const cv::gpu::GpuMat d_mask(mask); + cv::gpu::GpuMat dst(d_src.size(), d_src.type(), cv::Scalar::all(0)); - d_src.copyTo(d_dst, d_mask); + TEST_CYCLE() d_src.copyTo(dst, d_mask); - TEST_CYCLE() - { - d_src.copyTo(d_dst, d_mask); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { - cv::Mat dst; + cv::Mat dst(src.size(), src.type(), cv::Scalar::all(0)); - src.copyTo(dst, mask); - - TEST_CYCLE() - { - src.copyTo(dst, mask); - } + TEST_CYCLE() src.copyTo(dst, mask); CPU_SANITY_CHECK(dst); } @@ -144,42 +119,36 @@ PERF_TEST_P(Sz_Depth_Cn, MatOp_CopyToMasked, Combine(GPU_TYPICAL_MAT_SIZES, Valu DEF_PARAM_TEST(Sz_2Depth, cv::Size, MatDepth, MatDepth); -PERF_TEST_P(Sz_2Depth, MatOp_ConvertTo, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F, CV_64F), Values(CV_8U, CV_16U, CV_32F, CV_64F))) +PERF_TEST_P(Sz_2Depth, MatOp_ConvertTo, + Combine(GPU_TYPICAL_MAT_SIZES, + Values(CV_8U, CV_16U, CV_32F, CV_64F), + Values(CV_8U, CV_16U, CV_32F, CV_64F))) { - cv::Size size = GET_PARAM(0); - int depth1 = GET_PARAM(1); - int depth2 = GET_PARAM(2); + const cv::Size size = GET_PARAM(0); + const int depth1 = GET_PARAM(1); + const int depth2 = GET_PARAM(2); cv::Mat src(size, depth1); - fillRandom(src); + declare.in(src, WARMUP_RNG); + + const double a = 0.5; + const double b = 1.0; if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_src(src); - cv::gpu::GpuMat d_dst; + const cv::gpu::GpuMat d_src(src); + cv::gpu::GpuMat dst; - d_src.convertTo(d_dst, depth2, 0.5, 1.0); + TEST_CYCLE() d_src.convertTo(dst, depth2, a, b); - TEST_CYCLE() - { - d_src.convertTo(d_dst, depth2, 0.5, 1.0); - } - - GPU_SANITY_CHECK(d_dst); + GPU_SANITY_CHECK(dst); } else { cv::Mat dst; - src.convertTo(dst, depth2, 0.5, 1.0); - - TEST_CYCLE() - { - src.convertTo(dst, depth2, 0.5, 1.0); - } + TEST_CYCLE() src.convertTo(dst, depth2, a, b); CPU_SANITY_CHECK(dst); } } - -} // namespace diff --git a/modules/gpu/perf/perf_objdetect.cpp b/modules/gpu/perf/perf_objdetect.cpp index 6d040ac02f..969ac10762 100644 --- a/modules/gpu/perf/perf_objdetect.cpp +++ b/modules/gpu/perf/perf_objdetect.cpp @@ -3,90 +3,47 @@ using namespace std; using namespace testing; -namespace { - /////////////////////////////////////////////////////////////// // HOG DEF_PARAM_TEST_1(Image, string); -PERF_TEST_P(Image, ObjDetect_HOG, Values("gpu/hog/road.png")) +PERF_TEST_P(Image, ObjDetect_HOG, + Values("gpu/hog/road.png", + "gpu/caltech/image_00000009_0.png", + "gpu/caltech/image_00000032_0.png", + "gpu/caltech/image_00000165_0.png", + "gpu/caltech/image_00000261_0.png", + "gpu/caltech/image_00000469_0.png", + "gpu/caltech/image_00000527_0.png", + "gpu/caltech/image_00000574_0.png")) { - cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); + const cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); - std::vector found_locations; - if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_img(img); + const cv::gpu::GpuMat d_img(img); + std::vector gpu_found_locations; cv::gpu::HOGDescriptor d_hog; d_hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector()); - d_hog.detectMultiScale(d_img, found_locations); + TEST_CYCLE() d_hog.detectMultiScale(d_img, gpu_found_locations); - TEST_CYCLE() - { - d_hog.detectMultiScale(d_img, found_locations); - } + SANITY_CHECK(gpu_found_locations); } else { + std::vector cpu_found_locations; + cv::HOGDescriptor hog; hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector()); - hog.detectMultiScale(img, found_locations); + TEST_CYCLE() hog.detectMultiScale(img, cpu_found_locations); - TEST_CYCLE() - { - hog.detectMultiScale(img, found_locations); - } + SANITY_CHECK(cpu_found_locations); } - - SANITY_CHECK(found_locations); -} - -//===========test for CalTech data =============// -DEF_PARAM_TEST_1(HOG, string); - -PERF_TEST_P(HOG, CalTech, Values("gpu/caltech/image_00000009_0.png", "gpu/caltech/image_00000032_0.png", - "gpu/caltech/image_00000165_0.png", "gpu/caltech/image_00000261_0.png", "gpu/caltech/image_00000469_0.png", - "gpu/caltech/image_00000527_0.png", "gpu/caltech/image_00000574_0.png")) -{ - cv::Mat img = readImage(GetParam(), cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(img.empty()); - - std::vector found_locations; - - if (PERF_RUN_GPU()) - { - cv::gpu::GpuMat d_img(img); - - cv::gpu::HOGDescriptor d_hog; - d_hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector()); - - d_hog.detectMultiScale(d_img, found_locations); - - TEST_CYCLE() - { - d_hog.detectMultiScale(d_img, found_locations); - } - } - else - { - cv::HOGDescriptor hog; - hog.setSVMDetector(cv::gpu::HOGDescriptor::getDefaultPeopleDetector()); - - hog.detectMultiScale(img, found_locations); - - TEST_CYCLE() - { - hog.detectMultiScale(img, found_locations); - } - } - - SANITY_CHECK(found_locations); } /////////////////////////////////////////////////////////////// @@ -96,9 +53,9 @@ typedef pair pair_string; DEF_PARAM_TEST_1(ImageAndCascade, pair_string); PERF_TEST_P(ImageAndCascade, ObjDetect_HaarClassifier, - Values(make_pair("gpu/haarcascade/group_1_640x480_VGA.pgm", "gpu/perf/haarcascade_frontalface_alt.xml"))) + Values(make_pair("gpu/haarcascade/group_1_640x480_VGA.pgm", "gpu/perf/haarcascade_frontalface_alt.xml"))) { - cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + const cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); if (PERF_RUN_GPU()) @@ -106,33 +63,28 @@ PERF_TEST_P(ImageAndCascade, ObjDetect_HaarClassifier, cv::gpu::CascadeClassifier_GPU d_cascade; ASSERT_TRUE(d_cascade.load(perf::TestBase::getDataPath(GetParam().second))); - cv::gpu::GpuMat d_img(img); - cv::gpu::GpuMat d_objects_buffer; + const cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat objects_buffer; + int detections_num = 0; - d_cascade.detectMultiScale(d_img, d_objects_buffer); + TEST_CYCLE() detections_num = d_cascade.detectMultiScale(d_img, objects_buffer); - TEST_CYCLE() - { - d_cascade.detectMultiScale(d_img, d_objects_buffer); - } - - GPU_SANITY_CHECK(d_objects_buffer); + std::vector gpu_rects(detections_num); + cv::Mat gpu_rects_mat(1, detections_num, cv::DataType::type, &gpu_rects[0]); + objects_buffer.colRange(0, detections_num).download(gpu_rects_mat); + cv::groupRectangles(gpu_rects, 3, 0.2); + SANITY_CHECK(gpu_rects); } else { cv::CascadeClassifier cascade; ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath("gpu/perf/haarcascade_frontalface_alt.xml"))); - std::vector rects; + std::vector cpu_rects; - cascade.detectMultiScale(img, rects); + TEST_CYCLE() cascade.detectMultiScale(img, cpu_rects); - TEST_CYCLE() - { - cascade.detectMultiScale(img, rects); - } - - CPU_SANITY_CHECK(rects); + SANITY_CHECK(cpu_rects); } } @@ -140,9 +92,9 @@ PERF_TEST_P(ImageAndCascade, ObjDetect_HaarClassifier, // LBP cascade PERF_TEST_P(ImageAndCascade, ObjDetect_LBPClassifier, - Values(make_pair("gpu/haarcascade/group_1_640x480_VGA.pgm", "gpu/lbpcascade/lbpcascade_frontalface.xml"))) + Values(make_pair("gpu/haarcascade/group_1_640x480_VGA.pgm", "gpu/lbpcascade/lbpcascade_frontalface.xml"))) { - cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + const cv::Mat img = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(img.empty()); if (PERF_RUN_GPU()) @@ -150,34 +102,27 @@ PERF_TEST_P(ImageAndCascade, ObjDetect_LBPClassifier, cv::gpu::CascadeClassifier_GPU d_cascade; ASSERT_TRUE(d_cascade.load(perf::TestBase::getDataPath(GetParam().second))); - cv::gpu::GpuMat d_img(img); - cv::gpu::GpuMat d_gpu_rects; + const cv::gpu::GpuMat d_img(img); + cv::gpu::GpuMat objects_buffer; + int detections_num = 0; - d_cascade.detectMultiScale(d_img, d_gpu_rects); + TEST_CYCLE() detections_num = d_cascade.detectMultiScale(d_img, objects_buffer); - TEST_CYCLE() - { - d_cascade.detectMultiScale(d_img, d_gpu_rects); - } - - GPU_SANITY_CHECK(d_gpu_rects); + std::vector gpu_rects(detections_num); + cv::Mat gpu_rects_mat(1, detections_num, cv::DataType::type, &gpu_rects[0]); + objects_buffer.colRange(0, detections_num).download(gpu_rects_mat); + cv::groupRectangles(gpu_rects, 3, 0.2); + SANITY_CHECK(gpu_rects); } else { cv::CascadeClassifier cascade; ASSERT_TRUE(cascade.load(perf::TestBase::getDataPath("gpu/lbpcascade/lbpcascade_frontalface.xml"))); - std::vector rects; + std::vector cpu_rects; - cascade.detectMultiScale(img, rects); + TEST_CYCLE() cascade.detectMultiScale(img, cpu_rects); - TEST_CYCLE() - { - cascade.detectMultiScale(img, rects); - } - - CPU_SANITY_CHECK(rects); + SANITY_CHECK(cpu_rects); } } - -} // namespace \ No newline at end of file diff --git a/modules/gpu/perf/perf_video.cpp b/modules/gpu/perf/perf_video.cpp index 83213a1613..7d8fed6231 100644 --- a/modules/gpu/perf/perf_video.cpp +++ b/modules/gpu/perf/perf_video.cpp @@ -2,6 +2,7 @@ using namespace std; using namespace testing; +using namespace perf; namespace cv { @@ -11,17 +12,135 @@ namespace cv } } -namespace { - ////////////////////////////////////////////////////// -// BroxOpticalFlow +// InterpolateFrames typedef pair pair_string; DEF_PARAM_TEST_1(ImagePair, pair_string); +PERF_TEST_P(ImagePair, Video_InterpolateFrames, + Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) +{ + cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame0.empty()); + + cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame1.empty()); + + frame0.convertTo(frame0, CV_32FC1, 1.0 / 255.0); + frame1.convertTo(frame1, CV_32FC1, 1.0 / 255.0); + + if (PERF_RUN_GPU()) + { + const cv::gpu::GpuMat d_frame0(frame0); + const cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat d_fu, d_fv; + cv::gpu::GpuMat d_bu, d_bv; + + cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, + 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); + + d_flow(d_frame0, d_frame1, d_fu, d_fv); + d_flow(d_frame1, d_frame0, d_bu, d_bv); + + cv::gpu::GpuMat newFrame; + cv::gpu::GpuMat d_buf; + + TEST_CYCLE() cv::gpu::interpolateFrames(d_frame0, d_frame1, d_fu, d_fv, d_bu, d_bv, 0.5f, newFrame, d_buf); + + GPU_SANITY_CHECK(newFrame); + } + else + { + FAIL_NO_CPU(); + } +} + +////////////////////////////////////////////////////// +// CreateOpticalFlowNeedleMap + +PERF_TEST_P(ImagePair, Video_CreateOpticalFlowNeedleMap, + Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) +{ + cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame0.empty()); + + cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(frame1.empty()); + + frame0.convertTo(frame0, CV_32FC1, 1.0 / 255.0); + frame1.convertTo(frame1, CV_32FC1, 1.0 / 255.0); + + if (PERF_RUN_GPU()) + { + const cv::gpu::GpuMat d_frame0(frame0); + const cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat u; + cv::gpu::GpuMat v; + + cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, + 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); + + d_flow(d_frame0, d_frame1, u, v); + + cv::gpu::GpuMat vertex, colors; + + TEST_CYCLE() cv::gpu::createOpticalFlowNeedleMap(u, v, vertex, colors); + + GPU_SANITY_CHECK(vertex); + GPU_SANITY_CHECK(colors); + } + else + { + FAIL_NO_CPU(); + } +} + +////////////////////////////////////////////////////// +// GoodFeaturesToTrack + +DEF_PARAM_TEST(Image_MinDistance, string, double); + +PERF_TEST_P(Image_MinDistance, Video_GoodFeaturesToTrack, + Combine(Values("gpu/perf/aloe.png"), + Values(0.0, 3.0))) +{ + const string fileName = GET_PARAM(0); + const double minDistance = GET_PARAM(1); + + const cv::Mat image = readImage(fileName, cv::IMREAD_GRAYSCALE); + ASSERT_FALSE(image.empty()); + + const int maxCorners = 8000; + const double qualityLevel = 0.01; + + if (PERF_RUN_GPU()) + { + cv::gpu::GoodFeaturesToTrackDetector_GPU d_detector(maxCorners, qualityLevel, minDistance); + + const cv::gpu::GpuMat d_image(image); + cv::gpu::GpuMat pts; + + TEST_CYCLE() d_detector(d_image, pts); + + GPU_SANITY_CHECK(pts); + } + else + { + cv::Mat pts; + + TEST_CYCLE() cv::goodFeaturesToTrack(image, pts, maxCorners, qualityLevel, minDistance); + + CPU_SANITY_CHECK(pts); + } +} + +////////////////////////////////////////////////////// +// BroxOpticalFlow + PERF_TEST_P(ImagePair, Video_BroxOpticalFlow, - Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) + Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) { declare.time(10); @@ -36,166 +155,22 @@ PERF_TEST_P(ImagePair, Video_BroxOpticalFlow, if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_u; - cv::gpu::GpuMat d_v; + const cv::gpu::GpuMat d_frame0(frame0); + const cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat u; + cv::gpu::GpuMat v; cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); - d_flow(d_frame0, d_frame1, d_u, d_v); + TEST_CYCLE() d_flow(d_frame0, d_frame1, u, v); - TEST_CYCLE() - { - d_flow(d_frame0, d_frame1, d_u, d_v); - } - - GPU_SANITY_CHECK(d_u); - GPU_SANITY_CHECK(d_v); + GPU_SANITY_CHECK(u); + GPU_SANITY_CHECK(v); } else { - FAIL() << "No such CPU implementation analogy"; - } -} - -////////////////////////////////////////////////////// -// InterpolateFrames - -PERF_TEST_P(ImagePair, Video_InterpolateFrames, - Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) -{ - cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame0.empty()); - - cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame1.empty()); - - frame0.convertTo(frame0, CV_32FC1, 1.0 / 255.0); - frame1.convertTo(frame1, CV_32FC1, 1.0 / 255.0); - - if (PERF_RUN_GPU()) - { - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_fu, d_fv; - cv::gpu::GpuMat d_bu, d_bv; - - cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, - 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); - - d_flow(d_frame0, d_frame1, d_fu, d_fv); - d_flow(d_frame1, d_frame0, d_bu, d_bv); - - cv::gpu::GpuMat d_newFrame; - cv::gpu::GpuMat d_buf; - - cv::gpu::interpolateFrames(d_frame0, d_frame1, d_fu, d_fv, d_bu, d_bv, 0.5f, d_newFrame, d_buf); - - TEST_CYCLE() - { - cv::gpu::interpolateFrames(d_frame0, d_frame1, d_fu, d_fv, d_bu, d_bv, 0.5f, d_newFrame, d_buf); - } - - GPU_SANITY_CHECK(d_fu); - GPU_SANITY_CHECK(d_fv); - GPU_SANITY_CHECK(d_bu); - GPU_SANITY_CHECK(d_bv); - } - else - { - FAIL() << "No such CPU implementation analogy"; - } -} - -////////////////////////////////////////////////////// -// CreateOpticalFlowNeedleMap - -PERF_TEST_P(ImagePair, Video_CreateOpticalFlowNeedleMap, - Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) -{ - cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame0.empty()); - - cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(frame1.empty()); - - frame0.convertTo(frame0, CV_32FC1, 1.0 / 255.0); - frame1.convertTo(frame1, CV_32FC1, 1.0 / 255.0); - - if (PERF_RUN_GPU()) - { - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_u; - cv::gpu::GpuMat d_v; - - cv::gpu::BroxOpticalFlow d_flow(0.197f /*alpha*/, 50.0f /*gamma*/, 0.8f /*scale_factor*/, - 10 /*inner_iterations*/, 77 /*outer_iterations*/, 10 /*solver_iterations*/); - - d_flow(d_frame0, d_frame1, d_u, d_v); - - cv::gpu::GpuMat d_vertex, d_colors; - - cv::gpu::createOpticalFlowNeedleMap(d_u, d_v, d_vertex, d_colors); - - TEST_CYCLE() - { - cv::gpu::createOpticalFlowNeedleMap(d_u, d_v, d_vertex, d_colors); - } - - GPU_SANITY_CHECK(d_vertex); - GPU_SANITY_CHECK(d_colors); - } - else - { - FAIL() << "No such CPU implementation analogy"; - } -} - -////////////////////////////////////////////////////// -// GoodFeaturesToTrack - -DEF_PARAM_TEST(Image_MinDistance, string, double); - -PERF_TEST_P(Image_MinDistance, Video_GoodFeaturesToTrack, - Combine(Values("gpu/perf/aloe.png"), Values(0.0, 3.0))) -{ - string fileName = GET_PARAM(0); - double minDistance = GET_PARAM(1); - - cv::Mat image = readImage(fileName, cv::IMREAD_GRAYSCALE); - ASSERT_FALSE(image.empty()); - - if (PERF_RUN_GPU()) - { - cv::gpu::GoodFeaturesToTrackDetector_GPU d_detector(8000, 0.01, minDistance); - - cv::gpu::GpuMat d_image(image); - cv::gpu::GpuMat d_pts; - - d_detector(d_image, d_pts); - - TEST_CYCLE() - { - d_detector(d_image, d_pts); - } - - GPU_SANITY_CHECK(d_pts); - } - else - { - cv::Mat pts; - - cv::goodFeaturesToTrack(image, pts, 8000, 0.01, minDistance); - - TEST_CYCLE() - { - cv::goodFeaturesToTrack(image, pts, 8000, 0.01, minDistance); - } - - CPU_SANITY_CHECK(pts); + FAIL_NO_CPU(); } } @@ -204,27 +179,27 @@ PERF_TEST_P(Image_MinDistance, Video_GoodFeaturesToTrack, DEF_PARAM_TEST(ImagePair_Gray_NPts_WinSz_Levels_Iters, pair_string, bool, int, int, int, int); -PERF_TEST_P(ImagePair_Gray_NPts_WinSz_Levels_Iters, Video_PyrLKOpticalFlowSparse, Combine( - Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png")), - Bool(), - Values(1000, 2000, 4000, 8000), - Values(9, 13, 17, 21), - Values(1, 2, 3), - Values(1, 10, 30))) +PERF_TEST_P(ImagePair_Gray_NPts_WinSz_Levels_Iters, Video_PyrLKOpticalFlowSparse, + Combine(Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png")), + Bool(), + Values(8000), + Values(21), + Values(1, 3), + Values(1, 30))) { declare.time(20.0); - pair_string imagePair = GET_PARAM(0); - bool useGray = GET_PARAM(1); - int points = GET_PARAM(2); - int winSize = GET_PARAM(3); - int levels = GET_PARAM(4); - int iters = GET_PARAM(5); + const pair_string imagePair = GET_PARAM(0); + const bool useGray = GET_PARAM(1); + const int points = GET_PARAM(2); + const int winSize = GET_PARAM(3); + const int levels = GET_PARAM(4); + const int iters = GET_PARAM(5); - cv::Mat frame0 = readImage(imagePair.first, useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); + const cv::Mat frame0 = readImage(imagePair.first, useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); ASSERT_FALSE(frame0.empty()); - cv::Mat frame1 = readImage(imagePair.second, useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); + const cv::Mat frame1 = readImage(imagePair.second, useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR); ASSERT_FALSE(frame1.empty()); cv::Mat gray_frame; @@ -238,36 +213,28 @@ PERF_TEST_P(ImagePair_Gray_NPts_WinSz_Levels_Iters, Video_PyrLKOpticalFlowSparse if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_pts(pts.reshape(2, 1)); + const cv::gpu::GpuMat d_pts(pts.reshape(2, 1)); cv::gpu::PyrLKOpticalFlow d_pyrLK; d_pyrLK.winSize = cv::Size(winSize, winSize); d_pyrLK.maxLevel = levels - 1; d_pyrLK.iters = iters; - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_nextPts; - cv::gpu::GpuMat d_status; + const cv::gpu::GpuMat d_frame0(frame0); + const cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat nextPts; + cv::gpu::GpuMat status; - d_pyrLK.sparse(d_frame0, d_frame1, d_pts, d_nextPts, d_status); + TEST_CYCLE() d_pyrLK.sparse(d_frame0, d_frame1, d_pts, nextPts, status); - TEST_CYCLE() - { - d_pyrLK.sparse(d_frame0, d_frame1, d_pts, d_nextPts, d_status); - } - - GPU_SANITY_CHECK(d_status); + GPU_SANITY_CHECK(nextPts); + GPU_SANITY_CHECK(status); } else { cv::Mat nextPts; cv::Mat status; - cv::calcOpticalFlowPyrLK(frame0, frame1, pts, nextPts, status, cv::noArray(), - cv::Size(winSize, winSize), levels - 1, - cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, iters, 0.01)); - TEST_CYCLE() { cv::calcOpticalFlowPyrLK(frame0, frame1, pts, nextPts, status, cv::noArray(), @@ -275,6 +242,7 @@ PERF_TEST_P(ImagePair_Gray_NPts_WinSz_Levels_Iters, Video_PyrLKOpticalFlowSparse cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, iters, 0.01)); } + CPU_SANITY_CHECK(nextPts); CPU_SANITY_CHECK(status); } } @@ -284,50 +252,45 @@ PERF_TEST_P(ImagePair_Gray_NPts_WinSz_Levels_Iters, Video_PyrLKOpticalFlowSparse DEF_PARAM_TEST(ImagePair_WinSz_Levels_Iters, pair_string, int, int, int); -PERF_TEST_P(ImagePair_WinSz_Levels_Iters, Video_PyrLKOpticalFlowDense, Combine( - Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png")), - Values(3, 5, 7, 9, 13, 17, 21), - Values(1, 2, 3), - Values(1, 10))) +PERF_TEST_P(ImagePair_WinSz_Levels_Iters, Video_PyrLKOpticalFlowDense, + Combine(Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png")), + Values(3, 5, 7, 9, 13, 17, 21), + Values(1, 3), + Values(1, 10))) { declare.time(30); - pair_string imagePair = GET_PARAM(0); - int winSize = GET_PARAM(1); - int levels = GET_PARAM(2); - int iters = GET_PARAM(3); + const pair_string imagePair = GET_PARAM(0); + const int winSize = GET_PARAM(1); + const int levels = GET_PARAM(2); + const int iters = GET_PARAM(3); - cv::Mat frame0 = readImage(imagePair.first, cv::IMREAD_GRAYSCALE); + const cv::Mat frame0 = readImage(imagePair.first, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame0.empty()); - cv::Mat frame1 = readImage(imagePair.second, cv::IMREAD_GRAYSCALE); + const cv::Mat frame1 = readImage(imagePair.second, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame1.empty()); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_u; - cv::gpu::GpuMat d_v; + const cv::gpu::GpuMat d_frame0(frame0); + const cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat u; + cv::gpu::GpuMat v; cv::gpu::PyrLKOpticalFlow d_pyrLK; d_pyrLK.winSize = cv::Size(winSize, winSize); d_pyrLK.maxLevel = levels - 1; d_pyrLK.iters = iters; - d_pyrLK.dense(d_frame0, d_frame1, d_u, d_v); + TEST_CYCLE() d_pyrLK.dense(d_frame0, d_frame1, u, v); - TEST_CYCLE() - { - d_pyrLK.dense(d_frame0, d_frame1, d_u, d_v); - } - - GPU_SANITY_CHECK(d_u); - GPU_SANITY_CHECK(d_v); + GPU_SANITY_CHECK(u); + GPU_SANITY_CHECK(v); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } @@ -335,30 +298,30 @@ PERF_TEST_P(ImagePair_WinSz_Levels_Iters, Video_PyrLKOpticalFlowDense, Combine( // FarnebackOpticalFlow PERF_TEST_P(ImagePair, Video_FarnebackOpticalFlow, - Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) + Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) { declare.time(10); - cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + const cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame0.empty()); - cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + const cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame1.empty()); - int numLevels = 5; - double pyrScale = 0.5; - int winSize = 13; - int numIters = 10; - int polyN = 5; - double polySigma = 1.1; - int flags = 0; + const int numLevels = 5; + const double pyrScale = 0.5; + const int winSize = 13; + const int numIters = 10; + const int polyN = 5; + const double polySigma = 1.1; + const int flags = 0; if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_u; - cv::gpu::GpuMat d_v; + const cv::gpu::GpuMat d_frame0(frame0); + const cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat u; + cv::gpu::GpuMat v; cv::gpu::FarnebackOpticalFlow d_farneback; d_farneback.numLevels = numLevels; @@ -369,26 +332,16 @@ PERF_TEST_P(ImagePair, Video_FarnebackOpticalFlow, d_farneback.polySigma = polySigma; d_farneback.flags = flags; - d_farneback(d_frame0, d_frame1, d_u, d_v); + TEST_CYCLE() d_farneback(d_frame0, d_frame1, u, v); - TEST_CYCLE() - { - d_farneback(d_frame0, d_frame1, d_u, d_v); - } - - GPU_SANITY_CHECK(d_u); - GPU_SANITY_CHECK(d_v); + GPU_SANITY_CHECK(u, 1e-4); + GPU_SANITY_CHECK(v, 1e-4); } else { cv::Mat flow; - cv::calcOpticalFlowFarneback(frame0, frame1, flow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags); - - TEST_CYCLE() - { - cv::calcOpticalFlowFarneback(frame0, frame1, flow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags); - } + TEST_CYCLE() cv::calcOpticalFlowFarneback(frame0, frame1, flow, pyrScale, numLevels, winSize, numIters, polyN, polySigma, flags); CPU_SANITY_CHECK(flow); } @@ -398,34 +351,29 @@ PERF_TEST_P(ImagePair, Video_FarnebackOpticalFlow, // OpticalFlowDual_TVL1 PERF_TEST_P(ImagePair, Video_OpticalFlowDual_TVL1, - Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) + Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) { declare.time(20); - cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + const cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame0.empty()); - cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + const cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame1.empty()); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_flowx; - cv::gpu::GpuMat d_flowy; + const cv::gpu::GpuMat d_frame0(frame0); + const cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat u; + cv::gpu::GpuMat v; cv::gpu::OpticalFlowDual_TVL1_GPU d_alg; - d_alg(d_frame0, d_frame1, d_flowx, d_flowy); + TEST_CYCLE() d_alg(d_frame0, d_frame1, u, v); - TEST_CYCLE() - { - d_alg(d_frame0, d_frame1, d_flowx, d_flowy); - } - - GPU_SANITY_CHECK(d_flowx); - GPU_SANITY_CHECK(d_flowy); + GPU_SANITY_CHECK(u); + GPU_SANITY_CHECK(v); } else { @@ -433,12 +381,7 @@ PERF_TEST_P(ImagePair, Video_OpticalFlowDual_TVL1, cv::Ptr alg = cv::createOptFlow_DualTVL1(); - alg->calc(frame0, frame1, flow); - - TEST_CYCLE() - { - alg->calc(frame0, frame1, flow); - } + TEST_CYCLE() alg->calc(frame0, frame1, flow); CPU_SANITY_CHECK(flow); } @@ -466,98 +409,73 @@ void calcOpticalFlowBM(const cv::Mat& prev, const cv::Mat& curr, } PERF_TEST_P(ImagePair, Video_OpticalFlowBM, - Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) + Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) { declare.time(400); - cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + const cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame0.empty()); - cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + const cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame1.empty()); - cv::Size block_size(16, 16); - cv::Size shift_size(1, 1); - cv::Size max_range(16, 16); + const cv::Size block_size(16, 16); + const cv::Size shift_size(1, 1); + const cv::Size max_range(16, 16); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_velx, d_vely, buf; + const cv::gpu::GpuMat d_frame0(frame0); + const cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat u, v, buf; - cv::gpu::calcOpticalFlowBM(d_frame0, d_frame1, block_size, shift_size, max_range, false, d_velx, d_vely, buf); + TEST_CYCLE() cv::gpu::calcOpticalFlowBM(d_frame0, d_frame1, block_size, shift_size, max_range, false, u, v, buf); - TEST_CYCLE() - { - cv::gpu::calcOpticalFlowBM(d_frame0, d_frame1, block_size, shift_size, max_range, false, d_velx, d_vely, buf); - } - - GPU_SANITY_CHECK(d_velx); - GPU_SANITY_CHECK(d_vely); + GPU_SANITY_CHECK(u); + GPU_SANITY_CHECK(v); } else { - cv::Mat velx, vely; + cv::Mat u, v; - calcOpticalFlowBM(frame0, frame1, block_size, shift_size, max_range, false, velx, vely); + TEST_CYCLE() calcOpticalFlowBM(frame0, frame1, block_size, shift_size, max_range, false, u, v); - TEST_CYCLE() - { - calcOpticalFlowBM(frame0, frame1, block_size, shift_size, max_range, false, velx, vely); - } - - CPU_SANITY_CHECK(velx); - CPU_SANITY_CHECK(vely); + CPU_SANITY_CHECK(u); + CPU_SANITY_CHECK(v); } } PERF_TEST_P(ImagePair, Video_FastOpticalFlowBM, - Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) + Values(make_pair("gpu/opticalflow/frame0.png", "gpu/opticalflow/frame1.png"))) { declare.time(400); - cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); + const cv::Mat frame0 = readImage(GetParam().first, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame0.empty()); - cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); + const cv::Mat frame1 = readImage(GetParam().second, cv::IMREAD_GRAYSCALE); ASSERT_FALSE(frame1.empty()); - cv::Size block_size(16, 16); - cv::Size shift_size(1, 1); - cv::Size max_range(16, 16); + const cv::Size block_size(16, 16); + const cv::Size shift_size(1, 1); + const cv::Size max_range(16, 16); if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_frame0(frame0); - cv::gpu::GpuMat d_frame1(frame1); - cv::gpu::GpuMat d_velx, d_vely; + const cv::gpu::GpuMat d_frame0(frame0); + const cv::gpu::GpuMat d_frame1(frame1); + cv::gpu::GpuMat u, v; cv::gpu::FastOpticalFlowBM fastBM; - fastBM(d_frame0, d_frame1, d_velx, d_vely, max_range.width, block_size.width); + TEST_CYCLE() fastBM(d_frame0, d_frame1, u, v, max_range.width, block_size.width); - TEST_CYCLE() - { - fastBM(d_frame0, d_frame1, d_velx, d_vely, max_range.width, block_size.width); - } - - GPU_SANITY_CHECK(d_velx); - GPU_SANITY_CHECK(d_vely); + GPU_SANITY_CHECK(u); + GPU_SANITY_CHECK(v); } else { - cv::Mat velx, vely; - - calcOpticalFlowBM(frame0, frame1, block_size, shift_size, max_range, false, velx, vely); - - TEST_CYCLE() - { - calcOpticalFlowBM(frame0, frame1, block_size, shift_size, max_range, false, velx, vely); - } - - CPU_SANITY_CHECK(velx); - CPU_SANITY_CHECK(vely); + FAIL_NO_CPU(); } } @@ -566,11 +484,12 @@ PERF_TEST_P(ImagePair, Video_FastOpticalFlowBM, DEF_PARAM_TEST_1(Video, string); -PERF_TEST_P(Video, DISABLED_Video_FGDStatModel, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi")) +PERF_TEST_P(Video, Video_FGDStatModel, + Values(string("gpu/video/768x576.avi"))) { declare.time(60); - string inputFile = perf::TestBase::getDataPath(GetParam()); + const string inputFile = perf::TestBase::getDataPath(GetParam()); cv::VideoCapture cap(inputFile); ASSERT_TRUE(cap.isOpened()); @@ -597,6 +516,12 @@ PERF_TEST_P(Video, DISABLED_Video_FGDStatModel, Values("gpu/video/768x576.avi", d_model.update(d_frame); stopTimer(); } + + const cv::gpu::GpuMat background = d_model.background; + const cv::gpu::GpuMat foreground = d_model.foreground; + + GPU_SANITY_CHECK(background, 1e-2, ERROR_RELATIVE); + GPU_SANITY_CHECK(foreground, 1e-2, ERROR_RELATIVE); } else { @@ -614,6 +539,12 @@ PERF_TEST_P(Video, DISABLED_Video_FGDStatModel, Values("gpu/video/768x576.avi", cvUpdateBGStatModel(&ipl_frame, model); stopTimer(); } + + const cv::Mat background = model->background; + const cv::Mat foreground = model->foreground; + + CPU_SANITY_CHECK(background); + CPU_SANITY_CHECK(foreground); } } @@ -622,12 +553,14 @@ PERF_TEST_P(Video, DISABLED_Video_FGDStatModel, Values("gpu/video/768x576.avi", DEF_PARAM_TEST(Video_Cn_LearningRate, string, MatCn, double); -PERF_TEST_P(Video_Cn_LearningRate, DISABLED_Video_MOG, - Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), GPU_CHANNELS_1_3_4, Values(0.0, 0.01))) +PERF_TEST_P(Video_Cn_LearningRate, Video_MOG, + Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), + GPU_CHANNELS_1_3_4, + Values(0.0, 0.01))) { - string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); - int cn = GET_PARAM(1); - float learningRate = static_cast(GET_PARAM(2)); + const string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); + const int cn = GET_PARAM(1); + const float learningRate = static_cast(GET_PARAM(2)); cv::VideoCapture cap(inputFile); ASSERT_TRUE(cap.isOpened()); @@ -651,9 +584,9 @@ PERF_TEST_P(Video_Cn_LearningRate, DISABLED_Video_MOG, { cv::gpu::GpuMat d_frame(frame); cv::gpu::MOG_GPU d_mog; - cv::gpu::GpuMat d_foreground; + cv::gpu::GpuMat foreground; - d_mog(d_frame, d_foreground, learningRate); + d_mog(d_frame, foreground, learningRate); for (int i = 0; i < 10; ++i) { @@ -673,9 +606,11 @@ PERF_TEST_P(Video_Cn_LearningRate, DISABLED_Video_MOG, d_frame.upload(frame); startTimer(); next(); - d_mog(d_frame, d_foreground, learningRate); + d_mog(d_frame, foreground, learningRate); stopTimer(); } + + GPU_SANITY_CHECK(foreground); } else { @@ -703,6 +638,8 @@ PERF_TEST_P(Video_Cn_LearningRate, DISABLED_Video_MOG, mog(frame, foreground, learningRate); stopTimer(); } + + CPU_SANITY_CHECK(foreground); } } @@ -711,11 +648,12 @@ PERF_TEST_P(Video_Cn_LearningRate, DISABLED_Video_MOG, DEF_PARAM_TEST(Video_Cn, string, int); -PERF_TEST_P(Video_Cn, DISABLED_Video_MOG2, - Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Video_Cn, Video_MOG2, + Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), + GPU_CHANNELS_1_3_4)) { - string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); - int cn = GET_PARAM(1); + const string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); + const int cn = GET_PARAM(1); cv::VideoCapture cap(inputFile); ASSERT_TRUE(cap.isOpened()); @@ -739,9 +677,9 @@ PERF_TEST_P(Video_Cn, DISABLED_Video_MOG2, { cv::gpu::GpuMat d_frame(frame); cv::gpu::MOG2_GPU d_mog2; - cv::gpu::GpuMat d_foreground; + cv::gpu::GpuMat foreground; - d_mog2(d_frame, d_foreground); + d_mog2(d_frame, foreground); for (int i = 0; i < 10; ++i) { @@ -761,9 +699,11 @@ PERF_TEST_P(Video_Cn, DISABLED_Video_MOG2, d_frame.upload(frame); startTimer(); next(); - d_mog2(d_frame, d_foreground); + d_mog2(d_frame, foreground); stopTimer(); } + + GPU_SANITY_CHECK(foreground); } else { @@ -791,6 +731,8 @@ PERF_TEST_P(Video_Cn, DISABLED_Video_MOG2, mog2(frame, foreground); stopTimer(); } + + CPU_SANITY_CHECK(foreground); } } @@ -798,10 +740,11 @@ PERF_TEST_P(Video_Cn, DISABLED_Video_MOG2, // MOG2GetBackgroundImage PERF_TEST_P(Video_Cn, Video_MOG2GetBackgroundImage, - Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), GPU_CHANNELS_1_3_4)) + Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), + GPU_CHANNELS_1_3_4)) { - string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); - int cn = GET_PARAM(1); + const string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); + const int cn = GET_PARAM(1); cv::VideoCapture cap(inputFile); ASSERT_TRUE(cap.isOpened()); @@ -834,15 +777,11 @@ PERF_TEST_P(Video_Cn, Video_MOG2GetBackgroundImage, d_mog2(d_frame, d_foreground); } - cv::gpu::GpuMat d_background; - d_mog2.getBackgroundImage(d_background); + cv::gpu::GpuMat background; - TEST_CYCLE() - { - d_mog2.getBackgroundImage(d_background); - } + TEST_CYCLE() d_mog2.getBackgroundImage(background); - GPU_SANITY_CHECK(d_background); + GPU_SANITY_CHECK(background, 1); } else { @@ -868,12 +807,8 @@ PERF_TEST_P(Video_Cn, Video_MOG2GetBackgroundImage, } cv::Mat background; - mog2.getBackgroundImage(background); - TEST_CYCLE() - { - mog2.getBackgroundImage(background); - } + TEST_CYCLE() mog2.getBackgroundImage(background); CPU_SANITY_CHECK(background); } @@ -882,11 +817,12 @@ PERF_TEST_P(Video_Cn, Video_MOG2GetBackgroundImage, ////////////////////////////////////////////////////// // VIBE -PERF_TEST_P(Video_Cn, DISABLED_Video_VIBE, - Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), GPU_CHANNELS_1_3_4)) +PERF_TEST_P(Video_Cn, Video_VIBE, + Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), + GPU_CHANNELS_1_3_4)) { - string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); - int cn = GET_PARAM(1); + const string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); + const int cn = GET_PARAM(1); cv::VideoCapture cap(inputFile); ASSERT_TRUE(cap.isOpened()); @@ -908,10 +844,10 @@ PERF_TEST_P(Video_Cn, DISABLED_Video_VIBE, if (PERF_RUN_GPU()) { cv::gpu::GpuMat d_frame(frame); - cv::gpu::VIBE_GPU d_vibe; - cv::gpu::GpuMat d_foreground; + cv::gpu::VIBE_GPU vibe; + cv::gpu::GpuMat foreground; - d_vibe(d_frame, d_foreground); + vibe(d_frame, foreground); for (int i = 0; i < 10; ++i) { @@ -931,13 +867,15 @@ PERF_TEST_P(Video_Cn, DISABLED_Video_VIBE, d_frame.upload(frame); startTimer(); next(); - d_vibe(d_frame, d_foreground); + vibe(d_frame, foreground); stopTimer(); } + + GPU_SANITY_CHECK(foreground); } else { - FAIL() << "No such CPU implementation analogy"; + FAIL_NO_CPU(); } } @@ -946,12 +884,14 @@ PERF_TEST_P(Video_Cn, DISABLED_Video_VIBE, DEF_PARAM_TEST(Video_Cn_MaxFeatures, string, MatCn, int); -PERF_TEST_P(Video_Cn_MaxFeatures, DISABLED_Video_GMG, - Combine(Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi"), GPU_CHANNELS_1_3_4, Values(20, 40, 60))) +PERF_TEST_P(Video_Cn_MaxFeatures, Video_GMG, + Combine(Values(string("gpu/video/768x576.avi")), + GPU_CHANNELS_1_3_4, + Values(20, 40, 60))) { - std::string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); - int cn = GET_PARAM(1); - int maxFeatures = GET_PARAM(2); + const std::string inputFile = perf::TestBase::getDataPath(GET_PARAM(0)); + const int cn = GET_PARAM(1); + const int maxFeatures = GET_PARAM(2); cv::VideoCapture cap(inputFile); ASSERT_TRUE(cap.isOpened()); @@ -973,12 +913,12 @@ PERF_TEST_P(Video_Cn_MaxFeatures, DISABLED_Video_GMG, if (PERF_RUN_GPU()) { cv::gpu::GpuMat d_frame(frame); - cv::gpu::GpuMat d_fgmask; + cv::gpu::GpuMat foreground; cv::gpu::GMG_GPU d_gmg; d_gmg.maxFeatures = maxFeatures; - d_gmg(d_frame, d_fgmask); + d_gmg(d_frame, foreground); for (int i = 0; i < 150; ++i) { @@ -1003,20 +943,22 @@ PERF_TEST_P(Video_Cn_MaxFeatures, DISABLED_Video_GMG, d_frame.upload(frame); startTimer(); next(); - d_gmg(d_frame, d_fgmask); + d_gmg(d_frame, foreground); stopTimer(); } + + GPU_SANITY_CHECK(foreground); } else { - cv::Mat fgmask; + cv::Mat foreground; cv::Mat zeros(frame.size(), CV_8UC1, cv::Scalar::all(0)); cv::BackgroundSubtractorGMG gmg; gmg.set("maxFeatures", maxFeatures); gmg.initialize(frame.size(), 0.0, 255.0); - gmg(frame, fgmask); + gmg(frame, foreground); for (int i = 0; i < 150; ++i) { @@ -1039,21 +981,60 @@ PERF_TEST_P(Video_Cn_MaxFeatures, DISABLED_Video_GMG, } startTimer(); next(); - gmg(frame, fgmask); + gmg(frame, foreground); stopTimer(); } + + CPU_SANITY_CHECK(foreground); + } +} + +#ifdef HAVE_NVCUVID + +////////////////////////////////////////////////////// +// VideoReader + +PERF_TEST_P(Video, Video_VideoReader, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi")) +{ + declare.time(20); + + const string inputFile = perf::TestBase::getDataPath(GetParam()); + + if (PERF_RUN_GPU()) + { + cv::gpu::VideoReader_GPU d_reader(inputFile); + ASSERT_TRUE( d_reader.isOpened() ); + + cv::gpu::GpuMat frame; + + TEST_CYCLE_N(10) d_reader.read(frame); + + GPU_SANITY_CHECK(frame); + } + else + { + cv::VideoCapture reader(inputFile); + ASSERT_TRUE( reader.isOpened() ); + + cv::Mat frame; + + TEST_CYCLE_N(10) reader >> frame; + + CPU_SANITY_CHECK(frame); } } ////////////////////////////////////////////////////// // VideoWriter -PERF_TEST_P(Video, DISABLED_Video_VideoWriter, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi")) +#ifdef WIN32 + +PERF_TEST_P(Video, Video_VideoWriter, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi")) { declare.time(30); - string inputFile = perf::TestBase::getDataPath(GetParam()); - string outputFile = cv::tempfile(".avi"); + const string inputFile = perf::TestBase::getDataPath(GetParam()); + const string outputFile = cv::tempfile(".avi"); const double FPS = 25.0; @@ -1100,49 +1081,10 @@ PERF_TEST_P(Video, DISABLED_Video_VideoWriter, Values("gpu/video/768x576.avi", " stopTimer(); } } + + SANITY_CHECK(frame); } -////////////////////////////////////////////////////// -// VideoReader +#endif // WIN32 -PERF_TEST_P(Video, Video_VideoReader, Values("gpu/video/768x576.avi", "gpu/video/1920x1080.avi")) -{ - declare.time(20); - - string inputFile = perf::TestBase::getDataPath(GetParam()); - - if (PERF_RUN_GPU()) - { - cv::gpu::VideoReader_GPU d_reader(inputFile); - ASSERT_TRUE( d_reader.isOpened() ); - - cv::gpu::GpuMat d_frame; - - d_reader.read(d_frame); - - TEST_CYCLE_N(10) - { - d_reader.read(d_frame); - } - - GPU_SANITY_CHECK(d_frame); - } - else - { - cv::VideoCapture reader(inputFile); - ASSERT_TRUE( reader.isOpened() ); - - cv::Mat frame; - - reader >> frame; - - TEST_CYCLE_N(10) - { - reader >> frame; - } - - CPU_SANITY_CHECK(frame); - } -} - -} // namespace +#endif // HAVE_NVCUVID diff --git a/modules/gpu/perf/utility.cpp b/modules/gpu/perf/utility.cpp index c3099030b2..16c61e0c7d 100644 --- a/modules/gpu/perf/utility.cpp +++ b/modules/gpu/perf/utility.cpp @@ -2,13 +2,6 @@ using namespace std; using namespace cv; -using namespace cv::gpu; - -void fillRandom(Mat& m, double a, double b) -{ - RNG rng(123456789); - rng.fill(m, RNG::UNIFORM, Scalar::all(a), Scalar::all(b)); -} Mat readImage(const string& fileName, int flags) { @@ -188,4 +181,4 @@ void PrintTo(const CvtColorInfo& info, ostream* os) }; *os << str[info.code]; -} \ No newline at end of file +} diff --git a/modules/gpu/perf/utility.hpp b/modules/gpu/perf/utility.hpp index 6782b93768..cff4cdd77d 100644 --- a/modules/gpu/perf/utility.hpp +++ b/modules/gpu/perf/utility.hpp @@ -2,11 +2,9 @@ #define __OPENCV_PERF_GPU_UTILITY_HPP__ #include "opencv2/core/core.hpp" -#include "opencv2/core/gpumat.hpp" #include "opencv2/imgproc/imgproc.hpp" #include "opencv2/ts/ts_perf.hpp" -void fillRandom(cv::Mat& m, double a = 0.0, double b = 255.0); cv::Mat readImage(const std::string& fileName, int flags = cv::IMREAD_COLOR); using perf::MatType; @@ -17,12 +15,13 @@ CV_ENUM(BorderMode, cv::BORDER_REFLECT101, cv::BORDER_REPLICATE, cv::BORDER_CONS CV_ENUM(Interpolation, cv::INTER_NEAREST, cv::INTER_LINEAR, cv::INTER_CUBIC, cv::INTER_AREA) #define ALL_INTERPOLATIONS testing::ValuesIn(Interpolation::all()) + CV_ENUM(NormType, cv::NORM_INF, cv::NORM_L1, cv::NORM_L2, cv::NORM_HAMMING, cv::NORM_MINMAX) -const int Gray = 1, TwoChannel = 2, BGR = 3, BGRA = 4; +enum { Gray = 1, TwoChannel = 2, BGR = 3, BGRA = 4 }; CV_ENUM(MatCn, Gray, TwoChannel, BGR, BGRA) -#define GPU_CHANNELS_1_3_4 testing::Values(Gray, BGR, BGRA) -#define GPU_CHANNELS_1_3 testing::Values(Gray, BGR) +#define GPU_CHANNELS_1_3_4 testing::Values(MatCn(Gray), MatCn(BGR), MatCn(BGRA)) +#define GPU_CHANNELS_1_3 testing::Values(MatCn(Gray), MatCn(BGR)) struct CvtColorInfo { @@ -30,7 +29,8 @@ struct CvtColorInfo int dcn; int code; - explicit CvtColorInfo(int scn_=0, int dcn_=0, int code_=0) : scn(scn_), dcn(dcn_), code(code_) {} + CvtColorInfo() {} + explicit CvtColorInfo(int scn_, int dcn_, int code_) : scn(scn_), dcn(dcn_), code(code_) {} }; void PrintTo(const CvtColorInfo& info, std::ostream* os); @@ -46,39 +46,18 @@ DEF_PARAM_TEST(Sz_Depth_Cn, cv::Size, MatDepth, MatCn); #define GPU_TYPICAL_MAT_SIZES testing::Values(perf::sz720p, perf::szSXGA, perf::sz1080p) -#define GPU_SANITY_CHECK(dmat, ...) \ +#define FAIL_NO_CPU() FAIL() << "No such CPU implementation analogy" + +#define GPU_SANITY_CHECK(mat, ...) \ do{ \ - cv::Mat d##dmat(dmat); \ - SANITY_CHECK(d##dmat, ## __VA_ARGS__); \ + cv::Mat gpu_##mat(mat); \ + SANITY_CHECK(gpu_##mat, ## __VA_ARGS__); \ } while(0) -#define CPU_SANITY_CHECK(cmat, ...) \ +#define CPU_SANITY_CHECK(mat, ...) \ do{ \ - SANITY_CHECK(cmat, ## __VA_ARGS__); \ + cv::Mat cpu_##mat(mat); \ + SANITY_CHECK(cpu_##mat, ## __VA_ARGS__); \ } while(0) -#define GPU_SANITY_CHECK_KEYPOINTS(alg, dmat, ...) \ - do{ \ - cv::Mat d##dmat(dmat); \ - cv::Mat __pt_x = d##dmat.row(cv::gpu::alg##_GPU::X_ROW); \ - cv::Mat __pt_y = d##dmat.row(cv::gpu::alg##_GPU::Y_ROW); \ - cv::Mat __angle = d##dmat.row(cv::gpu::alg##_GPU::ANGLE_ROW); \ - cv::Mat __octave = d##dmat.row(cv::gpu::alg##_GPU::OCTAVE_ROW); \ - cv::Mat __size = d##dmat.row(cv::gpu::alg##_GPU::SIZE_ROW); \ - ::perf::Regression::add(this, std::string(#dmat) + "-pt-x-row", __pt_x, ## __VA_ARGS__); \ - ::perf::Regression::add(this, std::string(#dmat) + "-pt-y-row", __pt_y, ## __VA_ARGS__); \ - ::perf::Regression::add(this, std::string(#dmat) + "-angle-row", __angle, ## __VA_ARGS__); \ - ::perf::Regression::add(this, std::string(#dmat) + "octave-row", __octave, ## __VA_ARGS__); \ - ::perf::Regression::add(this, std::string(#dmat) + "-pt-size-row", __size, ## __VA_ARGS__); \ - } while(0) - -#define GPU_SANITY_CHECK_RESPONSE(alg, dmat, ...) \ - do{ \ - cv::Mat d##dmat(dmat); \ - cv::Mat __response = d##dmat.row(cv::gpu::alg##_GPU::RESPONSE_ROW); \ - ::perf::Regression::add(this, std::string(#dmat) + "-response-row", __response, ## __VA_ARGS__); \ - } while(0) - -#define FAIL_NO_CPU() FAIL() << "No such CPU implementation analogy" - #endif // __OPENCV_PERF_GPU_UTILITY_HPP__ diff --git a/modules/gpu/src/graphcuts.cpp b/modules/gpu/src/graphcuts.cpp index ab1607059a..49230e65a9 100644 --- a/modules/gpu/src/graphcuts.cpp +++ b/modules/gpu/src/graphcuts.cpp @@ -104,12 +104,12 @@ void cv::gpu::connectivityMask(const GpuMat& image, GpuMat& mask, const cv::Scal void cv::gpu::labelComponents(const GpuMat& mask, GpuMat& components, int flags, Stream& s) { - if (!TargetArchs::builtWith(SHARED_ATOMICS) || !DeviceInfo().supports(SHARED_ATOMICS)) - CV_Error(CV_StsNotImplemented, "The device doesn't support shared atomics and communicative synchronization!"); CV_Assert(!mask.empty() && mask.type() == CV_8U); - if (mask.size() != components.size() || components.type() != CV_32SC1) - components.create(mask.size(), CV_32SC1); + if (!deviceSupports(SHARED_ATOMICS)) + CV_Error(CV_StsNotImplemented, "The device doesn't support shared atomics and communicative synchronization!"); + + components.create(mask.size(), CV_32SC1); cudaStream_t stream = StreamAccessor::getStream(s); device::ccl::labelComponents(mask, components, flags, stream); diff --git a/modules/gpu/src/imgproc.cpp b/modules/gpu/src/imgproc.cpp index 3184717185..d9ca46844e 100644 --- a/modules/gpu/src/imgproc.cpp +++ b/modules/gpu/src/imgproc.cpp @@ -522,6 +522,7 @@ void cv::gpu::rotate(const GpuMat& src, GpuMat& dst, Size dsize, double angle, d CV_Assert(interpolation == INTER_NEAREST || interpolation == INTER_LINEAR || interpolation == INTER_CUBIC); dst.create(dsize, src.type()); + dst.setTo(Scalar::all(0)); funcs[src.depth()][src.channels() - 1](src, dst, dsize, angle, xShift, yShift, interpolation, StreamAccessor::getStream(stream)); } diff --git a/modules/gpu/src/mssegmentation.cpp b/modules/gpu/src/mssegmentation.cpp index 39c0b5c686..65b05b7c74 100644 --- a/modules/gpu/src/mssegmentation.cpp +++ b/modules/gpu/src/mssegmentation.cpp @@ -382,6 +382,7 @@ void cv::gpu::meanShiftSegmentation(const GpuMat& src, Mat& dst, int sp, int sr, dstcol[0] = static_cast(sumcol[0] / comps.size[parent]); dstcol[1] = static_cast(sumcol[1] / comps.size[parent]); dstcol[2] = static_cast(sumcol[2] / comps.size[parent]); + dstcol[3] = 255; } } } diff --git a/modules/gpu/src/pyrlk.cpp b/modules/gpu/src/pyrlk.cpp index 148bcb5dd9..ffc035c022 100644 --- a/modules/gpu/src/pyrlk.cpp +++ b/modules/gpu/src/pyrlk.cpp @@ -209,6 +209,8 @@ void cv::gpu::PyrLKOpticalFlow::dense(const GpuMat& prevImg, const GpuMat& nextI ensureSizeIsEnough(prevImg.size(), CV_32FC1, vPyr_[0]); ensureSizeIsEnough(prevImg.size(), CV_32FC1, uPyr_[1]); ensureSizeIsEnough(prevImg.size(), CV_32FC1, vPyr_[1]); + uPyr_[0].setTo(Scalar::all(0)); + vPyr_[0].setTo(Scalar::all(0)); uPyr_[1].setTo(Scalar::all(0)); vPyr_[1].setTo(Scalar::all(0)); diff --git a/modules/gpu/src/warp.cpp b/modules/gpu/src/warp.cpp index 0fb19addaa..827d5219f1 100644 --- a/modules/gpu/src/warp.cpp +++ b/modules/gpu/src/warp.cpp @@ -232,10 +232,8 @@ void cv::gpu::warpAffine(const GpuMat& src, GpuMat& dst, const Mat& M, Size dsiz }; bool useNpp = borderMode == BORDER_CONSTANT && ofs.x == 0 && ofs.y == 0 && useNppTab[src.depth()][src.channels() - 1][interpolation]; - #ifdef linux - // NPP bug on float data - useNpp = useNpp && src.depth() != CV_32F; - #endif + // NPP bug on float data + useNpp = useNpp && src.depth() != CV_32F; if (useNpp) { @@ -372,10 +370,8 @@ void cv::gpu::warpPerspective(const GpuMat& src, GpuMat& dst, const Mat& M, Size }; bool useNpp = borderMode == BORDER_CONSTANT && ofs.x == 0 && ofs.y == 0 && useNppTab[src.depth()][src.channels() - 1][interpolation]; - #ifdef linux - // NPP bug on float data - useNpp = useNpp && src.depth() != CV_32F; - #endif + // NPP bug on float data + useNpp = useNpp && src.depth() != CV_32F; if (useNpp) { From 4f7cfbc26ed42a881f34a77de0e19e3a4579334c Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 26 Feb 2013 13:50:33 +0400 Subject: [PATCH 05/33] fixed gpu bitwise operations with scalars --- modules/gpu/src/cuda/element_operations.cu | 9 ++++-- modules/gpu/src/element_operations.cpp | 36 ++++++++++------------ modules/gpu/test/test_core.cpp | 2 +- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/modules/gpu/src/cuda/element_operations.cu b/modules/gpu/src/cuda/element_operations.cu index 27fb61ff70..5165b352ae 100644 --- a/modules/gpu/src/cuda/element_operations.cu +++ b/modules/gpu/src/cuda/element_operations.cu @@ -2284,15 +2284,18 @@ namespace arithm template void bitScalarAnd(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); template void bitScalarAnd(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); - template void bitScalarAnd(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); + template void bitScalarAnd(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); + template void bitScalarAnd(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); template void bitScalarOr(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); template void bitScalarOr(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); - template void bitScalarOr(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); + template void bitScalarOr(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); + template void bitScalarOr(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); template void bitScalarXor(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); template void bitScalarXor(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); - template void bitScalarXor(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); + template void bitScalarXor(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); + template void bitScalarXor(PtrStepSzb src1, uint src2, PtrStepSzb dst, cudaStream_t stream); } ////////////////////////////////////////////////////////////////////////// diff --git a/modules/gpu/src/element_operations.cpp b/modules/gpu/src/element_operations.cpp index 3d6cde377c..eedb31364a 100644 --- a/modules/gpu/src/element_operations.cpp +++ b/modules/gpu/src/element_operations.cpp @@ -2280,11 +2280,11 @@ namespace { typedef void (*bit_scalar_func_t)(PtrStepSzb src1, unsigned int src2, PtrStepSzb dst, cudaStream_t stream); - template struct BitScalar + template struct BitScalar { static void call(const GpuMat& src, Scalar sc, GpuMat& dst, cudaStream_t stream) { - func(src, static_cast(sc.val[0]), dst, stream); + func(src, saturate_cast(sc.val[0]), dst, stream); } }; @@ -2292,14 +2292,12 @@ namespace { static void call(const GpuMat& src, Scalar sc, GpuMat& dst, cudaStream_t stream) { - Scalar_ isc = sc; - unsigned int packedVal = 0; - packedVal |= (isc.val[0] & 0xffff); - packedVal |= (isc.val[1] & 0xffff) << 8; - packedVal |= (isc.val[2] & 0xffff) << 16; - packedVal |= (isc.val[3] & 0xffff) << 24; + packedVal |= (saturate_cast(sc.val[0]) & 0xffff); + packedVal |= (saturate_cast(sc.val[1]) & 0xffff) << 8; + packedVal |= (saturate_cast(sc.val[2]) & 0xffff) << 16; + packedVal |= (saturate_cast(sc.val[3]) & 0xffff) << 24; func(src, packedVal, dst, stream); } @@ -2330,7 +2328,7 @@ namespace oSizeROI.width = src.cols; oSizeROI.height = src.rows; - const npp_t pConstants[] = {static_cast(sc.val[0]), static_cast(sc.val[1]), static_cast(sc.val[2]), static_cast(sc.val[3])}; + const npp_t pConstants[] = {saturate_cast(sc.val[0]), saturate_cast(sc.val[1]), saturate_cast(sc.val[2]), saturate_cast(sc.val[3])}; nppSafeCall( func(src.ptr(), static_cast(src.step), pConstants, dst.ptr(), static_cast(dst.step), oSizeROI) ); @@ -2350,7 +2348,7 @@ namespace oSizeROI.width = src.cols; oSizeROI.height = src.rows; - nppSafeCall( func(src.ptr(), static_cast(src.step), static_cast(sc.val[0]), dst.ptr(), static_cast(dst.step), oSizeROI) ); + nppSafeCall( func(src.ptr(), static_cast(src.step), saturate_cast(sc.val[0]), dst.ptr(), static_cast(dst.step), oSizeROI) ); if (stream == 0) cudaSafeCall( cudaDeviceSynchronize() ); @@ -2365,11 +2363,11 @@ void cv::gpu::bitwise_and(const GpuMat& src, const Scalar& sc, GpuMat& dst, Stre typedef void (*func_t)(const GpuMat& src, Scalar sc, GpuMat& dst, cudaStream_t stream); static const func_t funcs[5][4] = { - {BitScalar< bitScalarAnd >::call , 0, NppBitwiseC::call, BitScalar4< bitScalarAnd >::call}, + {BitScalar >::call , 0, NppBitwiseC::call, BitScalar4< bitScalarAnd >::call}, {0,0,0,0}, - {BitScalar< bitScalarAnd >::call, 0, NppBitwiseC::call, NppBitwiseC::call}, + {BitScalar >::call, 0, NppBitwiseC::call, NppBitwiseC::call}, {0,0,0,0}, - {BitScalar< bitScalarAnd >::call , 0, NppBitwiseC::call, NppBitwiseC::call} + {BitScalar >::call , 0, NppBitwiseC::call, NppBitwiseC::call} }; const int depth = src.depth(); @@ -2390,11 +2388,11 @@ void cv::gpu::bitwise_or(const GpuMat& src, const Scalar& sc, GpuMat& dst, Strea typedef void (*func_t)(const GpuMat& src, Scalar sc, GpuMat& dst, cudaStream_t stream); static const func_t funcs[5][4] = { - {BitScalar< bitScalarOr >::call , 0, NppBitwiseC::call, BitScalar4< bitScalarOr >::call}, + {BitScalar >::call , 0, NppBitwiseC::call, BitScalar4< bitScalarOr >::call}, {0,0,0,0}, - {BitScalar< bitScalarOr >::call, 0, NppBitwiseC::call, NppBitwiseC::call}, + {BitScalar >::call, 0, NppBitwiseC::call, NppBitwiseC::call}, {0,0,0,0}, - {BitScalar< bitScalarOr >::call , 0, NppBitwiseC::call, NppBitwiseC::call} + {BitScalar >::call , 0, NppBitwiseC::call, NppBitwiseC::call} }; const int depth = src.depth(); @@ -2415,11 +2413,11 @@ void cv::gpu::bitwise_xor(const GpuMat& src, const Scalar& sc, GpuMat& dst, Stre typedef void (*func_t)(const GpuMat& src, Scalar sc, GpuMat& dst, cudaStream_t stream); static const func_t funcs[5][4] = { - {BitScalar< bitScalarXor >::call , 0, NppBitwiseC::call, BitScalar4< bitScalarXor >::call}, + {BitScalar >::call , 0, NppBitwiseC::call, BitScalar4< bitScalarXor >::call}, {0,0,0,0}, - {BitScalar< bitScalarXor >::call, 0, NppBitwiseC::call, NppBitwiseC::call}, + {BitScalar >::call, 0, NppBitwiseC::call, NppBitwiseC::call}, {0,0,0,0}, - {BitScalar< bitScalarXor >::call , 0, NppBitwiseC::call, NppBitwiseC::call} + {BitScalar >::call , 0, NppBitwiseC::call, NppBitwiseC::call} }; const int depth = src.depth(); diff --git a/modules/gpu/test/test_core.cpp b/modules/gpu/test/test_core.cpp index 736256cd51..affc30610a 100644 --- a/modules/gpu/test/test_core.cpp +++ b/modules/gpu/test/test_core.cpp @@ -1873,7 +1873,7 @@ PARAM_TEST_CASE(Bitwise_Scalar, cv::gpu::DeviceInfo, cv::Size, MatDepth, Channel cv::gpu::setDevice(devInfo.deviceID()); src = randomMat(size, CV_MAKE_TYPE(depth, channels)); - cv::Scalar_ ival = randomScalar(0.0, 255.0); + cv::Scalar_ ival = randomScalar(0.0, std::numeric_limits::max()); val = ival; } }; From c9868fc01fb7d01b2135103efffe210481895e7b Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Tue, 26 Feb 2013 13:52:42 +0400 Subject: [PATCH 06/33] fixed warp tests --- modules/gpu/test/test_warp_affine.cpp | 2 ++ modules/gpu/test/test_warp_perspective.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/modules/gpu/test/test_warp_affine.cpp b/modules/gpu/test/test_warp_affine.cpp index de8bc5d795..fe3a1353b1 100644 --- a/modules/gpu/test/test_warp_affine.cpp +++ b/modules/gpu/test/test_warp_affine.cpp @@ -252,6 +252,8 @@ PARAM_TEST_CASE(WarpAffineNPP, cv::gpu::DeviceInfo, MatType, Inverse, Interpolat GPU_TEST_P(WarpAffineNPP, Accuracy) { cv::Mat src = readImageType("stereobp/aloe-L.png", type); + ASSERT_FALSE(src.empty()); + cv::Mat M = createTransfomMatrix(src.size(), CV_PI / 4); int flags = interpolation; if (inverse) diff --git a/modules/gpu/test/test_warp_perspective.cpp b/modules/gpu/test/test_warp_perspective.cpp index 534edc0d2b..dd2054a049 100644 --- a/modules/gpu/test/test_warp_perspective.cpp +++ b/modules/gpu/test/test_warp_perspective.cpp @@ -255,6 +255,8 @@ PARAM_TEST_CASE(WarpPerspectiveNPP, cv::gpu::DeviceInfo, MatType, Inverse, Inter GPU_TEST_P(WarpPerspectiveNPP, Accuracy) { cv::Mat src = readImageType("stereobp/aloe-L.png", type); + ASSERT_FALSE(src.empty()); + cv::Mat M = createTransfomMatrix(src.size(), CV_PI / 4); int flags = interpolation; if (inverse) From 024185b9ed7c290e19211a3c11d9502dc8ec1ca5 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Wed, 27 Feb 2013 12:41:33 +0400 Subject: [PATCH 07/33] Fix OpenCVConfig.cmake generated for Android platform (issue #2496) * fix path to libraries in Android SDK * allow to link to opencv_java.so as Android.mk does To link to opencv_java.so you can either change your cmake to find OpenCV as find_package(OpenCV opencv_java) or pass -DOpenCV_FIND_COMPONENTS=opencv_java to your cmake command --- cmake/OpenCVGenConfig.cmake | 13 +++++++++++-- cmake/templates/OpenCVConfig.cmake.in | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cmake/OpenCVGenConfig.cmake b/cmake/OpenCVGenConfig.cmake index f8d9e27db4..705ccc8df1 100644 --- a/cmake/OpenCVGenConfig.cmake +++ b/cmake/OpenCVGenConfig.cmake @@ -53,6 +53,10 @@ if(OpenCV_LIB_COMPONENTS) list(REMOVE_ITEM OPENCV_MODULES_CONFIGCMAKE ${OpenCV_LIB_COMPONENTS}) endif() +if(BUILD_FAT_JAVA_LIB AND HAVE_opencv_java) + list(APPEND OPENCV_MODULES_CONFIGCMAKE opencv_java) +endif() + macro(ocv_generate_dependencies_map_configcmake suffix configuration) set(OPENCV_DEPENDENCIES_MAP_${suffix} "") set(OPENCV_PROCESSED_LIBS "") @@ -126,8 +130,13 @@ configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig-version.cmake. set(OpenCV_INCLUDE_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/${OPENCV_INCLUDE_INSTALL_PATH}/opencv" "\${OpenCV_INSTALL_PATH}/${OPENCV_INCLUDE_INSTALL_PATH}\"") set(OpenCV2_INCLUDE_DIRS_CONFIGCMAKE "\"\"") -set(OpenCV_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/${OPENCV_LIB_INSTALL_PATH}\"") -set(OpenCV_3RDPARTY_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/${OPENCV_3P_LIB_INSTALL_PATH}\"") +if(ANDROID) + set(OpenCV_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/sdk/native/libs/\${ANDROID_NDK_ABI_NAME}\"") + set(OpenCV_3RDPARTY_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/sdk/native/3rdparty/libs/\${ANDROID_NDK_ABI_NAME}\"") +else() + set(OpenCV_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/${OPENCV_LIB_INSTALL_PATH}\"") + set(OpenCV_3RDPARTY_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/${OPENCV_3P_LIB_INSTALL_PATH}\"") +endif() if(INSTALL_TO_MANGLED_PATHS) string(REPLACE "OpenCV" "OpenCV-${OPENCV_VERSION}" OpenCV_3RDPARTY_LIB_DIRS_CONFIGCMAKE "${OPENCV_3P_LIB_INSTALL_PATH}") set(OpenCV_3RDPARTY_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/${OpenCV_3RDPARTY_LIB_DIRS_CONFIGCMAKE}\"") diff --git a/cmake/templates/OpenCVConfig.cmake.in b/cmake/templates/OpenCVConfig.cmake.in index 235c72b8dc..96473781da 100644 --- a/cmake/templates/OpenCVConfig.cmake.in +++ b/cmake/templates/OpenCVConfig.cmake.in @@ -151,6 +151,7 @@ endif() # ============================================================== if(NOT OpenCV_FIND_COMPONENTS) set(OpenCV_FIND_COMPONENTS ${OpenCV_LIB_COMPONENTS}) + list(REMOVE_ITEM OpenCV_FIND_COMPONENTS opencv_java) if(GTest_FOUND OR GTEST_FOUND) list(REMOVE_ITEM OpenCV_FIND_COMPONENTS opencv_ts) endif() From 69eebdd608b7bd5ba59c790c5a5e504f868d05b8 Mon Sep 17 00:00:00 2001 From: yao Date: Thu, 28 Feb 2013 09:03:10 +0800 Subject: [PATCH 08/33] fix the blend crash in some cases --- modules/ocl/src/blend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ocl/src/blend.cpp b/modules/ocl/src/blend.cpp index 5eead4766b..ed4a40069b 100644 --- a/modules/ocl/src/blend.cpp +++ b/modules/ocl/src/blend.cpp @@ -74,7 +74,7 @@ void cv::ocl::blendLinear(const oclMat &img1, const oclMat &img2, const oclMat & size_t localSize[] = {256, 1, 1}; vector< pair > args; - + result.create(img1.size(), CV_MAKE_TYPE(depth,img1.channels())); if(globalSize[0] != 0) { args.push_back( make_pair( sizeof(cl_mem), (void *)&result.data )); From ed3c3822fc7779fdb1145323e802801448f32f2b Mon Sep 17 00:00:00 2001 From: yao Date: Thu, 28 Feb 2013 12:15:13 +0800 Subject: [PATCH 09/33] adjust some test cases, use original template file name in Haar --- samples/ocl/performance.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/samples/ocl/performance.cpp b/samples/ocl/performance.cpp index 20fa04574e..c0073c5fb6 100644 --- a/samples/ocl/performance.cpp +++ b/samples/ocl/performance.cpp @@ -25,7 +25,7 @@ using namespace cv; // This program test most of the functions in ocl module and generate data metrix of x-factor in .csv files // All images needed in this test are in samples/gpu folder. -// For haar template, please rename it to facedetect.xml +// For haar template, haarcascade_frontalface_alt.xml shouold be in working directory void gen(Mat &mat, int rows, int cols, int type, Scalar low, Scalar high); string abspath(const string &relpath); @@ -707,7 +707,7 @@ TEST(matchTemplate) for (size_t j = 0; j < sizeof(all_type) / sizeof(int); j++) { - for(templ_size = 5; templ_size <=5; templ_size *= 5) + for(templ_size = 5; templ_size <= 5; templ_size *= 5) { gen(src, size, size, all_type[j], 0, 1); @@ -749,7 +749,7 @@ TEST(matchTemplate) for (size_t j = 0; j < sizeof(all_type_8U) / sizeof(int); j++) { - for(templ_size = 5; templ_size < 200; templ_size *= 5) + for(templ_size = 5; templ_size <= 5; templ_size *= 5) { SUBTEST << src.cols << 'x' << src.rows << "; " << type_name_8U[j] << "; templ " << templ_size << 'x' << templ_size << "; CCORR_NORMED"; @@ -1063,9 +1063,9 @@ TEST(Haar) CascadeClassifier faceCascadeCPU; - if (!faceCascadeCPU.load(abspath("facedetect.xml"))) + if (!faceCascadeCPU.load(abspath("haarcascade_frontalface_alt.xml"))) { - throw runtime_error("can't load facedetect.xml"); + throw runtime_error("can't load haarcascade_frontalface_alt.xml"); } vector faces; @@ -1079,9 +1079,9 @@ TEST(Haar) #ifdef USE_OPENCL ocl::CascadeClassifier_GPU faceCascade; - if (!faceCascade.load(abspath("facedetect.xml"))) + if (!faceCascade.load(abspath("haarcascade_frontalface_alt.xml"))) { - throw runtime_error("can't load facedetect.xml"); + throw runtime_error("can't load haarcascade_frontalface_alt.xml"); } ocl::oclMat d_img(img); From 7c1f1d8837497403504de49e8f4b311e1a20ca45 Mon Sep 17 00:00:00 2001 From: yao Date: Thu, 28 Feb 2013 14:05:36 +0800 Subject: [PATCH 10/33] fix bug #2787 --- modules/ocl/src/kernels/nonfree_surf.cl | 77 ++++++++----- modules/ocl/src/surf.cpp | 144 +++++++++++------------- 2 files changed, 116 insertions(+), 105 deletions(-) diff --git a/modules/ocl/src/kernels/nonfree_surf.cl b/modules/ocl/src/kernels/nonfree_surf.cl index 5916b2557c..69f64795e9 100644 --- a/modules/ocl/src/kernels/nonfree_surf.cl +++ b/modules/ocl/src/kernels/nonfree_surf.cl @@ -78,7 +78,7 @@ uchar read_imgTex(IMAGE_INT8 img, sampler_t sam, float2 coord, int rows, int col // dynamically change the precision used for floating type -#if defined (__ATI__) || defined (__NVIDIA__) +#if defined DOUBLE_SUPPORT #define F double #else #define F float @@ -299,7 +299,7 @@ __kernel __global const float * det, __global const float * trace, __global int4 * maxPosBuffer, - volatile __global unsigned int* maxCounter, + volatile __global int* maxCounter, int counter_offset, int det_step, // the step of det in bytes int trace_step, // the step of trace in bytes @@ -408,7 +408,7 @@ __kernel if(condmax) { - unsigned int ind = atomic_inc(maxCounter); + int ind = atomic_inc(maxCounter); if (ind < c_max_candidates) { @@ -427,7 +427,7 @@ __kernel __global float * det, __global float * trace, __global int4 * maxPosBuffer, - volatile __global unsigned int* maxCounter, + volatile __global int* maxCounter, int counter_offset, int det_step, // the step of det in bytes int trace_step, // the step of trace in bytes @@ -525,7 +525,7 @@ __kernel if(condmax) { - unsigned int ind = atomic_inc(maxCounter); + int ind = atomic_inc(maxCounter); if (ind < c_max_candidates) { @@ -585,7 +585,7 @@ __kernel __global const float * det, __global const int4 * maxPosBuffer, __global float * keypoints, - volatile __global unsigned int * featureCounter, + volatile __global int * featureCounter, int det_step, int keypoints_step, int c_img_rows, @@ -684,7 +684,7 @@ __kernel if ((c_img_rows + 1) >= grad_wav_size && (c_img_cols + 1) >= grad_wav_size) { // Get a new feature index. - unsigned int ind = atomic_inc(featureCounter); + int ind = atomic_inc(featureCounter); if (ind < c_max_features) { @@ -737,19 +737,19 @@ __constant float c_aptW[ORI_SAMPLES] = {0.001455130288377404f, 0.001707611023448 __constant float c_NX[2][5] = {{0, 0, 2, 4, -1}, {2, 0, 4, 4, 1}}; __constant float c_NY[2][5] = {{0, 0, 4, 2, 1}, {0, 2, 4, 4, -1}}; -void reduce_32_sum(volatile __local float * data, float partial_reduction, int tid) +void reduce_32_sum(volatile __local float * data, volatile float* partial_reduction, int tid) { -#define op(A, B) (A)+(B) - data[tid] = partial_reduction; +#define op(A, B) (*A)+(B) + data[tid] = *partial_reduction; barrier(CLK_LOCAL_MEM_FENCE); if (tid < 16) { - data[tid] = partial_reduction = op(partial_reduction, data[tid + 16]); - data[tid] = partial_reduction = op(partial_reduction, data[tid + 8 ]); - data[tid] = partial_reduction = op(partial_reduction, data[tid + 4 ]); - data[tid] = partial_reduction = op(partial_reduction, data[tid + 2 ]); - data[tid] = partial_reduction = op(partial_reduction, data[tid + 1 ]); + data[tid] = *partial_reduction = op(partial_reduction, data[tid + 16]); + data[tid] = *partial_reduction = op(partial_reduction, data[tid + 8 ]); + data[tid] = *partial_reduction = op(partial_reduction, data[tid + 4 ]); + data[tid] = *partial_reduction = op(partial_reduction, data[tid + 2 ]); + data[tid] = *partial_reduction = op(partial_reduction, data[tid + 1 ]); } #undef op } @@ -831,7 +831,7 @@ __kernel { const int dir = (i * 4 + get_local_id(1)) * ORI_SEARCH_INC; - float sumx = 0.0f, sumy = 0.0f; + volatile float sumx = 0.0f, sumy = 0.0f; int d = abs(convert_int_rte(s_angle[get_local_id(0)]) - dir); if (d < ORI_WIN / 2 || d > 360 - ORI_WIN / 2) { @@ -856,8 +856,8 @@ __kernel sumx += s_X[get_local_id(0) + 96]; sumy += s_Y[get_local_id(0) + 96]; } - reduce_32_sum(s_sumx + get_local_id(1) * 32, sumx, get_local_id(0)); - reduce_32_sum(s_sumy + get_local_id(1) * 32, sumy, get_local_id(0)); + reduce_32_sum(s_sumx + get_local_id(1) * 32, &sumx, get_local_id(0)); + reduce_32_sum(s_sumy + get_local_id(1) * 32, &sumy, get_local_id(0)); const float temp_mod = sumx * sumx + sumy * sumy; if (temp_mod > best_mod) @@ -892,14 +892,32 @@ __kernel kp_dir += 2.0f * CV_PI_F; kp_dir *= 180.0f / CV_PI_F; - kp_dir = 360.0f - kp_dir; - if (fabs(kp_dir - 360.f) < FLT_EPSILON) - kp_dir = 0.f; + //kp_dir = 360.0f - kp_dir; + //if (fabs(kp_dir - 360.f) < FLT_EPSILON) + // kp_dir = 0.f; featureDir[get_group_id(0)] = kp_dir; } } + +__kernel + void icvSetUpright( + __global float * keypoints, + int keypoints_step, + int nFeatures + ) +{ + keypoints_step /= sizeof(*keypoints); + __global float* featureDir = keypoints + ANGLE_ROW * keypoints_step; + + if(get_global_id(0) <= nFeatures) + { + featureDir[get_global_id(0)] = 90.0f; + } +} + + #undef ORI_SEARCH_INC #undef ORI_WIN #undef ORI_SAMPLES @@ -993,10 +1011,7 @@ void calc_dx_dy( const float centerX = featureX[get_group_id(0)]; const float centerY = featureY[get_group_id(0)]; const float size = featureSize[get_group_id(0)]; - float descriptor_dir = 360.0f - featureDir[get_group_id(0)]; - if (fabs(descriptor_dir - 360.f) < FLT_EPSILON) - descriptor_dir = 0.f; - descriptor_dir *= (float)(CV_PI_F / 180.0f); + float descriptor_dir = featureDir[get_group_id(0)] * (float)(CV_PI_F / 180.0f); /* The sampling intervals and wavelet sized for selecting an orientation and building the keypoint descriptor are defined relative to 's' */ @@ -1125,11 +1140,15 @@ __kernel { sdxabs[tid] = fabs(sdx[tid]); // |dx| array sdyabs[tid] = fabs(sdy[tid]); // |dy| array - //barrier(CLK_LOCAL_MEM_FENCE); - + } + barrier(CLK_LOCAL_MEM_FENCE); + if (tid < 25) + { reduce_sum25(sdx, sdy, sdxabs, sdyabs, tid); - //barrier(CLK_LOCAL_MEM_FENCE); - + } + barrier(CLK_LOCAL_MEM_FENCE); + if (tid < 25) + { volatile __global float* descriptors_block = descriptors + descriptors_step * get_group_id(0) + (get_group_id(1) << 2); // write dx, dy, |dx|, |dy| diff --git a/modules/ocl/src/surf.cpp b/modules/ocl/src/surf.cpp index 2e06f4439f..fec21f623e 100644 --- a/modules/ocl/src/surf.cpp +++ b/modules/ocl/src/surf.cpp @@ -57,6 +57,21 @@ namespace cv { ///////////////////////////OpenCL kernel strings/////////////////////////// extern const char *nonfree_surf; + + const char* noImage2dOption = "-D DISABLE_IMAGE2D"; + + void openCLExecuteKernelSURF(Context *clCxt , const char **source, string kernelName, size_t globalThreads[3], + size_t localThreads[3], vector< pair > &args, int channels, int depth) + { + if(support_image2d()) + { + openCLExecuteKernel(clCxt, source, kernelName, globalThreads, localThreads, args, channels, depth); + } + else + { + openCLExecuteKernel(clCxt, source, kernelName, globalThreads, localThreads, args, channels, depth, noImage2dOption); + } + } } } @@ -80,10 +95,6 @@ static inline int calcSize(int octave, int layer) return (HAAR_SIZE0 + HAAR_SIZE_INC * layer) << octave; } -namespace -{ - const char* noImage2dOption = "-D DISABLE_IMAGE2D"; -} class SURF_OCL_Invoker { @@ -100,15 +111,16 @@ public: void icvFindMaximaInLayer_gpu(const oclMat &det, const oclMat &trace, oclMat &maxPosBuffer, oclMat &maxCounter, int counterOffset, int octave, bool use_mask, int nLayers, int layer_rows, int layer_cols); - void icvInterpolateKeypoint_gpu(const oclMat &det, const oclMat &maxPosBuffer, unsigned int maxCounter, + void icvInterpolateKeypoint_gpu(const oclMat &det, const oclMat &maxPosBuffer, int maxCounter, oclMat &keypoints, oclMat &counters, int octave, int layer_rows, int maxFeatures); void icvCalcOrientation_gpu(const oclMat &keypoints, int nFeatures); + void icvSetUpright_gpu(const oclMat &keypoints, int nFeatures); + void compute_descriptors_gpu(const oclMat &descriptors, const oclMat &keypoints, int nFeatures); // end of kernel callers declarations - SURF_OCL_Invoker(SURF_OCL &surf, const oclMat &img, const oclMat &mask) : surf_(surf), img_cols(img.cols), img_rows(img.rows), @@ -182,8 +194,8 @@ public: icvFindMaximaInLayer_gpu(surf_.det, surf_.trace, surf_.maxPosBuffer, counters, 1 + octave, octave, use_mask, surf_.nOctaveLayers, layer_rows, layer_cols); - unsigned int maxCounter = Mat(counters).at(1 + octave); - maxCounter = std::min(maxCounter, static_cast(maxCandidates)); + int maxCounter = ((Mat)counters).at(1 + octave); + maxCounter = std::min(maxCounter, static_cast(maxCandidates)); if (maxCounter > 0) { @@ -191,15 +203,29 @@ public: keypoints, counters, octave, layer_rows, maxFeatures); } } - unsigned int featureCounter = Mat(counters).at(0); - featureCounter = std::min(featureCounter, static_cast(maxFeatures)); + int featureCounter = Mat(counters).at(0); + featureCounter = std::min(featureCounter, static_cast(maxFeatures)); keypoints.cols = featureCounter; if (surf_.upright) - keypoints.row(SURF_OCL::ANGLE_ROW).setTo(Scalar::all(90.0)); + { + //keypoints.row(SURF_OCL::ANGLE_ROW).setTo(Scalar::all(90.0)); + setUpright(keypoints); + } else + { findOrientation(keypoints); + } + } + + void setUpright(oclMat &keypoints) + { + const int nFeatures = keypoints.cols; + if(nFeatures > 0) + { + icvSetUpright_gpu(keypoints, keypoints.cols); + } } void findOrientation(oclMat &keypoints) @@ -484,14 +510,7 @@ void SURF_OCL_Invoker::icvCalcLayerDetAndTrace_gpu(oclMat &det, oclMat &trace, i divUp(max_samples_i, localThreads[1]) *localThreads[1] *(nOctaveLayers + 2), 1 }; - if(support_image2d()) - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); - } - else - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1, noImage2dOption); - } + openCLExecuteKernelSURF(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); } void SURF_OCL_Invoker::icvFindMaximaInLayer_gpu(const oclMat &det, const oclMat &trace, oclMat &maxPosBuffer, oclMat &maxCounter, int counterOffset, @@ -537,17 +556,10 @@ void SURF_OCL_Invoker::icvFindMaximaInLayer_gpu(const oclMat &det, const oclMat 1 }; - if(support_image2d()) - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); - } - else - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1, noImage2dOption); - } + openCLExecuteKernelSURF(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); } -void SURF_OCL_Invoker::icvInterpolateKeypoint_gpu(const oclMat &det, const oclMat &maxPosBuffer, unsigned int maxCounter, +void SURF_OCL_Invoker::icvInterpolateKeypoint_gpu(const oclMat &det, const oclMat &maxPosBuffer, int maxCounter, oclMat &keypoints, oclMat &counters, int octave, int layer_rows, int maxFeatures) { Context *clCxt = det.clCxt; @@ -569,14 +581,7 @@ void SURF_OCL_Invoker::icvInterpolateKeypoint_gpu(const oclMat &det, const oclMa size_t localThreads[3] = {3, 3, 3}; size_t globalThreads[3] = {maxCounter *localThreads[0], localThreads[1], 1}; - if(support_image2d()) - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); - } - else - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1, noImage2dOption); - } + openCLExecuteKernelSURF(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); } void SURF_OCL_Invoker::icvCalcOrientation_gpu(const oclMat &keypoints, int nFeatures) @@ -603,16 +608,27 @@ void SURF_OCL_Invoker::icvCalcOrientation_gpu(const oclMat &keypoints, int nFeat size_t localThreads[3] = {32, 4, 1}; size_t globalThreads[3] = {nFeatures *localThreads[0], localThreads[1], 1}; - if(support_image2d()) - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); - } - else - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1, noImage2dOption); - } + openCLExecuteKernelSURF(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); } +void SURF_OCL_Invoker::icvSetUpright_gpu(const oclMat &keypoints, int nFeatures) +{ + Context *clCxt = counters.clCxt; + string kernelName = "icvSetUpright"; + + vector< pair > args; + + args.push_back( make_pair( sizeof(cl_mem), (void *)&keypoints.data)); + args.push_back( make_pair( sizeof(cl_int), (void *)&keypoints.step)); + args.push_back( make_pair( sizeof(cl_int), (void *)&nFeatures)); + + size_t localThreads[3] = {256, 1, 1}; + size_t globalThreads[3] = {nFeatures, 1, 1}; + + openCLExecuteKernelSURF(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); +} + + void SURF_OCL_Invoker::compute_descriptors_gpu(const oclMat &descriptors, const oclMat &keypoints, int nFeatures) { // compute unnormalized descriptors, then normalize them - odd indexing since grid must be 2D @@ -648,14 +664,8 @@ void SURF_OCL_Invoker::compute_descriptors_gpu(const oclMat &descriptors, const args.push_back( make_pair( sizeof(cl_int), (void *)&_img.rows)); args.push_back( make_pair( sizeof(cl_int), (void *)&_img.cols)); args.push_back( make_pair( sizeof(cl_int), (void *)&_img.step)); - if(support_image2d()) - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); - } - else - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1, noImage2dOption); - } + + openCLExecuteKernelSURF(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); kernelName = "normalize_descriptors64"; @@ -668,14 +678,8 @@ void SURF_OCL_Invoker::compute_descriptors_gpu(const oclMat &descriptors, const args.clear(); args.push_back( make_pair( sizeof(cl_mem), (void *)&descriptors.data)); args.push_back( make_pair( sizeof(cl_int), (void *)&descriptors.step)); - if(support_image2d()) - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); - } - else - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1, noImage2dOption); - } + + openCLExecuteKernelSURF(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); } else { @@ -703,14 +707,8 @@ void SURF_OCL_Invoker::compute_descriptors_gpu(const oclMat &descriptors, const args.push_back( make_pair( sizeof(cl_int), (void *)&_img.rows)); args.push_back( make_pair( sizeof(cl_int), (void *)&_img.cols)); args.push_back( make_pair( sizeof(cl_int), (void *)&_img.step)); - if(support_image2d()) - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); - } - else - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1, noImage2dOption); - } + + openCLExecuteKernelSURF(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); kernelName = "normalize_descriptors128"; @@ -723,14 +721,8 @@ void SURF_OCL_Invoker::compute_descriptors_gpu(const oclMat &descriptors, const args.clear(); args.push_back( make_pair( sizeof(cl_mem), (void *)&descriptors.data)); args.push_back( make_pair( sizeof(cl_int), (void *)&descriptors.step)); - if(support_image2d()) - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); - } - else - { - openCLExecuteKernel(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1, noImage2dOption); - } + + openCLExecuteKernelSURF(clCxt, &nonfree_surf, kernelName, globalThreads, localThreads, args, -1, -1); } } From df456245e7cb6438456e5304b212bea8ea964809 Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Wed, 27 Feb 2013 16:44:36 +0400 Subject: [PATCH 11/33] fixed ffmpeg destination folder for NMake generator --- modules/highgui/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/highgui/CMakeLists.txt b/modules/highgui/CMakeLists.txt index 8474d5e625..7e5fae39bd 100644 --- a/modules/highgui/CMakeLists.txt +++ b/modules/highgui/CMakeLists.txt @@ -282,7 +282,7 @@ if(WIN32 AND WITH_FFMPEG) COMMAND ${CMAKE_COMMAND} -E copy "${ffmpeg_path}" "${EXECUTABLE_OUTPUT_PATH}/Release/${ffmpeg_bare_name_ver}" COMMAND ${CMAKE_COMMAND} -E copy "${ffmpeg_path}" "${EXECUTABLE_OUTPUT_PATH}/Debug/${ffmpeg_bare_name_ver}" COMMENT "Copying ${ffmpeg_path} to the output directory") - elseif(MSVC) + elseif(MSVC AND (CMAKE_GENERATOR MATCHES "Visual")) add_custom_command(TARGET ${the_module} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${ffmpeg_path}" "${EXECUTABLE_OUTPUT_PATH}/${CMAKE_BUILD_TYPE}/${ffmpeg_bare_name_ver}" COMMENT "Copying ${ffmpeg_path} to the output directory") From 504008dbe0335dac46f9e63da82361a7a2483adc Mon Sep 17 00:00:00 2001 From: yao Date: Thu, 28 Feb 2013 14:31:08 +0800 Subject: [PATCH 12/33] Fix ocl::bruteforcematcher crash on Intel OCL --- modules/ocl/src/brute_force_matcher.cpp | 40 +- modules/ocl/src/kernels/brute_force_match.cl | 1369 +++++++++--------- 2 files changed, 730 insertions(+), 679 deletions(-) diff --git a/modules/ocl/src/brute_force_matcher.cpp b/modules/ocl/src/brute_force_matcher.cpp index c81e342d35..76b1436d29 100644 --- a/modules/ocl/src/brute_force_matcher.cpp +++ b/modules/ocl/src/brute_force_matcher.cpp @@ -51,7 +51,6 @@ using namespace cv; using namespace cv::ocl; using namespace std; -using namespace std; namespace cv { namespace ocl @@ -62,7 +61,7 @@ namespace cv } template < int BLOCK_SIZE, int MAX_DESC_LEN, typename T/*, typename Mask*/ > -void matchUnrolledCached(const oclMat &query, const oclMat &train, const oclMat &mask, +void matchUnrolledCached(const oclMat &query, const oclMat &train, const oclMat &/*mask*/, const oclMat &trainIdx, const oclMat &distance, int distType) { cv::ocl::Context *ctx = query.clCxt; @@ -77,7 +76,7 @@ void matchUnrolledCached(const oclMat &query, const oclMat &train, const oclMat { args.push_back( make_pair( sizeof(cl_mem), (void *)&query.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&train.data )); - args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); + //args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&trainIdx.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&distance.data )); args.push_back( make_pair( smemSize, (void *)NULL)); @@ -103,7 +102,7 @@ void matchUnrolledCached(const oclMat /*query*/, const oclMat * /*trains*/, int } template < int BLOCK_SIZE, typename T/*, typename Mask*/ > -void match(const oclMat &query, const oclMat &train, const oclMat &mask, +void match(const oclMat &query, const oclMat &train, const oclMat &/*mask*/, const oclMat &trainIdx, const oclMat &distance, int distType) { cv::ocl::Context *ctx = query.clCxt; @@ -117,7 +116,7 @@ void match(const oclMat &query, const oclMat &train, const oclMat &mask, { args.push_back( make_pair( sizeof(cl_mem), (void *)&query.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&train.data )); - args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); + //args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&trainIdx.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&distance.data )); args.push_back( make_pair( smemSize, (void *)NULL)); @@ -143,7 +142,7 @@ void match(const oclMat /*query*/, const oclMat * /*trains*/, int /*n*/, const o //radius_matchUnrolledCached template < int BLOCK_SIZE, int MAX_DESC_LEN, typename T/*, typename Mask*/ > -void matchUnrolledCached(const oclMat &query, const oclMat &train, float maxDistance, const oclMat &mask, +void matchUnrolledCached(const oclMat &query, const oclMat &train, float maxDistance, const oclMat &/*mask*/, const oclMat &trainIdx, const oclMat &distance, const oclMat &nMatches, int distType) { cv::ocl::Context *ctx = query.clCxt; @@ -159,7 +158,7 @@ void matchUnrolledCached(const oclMat &query, const oclMat &train, float maxDist args.push_back( make_pair( sizeof(cl_mem), (void *)&query.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&train.data )); args.push_back( make_pair( sizeof(cl_float), (void *)&maxDistance )); - args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); + //args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&trainIdx.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&distance.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&nMatches.data )); @@ -183,7 +182,7 @@ void matchUnrolledCached(const oclMat &query, const oclMat &train, float maxDist //radius_match template < int BLOCK_SIZE, typename T/*, typename Mask*/ > -void radius_match(const oclMat &query, const oclMat &train, float maxDistance, const oclMat &mask, +void radius_match(const oclMat &query, const oclMat &train, float maxDistance, const oclMat &/*mask*/, const oclMat &trainIdx, const oclMat &distance, const oclMat &nMatches, int distType) { cv::ocl::Context *ctx = query.clCxt; @@ -198,7 +197,7 @@ void radius_match(const oclMat &query, const oclMat &train, float maxDistance, c args.push_back( make_pair( sizeof(cl_mem), (void *)&query.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&train.data )); args.push_back( make_pair( sizeof(cl_float), (void *)&maxDistance )); - args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); + //args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&trainIdx.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&distance.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&nMatches.data )); @@ -472,7 +471,7 @@ void matchDispatcher(const oclMat &query, const oclMat &train, int n, float maxD //knn match Dispatcher template < int BLOCK_SIZE, int MAX_DESC_LEN, typename T/*, typename Mask*/ > -void knn_matchUnrolledCached(const oclMat &query, const oclMat &train, const oclMat &mask, +void knn_matchUnrolledCached(const oclMat &query, const oclMat &train, const oclMat &/*mask*/, const oclMat &trainIdx, const oclMat &distance, int distType) { cv::ocl::Context *ctx = query.clCxt; @@ -487,7 +486,7 @@ void knn_matchUnrolledCached(const oclMat &query, const oclMat &train, const ocl { args.push_back( make_pair( sizeof(cl_mem), (void *)&query.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&train.data )); - args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); + //args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&trainIdx.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&distance.data )); args.push_back( make_pair( smemSize, (void *)NULL)); @@ -507,7 +506,7 @@ void knn_matchUnrolledCached(const oclMat &query, const oclMat &train, const ocl } template < int BLOCK_SIZE, typename T/*, typename Mask*/ > -void knn_match(const oclMat &query, const oclMat &train, const oclMat &mask, +void knn_match(const oclMat &query, const oclMat &train, const oclMat &/*mask*/, const oclMat &trainIdx, const oclMat &distance, int distType) { cv::ocl::Context *ctx = query.clCxt; @@ -521,7 +520,7 @@ void knn_match(const oclMat &query, const oclMat &train, const oclMat &mask, { args.push_back( make_pair( sizeof(cl_mem), (void *)&query.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&train.data )); - args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); + //args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&trainIdx.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&distance.data )); args.push_back( make_pair( smemSize, (void *)NULL)); @@ -540,7 +539,7 @@ void knn_match(const oclMat &query, const oclMat &train, const oclMat &mask, } template < int BLOCK_SIZE, int MAX_DESC_LEN, typename T/*, typename Mask*/ > -void calcDistanceUnrolled(const oclMat &query, const oclMat &train, const oclMat &mask, const oclMat &allDist, int distType) +void calcDistanceUnrolled(const oclMat &query, const oclMat &train, const oclMat &/*mask*/, const oclMat &allDist, int distType) { cv::ocl::Context *ctx = query.clCxt; size_t globalSize[] = {(query.rows + BLOCK_SIZE - 1) / BLOCK_SIZE * BLOCK_SIZE, BLOCK_SIZE, 1}; @@ -554,7 +553,7 @@ void calcDistanceUnrolled(const oclMat &query, const oclMat &train, const oclMat { args.push_back( make_pair( sizeof(cl_mem), (void *)&query.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&train.data )); - args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); + //args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&allDist.data )); args.push_back( make_pair( smemSize, (void *)NULL)); args.push_back( make_pair( sizeof(cl_int), (void *)&block_size )); @@ -573,7 +572,7 @@ void calcDistanceUnrolled(const oclMat &query, const oclMat &train, const oclMat } template < int BLOCK_SIZE, typename T/*, typename Mask*/ > -void calcDistance(const oclMat &query, const oclMat &train, const oclMat &mask, const oclMat &allDist, int distType) +void calcDistance(const oclMat &query, const oclMat &train, const oclMat &/*mask*/, const oclMat &allDist, int distType) { cv::ocl::Context *ctx = query.clCxt; size_t globalSize[] = {(query.rows + BLOCK_SIZE - 1) / BLOCK_SIZE * BLOCK_SIZE, BLOCK_SIZE, 1}; @@ -586,7 +585,7 @@ void calcDistance(const oclMat &query, const oclMat &train, const oclMat &mask, { args.push_back( make_pair( sizeof(cl_mem), (void *)&query.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&train.data )); - args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); + //args.push_back( make_pair( sizeof(cl_mem), (void *)&mask.data )); args.push_back( make_pair( sizeof(cl_mem), (void *)&allDist.data )); args.push_back( make_pair( smemSize, (void *)NULL)); args.push_back( make_pair( sizeof(cl_int), (void *)&block_size )); @@ -691,7 +690,7 @@ void findKnnMatch(int k, const oclMat &trainIdx, const oclMat &distance, const o } } -static void findKnnMatchDispatcher(int k, const oclMat &trainIdx, const oclMat &distance, const oclMat &allDist, int distType) +void findKnnMatchDispatcher(int k, const oclMat &trainIdx, const oclMat &distance, const oclMat &allDist, int distType) { findKnnMatch<256>(k, trainIdx, distance, allDist, distType); } @@ -1007,6 +1006,7 @@ void cv::ocl::BruteForceMatcher_OCL_base::matchConvert(const Mat &trainIdx, cons void cv::ocl::BruteForceMatcher_OCL_base::match(const oclMat &query, const oclMat &train, vector &matches, const oclMat &mask) { + assert(mask.empty()); // mask is not supported at the moment oclMat trainIdx, distance; matchSingle(query, train, trainIdx, distance, mask); matchDownload(trainIdx, distance, matches); @@ -1696,4 +1696,6 @@ void cv::ocl::BruteForceMatcher_OCL_base::radiusMatch(const oclMat &query, vecto oclMat trainIdx, imgIdx, distance, nMatches; radiusMatchCollection(query, trainIdx, imgIdx, distance, nMatches, maxDistance, masks); radiusMatchDownload(trainIdx, imgIdx, distance, nMatches, matches, compactResult); -} \ No newline at end of file +} + + diff --git a/modules/ocl/src/kernels/brute_force_match.cl b/modules/ocl/src/kernels/brute_force_match.cl index a5d0d7b516..e5dd29ee0a 100644 --- a/modules/ocl/src/kernels/brute_force_match.cl +++ b/modules/ocl/src/kernels/brute_force_match.cl @@ -3,14 +3,16 @@ int bit1Count(float x) { - int c = 0; - int ix = (int)x; - for (int i = 0 ; i < 32 ; i++) - { - c += ix & 0x1; - ix >>= 1; - } - return (float)c; + int c = 0; + int ix = (int)x; + + for (int i = 0 ; i < 32 ; i++) + { + c += ix & 0x1; + ix >>= 1; + } + + return (float)c; } /* 2dim launch, global size: dim0 is (query rows + block_size - 1) / block_size * block_size, dim1 is block_size local size: dim0 is block_size, dim1 is block_size. @@ -18,7 +20,7 @@ local size: dim0 is block_size, dim1 is block_size. __kernel void BruteForceMatch_UnrollMatch( __global float *query, __global float *train, - __global float *mask, + //__global float *mask, __global int *bestTrainIdx, __global float *bestDistance, __local float *sharebuffer, @@ -30,113 +32,122 @@ __kernel void BruteForceMatch_UnrollMatch( int train_cols, int step, int distType - ) +) { - const int lidx = get_local_id(0); - const int lidy = get_local_id(1); - const int groupidx = get_group_id(0); - - __local float *s_query = sharebuffer; - __local float *s_train = sharebuffer + block_size * max_desc_len; - - int queryIdx = groupidx * block_size + lidy; - // load the query into local memory. - for (int i = 0 ; i < max_desc_len / block_size; i ++) - { - int loadx = lidx + i * block_size; - s_query[lidy * max_desc_len + loadx] = loadx < query_cols ? query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx] : 0; - } - - float myBestDistance = MAX_FLOAT; - int myBestTrainIdx = -1; - - // loopUnrolledCached to find the best trainIdx and best distance. - volatile int imgIdx = 0; - for (int t = 0 ; t < (train_rows + block_size - 1) / block_size ; t++) - { - float result = 0; - for (int i = 0 ; i < max_desc_len / block_size ; i++) - { - //load a block_size * block_size block into local train. - const int loadx = lidx + i * block_size; - s_train[lidx * block_size + lidy] = loadx < train_cols ? train[min(t * block_size + lidy, train_rows - 1) * (step / sizeof(float)) + loadx] : 0; - - //synchronize to make sure each elem for reduceIteration in share memory is written already. - barrier(CLK_LOCAL_MEM_FENCE); - - /* there are threee types in the reducer. the first is L1Dist, which to sum the abs(v1, v2), the second is L2Dist, which to - sum the (v1 - v2) * (v1 - v2), the third is humming, which to popc(v1 ^ v2), popc is to count the bits are set to 1*/ - - switch(distType) - { - case 0: - for (int j = 0 ; j < block_size ; j++) - { - result += fabs(s_query[lidy * max_desc_len + i * block_size + j] - s_train[j * block_size + lidx]); - } - break; - case 1: - for (int j = 0 ; j < block_size ; j++) - { - float qr = s_query[lidy * max_desc_len + i * block_size + j] - s_train[j * block_size + lidx]; - result += qr * qr; - } - break; - case 2: - for (int j = 0 ; j < block_size ; j++) - { - //result += popcount((uint)s_query[lidy * max_desc_len + i * block_size + j] ^ (uint)s_train[j * block_size + lidx]); - result += bit1Count((uint)s_query[lidy * max_desc_len + i * block_size + j] ^ (uint)s_train[j * block_size + lidx]); - } - break; - } - - barrier(CLK_LOCAL_MEM_FENCE); - } - - int trainIdx = t * block_size + lidx; - - if (queryIdx < query_rows && trainIdx < train_rows && result < myBestDistance/* && mask(queryIdx, trainIdx)*/) - { - //bestImgIdx = imgIdx; - myBestDistance = result; - myBestTrainIdx = trainIdx; - } - } - - barrier(CLK_LOCAL_MEM_FENCE); - __local float *s_distance = (__local float*)(sharebuffer); - __local int* s_trainIdx = (__local int *)(sharebuffer + block_size * block_size); - - //find BestMatch - s_distance += lidy * block_size; - s_trainIdx += lidy * block_size; - s_distance[lidx] = myBestDistance; - s_trainIdx[lidx] = myBestTrainIdx; - - barrier(CLK_LOCAL_MEM_FENCE); - - //reduce -- now all reduce implement in each threads. - for (int k = 0 ; k < block_size; k++) - { - if (myBestDistance > s_distance[k]) - { - myBestDistance = s_distance[k]; - myBestTrainIdx = s_trainIdx[k]; - } - } - - if (queryIdx < query_rows && lidx == 0) - { - bestTrainIdx[queryIdx] = myBestTrainIdx; - bestDistance[queryIdx] = myBestDistance; - } + const int lidx = get_local_id(0); + const int lidy = get_local_id(1); + const int groupidx = get_group_id(0); + + __local float *s_query = sharebuffer; + __local float *s_train = sharebuffer + block_size * max_desc_len; + + int queryIdx = groupidx * block_size + lidy; + + // load the query into local memory. + for (int i = 0 ; i < max_desc_len / block_size; i ++) + { + int loadx = lidx + i * block_size; + s_query[lidy * max_desc_len + loadx] = loadx < query_cols ? query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx] : 0; + } + + float myBestDistance = MAX_FLOAT; + int myBestTrainIdx = -1; + + // loopUnrolledCached to find the best trainIdx and best distance. + volatile int imgIdx = 0; + + for (int t = 0 ; t < (train_rows + block_size - 1) / block_size ; t++) + { + float result = 0; + + for (int i = 0 ; i < max_desc_len / block_size ; i++) + { + //load a block_size * block_size block into local train. + const int loadx = lidx + i * block_size; + s_train[lidx * block_size + lidy] = loadx < train_cols ? train[min(t * block_size + lidy, train_rows - 1) * (step / sizeof(float)) + loadx] : 0; + + //synchronize to make sure each elem for reduceIteration in share memory is written already. + barrier(CLK_LOCAL_MEM_FENCE); + + /* there are threee types in the reducer. the first is L1Dist, which to sum the abs(v1, v2), the second is L2Dist, which to + sum the (v1 - v2) * (v1 - v2), the third is humming, which to popc(v1 ^ v2), popc is to count the bits are set to 1*/ + + switch (distType) + { + case 0: + + for (int j = 0 ; j < block_size ; j++) + { + result += fabs(s_query[lidy * max_desc_len + i * block_size + j] - s_train[j * block_size + lidx]); + } + + break; + case 1: + + for (int j = 0 ; j < block_size ; j++) + { + float qr = s_query[lidy * max_desc_len + i * block_size + j] - s_train[j * block_size + lidx]; + result += qr * qr; + } + + break; + case 2: + + for (int j = 0 ; j < block_size ; j++) + { + //result += popcount((uint)s_query[lidy * max_desc_len + i * block_size + j] ^ (uint)s_train[j * block_size + lidx]); + result += bit1Count((uint)s_query[lidy * max_desc_len + i * block_size + j] ^(uint)s_train[j * block_size + lidx]); + } + + break; + } + + barrier(CLK_LOCAL_MEM_FENCE); + } + + int trainIdx = t * block_size + lidx; + + if (queryIdx < query_rows && trainIdx < train_rows && result < myBestDistance/* && mask(queryIdx, trainIdx)*/) + { + //bestImgIdx = imgIdx; + myBestDistance = result; + myBestTrainIdx = trainIdx; + } + } + + barrier(CLK_LOCAL_MEM_FENCE); + __local float *s_distance = (__local float *)(sharebuffer); + __local int *s_trainIdx = (__local int *)(sharebuffer + block_size * block_size); + + //find BestMatch + s_distance += lidy * block_size; + s_trainIdx += lidy * block_size; + s_distance[lidx] = myBestDistance; + s_trainIdx[lidx] = myBestTrainIdx; + + barrier(CLK_LOCAL_MEM_FENCE); + + //reduce -- now all reduce implement in each threads. + for (int k = 0 ; k < block_size; k++) + { + if (myBestDistance > s_distance[k]) + { + myBestDistance = s_distance[k]; + myBestTrainIdx = s_trainIdx[k]; + } + } + + if (queryIdx < query_rows && lidx == 0) + { + bestTrainIdx[queryIdx] = myBestTrainIdx; + bestDistance[queryIdx] = myBestDistance; + } } __kernel void BruteForceMatch_Match( __global float *query, __global float *train, - __global float *mask, + //__global float *mask, __global int *bestTrainIdx, __global float *bestDistance, __local float *sharebuffer, @@ -147,108 +158,115 @@ __kernel void BruteForceMatch_Match( int train_cols, int step, int distType - ) +) { - const int lidx = get_local_id(0); - const int lidy = get_local_id(1); - const int groupidx = get_group_id(0); - - const int queryIdx = groupidx * block_size + lidy; - - float myBestDistance = MAX_FLOAT; - int myBestTrainIdx = -1; - - __local float *s_query = sharebuffer; - __local float *s_train = sharebuffer + block_size * block_size; - - // loop - for (int t = 0 ; t < (train_rows + block_size - 1) / block_size ; t++) - { - //Dist dist; - float result = 0; - for (int i = 0 ; i < (query_cols + block_size - 1) / block_size ; i++) - { - const int loadx = lidx + i * block_size; - //load query and train into local memory - s_query[lidy * block_size + lidx] = 0; - s_train[lidx * block_size + lidy] = 0; - - if (loadx < query_cols) - { - s_query[lidy * block_size + lidx] = query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx]; - s_train[lidx * block_size + lidy] = train[min(t * block_size + lidy, train_rows - 1) * (step / sizeof(float)) + loadx]; - } - - barrier(CLK_LOCAL_MEM_FENCE); - - /* there are threee types in the reducer. the first is L1Dist, which to sum the abs(v1, v2), the second is L2Dist, which to - sum the (v1 - v2) * (v1 - v2), the third is humming, which to popc(v1 ^ v2), popc is to count the bits are set to 1*/ - - switch(distType) - { - case 0: - for (int j = 0 ; j < block_size ; j++) - { - result += fabs(s_query[lidy * block_size + j] - s_train[j * block_size + lidx]); - } - break; - case 1: - for (int j = 0 ; j < block_size ; j++) - { - float qr = s_query[lidy * block_size + j] - s_train[j * block_size + lidx]; - result += qr * qr; - } - break; - case 2: - for (int j = 0 ; j < block_size ; j++) - { - //result += popcount((uint)s_query[lidy * block_size + j] ^ (uint)s_train[j * block_size + lidx]); - result += bit1Count((uint)s_query[lidy * block_size + j] ^ (uint)s_train[(uint)j * block_size + lidx]); - } - break; - } - - barrier(CLK_LOCAL_MEM_FENCE); - } - - const int trainIdx = t * block_size + lidx; - - if (queryIdx < query_rows && trainIdx < train_rows && result < myBestDistance /*&& mask(queryIdx, trainIdx)*/) - { - //myBestImgidx = imgIdx; - myBestDistance = result; - myBestTrainIdx = trainIdx; - } - } - - barrier(CLK_LOCAL_MEM_FENCE); - - __local float *s_distance = (__local float *)sharebuffer; - __local int *s_trainIdx = (__local int *)(sharebuffer + block_size * block_size); - - //findBestMatch - s_distance += lidy * block_size; - s_trainIdx += lidy * block_size; - s_distance[lidx] = myBestDistance; - s_trainIdx[lidx] = myBestTrainIdx; - - barrier(CLK_LOCAL_MEM_FENCE); - - //reduce -- now all reduce implement in each threads. - for (int k = 0 ; k < block_size; k++) - { - if (myBestDistance > s_distance[k]) - { - myBestDistance = s_distance[k]; - myBestTrainIdx = s_trainIdx[k]; - } - } - - if (queryIdx < query_rows && lidx == 0) - { - bestTrainIdx[queryIdx] = myBestTrainIdx; - bestDistance[queryIdx] = myBestDistance; - } + const int lidx = get_local_id(0); + const int lidy = get_local_id(1); + const int groupidx = get_group_id(0); + + const int queryIdx = groupidx * block_size + lidy; + + float myBestDistance = MAX_FLOAT; + int myBestTrainIdx = -1; + + __local float *s_query = sharebuffer; + __local float *s_train = sharebuffer + block_size * block_size; + + // loop + for (int t = 0 ; t < (train_rows + block_size - 1) / block_size ; t++) + { + //Dist dist; + float result = 0; + + for (int i = 0 ; i < (query_cols + block_size - 1) / block_size ; i++) + { + const int loadx = lidx + i * block_size; + //load query and train into local memory + s_query[lidy * block_size + lidx] = 0; + s_train[lidx * block_size + lidy] = 0; + + if (loadx < query_cols) + { + s_query[lidy * block_size + lidx] = query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx]; + s_train[lidx * block_size + lidy] = train[min(t * block_size + lidy, train_rows - 1) * (step / sizeof(float)) + loadx]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + /* there are threee types in the reducer. the first is L1Dist, which to sum the abs(v1, v2), the second is L2Dist, which to + sum the (v1 - v2) * (v1 - v2), the third is humming, which to popc(v1 ^ v2), popc is to count the bits are set to 1*/ + + switch (distType) + { + case 0: + + for (int j = 0 ; j < block_size ; j++) + { + result += fabs(s_query[lidy * block_size + j] - s_train[j * block_size + lidx]); + } + + break; + case 1: + + for (int j = 0 ; j < block_size ; j++) + { + float qr = s_query[lidy * block_size + j] - s_train[j * block_size + lidx]; + result += qr * qr; + } + + break; + case 2: + + for (int j = 0 ; j < block_size ; j++) + { + //result += popcount((uint)s_query[lidy * block_size + j] ^ (uint)s_train[j * block_size + lidx]); + result += bit1Count((uint)s_query[lidy * block_size + j] ^(uint)s_train[(uint)j * block_size + lidx]); + } + + break; + } + + barrier(CLK_LOCAL_MEM_FENCE); + } + + const int trainIdx = t * block_size + lidx; + + if (queryIdx < query_rows && trainIdx < train_rows && result < myBestDistance /*&& mask(queryIdx, trainIdx)*/) + { + //myBestImgidx = imgIdx; + myBestDistance = result; + myBestTrainIdx = trainIdx; + } + } + + barrier(CLK_LOCAL_MEM_FENCE); + + __local float *s_distance = (__local float *)sharebuffer; + __local int *s_trainIdx = (__local int *)(sharebuffer + block_size * block_size); + + //findBestMatch + s_distance += lidy * block_size; + s_trainIdx += lidy * block_size; + s_distance[lidx] = myBestDistance; + s_trainIdx[lidx] = myBestTrainIdx; + + barrier(CLK_LOCAL_MEM_FENCE); + + //reduce -- now all reduce implement in each threads. + for (int k = 0 ; k < block_size; k++) + { + if (myBestDistance > s_distance[k]) + { + myBestDistance = s_distance[k]; + myBestTrainIdx = s_trainIdx[k]; + } + } + + if (queryIdx < query_rows && lidx == 0) + { + bestTrainIdx[queryIdx] = myBestTrainIdx; + bestDistance[queryIdx] = myBestDistance; + } } //radius_unrollmatch @@ -256,7 +274,7 @@ __kernel void BruteForceMatch_RadiusUnrollMatch( __global float *query, __global float *train, float maxDistance, - __global float *mask, + //__global float *mask, __global int *bestTrainIdx, __global float *bestDistance, __global int *nMatches, @@ -271,71 +289,78 @@ __kernel void BruteForceMatch_RadiusUnrollMatch( int step, int ostep, int distType - ) +) { - const int lidx = get_local_id(0); - const int lidy = get_local_id(1); - const int groupidx = get_group_id(0); - const int groupidy = get_group_id(1); - - const int queryIdx = groupidy * block_size + lidy; - const int trainIdx = groupidx * block_size + lidx; - - __local float *s_query = sharebuffer; - __local float *s_train = sharebuffer + block_size * block_size; - - float result = 0; - for (int i = 0 ; i < max_desc_len / block_size ; ++i) - { - //load a block_size * block_size block into local train. - const int loadx = lidx + i * block_size; - - s_query[lidy * block_size + lidx] = loadx < query_cols ? query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx] : 0; - s_train[lidx * block_size + lidy] = loadx < query_cols ? train[min(groupidx * block_size + lidy, train_rows - 1) * (step / sizeof(float)) + loadx] : 0; - - //synchronize to make sure each elem for reduceIteration in share memory is written already. - barrier(CLK_LOCAL_MEM_FENCE); - - /* there are three types in the reducer. the first is L1Dist, which to sum the abs(v1, v2), the second is L2Dist, which to - sum the (v1 - v2) * (v1 - v2), the third is humming, which to popc(v1 ^ v2), popc is to count the bits are set to 1*/ - - switch(distType) - { - case 0: - for (int j = 0 ; j < block_size ; ++j) - { - result += fabs(s_query[lidy * block_size + j] - s_train[j * block_size + lidx]); - } - break; - case 1: - for (int j = 0 ; j < block_size ; ++j) - { - float qr = s_query[lidy * block_size + j] - s_train[j * block_size + lidx]; - result += qr * qr; - } - break; - case 2: - for (int j = 0 ; j < block_size ; ++j) - { - result += bit1Count((uint)s_query[lidy * block_size + j] ^ (uint)s_train[j * block_size + lidx]); - } - break; - } - - barrier(CLK_LOCAL_MEM_FENCE); - } - - if (queryIdx < query_rows && trainIdx < train_rows && result < maxDistance/* && mask(queryIdx, trainIdx)*/) - { - unsigned int ind = atom_inc(nMatches + queryIdx/*, (unsigned int) -1*/); - - if(ind < bestTrainIdx_cols) - { - //bestImgIdx = imgIdx; - bestTrainIdx[queryIdx * (ostep / sizeof(int)) + ind] = trainIdx; - bestDistance[queryIdx * (ostep / sizeof(float)) + ind] = result; - } - } + const int lidx = get_local_id(0); + const int lidy = get_local_id(1); + const int groupidx = get_group_id(0); + const int groupidy = get_group_id(1); + + const int queryIdx = groupidy * block_size + lidy; + const int trainIdx = groupidx * block_size + lidx; + + __local float *s_query = sharebuffer; + __local float *s_train = sharebuffer + block_size * block_size; + + float result = 0; + + for (int i = 0 ; i < max_desc_len / block_size ; ++i) + { + //load a block_size * block_size block into local train. + const int loadx = lidx + i * block_size; + + s_query[lidy * block_size + lidx] = loadx < query_cols ? query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx] : 0; + s_train[lidx * block_size + lidy] = loadx < query_cols ? train[min(groupidx * block_size + lidy, train_rows - 1) * (step / sizeof(float)) + loadx] : 0; + + //synchronize to make sure each elem for reduceIteration in share memory is written already. + barrier(CLK_LOCAL_MEM_FENCE); + + /* there are three types in the reducer. the first is L1Dist, which to sum the abs(v1, v2), the second is L2Dist, which to + sum the (v1 - v2) * (v1 - v2), the third is humming, which to popc(v1 ^ v2), popc is to count the bits are set to 1*/ + + switch (distType) + { + case 0: + + for (int j = 0 ; j < block_size ; ++j) + { + result += fabs(s_query[lidy * block_size + j] - s_train[j * block_size + lidx]); + } + + break; + case 1: + + for (int j = 0 ; j < block_size ; ++j) + { + float qr = s_query[lidy * block_size + j] - s_train[j * block_size + lidx]; + result += qr * qr; + } + + break; + case 2: + + for (int j = 0 ; j < block_size ; ++j) + { + result += bit1Count((uint)s_query[lidy * block_size + j] ^(uint)s_train[j * block_size + lidx]); + } + + break; + } + + barrier(CLK_LOCAL_MEM_FENCE); + } + + if (queryIdx < query_rows && trainIdx < train_rows && result < maxDistance/* && mask(queryIdx, trainIdx)*/) + { + unsigned int ind = atom_inc(nMatches + queryIdx/*, (unsigned int) -1*/); + + if (ind < bestTrainIdx_cols) + { + //bestImgIdx = imgIdx; + bestTrainIdx[queryIdx * (ostep / sizeof(int)) + ind] = trainIdx; + bestDistance[queryIdx * (ostep / sizeof(float)) + ind] = result; + } + } } //radius_match @@ -343,7 +368,7 @@ __kernel void BruteForceMatch_RadiusMatch( __global float *query, __global float *train, float maxDistance, - __global float *mask, + //__global float *mask, __global int *bestTrainIdx, __global float *bestDistance, __global int *nMatches, @@ -357,78 +382,85 @@ __kernel void BruteForceMatch_RadiusMatch( int step, int ostep, int distType - ) +) { - const int lidx = get_local_id(0); - const int lidy = get_local_id(1); - const int groupidx = get_group_id(0); - const int groupidy = get_group_id(1); - - const int queryIdx = groupidy * block_size + lidy; - const int trainIdx = groupidx * block_size + lidx; - - __local float *s_query = sharebuffer; - __local float *s_train = sharebuffer + block_size * block_size; - - float result = 0; - for (int i = 0 ; i < (query_cols + block_size - 1) / block_size ; ++i) - { - //load a block_size * block_size block into local train. - const int loadx = lidx + i * block_size; - - s_query[lidy * block_size + lidx] = loadx < query_cols ? query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx] : 0; - s_train[lidx * block_size + lidy] = loadx < query_cols ? train[min(groupidx * block_size + lidy, train_rows - 1) * (step / sizeof(float)) + loadx] : 0; - - //synchronize to make sure each elem for reduceIteration in share memory is written already. - barrier(CLK_LOCAL_MEM_FENCE); - - /* there are three types in the reducer. the first is L1Dist, which to sum the abs(v1, v2), the second is L2Dist, which to - sum the (v1 - v2) * (v1 - v2), the third is humming, which to popc(v1 ^ v2), popc is to count the bits are set to 1*/ - - switch(distType) - { - case 0: - for (int j = 0 ; j < block_size ; ++j) - { - result += fabs(s_query[lidy * block_size + j] - s_train[j * block_size + lidx]); - } - break; - case 1: - for (int j = 0 ; j < block_size ; ++j) - { - float qr = s_query[lidy * block_size + j] - s_train[j * block_size + lidx]; - result += qr * qr; - } - break; - case 2: - for (int j = 0 ; j < block_size ; ++j) - { - result += bit1Count((uint)s_query[lidy * block_size + j] ^ (uint)s_train[j * block_size + lidx]); - } - break; - } - - barrier(CLK_LOCAL_MEM_FENCE); - } - - if (queryIdx < query_rows && trainIdx < train_rows && result < maxDistance/* && mask(queryIdx, trainIdx)*/) - { - unsigned int ind = atom_inc(nMatches + queryIdx/*, (unsigned int) -1*/); - - if(ind < bestTrainIdx_cols) - { - //bestImgIdx = imgIdx; - bestTrainIdx[queryIdx * (ostep / sizeof(int)) + ind] = trainIdx; - bestDistance[queryIdx * (ostep / sizeof(float)) + ind] = result; - } - } + const int lidx = get_local_id(0); + const int lidy = get_local_id(1); + const int groupidx = get_group_id(0); + const int groupidy = get_group_id(1); + + const int queryIdx = groupidy * block_size + lidy; + const int trainIdx = groupidx * block_size + lidx; + + __local float *s_query = sharebuffer; + __local float *s_train = sharebuffer + block_size * block_size; + + float result = 0; + + for (int i = 0 ; i < (query_cols + block_size - 1) / block_size ; ++i) + { + //load a block_size * block_size block into local train. + const int loadx = lidx + i * block_size; + + s_query[lidy * block_size + lidx] = loadx < query_cols ? query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx] : 0; + s_train[lidx * block_size + lidy] = loadx < query_cols ? train[min(groupidx * block_size + lidy, train_rows - 1) * (step / sizeof(float)) + loadx] : 0; + + //synchronize to make sure each elem for reduceIteration in share memory is written already. + barrier(CLK_LOCAL_MEM_FENCE); + + /* there are three types in the reducer. the first is L1Dist, which to sum the abs(v1, v2), the second is L2Dist, which to + sum the (v1 - v2) * (v1 - v2), the third is humming, which to popc(v1 ^ v2), popc is to count the bits are set to 1*/ + + switch (distType) + { + case 0: + + for (int j = 0 ; j < block_size ; ++j) + { + result += fabs(s_query[lidy * block_size + j] - s_train[j * block_size + lidx]); + } + + break; + case 1: + + for (int j = 0 ; j < block_size ; ++j) + { + float qr = s_query[lidy * block_size + j] - s_train[j * block_size + lidx]; + result += qr * qr; + } + + break; + case 2: + + for (int j = 0 ; j < block_size ; ++j) + { + result += bit1Count((uint)s_query[lidy * block_size + j] ^(uint)s_train[j * block_size + lidx]); + } + + break; + } + + barrier(CLK_LOCAL_MEM_FENCE); + } + + if (queryIdx < query_rows && trainIdx < train_rows && result < maxDistance/* && mask(queryIdx, trainIdx)*/) + { + unsigned int ind = atom_inc(nMatches + queryIdx/*, (unsigned int) -1*/); + + if (ind < bestTrainIdx_cols) + { + //bestImgIdx = imgIdx; + bestTrainIdx[queryIdx * (ostep / sizeof(int)) + ind] = trainIdx; + bestDistance[queryIdx * (ostep / sizeof(float)) + ind] = result; + } + } } __kernel void BruteForceMatch_knnUnrollMatch( __global float *query, __global float *train, - __global float *mask, + //__global float *mask, __global int2 *bestTrainIdx, __global float2 *bestDistance, __local float *sharebuffer, @@ -440,169 +472,178 @@ __kernel void BruteForceMatch_knnUnrollMatch( int train_cols, int step, int distType - ) +) { - const int lidx = get_local_id(0); - const int lidy = get_local_id(1); - const int groupidx = get_group_id(0); - - const int queryIdx = groupidx * block_size + lidy; - local float *s_query = sharebuffer; - local float *s_train = sharebuffer + block_size * max_desc_len; - - // load the query into local memory. - for (int i = 0 ; i < max_desc_len / block_size; i ++) - { - int loadx = lidx + i * block_size; - s_query[lidy * max_desc_len + loadx] = loadx < query_cols ? query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx] : 0; - } - - float myBestDistance1 = MAX_FLOAT; - float myBestDistance2 = MAX_FLOAT; - int myBestTrainIdx1 = -1; - int myBestTrainIdx2 = -1; - - //loopUnrolledCached - volatile int imgIdx = 0; - for (int t = 0 ; t < (train_rows + block_size - 1) / block_size ; t++) - { - float result = 0; - for (int i = 0 ; i < max_desc_len / block_size ; i++) - { - const int loadX = lidx + i * block_size; - //load a block_size * block_size block into local train. - const int loadx = lidx + i * block_size; - s_train[lidx * block_size + lidy] = loadx < train_cols ? train[min(t * block_size + lidy, train_rows - 1) * (step / sizeof(float)) + loadx] : 0; - - //synchronize to make sure each elem for reduceIteration in share memory is written already. - barrier(CLK_LOCAL_MEM_FENCE); - - /* there are threee types in the reducer. the first is L1Dist, which to sum the abs(v1, v2), the second is L2Dist, which to - sum the (v1 - v2) * (v1 - v2), the third is humming, which to popc(v1 ^ v2), popc is to count the bits are set to 1*/ - - switch(distType) - { - case 0: - for (int j = 0 ; j < block_size ; j++) - { - result += fabs(s_query[lidy * max_desc_len + i * block_size + j] - s_train[j * block_size + lidx]); - } - break; - case 1: - for (int j = 0 ; j < block_size ; j++) - { - float qr = s_query[lidy * max_desc_len + i * block_size + j] - s_train[j * block_size + lidx]; - result += qr * qr; - } - break; - case 2: - for (int j = 0 ; j < block_size ; j++) - { - //result += popcount((uint)s_query[lidy * max_desc_len + i * block_size + j] ^ (uint)s_train[j * block_size + lidx]); - result += bit1Count((uint)s_query[lidy * max_desc_len + i * block_size + j] ^ (uint)s_train[j * block_size + lidx]); - } - break; - } - - barrier(CLK_LOCAL_MEM_FENCE); - } - - const int trainIdx = t * block_size + lidx; - - if (queryIdx < query_rows && trainIdx < train_rows) - { - if (result < myBestDistance1) - { - myBestDistance2 = myBestDistance1; - myBestTrainIdx2 = myBestTrainIdx1; - myBestDistance1 = result; - myBestTrainIdx1 = trainIdx; - } - else if (result < myBestDistance2) - { - myBestDistance2 = result; - myBestTrainIdx2 = trainIdx; - } - } - } - - barrier(CLK_LOCAL_MEM_FENCE); - - local float *s_distance = (local float *)sharebuffer; - local int *s_trainIdx = (local int *)(sharebuffer + block_size * block_size); - - // find BestMatch - s_distance += lidy * block_size; - s_trainIdx += lidy * block_size; - - s_distance[lidx] = myBestDistance1; - s_trainIdx[lidx] = myBestTrainIdx1; - - float bestDistance1 = MAX_FLOAT; - float bestDistance2 = MAX_FLOAT; - int bestTrainIdx1 = -1; - int bestTrainIdx2 = -1; - barrier(CLK_LOCAL_MEM_FENCE); - - if (lidx == 0) - { - for (int i = 0 ; i < block_size ; i++) - { - float val = s_distance[i]; - if (val < bestDistance1) - { - bestDistance2 = bestDistance1; - bestTrainIdx2 = bestTrainIdx1; - - bestDistance1 = val; - bestTrainIdx1 = s_trainIdx[i]; - } - else if (val < bestDistance2) - { - bestDistance2 = val; - bestTrainIdx2 = s_trainIdx[i]; - } - } - } - - barrier(CLK_LOCAL_MEM_FENCE); - - s_distance[lidx] = myBestDistance2; - s_trainIdx[lidx] = myBestTrainIdx2; - - barrier(CLK_LOCAL_MEM_FENCE); - - if (lidx == 0) - { - for (int i = 0 ; i < block_size ; i++) - { - float val = s_distance[i]; - - if (val < bestDistance2) - { - bestDistance2 = val; - bestTrainIdx2 = s_trainIdx[i]; - } - } - } - - myBestDistance1 = bestDistance1; - myBestDistance2 = bestDistance2; - - myBestTrainIdx1 = bestTrainIdx1; - myBestTrainIdx2 = bestTrainIdx2; - - if (queryIdx < query_rows && lidx == 0) - { - bestTrainIdx[queryIdx] = (int2)(myBestTrainIdx1, myBestTrainIdx2); - bestDistance[queryIdx] = (float2)(myBestDistance1, myBestDistance2); - } + const int lidx = get_local_id(0); + const int lidy = get_local_id(1); + const int groupidx = get_group_id(0); + + const int queryIdx = groupidx * block_size + lidy; + local float *s_query = sharebuffer; + local float *s_train = sharebuffer + block_size * max_desc_len; + + // load the query into local memory. + for (int i = 0 ; i < max_desc_len / block_size; i ++) + { + int loadx = lidx + i * block_size; + s_query[lidy * max_desc_len + loadx] = loadx < query_cols ? query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx] : 0; + } + + float myBestDistance1 = MAX_FLOAT; + float myBestDistance2 = MAX_FLOAT; + int myBestTrainIdx1 = -1; + int myBestTrainIdx2 = -1; + + //loopUnrolledCached + volatile int imgIdx = 0; + + for (int t = 0 ; t < (train_rows + block_size - 1) / block_size ; t++) + { + float result = 0; + + for (int i = 0 ; i < max_desc_len / block_size ; i++) + { + const int loadX = lidx + i * block_size; + //load a block_size * block_size block into local train. + const int loadx = lidx + i * block_size; + s_train[lidx * block_size + lidy] = loadx < train_cols ? train[min(t * block_size + lidy, train_rows - 1) * (step / sizeof(float)) + loadx] : 0; + + //synchronize to make sure each elem for reduceIteration in share memory is written already. + barrier(CLK_LOCAL_MEM_FENCE); + + /* there are threee types in the reducer. the first is L1Dist, which to sum the abs(v1, v2), the second is L2Dist, which to + sum the (v1 - v2) * (v1 - v2), the third is humming, which to popc(v1 ^ v2), popc is to count the bits are set to 1*/ + + switch (distType) + { + case 0: + + for (int j = 0 ; j < block_size ; j++) + { + result += fabs(s_query[lidy * max_desc_len + i * block_size + j] - s_train[j * block_size + lidx]); + } + + break; + case 1: + + for (int j = 0 ; j < block_size ; j++) + { + float qr = s_query[lidy * max_desc_len + i * block_size + j] - s_train[j * block_size + lidx]; + result += qr * qr; + } + + break; + case 2: + + for (int j = 0 ; j < block_size ; j++) + { + //result += popcount((uint)s_query[lidy * max_desc_len + i * block_size + j] ^ (uint)s_train[j * block_size + lidx]); + result += bit1Count((uint)s_query[lidy * max_desc_len + i * block_size + j] ^(uint)s_train[j * block_size + lidx]); + } + + break; + } + + barrier(CLK_LOCAL_MEM_FENCE); + } + + const int trainIdx = t * block_size + lidx; + + if (queryIdx < query_rows && trainIdx < train_rows) + { + if (result < myBestDistance1) + { + myBestDistance2 = myBestDistance1; + myBestTrainIdx2 = myBestTrainIdx1; + myBestDistance1 = result; + myBestTrainIdx1 = trainIdx; + } + else if (result < myBestDistance2) + { + myBestDistance2 = result; + myBestTrainIdx2 = trainIdx; + } + } + } + + barrier(CLK_LOCAL_MEM_FENCE); + + local float *s_distance = (local float *)sharebuffer; + local int *s_trainIdx = (local int *)(sharebuffer + block_size * block_size); + + // find BestMatch + s_distance += lidy * block_size; + s_trainIdx += lidy * block_size; + + s_distance[lidx] = myBestDistance1; + s_trainIdx[lidx] = myBestTrainIdx1; + + float bestDistance1 = MAX_FLOAT; + float bestDistance2 = MAX_FLOAT; + int bestTrainIdx1 = -1; + int bestTrainIdx2 = -1; + barrier(CLK_LOCAL_MEM_FENCE); + + if (lidx == 0) + { + for (int i = 0 ; i < block_size ; i++) + { + float val = s_distance[i]; + + if (val < bestDistance1) + { + bestDistance2 = bestDistance1; + bestTrainIdx2 = bestTrainIdx1; + + bestDistance1 = val; + bestTrainIdx1 = s_trainIdx[i]; + } + else if (val < bestDistance2) + { + bestDistance2 = val; + bestTrainIdx2 = s_trainIdx[i]; + } + } + } + + barrier(CLK_LOCAL_MEM_FENCE); + + s_distance[lidx] = myBestDistance2; + s_trainIdx[lidx] = myBestTrainIdx2; + + barrier(CLK_LOCAL_MEM_FENCE); + + if (lidx == 0) + { + for (int i = 0 ; i < block_size ; i++) + { + float val = s_distance[i]; + + if (val < bestDistance2) + { + bestDistance2 = val; + bestTrainIdx2 = s_trainIdx[i]; + } + } + } + + myBestDistance1 = bestDistance1; + myBestDistance2 = bestDistance2; + + myBestTrainIdx1 = bestTrainIdx1; + myBestTrainIdx2 = bestTrainIdx2; + + if (queryIdx < query_rows && lidx == 0) + { + bestTrainIdx[queryIdx] = (int2)(myBestTrainIdx1, myBestTrainIdx2); + bestDistance[queryIdx] = (float2)(myBestDistance1, myBestDistance2); + } } __kernel void BruteForceMatch_knnMatch( __global float *query, __global float *train, - __global float *mask, + //__global float *mask, __global int2 *bestTrainIdx, __global float2 *bestDistance, __local float *sharebuffer, @@ -613,166 +654,174 @@ __kernel void BruteForceMatch_knnMatch( int train_cols, int step, int distType - ) +) { - const int lidx = get_local_id(0); - const int lidy = get_local_id(1); - const int groupidx = get_group_id(0); - - const int queryIdx = groupidx * block_size + lidy; - local float *s_query = sharebuffer; - local float *s_train = sharebuffer + block_size * block_size; - - float myBestDistance1 = MAX_FLOAT; - float myBestDistance2 = MAX_FLOAT; - int myBestTrainIdx1 = -1; - int myBestTrainIdx2 = -1; - - //loop - for (int t = 0 ; t < (train_rows + block_size - 1) / block_size ; t++) - { - float result = 0.0f; - for (int i = 0 ; i < (query_cols + block_size -1) / block_size ; i++) - { - const int loadx = lidx + i * block_size; - //load query and train into local memory - s_query[lidy * block_size + lidx] = 0; - s_train[lidx * block_size + lidy] = 0; - - if (loadx < query_cols) - { - s_query[lidy * block_size + lidx] = query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx]; - s_train[lidx * block_size + lidy] = train[min(t * block_size + lidy, train_rows - 1) * (step / sizeof(float)) + loadx]; - } - - barrier(CLK_LOCAL_MEM_FENCE); - - /* there are threee types in the reducer. the first is L1Dist, which to sum the abs(v1, v2), the second is L2Dist, which to - sum the (v1 - v2) * (v1 - v2), the third is humming, which to popc(v1 ^ v2), popc is to count the bits are set to 1*/ - - switch(distType) - { - case 0: - for (int j = 0 ; j < block_size ; j++) - { - result += fabs(s_query[lidy * block_size + j] - s_train[j * block_size + lidx]); - } - break; - case 1: - for (int j = 0 ; j < block_size ; j++) - { - float qr = s_query[lidy * block_size + j] - s_train[j * block_size + lidx]; - result += qr * qr; - } - break; - case 2: - for (int j = 0 ; j < block_size ; j++) - { - //result += popcount((uint)s_query[lidy * block_size + j] ^ (uint)s_train[j * block_size + lidx]); - result += bit1Count((uint)s_query[lidy * block_size + j] ^ (uint)s_train[(uint)j * block_size + lidx]); - } - break; - } - - barrier(CLK_LOCAL_MEM_FENCE); - } - - const int trainIdx = t * block_size + lidx; - - if (queryIdx < query_rows && trainIdx < train_rows /*&& mask(queryIdx, trainIdx)*/) - { - if (result < myBestDistance1) - { - myBestDistance2 = myBestDistance1; - myBestTrainIdx2 = myBestTrainIdx1; - myBestDistance1 = result; - myBestTrainIdx1 = trainIdx; - } - else if (result < myBestDistance2) - { - myBestDistance2 = result; - myBestTrainIdx2 = trainIdx; - } - } - } - - barrier(CLK_LOCAL_MEM_FENCE); - - __local float *s_distance = (__local float *)sharebuffer; - __local int *s_trainIdx = (__local int *)(sharebuffer + block_size * block_size); - - //findBestMatch - s_distance += lidy * block_size; - s_trainIdx += lidy * block_size; - - s_distance[lidx] = myBestDistance1; - s_trainIdx[lidx] = myBestTrainIdx1; - - float bestDistance1 = MAX_FLOAT; - float bestDistance2 = MAX_FLOAT; - int bestTrainIdx1 = -1; - int bestTrainIdx2 = -1; - barrier(CLK_LOCAL_MEM_FENCE); - - if (lidx == 0) - { - for (int i = 0 ; i < block_size ; i++) - { - float val = s_distance[i]; - if (val < bestDistance1) - { - bestDistance2 = bestDistance1; - bestTrainIdx2 = bestTrainIdx1; - - bestDistance1 = val; - bestTrainIdx1 = s_trainIdx[i]; - } - else if (val < bestDistance2) - { - bestDistance2 = val; - bestTrainIdx2 = s_trainIdx[i]; - } - } - } - - barrier(CLK_LOCAL_MEM_FENCE); - - s_distance[lidx] = myBestDistance2; - s_trainIdx[lidx] = myBestTrainIdx2; - - barrier(CLK_LOCAL_MEM_FENCE); - - if (lidx == 0) - { - for (int i = 0 ; i < block_size ; i++) - { - float val = s_distance[i]; - - if (val < bestDistance2) - { - bestDistance2 = val; - bestTrainIdx2 = s_trainIdx[i]; - } - } - } - - myBestDistance1 = bestDistance1; - myBestDistance2 = bestDistance2; - - myBestTrainIdx1 = bestTrainIdx1; - myBestTrainIdx2 = bestTrainIdx2; - - if (queryIdx < query_rows && lidx == 0) - { - bestTrainIdx[queryIdx] = (int2)(myBestTrainIdx1, myBestTrainIdx2); - bestDistance[queryIdx] = (float2)(myBestDistance1, myBestDistance2); - } + const int lidx = get_local_id(0); + const int lidy = get_local_id(1); + const int groupidx = get_group_id(0); + + const int queryIdx = groupidx * block_size + lidy; + local float *s_query = sharebuffer; + local float *s_train = sharebuffer + block_size * block_size; + + float myBestDistance1 = MAX_FLOAT; + float myBestDistance2 = MAX_FLOAT; + int myBestTrainIdx1 = -1; + int myBestTrainIdx2 = -1; + + //loop + for (int t = 0 ; t < (train_rows + block_size - 1) / block_size ; t++) + { + float result = 0.0f; + + for (int i = 0 ; i < (query_cols + block_size - 1) / block_size ; i++) + { + const int loadx = lidx + i * block_size; + //load query and train into local memory + s_query[lidy * block_size + lidx] = 0; + s_train[lidx * block_size + lidy] = 0; + + if (loadx < query_cols) + { + s_query[lidy * block_size + lidx] = query[min(queryIdx, query_rows - 1) * (step / sizeof(float)) + loadx]; + s_train[lidx * block_size + lidy] = train[min(t * block_size + lidy, train_rows - 1) * (step / sizeof(float)) + loadx]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + /* there are threee types in the reducer. the first is L1Dist, which to sum the abs(v1, v2), the second is L2Dist, which to + sum the (v1 - v2) * (v1 - v2), the third is humming, which to popc(v1 ^ v2), popc is to count the bits are set to 1*/ + + switch (distType) + { + case 0: + + for (int j = 0 ; j < block_size ; j++) + { + result += fabs(s_query[lidy * block_size + j] - s_train[j * block_size + lidx]); + } + + break; + case 1: + + for (int j = 0 ; j < block_size ; j++) + { + float qr = s_query[lidy * block_size + j] - s_train[j * block_size + lidx]; + result += qr * qr; + } + + break; + case 2: + + for (int j = 0 ; j < block_size ; j++) + { + //result += popcount((uint)s_query[lidy * block_size + j] ^ (uint)s_train[j * block_size + lidx]); + result += bit1Count((uint)s_query[lidy * block_size + j] ^(uint)s_train[(uint)j * block_size + lidx]); + } + + break; + } + + barrier(CLK_LOCAL_MEM_FENCE); + } + + const int trainIdx = t * block_size + lidx; + + if (queryIdx < query_rows && trainIdx < train_rows /*&& mask(queryIdx, trainIdx)*/) + { + if (result < myBestDistance1) + { + myBestDistance2 = myBestDistance1; + myBestTrainIdx2 = myBestTrainIdx1; + myBestDistance1 = result; + myBestTrainIdx1 = trainIdx; + } + else if (result < myBestDistance2) + { + myBestDistance2 = result; + myBestTrainIdx2 = trainIdx; + } + } + } + + barrier(CLK_LOCAL_MEM_FENCE); + + __local float *s_distance = (__local float *)sharebuffer; + __local int *s_trainIdx = (__local int *)(sharebuffer + block_size * block_size); + + //findBestMatch + s_distance += lidy * block_size; + s_trainIdx += lidy * block_size; + + s_distance[lidx] = myBestDistance1; + s_trainIdx[lidx] = myBestTrainIdx1; + + float bestDistance1 = MAX_FLOAT; + float bestDistance2 = MAX_FLOAT; + int bestTrainIdx1 = -1; + int bestTrainIdx2 = -1; + barrier(CLK_LOCAL_MEM_FENCE); + + if (lidx == 0) + { + for (int i = 0 ; i < block_size ; i++) + { + float val = s_distance[i]; + + if (val < bestDistance1) + { + bestDistance2 = bestDistance1; + bestTrainIdx2 = bestTrainIdx1; + + bestDistance1 = val; + bestTrainIdx1 = s_trainIdx[i]; + } + else if (val < bestDistance2) + { + bestDistance2 = val; + bestTrainIdx2 = s_trainIdx[i]; + } + } + } + + barrier(CLK_LOCAL_MEM_FENCE); + + s_distance[lidx] = myBestDistance2; + s_trainIdx[lidx] = myBestTrainIdx2; + + barrier(CLK_LOCAL_MEM_FENCE); + + if (lidx == 0) + { + for (int i = 0 ; i < block_size ; i++) + { + float val = s_distance[i]; + + if (val < bestDistance2) + { + bestDistance2 = val; + bestTrainIdx2 = s_trainIdx[i]; + } + } + } + + myBestDistance1 = bestDistance1; + myBestDistance2 = bestDistance2; + + myBestTrainIdx1 = bestTrainIdx1; + myBestTrainIdx2 = bestTrainIdx2; + + if (queryIdx < query_rows && lidx == 0) + { + bestTrainIdx[queryIdx] = (int2)(myBestTrainIdx1, myBestTrainIdx2); + bestDistance[queryIdx] = (float2)(myBestDistance1, myBestDistance2); + } } kernel void BruteForceMatch_calcDistanceUnrolled( __global float *query, __global float *train, - __global float *mask, + //__global float *mask, __global float *allDist, __local float *sharebuffer, int block_size, @@ -784,13 +833,13 @@ kernel void BruteForceMatch_calcDistanceUnrolled( int step, int distType) { - /* Todo */ + /* Todo */ } kernel void BruteForceMatch_calcDistance( __global float *query, __global float *train, - __global float *mask, + //__global float *mask, __global float *allDist, __local float *sharebuffer, int block_size, @@ -801,16 +850,16 @@ kernel void BruteForceMatch_calcDistance( int step, int distType) { - /* Todo */ + /* Todo */ } kernel void BruteForceMatch_findBestMatch( __global float *allDist, __global int *bestTrainIdx, __global float *bestDistance, - int k, - int block_size - ) + int k, + int block_size +) { - /* Todo */ + /* Todo */ } \ No newline at end of file From 61ef48eee64f2dcd0f3b4aba601d9374bf84276d Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Wed, 27 Feb 2013 14:39:28 +0400 Subject: [PATCH 13/33] fixed OpenCVConfig for cross-compilation: * added CUDA to EXTRA libs if OpenCV uses it * added -rpath-link option for linker if OpenCV was built as SHARED libs --- cmake/templates/OpenCVConfig.cmake.in | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cmake/templates/OpenCVConfig.cmake.in b/cmake/templates/OpenCVConfig.cmake.in index 235c72b8dc..ea331febf1 100644 --- a/cmake/templates/OpenCVConfig.cmake.in +++ b/cmake/templates/OpenCVConfig.cmake.in @@ -221,7 +221,7 @@ foreach(__opttype OPT DBG) endif() # CUDA - if(OpenCV_CUDA_VERSION AND WIN32 AND NOT OpenCV_SHARED) + if(OpenCV_CUDA_VERSION AND (CMAKE_CROSSCOMPILING OR (WIN32 AND NOT OpenCV_SHARED))) if(NOT CUDA_FOUND) find_package(CUDA ${OpenCV_CUDA_VERSION} EXACT REQUIRED) else() @@ -304,3 +304,11 @@ else() SET(OpenCV_LIB_DIR ${OpenCV_LIB_DIR_OPT} ${OpenCV_3RDPARTY_LIB_DIR_OPT}) endif() set(OpenCV_LIBRARIES ${OpenCV_LIBS}) + +if(CMAKE_CROSSCOMPILING AND OpenCV_SHARED AND (CMAKE_SYSTEM_NAME MATCHES "Linux")) + foreach(dir ${OpenCV_LIB_DIR}) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath-link,${dir}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath-link,${dir}") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-rpath-link,${dir}") + endforeach() +endif() From f79134481032ce8c14e6ad42d7c8f3583bc245f1 Mon Sep 17 00:00:00 2001 From: yao Date: Thu, 28 Feb 2013 14:37:37 +0800 Subject: [PATCH 14/33] linux warning fix --- modules/ocl/src/surf.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ocl/src/surf.cpp b/modules/ocl/src/surf.cpp index fec21f623e..e2ac21b972 100644 --- a/modules/ocl/src/surf.cpp +++ b/modules/ocl/src/surf.cpp @@ -60,7 +60,7 @@ namespace cv const char* noImage2dOption = "-D DISABLE_IMAGE2D"; - void openCLExecuteKernelSURF(Context *clCxt , const char **source, string kernelName, size_t globalThreads[3], + static void openCLExecuteKernelSURF(Context *clCxt , const char **source, string kernelName, size_t globalThreads[3], size_t localThreads[3], vector< pair > &args, int channels, int depth) { if(support_image2d()) From f12369a53c86239579ebf533f276d6fe9992abd3 Mon Sep 17 00:00:00 2001 From: yao Date: Thu, 28 Feb 2013 16:56:39 +0800 Subject: [PATCH 15/33] Fix ocl::HOG crash on Intel OCL --- modules/ocl/src/kernels/objdetect_hog.cl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/ocl/src/kernels/objdetect_hog.cl b/modules/ocl/src/kernels/objdetect_hog.cl index 076c22cb89..db11ed1410 100644 --- a/modules/ocl/src/kernels/objdetect_hog.cl +++ b/modules/ocl/src/kernels/objdetect_hog.cl @@ -140,6 +140,10 @@ float reduce_smem(volatile __local float* smem, int size) if (tid < 32) { if (size >= 64) smem[tid] = sum = sum + smem[tid + 32]; + } + barrier(CLK_LOCAL_MEM_FENCE); + if (tid < 16) + { if (size >= 32) smem[tid] = sum = sum + smem[tid + 16]; if (size >= 16) smem[tid] = sum = sum + smem[tid + 8]; if (size >= 8) smem[tid] = sum = sum + smem[tid + 4]; @@ -224,6 +228,11 @@ __kernel void classify_hists_kernel(const int cblock_hist_size, const int cdescr { volatile __local float* smem = products; smem[tid] = product = product + smem[tid + 32]; + } + barrier(CLK_LOCAL_MEM_FENCE); + if (tid < 16) + { + volatile __local float* smem = products; smem[tid] = product = product + smem[tid + 16]; smem[tid] = product = product + smem[tid + 8]; smem[tid] = product = product + smem[tid + 4]; From ddc2e334da7148a714f0dd5e2eb00a2081270ccf Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Wed, 27 Feb 2013 14:03:02 +0400 Subject: [PATCH 16/33] OpenCV version swithed to 4 digit in GUI and package revision number. --- android/libinfo/info.c | 2 +- android/package/AndroidManifest.xml | 4 +-- .../engine/jni/NativeService/PackageInfo.cpp | 20 ++++++++++---- .../engine/jni/Tests/PackageInfoTest.cpp | 14 ++++++++++ .../engine/manager/ManagerActivity.java | 26 ++++++++++++------- 5 files changed, 48 insertions(+), 18 deletions(-) diff --git a/android/libinfo/info.c b/android/libinfo/info.c index 225cc10c1a..073a505575 100644 --- a/android/libinfo/info.c +++ b/android/libinfo/info.c @@ -7,7 +7,7 @@ const char* GetLibraryList(void); JNIEXPORT jstring JNICALL Java_org_opencv_android_StaticHelper_getLibraryList(JNIEnv *, jclass); #define PACKAGE_NAME "org.opencv.lib_v" CVAUX_STR(CV_VERSION_EPOCH) CVAUX_STR(CV_VERSION_MAJOR) "_" ANDROID_PACKAGE_PLATFORM -#define PACKAGE_REVISION CVAUX_STR(CV_VERSION_MINOR) "." CVAUX_STR(ANDROID_PACKAGE_RELEASE) +#define PACKAGE_REVISION CVAUX_STR(CV_VERSION_MINOR) "." CVAUX_STR(ANDROID_PACKAGE_RELEASE) "." CVAUX_STR(CV_VERSION_REVISION) const char* GetPackageName(void) { diff --git a/android/package/AndroidManifest.xml b/android/package/AndroidManifest.xml index 3b6bc7d047..8997b161bc 100644 --- a/android/package/AndroidManifest.xml +++ b/android/package/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="@OPENCV_VERSION_PATCH@@OPENCV_VERSION_TWEAK@@ANDROID_PACKAGE_RELEASE@" + android:versionName="@OPENCV_VERSION_PATCH@.@OPENCV_VERSION_TWEAK@.@ANDROID_PACKAGE_RELEASE@" > diff --git a/android/service/engine/jni/NativeService/PackageInfo.cpp b/android/service/engine/jni/NativeService/PackageInfo.cpp index 7428de01b0..2eb8230739 100644 --- a/android/service/engine/jni/NativeService/PackageInfo.cpp +++ b/android/service/engine/jni/NativeService/PackageInfo.cpp @@ -136,7 +136,17 @@ inline int SplitVersion(const vector& features, const string& package_ve // Taking release and build number from package revision vector tmp2 = SplitStringVector(package_version, '.'); - result += atoi(tmp2[0].c_str())*100 + atoi(tmp2[1].c_str()); + if (tmp2.size() == 2) + { + // the 2nd digit is revision + result += atoi(tmp2[0].c_str())*100 + 00; + } + else + { + // the 2nd digit is part of library version + // the 3rd digit is revision + result += atoi(tmp2[0].c_str())*100 + atoi(tmp2[1].c_str()); + } } else { @@ -194,10 +204,10 @@ inline int SplitPlatfrom(const vector& features) * Example: armv7_neon */ PackageInfo::PackageInfo(int version, int platform, int cpu_id, std::string install_path): -Version(version), -Platform(platform), -CpuID(cpu_id), -InstallPath("") + Version(version), + Platform(platform), + CpuID(cpu_id), + InstallPath("") { #ifndef __SUPPORT_TEGRA3 Platform = PLATFORM_UNKNOWN; diff --git a/android/service/engine/jni/Tests/PackageInfoTest.cpp b/android/service/engine/jni/Tests/PackageInfoTest.cpp index 2e747c305d..6bc84856ce 100644 --- a/android/service/engine/jni/Tests/PackageInfoTest.cpp +++ b/android/service/engine/jni/Tests/PackageInfoTest.cpp @@ -157,6 +157,20 @@ TEST(PackageInfo, MipsFromFullName) } #endif +TEST(PackageInfo, Check2DigitRevision) +{ + PackageInfo info("org.opencv.lib_v23_armv7a_neon", "/data/data/org.opencv.lib_v23_armv7_neon", "4.1"); + EXPECT_EQ(2030400, info.GetVersion()); + EXPECT_EQ(ARCH_ARMv7 | FEATURES_HAS_NEON, info.GetCpuID()); +} + +TEST(PackageInfo, Check3DigitRevision) +{ + PackageInfo info("org.opencv.lib_v23_armv7a_neon", "/data/data/org.opencv.lib_v23_armv7_neon", "4.1.5"); + EXPECT_EQ(2030401, info.GetVersion()); + EXPECT_EQ(ARCH_ARMv7 | FEATURES_HAS_NEON, info.GetCpuID()); +} + TEST(PackageInfo, Comparator1) { PackageInfo info1(2040000, PLATFORM_UNKNOWN, ARCH_X86); diff --git a/android/service/engine/src/org/opencv/engine/manager/ManagerActivity.java b/android/service/engine/src/org/opencv/engine/manager/ManagerActivity.java index 6f604fb875..fad2797727 100644 --- a/android/service/engine/src/org/opencv/engine/manager/ManagerActivity.java +++ b/android/service/engine/src/org/opencv/engine/manager/ManagerActivity.java @@ -299,10 +299,9 @@ public class ManagerActivity extends Activity else NativeLibDir = "/data/data/" + mInstalledPackageInfo[i].packageName + "/lib"; - OpenCVLibraryInfo NativeInfo = new OpenCVLibraryInfo(NativeLibDir); - if (PackageName.equals("org.opencv.engine")) { + OpenCVLibraryInfo NativeInfo = new OpenCVLibraryInfo(NativeLibDir); if (NativeInfo.status()) { PublicName = "Built-in OpenCV library"; @@ -348,9 +347,7 @@ public class ManagerActivity extends Activity if (null != ActivePackagePath) { - int start = ActivePackagePath.indexOf(mInstalledPackageInfo[i].packageName); - int stop = start + mInstalledPackageInfo[i].packageName.length(); - if (start >= 0 && ActivePackagePath.charAt(stop) == '/') + if (ActivePackagePath.equals(NativeLibDir)) { temp.put("Activity", "y"); Tags = "active"; @@ -405,13 +402,22 @@ public class ManagerActivity extends Activity if (OpenCVersion == null || PackageVersion == null) return "unknown"; - int dot = PackageVersion.indexOf("."); - if (dot == -1 || OpenCVersion.length() == 0) + String[] revisions = PackageVersion.split("\\."); + + if (revisions.length <= 1 || OpenCVersion.length() == 0) return "unknown"; else - return OpenCVersion.substring(0, OpenCVersion.length()-1) + "." + - OpenCVersion.toCharArray()[OpenCVersion.length()-1] + "." + - PackageVersion.substring(0, dot) + " rev " + PackageVersion.substring(dot+1); + if (revisions.length == 2) + // the 2nd digit is revision + return OpenCVersion.substring(0, OpenCVersion.length()-1) + "." + + OpenCVersion.toCharArray()[OpenCVersion.length()-1] + "." + + revisions[0] + " rev " + revisions[1]; + else + // the 2nd digit is part of library version + // the 3rd digit is revision + return OpenCVersion.substring(0, OpenCVersion.length()-1) + "." + + OpenCVersion.toCharArray()[OpenCVersion.length()-1] + "." + + revisions[0] + "." + revisions[1] + " rev " + revisions[2]; } protected String ConvertPackageName(String Name, String Version) From 5321da92cbde406821817fc323b0045799c66004 Mon Sep 17 00:00:00 2001 From: Andrey Pavlenko Date: Mon, 18 Feb 2013 11:23:44 +0400 Subject: [PATCH 17/33] adding/fixing version suffix for desktop java library on all OSes --- modules/java/CMakeLists.txt | 12 +++++++++--- modules/java/generator/gen_java.py | 27 ++++++++++++++++++++------- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/modules/java/CMakeLists.txt b/modules/java/CMakeLists.txt index 2fc52a703c..2639fe5a5c 100644 --- a/modules/java/CMakeLists.txt +++ b/modules/java/CMakeLists.txt @@ -217,6 +217,12 @@ endif(ANDROID AND ANDROID_EXECUTABLE) set(step3_depends ${step2_depends} ${step3_input_files} ${copied_files}) +if(ANDROID) + set(LIB_NAME_SUFIX "") +else() + set(LIB_NAME_SUFIX "${OPENCV_VERSION_MAJOR}${OPENCV_VERSION_MINOR}${OPENCV_VERSION_PATCH}") +endif() + # step 4: build jar if(ANDROID) set(JAR_FILE "${OpenCV_BINARY_DIR}/bin/classes.jar") @@ -241,7 +247,7 @@ if(ANDROID) ) endif() else(ANDROID) - set(JAR_NAME opencv-${OPENCV_VERSION}.jar) + set(JAR_NAME opencv-${LIB_NAME_SUFIX}.jar) set(JAR_FILE "${OpenCV_BINARY_DIR}/bin/${JAR_NAME}") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/build.xml.in" "${OpenCV_BINARY_DIR}/build.xml" IMMEDIATE @ONLY) list(APPEND step3_depends "${OpenCV_BINARY_DIR}/build.xml") @@ -294,8 +300,8 @@ endif() # Additional target properties set_target_properties(${the_module} PROPERTIES - OUTPUT_NAME "${the_module}${OPENCV_DLLVERSION}" - DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" + OUTPUT_NAME "${the_module}${LIB_NAME_SUFIX}" + #DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} INSTALL_NAME_DIR ${OPENCV_LIB_INSTALL_PATH} diff --git a/modules/java/generator/gen_java.py b/modules/java/generator/gen_java.py index 0f3ba1d336..2b4aad2226 100755 --- a/modules/java/generator/gen_java.py +++ b/modules/java/generator/gen_java.py @@ -559,6 +559,15 @@ func_arg_fix = { }, # '', i.e. no class } # func_arg_fix + +def getLibVersion(version_hpp_path): + version_file = open(version_hpp_path, "rt").read() + epoch = re.search("^W*#\W*define\W+CV_VERSION_EPOCH\W+(\d+)\W*$", version_file, re.MULTILINE).group(1) + major = re.search("^W*#\W*define\W+CV_VERSION_MAJOR\W+(\d+)\W*$", version_file, re.MULTILINE).group(1) + minor = re.search("^W*#\W*define\W+CV_VERSION_MINOR\W+(\d+)\W*$", version_file, re.MULTILINE).group(1) + patch = re.search("^W*#\W*define\W+CV_VERSION_REVISION\W+(\d+)\W*$", version_file, re.MULTILINE).group(1) + return (epoch, major, minor, patch) + class ConstInfo(object): def __init__(self, cname, name, val, addedManually=False): self.cname = cname @@ -721,13 +730,17 @@ $imports public class %(jc)s { """ % { 'm' : self.module, 'jc' : jname } ) -# self.java_code[class_name]["jn_code"].write(""" -# // -# // native stuff -# // -# static { System.loadLibrary("opencv_java"); } -#""" ) - + if class_name == 'Core': + (epoch, major, minor, patch) = getLibVersion( + (os.path.dirname(__file__) or '.') + '/../../core/include/opencv2/core/version.hpp') + version_str = '.'.join( (epoch, major, minor, patch) ) + version_suffix = ''.join( (epoch, major, minor) ) + #if version_suffix.endswith('0'): + # version_suffix = version_suffix[0 : -1] + self.classes[class_name].imports.add("java.lang.String") + self.java_code[class_name]["j_code"].write(""" + public static final String VERSION = "%(v)s", VERSION_SUFFIX = "%(vs)s"; +""" % { 'v' : version_str, 'vs' : version_suffix } ) def add_class(self, decl): From 29b763dc60c25f08ea188cac1f809cedaf9c8d28 Mon Sep 17 00:00:00 2001 From: Andrey Pavlenko Date: Thu, 28 Feb 2013 16:24:52 +0400 Subject: [PATCH 18/33] updating samples to load JNI lib with correct suffix --- samples/java/ant/src/SimpleSample.java | 4 +++- samples/java/eclipse/HelloCV/src/Main.java | 4 +++- samples/java/sbt/src/main/scala/Main.scala | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/samples/java/ant/src/SimpleSample.java b/samples/java/ant/src/SimpleSample.java index 990536f2b8..fb8be464d8 100644 --- a/samples/java/ant/src/SimpleSample.java +++ b/samples/java/ant/src/SimpleSample.java @@ -1,12 +1,14 @@ +import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.CvType; import org.opencv.core.Scalar; class SimpleSample { - static{ System.loadLibrary("opencv_java244"); } + static{ System.loadLibrary("opencv_java" + Core.VERSION_SUFFIX); } public static void main(String[] args) { + System.out.println("Welcome to OpenCV " + Core.VERSION); Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0)); System.out.println("OpenCV Mat: " + m); Mat mr1 = m.row(1); diff --git a/samples/java/eclipse/HelloCV/src/Main.java b/samples/java/eclipse/HelloCV/src/Main.java index 0e9bb5898f..18d4b3db57 100644 --- a/samples/java/eclipse/HelloCV/src/Main.java +++ b/samples/java/eclipse/HelloCV/src/Main.java @@ -1,10 +1,12 @@ +import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.Mat; public class Main { public static void main(String[] args) { - System.loadLibrary("opencv_java244"); + System.out.println("Welcome to OpenCV " + Core.VERSION); + System.loadLibrary("opencv_java" + Core.VERSION_SUFFIX); Mat m = Mat.eye(3, 3, CvType.CV_8UC1); System.out.println("m = " + m.dump()); } diff --git a/samples/java/sbt/src/main/scala/Main.scala b/samples/java/sbt/src/main/scala/Main.scala index 4a68d144a4..f2de5c350a 100644 --- a/samples/java/sbt/src/main/scala/Main.scala +++ b/samples/java/sbt/src/main/scala/Main.scala @@ -8,11 +8,14 @@ * You're invited to submit your own examples, in any JVM language of * your choosing so long as you can get them to build. */ + +import org.opencv.core.Core + object Main extends App { // We must load the native library before using any OpenCV functions. // You must load this library _exactly once_ per Java invocation. // If you load it more than once, you will get a java.lang.UnsatisfiedLinkError. - System.loadLibrary("opencv_java") + System.loadLibrary("opencv_java" + Core.VERSION_SUFFIX) ScalaCorrespondenceMatchingDemo.run() ScalaDetectFaceDemo.run() From bd38a1945d0e04f05ca2eb9b969d21437a76907d Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Thu, 28 Feb 2013 16:32:13 +0400 Subject: [PATCH 19/33] Honor 2-digit python version --- cmake/OpenCVDetectPython.cmake | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/cmake/OpenCVDetectPython.cmake b/cmake/OpenCVDetectPython.cmake index 6b98bc0974..73143b7341 100644 --- a/cmake/OpenCVDetectPython.cmake +++ b/cmake/OpenCVDetectPython.cmake @@ -19,18 +19,25 @@ unset(HAVE_SPHINX CACHE) if(PYTHON_EXECUTABLE) if(PYTHON_VERSION_STRING) set(PYTHON_VERSION_MAJOR_MINOR "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") - string(REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" PYTHON_VERSION_FULL "${PYTHON_VERSION_STRING}") + set(PYTHON_VERSION_FULL "${PYTHON_VERSION_STRING}") else() execute_process(COMMAND ${PYTHON_EXECUTABLE} --version ERROR_VARIABLE PYTHON_VERSION_FULL ERROR_STRIP_TRAILING_WHITESPACE) string(REGEX MATCH "[0-9]+.[0-9]+" PYTHON_VERSION_MAJOR_MINOR "${PYTHON_VERSION_FULL}") - string(REGEX MATCH "[0-9]+.[0-9]+.[0-9]+" PYTHON_VERSION_FULL "${PYTHON_VERSION_FULL}") + endif() + + if("${PYTHON_VERSION_FULL}" MATCHES "[0-9]+.[0-9]+.[0-9]+") + set(PYTHON_VERSION_FULL "${CMAKE_MATCH_0}") + elseif("${PYTHON_VERSION_FULL}" MATCHES "[0-9]+.[0-9]+") + set(PYTHON_VERSION_FULL "${CMAKE_MATCH_0}") + else() + unset(PYTHON_VERSION_FULL) endif() if(NOT ANDROID AND NOT IOS) - if(CMAKE_VERSION VERSION_GREATER 2.8.8) + if(CMAKE_VERSION VERSION_GREATER 2.8.8 AND PYTHON_VERSION_FULL) find_host_package(PythonLibs ${PYTHON_VERSION_FULL} EXACT) else() find_host_package(PythonLibs ${PYTHON_VERSION_FULL}) From f533f0dca95c9888462c8de8f889c0eef57347ed Mon Sep 17 00:00:00 2001 From: Vladislav Vinogradov Date: Thu, 28 Feb 2013 16:43:08 +0400 Subject: [PATCH 20/33] fixed gpu sanity tests --- modules/gpu/perf/perf_core.cpp | 46 ++++++++++++++-------------- modules/gpu/perf/perf_features2d.cpp | 2 +- modules/gpu/perf/perf_imgproc.cpp | 14 ++++----- modules/gpu/perf/perf_labeling.cpp | 4 +-- modules/gpu/perf/perf_matop.cpp | 6 ++-- modules/gpu/perf/perf_video.cpp | 14 ++++++--- modules/gpu/src/cuda/bgfg_mog.cu | 4 +-- modules/gpu/src/cuda/ccomponetns.cu | 4 +-- modules/gpu/test/test_bgfg.cpp | 31 +++++++++++++------ 9 files changed, 71 insertions(+), 54 deletions(-) diff --git a/modules/gpu/perf/perf_core.cpp b/modules/gpu/perf/perf_core.cpp index d0529e80a4..22840f9f46 100644 --- a/modules/gpu/perf/perf_core.cpp +++ b/modules/gpu/perf/perf_core.cpp @@ -35,7 +35,7 @@ PERF_TEST_P(Sz_Depth_Cn, Core_Merge, TEST_CYCLE() cv::gpu::merge(d_src, dst); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-10); } else { @@ -72,8 +72,8 @@ PERF_TEST_P(Sz_Depth_Cn, Core_Split, const cv::gpu::GpuMat& dst0 = dst[0]; const cv::gpu::GpuMat& dst1 = dst[1]; - GPU_SANITY_CHECK(dst0); - GPU_SANITY_CHECK(dst1); + GPU_SANITY_CHECK(dst0, 1e-10); + GPU_SANITY_CHECK(dst1, 1e-10); } else { @@ -113,7 +113,7 @@ PERF_TEST_P(Sz_Depth, Core_AddMat, TEST_CYCLE() cv::gpu::add(d_src1, d_src2, dst); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-10); } else { @@ -148,7 +148,7 @@ PERF_TEST_P(Sz_Depth, Core_AddScalar, TEST_CYCLE() cv::gpu::add(d_src, s, dst); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-10); } else { @@ -184,7 +184,7 @@ PERF_TEST_P(Sz_Depth, Core_SubtractMat, TEST_CYCLE() cv::gpu::subtract(d_src1, d_src2, dst); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-10); } else { @@ -219,7 +219,7 @@ PERF_TEST_P(Sz_Depth, Core_SubtractScalar, TEST_CYCLE() cv::gpu::subtract(d_src, s, dst); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-10); } else { @@ -255,7 +255,7 @@ PERF_TEST_P(Sz_Depth, Core_MultiplyMat, TEST_CYCLE() cv::gpu::multiply(d_src1, d_src2, dst); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-6); } else { @@ -290,7 +290,7 @@ PERF_TEST_P(Sz_Depth, Core_MultiplyScalar, TEST_CYCLE() cv::gpu::multiply(d_src, s, dst); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-6); } else { @@ -326,7 +326,7 @@ PERF_TEST_P(Sz_Depth, Core_DivideMat, TEST_CYCLE() cv::gpu::divide(d_src1, d_src2, dst); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-6); } else { @@ -361,7 +361,7 @@ PERF_TEST_P(Sz_Depth, Core_DivideScalar, TEST_CYCLE() cv::gpu::divide(d_src, s, dst); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-6); } else { @@ -396,7 +396,7 @@ PERF_TEST_P(Sz_Depth, Core_DivideScalarInv, TEST_CYCLE() cv::gpu::divide(s[0], d_src, dst); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-6); } else { @@ -432,7 +432,7 @@ PERF_TEST_P(Sz_Depth, Core_AbsDiffMat, TEST_CYCLE() cv::gpu::absdiff(d_src1, d_src2, dst); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-10); } else { @@ -467,7 +467,7 @@ PERF_TEST_P(Sz_Depth, Core_AbsDiffScalar, TEST_CYCLE() cv::gpu::absdiff(d_src, s, dst); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-10); } else { @@ -1247,7 +1247,7 @@ PERF_TEST_P(Sz_3Depth, Core_AddWeighted, TEST_CYCLE() cv::gpu::addWeighted(d_src1, 0.5, d_src2, 0.5, 10.0, dst, dst_depth); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-10); } else { @@ -1296,7 +1296,7 @@ PERF_TEST_P(Sz_Type_Flags, Core_GEMM, TEST_CYCLE() cv::gpu::gemm(d_src1, d_src2, 1.0, d_src3, 1.0, dst, flags); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-6); } else { @@ -1330,7 +1330,7 @@ PERF_TEST_P(Sz_Type, Core_Transpose, TEST_CYCLE() cv::gpu::transpose(d_src, dst); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-10); } else { @@ -1605,7 +1605,7 @@ PERF_TEST_P(Sz_AngleInDegrees, Core_Phase, TEST_CYCLE() cv::gpu::phase(d_src1, d_src2, dst, angleInDegrees); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE); } else { @@ -1643,7 +1643,7 @@ PERF_TEST_P(Sz_AngleInDegrees, Core_CartToPolar, TEST_CYCLE() cv::gpu::cartToPolar(d_src1, d_src2, magnitude, angle, angleInDegrees); GPU_SANITY_CHECK(magnitude); - GPU_SANITY_CHECK(angle); + GPU_SANITY_CHECK(angle, 1e-6, ERROR_RELATIVE); } else { @@ -1933,8 +1933,8 @@ PERF_TEST_P(Sz_Depth, Core_MinMax, TEST_CYCLE() cv::gpu::minMax(d_src, &gpu_minVal, &gpu_maxVal, cv::gpu::GpuMat(), d_buf); - SANITY_CHECK(gpu_minVal); - SANITY_CHECK(gpu_maxVal); + SANITY_CHECK(gpu_minVal, 1e-10); + SANITY_CHECK(gpu_maxVal, 1e-10); } else { @@ -1969,8 +1969,8 @@ PERF_TEST_P(Sz_Depth, Core_MinMaxLoc, TEST_CYCLE() cv::gpu::minMaxLoc(d_src, &gpu_minVal, &gpu_maxVal, &gpu_minLoc, &gpu_maxLoc, cv::gpu::GpuMat(), d_valbuf, d_locbuf); - SANITY_CHECK(gpu_minVal); - SANITY_CHECK(gpu_maxVal); + SANITY_CHECK(gpu_minVal, 1e-10); + SANITY_CHECK(gpu_maxVal, 1e-10); } else { diff --git a/modules/gpu/perf/perf_features2d.cpp b/modules/gpu/perf/perf_features2d.cpp index 67de9a1eac..480f582383 100644 --- a/modules/gpu/perf/perf_features2d.cpp +++ b/modules/gpu/perf/perf_features2d.cpp @@ -86,7 +86,7 @@ PERF_TEST_P(Image, Features2D_SURF, sortKeyPoints(gpu_keypoints, gpu_descriptors); SANITY_CHECK_KEYPOINTS(gpu_keypoints); - SANITY_CHECK(gpu_descriptors); + SANITY_CHECK(gpu_descriptors, 1e-3); } else { diff --git a/modules/gpu/perf/perf_imgproc.cpp b/modules/gpu/perf/perf_imgproc.cpp index 62915c85ce..be6eb4877c 100644 --- a/modules/gpu/perf/perf_imgproc.cpp +++ b/modules/gpu/perf/perf_imgproc.cpp @@ -106,7 +106,7 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Scale, ImgProc_Resize, Combine(GPU_TYPICAL_MAT_SIZES, Values(CV_8U, CV_16U, CV_32F), GPU_CHANNELS_1_3_4, - ALL_INTERPOLATIONS, + Values(Interpolation(cv::INTER_NEAREST), Interpolation(cv::INTER_LINEAR), Interpolation(cv::INTER_CUBIC)), Values(0.5, 0.3, 2.0))) { declare.time(20.0); @@ -129,7 +129,7 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Scale, ImgProc_Resize, TEST_CYCLE() cv::gpu::resize(d_src, dst, cv::Size(), f, f, interpolation); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-3, ERROR_RELATIVE); } else { @@ -224,7 +224,7 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Border, ImgProc_WarpAffine, TEST_CYCLE() cv::gpu::warpAffine(d_src, dst, M, size, interpolation, borderMode); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1); } else { @@ -272,7 +272,7 @@ PERF_TEST_P(Sz_Depth_Cn_Inter_Border, ImgProc_WarpPerspective, TEST_CYCLE() cv::gpu::warpPerspective(d_src, dst, M, size, interpolation, borderMode); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1); } else { @@ -351,7 +351,7 @@ PERF_TEST_P(Sz_Depth_Op, ImgProc_Threshold, TEST_CYCLE() cv::gpu::threshold(d_src, dst, 100.0, 255.0, threshOp); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-10); } else { @@ -1199,7 +1199,7 @@ PERF_TEST_P(Sz_Depth_Cn_Inter, ImgProc_Rotate, TEST_CYCLE() cv::gpu::rotate(d_src, dst, size, 30.0, 0, 0, interpolation); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-3, ERROR_RELATIVE); } else { @@ -1425,7 +1425,7 @@ PERF_TEST_P(Sz_Type_Op, ImgProc_AlphaComp, TEST_CYCLE() cv::gpu::alphaComp(d_img1, d_img2, dst, alpha_op); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-3, ERROR_RELATIVE); } else { diff --git a/modules/gpu/perf/perf_labeling.cpp b/modules/gpu/perf/perf_labeling.cpp index 15d286bafe..f3ad12c949 100644 --- a/modules/gpu/perf/perf_labeling.cpp +++ b/modules/gpu/perf/perf_labeling.cpp @@ -98,7 +98,7 @@ struct GreedyLabeling dot* stack; }; -PERF_TEST_P(Image, Labeling_ConnectivityMask, +PERF_TEST_P(Image, DISABLED_Labeling_ConnectivityMask, Values("gpu/labeling/aloe-disp.png")) { declare.time(1.0); @@ -121,7 +121,7 @@ PERF_TEST_P(Image, Labeling_ConnectivityMask, } } -PERF_TEST_P(Image, Labeling_ConnectedComponents, +PERF_TEST_P(Image, DISABLED_Labeling_ConnectedComponents, Values("gpu/labeling/aloe-disp.png")) { declare.time(1.0); diff --git a/modules/gpu/perf/perf_matop.cpp b/modules/gpu/perf/perf_matop.cpp index aeea1b5181..1696e3a7eb 100644 --- a/modules/gpu/perf/perf_matop.cpp +++ b/modules/gpu/perf/perf_matop.cpp @@ -64,7 +64,7 @@ PERF_TEST_P(Sz_Depth_Cn, MatOp_SetToMasked, TEST_CYCLE() dst.setTo(val, d_mask); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-10); } else { @@ -102,7 +102,7 @@ PERF_TEST_P(Sz_Depth_Cn, MatOp_CopyToMasked, TEST_CYCLE() d_src.copyTo(dst, d_mask); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-10); } else { @@ -141,7 +141,7 @@ PERF_TEST_P(Sz_2Depth, MatOp_ConvertTo, TEST_CYCLE() d_src.convertTo(dst, depth2, a, b); - GPU_SANITY_CHECK(dst); + GPU_SANITY_CHECK(dst, 1e-10); } else { diff --git a/modules/gpu/perf/perf_video.cpp b/modules/gpu/perf/perf_video.cpp index 7d8fed6231..61c2687ca9 100644 --- a/modules/gpu/perf/perf_video.cpp +++ b/modules/gpu/perf/perf_video.cpp @@ -372,8 +372,8 @@ PERF_TEST_P(ImagePair, Video_OpticalFlowDual_TVL1, TEST_CYCLE() d_alg(d_frame0, d_frame1, u, v); - GPU_SANITY_CHECK(u); - GPU_SANITY_CHECK(v); + GPU_SANITY_CHECK(u, 1e-4); + GPU_SANITY_CHECK(v, 1e-4); } else { @@ -470,8 +470,8 @@ PERF_TEST_P(ImagePair, Video_FastOpticalFlowBM, TEST_CYCLE() fastBM(d_frame0, d_frame1, u, v, max_range.width, block_size.width); - GPU_SANITY_CHECK(u); - GPU_SANITY_CHECK(v); + GPU_SANITY_CHECK(u, 2); + GPU_SANITY_CHECK(v, 2); } else { @@ -675,8 +675,10 @@ PERF_TEST_P(Video_Cn, Video_MOG2, if (PERF_RUN_GPU()) { - cv::gpu::GpuMat d_frame(frame); cv::gpu::MOG2_GPU d_mog2; + d_mog2.bShadowDetection = false; + + cv::gpu::GpuMat d_frame(frame); cv::gpu::GpuMat foreground; d_mog2(d_frame, foreground); @@ -708,6 +710,8 @@ PERF_TEST_P(Video_Cn, Video_MOG2, else { cv::BackgroundSubtractorMOG2 mog2; + mog2.set("detectShadows", false); + cv::Mat foreground; mog2(frame, foreground); diff --git a/modules/gpu/src/cuda/bgfg_mog.cu b/modules/gpu/src/cuda/bgfg_mog.cu index 4f78dbd2da..d99ffc498a 100644 --- a/modules/gpu/src/cuda/bgfg_mog.cu +++ b/modules/gpu/src/cuda/bgfg_mog.cu @@ -648,7 +648,7 @@ namespace cv { namespace gpu { namespace device tWeight += gmm_weight(mode * frame.rows + y, x); if (tWeight > c_TB) break; - }; + } } fgmask(y, x) = background ? 0 : isShadow ? c_shadowVal : 255; @@ -761,4 +761,4 @@ namespace cv { namespace gpu { namespace device }}} -#endif /* CUDA_DISABLER */ \ No newline at end of file +#endif /* CUDA_DISABLER */ diff --git a/modules/gpu/src/cuda/ccomponetns.cu b/modules/gpu/src/cuda/ccomponetns.cu index c094e08c0e..0533522bed 100644 --- a/modules/gpu/src/cuda/ccomponetns.cu +++ b/modules/gpu/src/cuda/ccomponetns.cu @@ -194,10 +194,10 @@ namespace cv { namespace gpu { namespace device if ( y > 0 && connected(intensity, image(y - 1, x))) c |= UP; - if ( x - 1 < image.cols && connected(intensity, image(y, x + 1))) + if ( x + 1 < image.cols && connected(intensity, image(y, x + 1))) c |= RIGHT; - if ( y - 1 < image.rows && connected(intensity, image(y + 1, x))) + if ( y + 1 < image.rows && connected(intensity, image(y + 1, x))) c |= DOWN; components(y, x) = c; diff --git a/modules/gpu/test/test_bgfg.cpp b/modules/gpu/test/test_bgfg.cpp index bac835ef1b..ebf0a88afa 100644 --- a/modules/gpu/test/test_bgfg.cpp +++ b/modules/gpu/test/test_bgfg.cpp @@ -207,11 +207,17 @@ INSTANTIATE_TEST_CASE_P(GPU_Video, MOG, testing::Combine( ////////////////////////////////////////////////////// // MOG2 -PARAM_TEST_CASE(MOG2, cv::gpu::DeviceInfo, std::string, UseGray, UseRoi) +namespace +{ + IMPLEMENT_PARAM_CLASS(DetectShadow, bool) +} + +PARAM_TEST_CASE(MOG2, cv::gpu::DeviceInfo, std::string, UseGray, DetectShadow, UseRoi) { cv::gpu::DeviceInfo devInfo; std::string inputFile; bool useGray; + bool detectShadow; bool useRoi; virtual void SetUp() @@ -220,10 +226,9 @@ PARAM_TEST_CASE(MOG2, cv::gpu::DeviceInfo, std::string, UseGray, UseRoi) cv::gpu::setDevice(devInfo.deviceID()); inputFile = std::string(cvtest::TS::ptr()->get_data_path()) + "video/" + GET_PARAM(1); - useGray = GET_PARAM(2); - - useRoi = GET_PARAM(3); + detectShadow = GET_PARAM(3); + useRoi = GET_PARAM(4); } }; @@ -237,9 +242,11 @@ GPU_TEST_P(MOG2, Update) ASSERT_FALSE(frame.empty()); cv::gpu::MOG2_GPU mog2; + mog2.bShadowDetection = detectShadow; cv::gpu::GpuMat foreground = createMat(frame.size(), CV_8UC1, useRoi); cv::BackgroundSubtractorMOG2 mog2_gold; + mog2_gold.set("detectShadows", detectShadow); cv::Mat foreground_gold; for (int i = 0; i < 10; ++i) @@ -258,11 +265,14 @@ GPU_TEST_P(MOG2, Update) mog2_gold(frame, foreground_gold); - double norm = cv::norm(foreground_gold, cv::Mat(foreground), cv::NORM_L1); - - norm /= foreground_gold.size().area(); - - ASSERT_LE(norm, 0.09); + if (detectShadow) + { + ASSERT_MAT_SIMILAR(foreground_gold, foreground, 1e-2); + } + else + { + ASSERT_MAT_NEAR(foreground_gold, foreground, 0); + } } } @@ -277,9 +287,11 @@ GPU_TEST_P(MOG2, getBackgroundImage) cv::Mat frame; cv::gpu::MOG2_GPU mog2; + mog2.bShadowDetection = detectShadow; cv::gpu::GpuMat foreground; cv::BackgroundSubtractorMOG2 mog2_gold; + mog2_gold.set("detectShadows", detectShadow); cv::Mat foreground_gold; for (int i = 0; i < 10; ++i) @@ -305,6 +317,7 @@ INSTANTIATE_TEST_CASE_P(GPU_Video, MOG2, testing::Combine( ALL_DEVICES, testing::Values(std::string("768x576.avi")), testing::Values(UseGray(true), UseGray(false)), + testing::Values(DetectShadow(true), DetectShadow(false)), WHOLE_SUBMAT)); ////////////////////////////////////////////////////// From c24d7cc066f28770a5b93054caf78ca95c15852b Mon Sep 17 00:00:00 2001 From: Andrey Pavlenko Date: Thu, 28 Feb 2013 16:56:53 +0400 Subject: [PATCH 21/33] adding more version-related variables --- modules/java/generator/gen_java.py | 5 +++-- samples/java/ant/src/SimpleSample.java | 2 +- samples/java/eclipse/HelloCV/src/Main.java | 2 +- samples/java/sbt/src/main/scala/Main.scala | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/java/generator/gen_java.py b/modules/java/generator/gen_java.py index 2b4aad2226..89b59bdf2b 100755 --- a/modules/java/generator/gen_java.py +++ b/modules/java/generator/gen_java.py @@ -739,8 +739,9 @@ public class %(jc)s { # version_suffix = version_suffix[0 : -1] self.classes[class_name].imports.add("java.lang.String") self.java_code[class_name]["j_code"].write(""" - public static final String VERSION = "%(v)s", VERSION_SUFFIX = "%(vs)s"; -""" % { 'v' : version_str, 'vs' : version_suffix } ) + public static final String VERSION = "%(v)s", NATIVE_LIBRARY_NAME = "opencv_java%(vs)s"; + public static final int VERSION_EPOCH = %(ep)s, VERSION_MAJOR = %(ma)s, VERSION_MINOR = %(mi)s, VERSION_PATCH = %(pa)s; +""" % { 'v' : version_str, 'vs' : version_suffix, 'ep' : epoch, 'ma' : major, 'mi' : minor, 'pa' : patch } ) def add_class(self, decl): diff --git a/samples/java/ant/src/SimpleSample.java b/samples/java/ant/src/SimpleSample.java index fb8be464d8..a0375c5624 100644 --- a/samples/java/ant/src/SimpleSample.java +++ b/samples/java/ant/src/SimpleSample.java @@ -5,7 +5,7 @@ import org.opencv.core.Scalar; class SimpleSample { - static{ System.loadLibrary("opencv_java" + Core.VERSION_SUFFIX); } + static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); } public static void main(String[] args) { System.out.println("Welcome to OpenCV " + Core.VERSION); diff --git a/samples/java/eclipse/HelloCV/src/Main.java b/samples/java/eclipse/HelloCV/src/Main.java index 18d4b3db57..44f2bb02b3 100644 --- a/samples/java/eclipse/HelloCV/src/Main.java +++ b/samples/java/eclipse/HelloCV/src/Main.java @@ -6,7 +6,7 @@ public class Main { public static void main(String[] args) { System.out.println("Welcome to OpenCV " + Core.VERSION); - System.loadLibrary("opencv_java" + Core.VERSION_SUFFIX); + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); Mat m = Mat.eye(3, 3, CvType.CV_8UC1); System.out.println("m = " + m.dump()); } diff --git a/samples/java/sbt/src/main/scala/Main.scala b/samples/java/sbt/src/main/scala/Main.scala index f2de5c350a..6f07aa19ce 100644 --- a/samples/java/sbt/src/main/scala/Main.scala +++ b/samples/java/sbt/src/main/scala/Main.scala @@ -15,7 +15,7 @@ object Main extends App { // We must load the native library before using any OpenCV functions. // You must load this library _exactly once_ per Java invocation. // If you load it more than once, you will get a java.lang.UnsatisfiedLinkError. - System.loadLibrary("opencv_java" + Core.VERSION_SUFFIX) + System.loadLibrary(Core.NATIVE_LIBRARY_NAME) ScalaCorrespondenceMatchingDemo.run() ScalaDetectFaceDemo.run() From d18b2c2502cdb182225bce80350b4a149d60768a Mon Sep 17 00:00:00 2001 From: Andrey Pavlenko Date: Thu, 28 Feb 2013 17:19:52 +0400 Subject: [PATCH 22/33] patch -> revision --- modules/java/generator/gen_java.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/modules/java/generator/gen_java.py b/modules/java/generator/gen_java.py index 89b59bdf2b..c0da34fe09 100755 --- a/modules/java/generator/gen_java.py +++ b/modules/java/generator/gen_java.py @@ -565,8 +565,8 @@ def getLibVersion(version_hpp_path): epoch = re.search("^W*#\W*define\W+CV_VERSION_EPOCH\W+(\d+)\W*$", version_file, re.MULTILINE).group(1) major = re.search("^W*#\W*define\W+CV_VERSION_MAJOR\W+(\d+)\W*$", version_file, re.MULTILINE).group(1) minor = re.search("^W*#\W*define\W+CV_VERSION_MINOR\W+(\d+)\W*$", version_file, re.MULTILINE).group(1) - patch = re.search("^W*#\W*define\W+CV_VERSION_REVISION\W+(\d+)\W*$", version_file, re.MULTILINE).group(1) - return (epoch, major, minor, patch) + revision = re.search("^W*#\W*define\W+CV_VERSION_REVISION\W+(\d+)\W*$", version_file, re.MULTILINE).group(1) + return (epoch, major, minor, revision) class ConstInfo(object): def __init__(self, cname, name, val, addedManually=False): @@ -731,17 +731,15 @@ public class %(jc)s { """ % { 'm' : self.module, 'jc' : jname } ) if class_name == 'Core': - (epoch, major, minor, patch) = getLibVersion( + (epoch, major, minor, revision) = getLibVersion( (os.path.dirname(__file__) or '.') + '/../../core/include/opencv2/core/version.hpp') - version_str = '.'.join( (epoch, major, minor, patch) ) + version_str = '.'.join( (epoch, major, minor, revision) ) version_suffix = ''.join( (epoch, major, minor) ) - #if version_suffix.endswith('0'): - # version_suffix = version_suffix[0 : -1] self.classes[class_name].imports.add("java.lang.String") self.java_code[class_name]["j_code"].write(""" public static final String VERSION = "%(v)s", NATIVE_LIBRARY_NAME = "opencv_java%(vs)s"; - public static final int VERSION_EPOCH = %(ep)s, VERSION_MAJOR = %(ma)s, VERSION_MINOR = %(mi)s, VERSION_PATCH = %(pa)s; -""" % { 'v' : version_str, 'vs' : version_suffix, 'ep' : epoch, 'ma' : major, 'mi' : minor, 'pa' : patch } ) + public static final int VERSION_EPOCH = %(ep)s, VERSION_MAJOR = %(ma)s, VERSION_MINOR = %(mi)s, VERSION_REVISION = %(re)s; +""" % { 'v' : version_str, 'vs' : version_suffix, 'ep' : epoch, 'ma' : major, 'mi' : minor, 're' : revision } ) def add_class(self, decl): From af2552d72c1e29acfabb022b832efba73b6a7c2a Mon Sep 17 00:00:00 2001 From: Andrey Pavlenko Date: Thu, 28 Feb 2013 18:12:36 +0400 Subject: [PATCH 23/33] fixing issues from http://www.code.opencv.org/issues/2807 --- .../desktop_java/images/eclipse_run.png | Bin 72074 -> 75383 bytes .../desktop_java/java_dev_intro.rst | 63 +++++++++++------- samples/java/ant/build.xml | 2 +- 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/doc/tutorials/introduction/desktop_java/images/eclipse_run.png b/doc/tutorials/introduction/desktop_java/images/eclipse_run.png index 2efc8e67155fa7f86c7955ee53b931cee7e38999..fee34afa10c4694da449ac12e2f85b5a1da2cb0e 100644 GIT binary patch literal 75383 zcmZs?1yEc~&^C&@B?J#1LU4Br7A#2ch2XFRcXtT{C%A72?y|VMJ1p+7xVtWwyx;fV zy7$&SRa;YMPMtHe(>>i!cRv%Rq9lWjL5cwf2Zt>uE2Rnthe!hlhoFas@Y*BJtX}lm zz&okRNWhhkz2ASmK{6Lt6o-SWiotv`LVmqRx0eMt!NK8l|NFuB+ZCF=c9J?vYdfpi z0iE599L?ZVj4W)OS(T*Ksa&~Od008v*{>Y4;ox5U2<|?OHSa!X*O>uYs+k$*|Jsl*VI)~A)X>O5(G)akilpQdhmL6r4}M?&+L`sg?o=H6V~R8rDhvUP<8L?N?snpe|1UxKWF7BuuS&!)&s z`l84s>TBHiLi^Jen~zJ&n&p5|HY@sN z*<}&hR)v~tiv(Y+_KRgC|BXT=h1}(lit)@iRNluscUFF4HQss_ClGk$`WeCIly-CU z@SaHj;Gl8GUFh)W#N#|qt0@Tf=y`Kw2+nxaJWIUN>n?zKyJ@-Met!4o9UO$ru7$&F zD8b`$hwjN|V3@6yd)wgUS&Y!Pxuv*@wz-t9wQ{hT2l%d7b0#GloF7TUra7OG&3Bqu zRr-?J^-)GhZ$1|s*f)(FWx<=Ymhy4F=;@0seFb-5X2aCyBggLZ;cI%d+;>MYl)dX~IZh|ARns@0aM$L6k8t{_7%F00hz!BT41fO*^2 z<0cjGVT-ZQ_?$`!%96v_kHOvI`0)el#|6tE8zEgq=59lcCC+zCY2VDu_ce4img4k( zhG6_bDDu$vOM8oWZQqk)CV@J)V~Lfm-(Hw`NxI<13F0jk zgftr3c`V1(psT^>^5nC3$rEKGov0|Sk)-(@vb|bNwj`P^T2fStAD5txY8bn5G^bxU z)RfZhA)-B*bls~Prnl167CGOs)F##I{E4+cG`)gA zn}bmJ`4dLNHj9Y$z6TT1eBkiMT^6$Wz{AQ5vUwz3C^oqt{D|cYJJY*)$1dhRUBRg- zBf{7u9&3;8(u#K@7{N7g;5H@iHpWW{*n`Fh##{yCDqP*>K?s2vnWnn6_P5&K+Q)qa zE;FRUq>8m~OI^2yildmA_{vM?E32)$ho-QZBKS&~b=sTkpAWn(%?gx6&glaIkvVXM za3v|qOdA`alqje~9m!gKs@_U74!wKwABr#O6b*?wwJSgX9x>=;^HG7Jf;avBYh>Tq^v$&=udX2PID zLDHGpniR|sAA$zdVID(x-)vOOXV*eFMm!Yc?{S1r2w3>mVOcDrjda)6Rq&|rb^JhR z(ky33AgEoeRXF^`Vo}LE zugiAyvmzGh?QAJPvla+|k`BbqLmdlzz`@cJx@NGKqQFaC;Ai zLxd}VE2r?>%ML!QXr~By+Zs*qwvQ8@P?AYPi}9OY%OX}1vgRz7wDuw-$-31{&jx*n zRo~{^I&YN7CVQg8kEZ)o-}3Xt>CZ^0*(DlC?IzEqc;jTfbtblA@a&RyhAsr!}F-_5cOn6pR>Qwzbh>(T=(jcY;3`u(GlBL?V$>CNF0bW?_CB;SfzL0nZ zrmI=nNQ$>0LRyv(fC_xKY#zJdU?{^eFUAmAgT_p)_rtD~>6p2AIlth}GFF_SP!0 z1b;Ug?(`yafeWFmA6(5gMxK6hMG%fL>+^%1H%6*|axoH)6@KT>u{3(iRV6i_bwBnP zg2(ew4sEc4H3J?%z?PxWV6O@50wfcS4e9YSnRk{lTM`kCFv>5yoMqNWq#)-a8NgSe z0Xv<3-bA|GSuX^7c&#dAh+MU=w!egEg*?wap3;x$^V^MAU7EpZd)uoZF@MoYDABoO z)MZm^RyE^9dlxB<*>myddxhp|oQz_RC>c^P@4?p?XQY|J2%O4DY9jvDj!ER4lJ|8} z7^F%ZAj0%_HZj1{9h7RO$?TQLf#sn%GlPv47uOp{us4m#^Rzxlc1nIE~(St9Ohf7Nf|DJ4x zO*2}ikGxqnoc+mUh7yD&_VNgdh<-2l4BftBqc`^!xIapcXZs4u5O|(0-3RHXi89zd zt2!} zp3PeTdX%ij*_IIpgC-0M#Zxw2C({7oHQ~QEc9puMk41WmT3lTku)vJB0$41F#@}Up z72q>}8Va@ZKBa#ZIY}fELX3{a{8;X7tMW@ z4dT7{v~&Kh0F{C%bssF(1FOR9I|Ndk5jicr3?G;s%>nLK_ z>QGW9NftF*Ua;62Q+`BZwpyf57JdA13sz?JgUP{mLGOHEavZg)ko@-ZI+9Z=q%OdF zLdv%ij+Ngl$7Qns(|uVW-kar`D)WL!We_LqD&f2!KXQDf?b@!LbR88uYa@EuXEOao zgvV(zS8-T$t?6m_c+DrVN&`4lp)$)`0NYH*VE)Y*BSEmzl&|b94 z+!h-0OPjq}V(<^~G%qW34&jqnHHPp&(!D{ zWz3NFKTz~qzePs9A*Xzyo*z7?%#V6G8|lI2`WP)JOHMK6t;@pk%KvKYC> z*?ysfWpAL*^*EpVn^I@AjW^ofvS@>ytO1HN9ui}*eh)p9=6!w%ys(`3Eipk+SdM}& zFASPbCTudh0fwHoUAb(6=-WI`gMZ`t-Au-V`$UDzkHAi1zLqyaxPIr`6>IHV1{7^j zgO>}~Fj!fyROLzAIU$y7Hd;a43YU;WeO^- zleQvsu{&!_y0V}(k&M{0AY9iV$%wBIdA2|gop8wrmUB4#jfG`qZAzw}#!1hr+O}CV z&fk%knEmrW+Z29Umey|={V{r)5VG8vGMu&-(taMO$uj~oM;R7lN9?i za$Zj%tZ)=-Oyn3bnnLGd#W5n7nA&dK&tci$sd=J)RJ*ZtWM2B>bk_iBj;?rPa~noW zA`sRsW6+}71iVEL61Rn3;qn^J=|FnyDF*nWf!mRdCoh7xD{(xxFSgIm?Mr7Jr@Ufk z%{I7CtoH$HCl7~qw=kE9fOgo<*_yA@cIR4#`x##W<&)w=P`f}$JwuFWSA=1n#j`D)8$E#-OA&=?yb-H11P`EeRn<-73<}?UF-t<;yXuK?q#{K`OXlH zmqdY#snnJ>g=aswOPj}ruJ#y3ts`P1nUXf;x}N8!>(v(yDf%jD5eMpG$6R7PCA-z)Y%PR3onYkQj3$81a4$Q}CGc3x*Y!M!cDZfE5ov&7dWEv*d)sr$k2N|<1rd*E zBSHX7uwbl`vuK=cWjcv_UsxoKIhJFXg2npZLK@oEP_z2|_8yH~%RBi3a zw~B}KUX6dX6ZVFTy*|wF-S2+6_RG+F7#$K@soGI?D{Xy@#&%n)x<3)BTlIO2_Oe^^ zIkkB_C3in-3kZb?pUs0%vmP!xru`^VSm(FfUow-2<&6mZ?J1726x{=N;O=vm`RvzP z5vk1wDCHO2Z^;i&Vb_bzeyuyouR-2@g3!z3%QP2oG_A&HYRT!=PQcUsaUWl3Jnwi= zxK`+L1a{;U>ZmrG`JKnBe-1y%@1jqO7L;0ZHq3I6z&x6Wj8=WAwmHgJoLyd8sSV#* z3PE-q$#n-K6(Y=~S@LeBY_i&Xj>nNXNl7^ilB1uW$Q6XiwgCL}635%RRJP6uVm@H4 zIwS139D`6&YV(ff_kx2_+u9}iu=fS^&yJ`g$-0WK7O!4CR!=%|IkO-KCZVfa*7k`n zPSV+36>dk@d8hWvarCv!YhHi}S=giQYYWte+(UQXIHlHQ?cC!KcWmts*B70w{usaS zH>ewxM4R5=d%XG0(a=;M1r`A)lA)%V2|ZRyB~g_2Z^G`Xf|nL}_6WEN}-Tp>2ml^zThQu^~bl@RFH5b z)H1rosEFnAy+=wNa*9iPIN-AmQXP^>E{{+K~G0U<$o&>Q8%c3*h5t;3~#tx|w zV>Z$%M=K4+6c=c-O@G^x(vepuoV>jCtGMNfP2X8VqPIfFwp*TN3rB{vjJzOY_#>KX zL3aXmes}@B?~d&~$9@oVf3LDWHaOLJT-PI`XtCM~a%j$H?!)iO6 zSZ|JgZRWe(GCl8Z3n=e>9%$Q5J|@WuYsZKI(Tpa?gfAY|VxC|<-5*c~7+ucv9xcX% zP}XXF*cmY8gB`Q4;H5M_>vv zyr8AVqxqrz=H#yn*Uwt0qTZfK4i`e?Dzquccxs9vmfjKRpM2mC#||w+!W6(cc}V!70N;0=JD?w|-^Egi+`@M>9_p z8)<&yYAN`ILmKC@G5F5C8c(>F`Cyc$yfoshkEvSF{wo}ze)Fp|;Rt@=A|sH=IrByS z@GmQQ2aZ!y9$m9XvxWyprNJw7&izb(r(3hn&UMf)h}HM3oyKQ1yrCC5mBJU%LapVq zh2~^M(uYR^%xqCPdyZCHqX*G|gp|ruj<0`j9q$6ggEg9!NRDK`=x;7j>bH2iT$ii$ zxE65ef`yKQ9Hx)Cg3+wp3P_Ij7FxcEJO0*MzXV^y&AWdgE1=Rp z5rmMJEGczIG7)d)rX->)HHm#@g>uN5!Tp|uz<(~3Nj7CvTVME-T`f#J0l^hr(wF8q zL{$@ekNcI^MvVjzmxV>z_0FC1RSLnV`fjrHK!%iF!qLDmz~d*ApNN$bKKB>;vA9oeZY#va5f;Q)hZ; zG^rX5dS>cprYf^OhBijl@LR(JMPSP%{o^}jEAds9ZV#57vqwt1C|)+!E2~(O(V4@_ z?>Rm`%HKbn^@RHs;=|s>)Nk+qLZ`cFNg5G-hyQ1 zylJi}V<;c`w`5+<@51~#5on*J_J_vW9={I zRwf`CCUwR@jk3SF;3PGpYnQLZb`xE76TNwbMz7%ZitL}0ePV&jJ}1lsBi|008&D>u zCDq=qHxe`}v8=czEOLz2QR?Q`LkIgi+7v`>D^KHNg34CXlf1W|HnI+>N!FRQ8 z{ZK*;I}!J9b^u*mppBE!60TWTl55rWR=S_3MSqTQ;kkP26emjrx=`yR^N|f^I>$$Os?802yj8n7 z*7kNh?7~-|KheLu|DABk=FRUsmIm#oQ(G@l^1cWPj#1M!f;+KuhQpcvL4-wH{aeT^ z9c%RsaEJz6JK~UwzxxyYw3toa%Q{wRM72QochO1Fx_ugoq_1~QY;dfHx@nxyf~K&> zh@wk4!Yl*l57|vLaK)YV?d*1#*xemm`hl-8mK3e?YuqVSQA2;hC?dS38Vqd|m#c9waA z7ZP)ZKg8~YX>aOZX(tFFd-V4$ugz=K$KxQ7C+DNL!;=I&by+5T*s-yzWu9SQRpUy5 z=5fe5fA8#(K(F=V#$`b@hFIDaRBNr2rO;9!R+?RbmIdFslk+QRR8MpRoNCURcq)(x z@;MMJ~tF153O{gWPGs zwM1dj2HPh~nHT5H44{_uhrt0!6B!B;p^N#u-}L=4!aPQ%4?Vxl>7)5y_J55G(pKkV zp$?~BXqFQVr(F={4rK^GJ#D|){TMAv|K&BviHV}?B~LqpO}-`@%Cws-PXf`EvDG*f zs9Csx`^1>+hXeQF4779JPj~g0V)Io-eZLjKVaNJeu0Vs;K|KL7bIO(0?WY!wbTL1> zm3;+`2W0XKA~1tmoIeJ*|8(OGSjy7z6@+?Z_-=`m(NoQJIczS zUmpUW*TFW){FJ5z~()3|z^>Cv}`NNN&}U^iLt8_AnUY5;45h@pE`lH#E8 zsaKtc2F{p$|0DeCcK(C#`x_N!rOSr`oYl9_>#;-uH8>zazp6q_OMrB3Pk2<4-uDu4 z++t3_xF7%iaJ$$&P0Js={G!U+?KGo^(FjyTxCZ;i?a2ZI*xfW+OrAl@_t_M+#aJeA z%M{9JIqx>Q>%C=Arzr6wz{aFmAR{<|hqHOJSM>3DlpvWE`q8c}qvc-yBL9iJ2gA*p zaj~k%ov5l>gsg+{#=0<96S_i0@WK54`$}tosluhX8T3?6wAN+%f`p5*WuGYdLcs{Y zbTDe1@3o**Unv;|j|W$0BQu+_+xE=t0I9pDS2}5MzFALHu;`@|&`1ppzwt?KG@UAU z2wOW|bV7#JS9dT=WPUhqHi7J-MKZRab@@|JWVI-gP;)?>aFrsXT? z5fPcG%o?*-Je7N`MOR-4>Aqw#f3{@5A(evR99c8s7%>yGGUuJfYU)!dCJiHK%~lON zH!?p2lJkB?Q;0hmETscibN6BN1VJbNxx&AX82{Bu;}P_YhHXDg8b^D}1Lg69gB24yvXQS5OiPD zJtDdpHA*{>?`=AKCWD?SD%TUSyN#VQ?m@5lY}=y^qj53gYMD?G%J9~+%a{9G5aZ3+ zIBd6j?xjCx?xjM;50=w!dpEh&emCBa`u(=YAB1(kCPv~oJstwPFjt0MJkZ<01Zv5$ zn(k5V)Q_}=`X7ovG4M7xypr^>GIhmlQBMEP20=Sw$IQjQ1?Li(~nyRy`)t_!G|E9I&;^`ZOu zZx*8V^lH1VO9fFczvr=)H=}|`Ln(57yoBqG4U#jdE7Nn>+3sab z0p_*{Hr1rw)qJwxkiltjk@0Ax_6Xo6aR7U`MUArZoyOnXy!{alSo+=$OKn9;YfXzK z^P=YFJJaGAHvXb-Ad3W#VrJEbPfw^Dlc4NX;LEJtBW_yiW4a?`#LP)~7#LjDg8RlZ zo5|TgKu?2~i#;IkwQl?wi(wtT&fC2X3-?3#sj}KyRH2tv%$>L3vZ5gjovUuX_KOY? zx`o3$XEgO<`JJIJK8@cocgq-3ey4w@aqP08Ef(J&5pd_`@3cw29RJS6m1q1j*uErm5&D(=g0I5@*KUtfrzOozb!t+Oq-ICqgc@ zra(p6$SvTl2^cD+WieHP;!rEmf>^qA4ZFV6{dPI3$2PG)X?I+UYoJEJXV%Zt{#TvC z5MVen?fOVA_N~Db#fFa4mg3Bdt~24GQz1OtL=FbcnIBg_YibA-?$HFB>8 z25=#8Z~CWg@%B?`ksTD$VSOhJ7~Hns9O?OT-m_qdAsm*|a*vdi!V$dr&Lysm0u^hg z5}%ez0~f`qOe!`Mr~iR+#MBhOa()=2a~_ZS(r_P6!K_pz1Z^YIg_y2~kbPWDYR_{Juc{U;!yP+sh8ogE5M1M=%z&|tg|3Ds-JBh(fy=O zH{xIDcrPv3o7_jGY)caxUZ`LWVc5>?h+lpA@W6{M0cGf82#0S*QN3~rb}mmeMjiA# zx$e*?TBsBbyWmE38mSi0_Wq@EZV2G7!YW9z_%$(%<(6A=W}uOCrp2R){yMXV?*WGH z3Uv=bM#vufNFH@C8evT{E~DY`nY#=@2e@xn)*SVkpVVqQej8;Go$}LC&>-#2az4}u zD?u(I0G{S)^Avd!2bH7-*%55QrwtA$J7G(U7TN-tsq3!tLG^6uiZ8(k>0f2$if9xx z9PpRF4VjAE{6gYFQ58&j`#HRoIP|`-13aWf8Bj0EMXQ3$$^_X9&)H^>fKgGW@7nTU zW5Sn=S43+64;2VO{m-f4uu)f1ebG65W37}MiZ$vTlCgg-!4TYEa^S1stoUJHcM;;M z3`{on@%qUYG{+@ZTHgA-wz|ocDF~=vR$DW*$ZI>KP-?Ykh>j0bvV*r|DgI`_Q)X}; z(T?@48h$wPTYPy8BT`)l#;0Xgt-5&Rj zhrjw4)r7{|nV*_!duoXm_D?-)ZF;v?deRbS>vTz%Ez1<$g39gKxKf{3*;=p35JYIg zvBw*zX@2Awr8Uz5#b@l=3~o&~Wx4+k+39~cPcq1G8CbbyVSvvzu`9J!tv_Cw5C8Dh z|2EMWaQyJ1VK^+PBL|JHWzDGnAHtLp{O6D3DUb!o^x|sNf7G4-`*p({II4K_5zEsf zTkCzP{|He3OS6I_sQd;OJIDpBt#zB@as8A1e@6Rn(D_er1KT9vG#$a=5?#f*^Hikc z)7h}yA?2^lJR8yH^i&^@jLEW7SYOOFNvc&NCNQqGl6)8>vP$$nl(pI{R>hJ+E8_Ak zV~blF{@PjnO;qCXcFnPGXm$2ii7`Zrt2QCcP0=Sku~%vo4Wgm`b2$B>MznEr0cqpw zTm(8Q=0i$oUx+*N@)eWQ8{VH^{)pNhL^}MlTP+x`uCJT9>FSf$RAp5oxTd<-lnf-_ zV6yDs#2-9=6xVnAJFF4S?QaTW zoo)!izWs&!y?aSvOuNZObsW4I1tEuIX?oJrS+LMs+f3K_L>Q}!$>bAc0&1~Y^s#!t z9!C`Xt#Kw6F@fE_OW=k8X=AB+_;&%O`oOh%bVNZ(tQa(?m~kiQUr|~WE>^CSxh_~p zuVCdWH@m4tsJk@$U>38H=cDekdza1WDMzT}uTfSDZ_3n^h%>Fi6vht1`;y3b{)jAv zJ4o(voXJK4dyCu;6C%ZjJk9zuZUYPH r(BY1~9)qEk24bKpE1cIEX#hmNE$CRr# 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

xyavj55B6PO}pMKfJNcG!1}OsF!nZ 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 diff --git a/doc/tutorials/introduction/desktop_java/java_dev_intro.rst b/doc/tutorials/introduction/desktop_java/java_dev_intro.rst index 2bb50f00ed..3676871449 100644 --- a/doc/tutorials/introduction/desktop_java/java_dev_intro.rst +++ b/doc/tutorials/introduction/desktop_java/java_dev_intro.rst @@ -5,7 +5,7 @@ Introduction to Java Development ******************************** -Last updated: 12 February, 2013. +Last updated: 28 February, 2013. As of OpenCV 2.4.4, OpenCV supports desktop Java development using nearly the same interface as for Android development. This guide will help you to create your first Java (or Scala) application using OpenCV. @@ -28,10 +28,14 @@ In this guide, we will: The same process was used to create the samples in the :file:`samples/java` folder of the OpenCV repository, so consult those files if you get lost. -Get OpenCV with desktop Java support -************************************ +Get proper OpenCV +***************** Starting from version 2.4.4 OpenCV includes desktop Java bindings. + +Download +######## + The most simple way to get it is downloading the appropriate package of **version 2.4.4 or higher** from the `OpenCV SourceForge repository `_. @@ -45,8 +49,8 @@ In order to build OpenCV with Java bindings you need :abbr:`JDK (Java Developmen (we recommend `Oracle/Sun JDK 6 or 7 `_), `Apache Ant `_ and `Python` v2.6 or higher to be installed. -Build OpenCV -############ +Build +##### Let's build OpenCV: @@ -83,6 +87,16 @@ through the CMake output for any Java-related tools that aren't found and instal :alt: CMake output :align: center +.. note:: If ``CMake`` can't find Java in your system set the ``JAVA_HOME`` + environment variable with the path to installed JDK + before running it. E.g.: + + .. code-block:: bash + + export JAVA_HOME=/usr/lib/jvm/java-6-oracle + cmake -DBUILD_SHARED_LIBS=OFF .. + + Now start the build: .. code-block:: bash @@ -95,20 +109,20 @@ or msbuild /m OpenCV.sln /t:Build /p:Configuration=Release /v:m -Besides all this will create a ``jar`` containing the Java interface (:file:`bin/opencv_2.4.4.jar`) +Besides all this will create a ``jar`` containing the Java interface (:file:`bin/opencv-244.jar`) and a native dynamic library containing Java bindings and all the OpenCV stuff -(:file:`bin/Release/opencv_java244.dll` or :file:`bin/libopencv_java244.so` respectively). +(:file:`bin/Release/opencv_java244.dll` or :file:`lib/libopencv_java244.so` respectively). We'll use these files later. -Create a simple Java sample and an Ant build file for it -******************************************************** +Java sample with Ant +******************** .. note:: The described sample is provided with OpenCV library in the :file:`opencv/samples/java/ant` folder. * Create a folder where you'll develop this sample application. -* In this folder create an XML file with the following content using any text editor: +* In this folder create the :file:`build.xml` file with the following content using any text editor: .. code-block:: xml :linenos: @@ -135,7 +149,7 @@ Create a simple Java sample and an Ant build file for it - + @@ -181,15 +195,17 @@ Create a simple Java sample and an Ant build file for it * Put the following Java code into the :file:`SimpleSample.java` file: .. code-block:: java + import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.core.CvType; import org.opencv.core.Scalar; class SimpleSample { - static{ System.loadLibrary("opencv_java244"); } + static{ System.loadLibrary(Core.NATIVE_LIBRARY_NAME); } public static void main(String[] args) { + System.out.println("Welcome to OpenCV " + Core.VERSION); Mat m = new Mat(5, 10, CvType.CV_8UC1, new Scalar(0)); System.out.println("OpenCV Mat: " + m); Mat mr1 = m.row(1); @@ -219,8 +235,8 @@ Create a simple Java sample and an Ant build file for it :alt: run app with Ant :align: center -Create a simple Java project in Eclipse -*************************************** +Java project in Eclipse +*********************** Now let's look at the possiblity of using OpenCV in Java when developing in Eclipse IDE. @@ -293,12 +309,13 @@ Now let's look at the possiblity of using OpenCV in Java when developing in Ecli * Put some simple OpenCV calls there, e.g.: .. code-block:: java + import org.opencv.core.Core; import org.opencv.core.CvType; import org.opencv.core.Mat; public class Main { public static void main(String[] args) { - System.loadLibrary("opencv_java244"); + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); Mat m = Mat.eye(3, 3, CvType.CV_8UC1); System.out.println("m = " + m.dump()); } @@ -310,8 +327,8 @@ Now let's look at the possiblity of using OpenCV in Java when developing in Ecli :alt: Eclipse: run :align: center -Create an SBT project and samples in Java and Scala -*************************************************** +SBT project for Java and Scala +****************************** Now we'll create a simple Java application using SBT. This serves as a brief introduction to those unfamiliar with this build tool. We're using SBT because it is particularly easy and powerful. @@ -409,8 +426,8 @@ You should see something like this: :alt: SBT run :align: center -Copy the OpenCV jar and write a simple application -******************************************************** +Running SBT samples +################### Now we'll create a simple face detection application using OpenCV. @@ -424,7 +441,7 @@ You can optionally rerun ``sbt eclipse`` to update your Eclipse project. cp /build/bin/opencv_.jar lib/ sbt eclipse -Next, create the directory src/main/resources and download this Lena image into it: +Next, create the directory :file:`src/main/resources` and download this Lena image into it: .. image:: images/lena.png :alt: Lena @@ -433,7 +450,7 @@ Next, create the directory src/main/resources and download this Lena image into Make sure it's called :file:`"lena.png"`. Items in the resources directory are available to the Java application at runtime. -Next, copy :file:`lbpcascade_frontalface.xml` from :file:`opencv/data/` into the :file:`resources` +Next, copy :file:`lbpcascade_frontalface.xml` from :file:`opencv/data/lbpcascades/` into the :file:`resources` directory: .. code-block:: bash @@ -490,12 +507,12 @@ Now modify src/main/java/HelloOpenCV.java so it contains the following Java code System.out.println("Hello, OpenCV"); // Load the native library. - System.loadLibrary("opencv_java244"); + System.loadLibrary(Core.NATIVE_LIBRARY_NAME); new DetectFaceDemo().run(); } } -Note the call to ``System.loadLibrary("opencv_java244")``. +Note the call to ``System.loadLibrary(Core.NATIVE_LIBRARY_NAME)``. This command must be executed exactly once per Java process prior to using any native OpenCV methods. If you don't call it, you will get ``UnsatisfiedLink errors``. You will also get errors if you try to load OpenCV when it has already been loaded. diff --git a/samples/java/ant/build.xml b/samples/java/ant/build.xml index 924af1f131..d817aa63dd 100644 --- a/samples/java/ant/build.xml +++ b/samples/java/ant/build.xml @@ -20,7 +20,7 @@ - + From 3cfd3d3ee0ed45494433b135d43c1dc1a38f8659 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 28 Feb 2013 21:43:57 +0400 Subject: [PATCH 24/33] Build with OpenCV.mk for all terget fixed. --- cmake/templates/OpenCV.mk.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/templates/OpenCV.mk.in b/cmake/templates/OpenCV.mk.in index 9054fe990c..078e02039f 100644 --- a/cmake/templates/OpenCV.mk.in +++ b/cmake/templates/OpenCV.mk.in @@ -92,7 +92,7 @@ define add_opencv_camera_module include $(PREBUILT_SHARED_LIBRARY) endef -ifeq ($(OPENCV_MK_ALREADY_INCLUDED),) +ifeq ($(OPENCV_MK_$(OPENCV_TARGET_ARCH_ABI)_ALREADY_INCLUDED),) ifeq ($(OPENCV_INSTALL_MODULES),on) $(foreach module,$(OPENCV_LIBS),$(eval $(call add_opencv_module,$(module)))) endif @@ -105,7 +105,7 @@ ifeq ($(OPENCV_MK_ALREADY_INCLUDED),) endif #turn off module installation to prevent their redefinition - OPENCV_MK_ALREADY_INCLUDED:=on + OPENCV_MK_$(OPENCV_TARGET_ARCH_ABI)_ALREADY_INCLUDED:=on endif ifeq ($(OPENCV_LOCAL_CFLAGS),) From 82b9854837b58386726dc4eb21b9c28b2637308b Mon Sep 17 00:00:00 2001 From: yao Date: Fri, 1 Mar 2013 08:47:20 +0800 Subject: [PATCH 25/33] fix compile warnings --- modules/ocl/src/brute_force_matcher.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ocl/src/brute_force_matcher.cpp b/modules/ocl/src/brute_force_matcher.cpp index 76b1436d29..818f3c18f3 100644 --- a/modules/ocl/src/brute_force_matcher.cpp +++ b/modules/ocl/src/brute_force_matcher.cpp @@ -690,7 +690,7 @@ void findKnnMatch(int k, const oclMat &trainIdx, const oclMat &distance, const o } } -void findKnnMatchDispatcher(int k, const oclMat &trainIdx, const oclMat &distance, const oclMat &allDist, int distType) +static void findKnnMatchDispatcher(int k, const oclMat &trainIdx, const oclMat &distance, const oclMat &allDist, int distType) { findKnnMatch<256>(k, trainIdx, distance, allDist, distType); } From 8f3883a28d1d48b5f1d117c2ea4e5f74dc216a16 Mon Sep 17 00:00:00 2001 From: yao Date: Fri, 1 Mar 2013 10:06:51 +0800 Subject: [PATCH 26/33] fix a compile warning --- samples/ocl/performance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/ocl/performance.cpp b/samples/ocl/performance.cpp index c0073c5fb6..b2a6d85ad9 100644 --- a/samples/ocl/performance.cpp +++ b/samples/ocl/performance.cpp @@ -4345,7 +4345,7 @@ int main(int argc, const char *argv[]) { if (device == devidx) { - ocl::setDevice(oclinfo[i], j); + ocl::setDevice(oclinfo[i], (int)j); TestSystem::instance().setRecordName(oclinfo[i].DeviceName[j]); printf("\nuse %d: %s\n", devidx, oclinfo[i].DeviceName[j].c_str()); goto END_DEV; From da455efc260cacbf4ced334c0bc42a640406ba4e Mon Sep 17 00:00:00 2001 From: Alexander Smorkalov Date: Fri, 1 Mar 2013 12:44:14 +0400 Subject: [PATCH 27/33] Full package version fixed. --- android/libinfo/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/libinfo/info.c b/android/libinfo/info.c index 073a505575..cfdc881c51 100644 --- a/android/libinfo/info.c +++ b/android/libinfo/info.c @@ -7,7 +7,7 @@ const char* GetLibraryList(void); JNIEXPORT jstring JNICALL Java_org_opencv_android_StaticHelper_getLibraryList(JNIEnv *, jclass); #define PACKAGE_NAME "org.opencv.lib_v" CVAUX_STR(CV_VERSION_EPOCH) CVAUX_STR(CV_VERSION_MAJOR) "_" ANDROID_PACKAGE_PLATFORM -#define PACKAGE_REVISION CVAUX_STR(CV_VERSION_MINOR) "." CVAUX_STR(ANDROID_PACKAGE_RELEASE) "." CVAUX_STR(CV_VERSION_REVISION) +#define PACKAGE_REVISION CVAUX_STR(CV_VERSION_MINOR) "." CVAUX_STR(CV_VERSION_REVISION) "." CVAUX_STR(ANDROID_PACKAGE_RELEASE) const char* GetPackageName(void) { From 22d33373fa7e1484838c715c640c20fc037b2f20 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Fri, 1 Mar 2013 12:17:05 +0400 Subject: [PATCH 28/33] Fix build warnings on MSVC x64 and OS X clang --- cmake/OpenCVCompilerOptions.cmake | 2 +- cmake/OpenCVDetectCXXCompiler.cmake | 22 +++++++++++----------- samples/c/smiledetect.cpp | 6 +++--- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cmake/OpenCVCompilerOptions.cmake b/cmake/OpenCVCompilerOptions.cmake index 8981f4b849..aeed112ae0 100644 --- a/cmake/OpenCVCompilerOptions.cmake +++ b/cmake/OpenCVCompilerOptions.cmake @@ -97,7 +97,7 @@ if(CMAKE_COMPILER_IS_GNUCXX) endif() # We need pthread's - if(UNIX AND NOT ANDROID) + if(UNIX AND NOT ANDROID AND NOT (APPLE AND CMAKE_COMPILER_IS_CLANGCXX)) add_extra_compiler_option(-pthread) endif() diff --git a/cmake/OpenCVDetectCXXCompiler.cmake b/cmake/OpenCVDetectCXXCompiler.cmake index 7b6ff5e5bc..6e02780009 100644 --- a/cmake/OpenCVDetectCXXCompiler.cmake +++ b/cmake/OpenCVDetectCXXCompiler.cmake @@ -5,17 +5,17 @@ if(CMAKE_CL_64) set(MSVC64 1) endif() -if(NOT APPLE) - if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set(CMAKE_COMPILER_IS_GNUCXX 1) - set(CMAKE_COMPILER_IS_CLANGCXX 1) - set(ENABLE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE) - endif() - if(CMAKE_C_COMPILER_ID STREQUAL "Clang") - set(CMAKE_COMPILER_IS_GNUCC 1) - set(CMAKE_COMPILER_IS_CLANGCC 1) - set(ENABLE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE) - endif() +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(CMAKE_COMPILER_IS_GNUCXX 1) + set(CMAKE_COMPILER_IS_CLANGCXX 1) +endif() +if(CMAKE_C_COMPILER_ID STREQUAL "Clang") + set(CMAKE_COMPILER_IS_GNUCC 1) + set(CMAKE_COMPILER_IS_CLANGCC 1) +endif() + +if((CMAKE_COMPILER_IS_CLANGCXX OR CMAKE_COMPILER_IS_CLANGCC) AND NOT CMAKE_GENERATOR MATCHES "Xcode") + set(ENABLE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE) endif() # ---------------------------------------------------------------------------- diff --git a/samples/c/smiledetect.cpp b/samples/c/smiledetect.cpp index ff032e4791..c54c724398 100644 --- a/samples/c/smiledetect.cpp +++ b/samples/c/smiledetect.cpp @@ -116,7 +116,7 @@ int main( int argc, const char** argv ) { cout << "In capture ..." << endl; cout << endl << "NOTE: Smile intensity will only be valid after a first smile has been detected" << endl; - + for(;;) { IplImage* iplImg = cvQueryFrame( capture ); @@ -229,8 +229,8 @@ void detectAndDraw( Mat& img, CascadeClassifier& cascade, // The number of detected neighbors depends on image size (and also illumination, etc.). The // following steps use a floating minimum and maximum of neighbors. Intensity thus estimated will be - //accurate only after a first smile has been displayed by the user. - const int smile_neighbors = nestedObjects.size(); + //accurate only after a first smile has been displayed by the user. + const int smile_neighbors = (int)nestedObjects.size(); static int max_neighbors=-1; static int min_neighbors=-1; if (min_neighbors == -1) min_neighbors = smile_neighbors; From 978132edc1cf1ae2590f9daef7a857f02e4160d2 Mon Sep 17 00:00:00 2001 From: Andrey Pavlenko Date: Fri, 1 Mar 2013 13:52:14 +0400 Subject: [PATCH 29/33] minor Android tutorial fixes --- .../android_binary_package/O4A_SDK.rst | 18 ++++++++++-------- .../android_dev_intro.rst | 16 ++++++++-------- .../images/eclipse_10_crystal_clean.png | Bin 49869 -> 47163 bytes .../images/eclipse_7_select_projects.png | Bin 28934 -> 41063 bytes .../images/eclipse_cdt_cfg4.png | Bin 51604 -> 51772 bytes .../images/emulator_canny.png | Bin 27606 -> 25443 bytes 6 files changed, 18 insertions(+), 16 deletions(-) diff --git a/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst b/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst index 3730a8f402..e509ce8108 100644 --- a/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst +++ b/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst @@ -159,7 +159,7 @@ Get the OpenCV4Android SDK unzip ~/Downloads/OpenCV-2.4.4-android-sdk.zip -.. |opencv_android_bin_pack| replace:: OpenCV-2.4.4-android-sdk.zip +.. |opencv_android_bin_pack| replace:: :file:`OpenCV-2.4.4-android-sdk.zip` .. _opencv_android_bin_pack_url: http://sourceforge.net/projects/opencvlibrary/files/opencv-android/2.4.4/OpenCV-2.4.4-android-sdk.zip/download .. |opencv_android_bin_pack_url| replace:: |opencv_android_bin_pack| .. |seven_zip| replace:: 7-Zip @@ -184,7 +184,7 @@ Import OpenCV library and samples to the Eclipse You can simply reference it in your projects. Each sample included into the |opencv_android_bin_pack| is a regular Android project that already - references OpenCV library.Follow the steps below to import OpenCV and samples into the workspace: + references OpenCV library. Follow the steps below to import OpenCV and samples into the workspace: .. note:: OpenCV samples are indeed **dependent** on OpenCV library project so don't forget to import it to your workspace as well. @@ -246,8 +246,8 @@ Running OpenCV Samples ---------------------- At this point you should be able to build and run the samples. Keep in mind, that -``face-detection``, ``Tutorial 3` and ``Tutorial 4`` include some native code and -require Android NDK and CDT plugin for Eclipse to build working applications. If you haven't +``face-detection`` and ``Tutorial 2 - Mixed Processing`` include some native code and +require Android NDK and NDK/CDT plugin for Eclipse to build working applications. If you haven't installed these tools, see the corresponding section of :ref:`Android_Dev_Intro`. .. warning:: Please consider that some samples use Android Java Camera API, which is accessible @@ -295,7 +295,7 @@ Well, running samples from Eclipse is very simple: .. code-block:: sh :linenos: - /platform-tools/adb install /apk/OpenCV_2.4.4_Manager_armv7a-neon.apk + /platform-tools/adb install /apk/OpenCV_2.4.4_Manager_2.6_armv7a-neon.apk .. note:: ``armeabi``, ``armv7a-neon``, ``arm7a-neon-android8``, ``mips`` and ``x86`` stand for platform targets: @@ -326,15 +326,17 @@ Well, running samples from Eclipse is very simple: When done, you will be able to run OpenCV samples on your device/emulator seamlessly. -* Here is ``Tutorial 2 - Use OpenCV Camera`` sample, running on top of stock camera-preview of the emulator. +* Here is ``Sample - image-manipulations`` sample, running on top of stock camera-preview of the emulator. .. image:: images/emulator_canny.png :height: 600px - :alt: Tutorial 1 Basic - 1. Add OpenCV - running Canny + :alt: 'Sample - image-manipulations' running Canny :align: center What's next =========== -Now, when you have your instance of OpenCV4Adroid SDK set up and configured, you may want to proceed to using OpenCV in your own application. You can learn how to do that in a separate :ref:`dev_with_OCV_on_Android` tutorial. \ No newline at end of file +Now, when you have your instance of OpenCV4Adroid SDK set up and configured, +you may want to proceed to using OpenCV in your own application. +You can learn how to do that in a separate :ref:`dev_with_OCV_on_Android` tutorial. diff --git a/doc/tutorials/introduction/android_binary_package/android_dev_intro.rst b/doc/tutorials/introduction/android_binary_package/android_dev_intro.rst index 021561e8cb..9545bee286 100644 --- a/doc/tutorials/introduction/android_binary_package/android_dev_intro.rst +++ b/doc/tutorials/introduction/android_binary_package/android_dev_intro.rst @@ -103,8 +103,8 @@ You need the following software to be installed in order to develop for Android Here is Google's `install guide `_ for the SDK. - .. note:: You can choose downloading ``ADT Bundle package`` that in addition to Android SDK Tools includes - Eclipse + ADT + CDT plugins, Android Platform-tools, the latest Android platform and the latest + .. note:: You can choose downloading **ADT Bundle package** that in addition to Android SDK Tools includes + Eclipse + ADT + NDK/CDT plugins, Android Platform-tools, the latest Android platform and the latest Android system image for the emulator - this is the best choice for those who is setting up Android development environment the first time! @@ -112,15 +112,15 @@ You need the following software to be installed in order to develop for Android for use on amd64 and ia64 systems to be installed. You can install them with the following command: - .. code-block:: bash + .. code-block:: bash - sudo apt-get install ia32-libs + sudo apt-get install ia32-libs - For Red Hat based systems the following command might be helpful: + For Red Hat based systems the following command might be helpful: - .. code-block:: bash + .. code-block:: bash - sudo yum install libXtst.i386 + sudo yum install libXtst.i386 #. **Android SDK components** @@ -148,7 +148,7 @@ You need the following software to be installed in order to develop for Android Check the `Android SDK System Requirements `_ document for a list of Eclipse versions that are compatible with the Android SDK. - For OpenCV 2.4.x we recommend **Eclipse 3.7 (Indigo)** or later versions. They work well for + For OpenCV 2.4.x we recommend **Eclipse 3.7 (Indigo)** or **Eclipse 4.2 (Juno)**. They work well for OpenCV under both Windows and Linux. If you have no Eclipse installed, you can get it from the `official site `_. diff --git a/doc/tutorials/introduction/android_binary_package/images/eclipse_10_crystal_clean.png b/doc/tutorials/introduction/android_binary_package/images/eclipse_10_crystal_clean.png index 18e14d1c0f943920520447d057b1a6c710cb6638..499247a48261abc3cda959359ba8a784542846e9 100644 GIT binary patch literal 47163 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�Von=bGfpoF0oV= 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

6ysZwCd0BmP{3XMfj^$f+J>L)WK?1; z?n15nn0XbfscOJ51Q_hN5?c-F&f13;qx$}nUoA&Js~%UbqzpihwB?xth9H3&$vap( z3}&JG4ZHZNX42LUztO`}M&o~lliLKIDfMR%Do1o_#0OI{V+Wb$&G94NeLE=%H4zBP z5#CW;ATp_w-7DAZ;&>sgdTGN<|4ZiKL;qpx^G8AJ#hHV)TUlv!sZuP#1uX=xo_SSj zEw6Q!;lAm0@Q(R@2|g)?q@DAPZSMz-FB)K^B~lo)7)-hVkrZPehFJl5)JGN;kq;n` z>d{v+2kR;a4GlAnG*Jm}pMg^ZYnQ7FE50wdnGVX|k6N#YiquIa>jXJV^$r62s zHzf2*nYK_D0T3Aw6A0QJ<)P^Q9@ObwqqiN-<1bM-htJ)nc(Uji+c952QeR}^DlI)> z2ITd6lFs6NZNFbrDp6)km8KtO@t~a1h4S5DF$nZO-emW+Li0t=MuP>A@l&?d8C4e3 zqsH3Udqu0l0~D=VG?PuBd{Gcmq8M`x$IDQgEX^co>7lX6Smoi>hQnCIsjJPlrM_LI zFoQ7^eb3bd(ME!;TG^b%8hhORfAPw6yAq6d08#OHHN&2uORzG-obsR!-S?)#s`Cqg~eep_bqR-$#gO| zG!%9n@vD=8{5==IQm*yx?~%6zR!o=*&}(r$XiJ-O9+9z#IZP%Q{-(d{_C#0CG)=h2 zBy-k1j0JT^@JF=z_~=;LFq6@+(^bH$@nZ4Qq zamM?-aa^h>3G$jP>8pA16r{oGkEfgTUoNX*Yy8Oh(_L?cUhktmX{7U-I%S|at7h|+ zIv`()j%E&!*T8{y`U;?bEZCImNYSqL#af{{^d~6+fQ*O0Ij^73#}ijcP7Pj}xo%9a4%8&0nEOecp>1=E1!Thf zc|ro!0D?TY6`<$1&&(h|u>ckd#BFNTB5fVw5x3Dwc(Eomi|}pB$n52{XbB zNY2>Za@lR0=UOyRxBf)9xw$c!jNLHlRs0(&gfm=Y$d$HfODzT!QUbW1BtY20zxn3h zaW_!D*)*4+R96?xzEkr@A~0pq(fTb#r7D(VU~nc#xm-=vSji$%aIajgvJw3f3SbN2 zk1vuN@#t(?05E$(OpQF?uT&lWPjt|BYUB7RQCUk_UAl?*NHDG9Cyjy3N0urm6PjU_ z+1&wrq}uwXUQAB?12Xpb*8K0+))z>iBpC^(6VWI-`?1Gq+snMe;CEzYt}vw;@VvrG zFi`9ut`_`1g$=6h{|{lqD6Cff+fz*iiq&C?G0EDC@{?W|X}y;E=k7X+hzN#a^aHi6 zX`83dSdrc!(TTUqxk*qnwHk~#EK{rEb;}t_Wc;sq!46nlTr4`T2H|^-P_)WG#y5Ns zq#jK0NxGLS+|k{>cHejP)8-~%6M2mb*Imff2KF3j0;i|9x7PzAP!5L=4R2QC(db^d z`)2w5oXPQ%|HYtg=g7Fm=vFemuO#cw^c>Ca`)DcW=WO2R8`Yj3#;=Rk zI_YHbW3qnJh8kZEFCHfw85y}16y@hTO6EWd09`z!@N*ww;&${@d(d~pTymB&yxmGxQdE4f|4v3G(*Ce3%J)UIlYzrYU$KfKQG4Bl1(Hu6 z76nanbj&M*<__bA*W>K&i;E7A$Jx*u_(13{em`VF{$ksCNA@W0jTO=RoJP6yJ*fQM zPes3+dfS)~$QwwhsHjd5st7dJ`??+<`1bF-3@VzRJQfI^gx9^VN$y2g-KUYZ79(^C z$_XAG&ki9f-_13vsf&yHHrv{L+?O6sjak5!DojWLi1@5~J7W@)b)Uo2FE3ih*sg%< zogBvvtnGo7W5Vp)e_U_t_#)6y{565$vnp+Ep(!nZ(>ib>T&u?#@m(nB^(YG1zCareCJ2kmdvje*^@dLuns)Db6o1Ui z!DOR5@i`tejk<=<*{^R(7(D!<-|vUL5W)5f9AJWu_@$@d=&jwOgY*7vzrl;w{SC5a zT@(N#zl73j@?HJw%;lE(3IYtkR!EBN=7e?)aUHSwEOd?atV@mV@45A=l6WRg zt$np>FTmEgY^s^VYso;jGOO8fcaCZ8 zYg0ru8K}kXT(9NstpW7VY z%32%o8-gWBS=4+!=Lc8mh2ip$+TXnv@t_8Z-CL4&v%*-rISn2$B zK_P}7{WUTd$~+~;C-A)721xtaWi<=AxWzkE3=6#X-pIZ@|;#?V^)A(V3;x ziepBCG^_!r**mS^c9FwiI9qnBjrf`nP)?NTy?o^>m2&E1kJlzb#q-L_{g_as$@QD{ zA|SO0lsVx0JFRe-ya|=0evU2L_%2DslhE=$C=&vDXWYEjZWkC0>t{J6rEpz7d}%*rP;L4>n$C2Dy6Z9^H4J*lAvR8MnFIZ8 z0{$!?hiGd-=2Y@tG|d#B+s!QnPI2#M_Nt9(|4MP*lil-HbOIjTcdj>H%W)p(eTU>Et7+BL~ zaU>Y$`vLWbJCac5>=Ss{1aySze*;Q?6G7zCFKCWYrVDH;R7q@WbV>*@lYfz7E=+Qa zaTy-Hl#6I7G(x=Ie^6y$bM43gw`1XoOuN~~^7%y}jfYy*Vlvd;zKxH|VepaxFMkXf8YJTsQ+>a#`*j{$YCF2%23dglsxl=!Uqy z{1$2A9E3<6a~OL;-BQv?lna%Ek~+ll73jqu^5iGvoqw|A`zevdfCA`vAn^LJ61&Fc zh)}=7z*@){6|Zeb{^~T`T?Gb+#($OIvxt<>yyjc(w<~%gJ9;~kgfw9{=|Ua6{+z)( z{Kqv8HBw`F`M+ubATsv!_6d=Y>T~?S`Gp{KnomOo@9!2&)~s#2CL{ThygD1HXx;QT ztjbkFRHGvPQE>ZyPbIg)HaHd zkP-o1Ln1?8BNDL8;Hs)#e6$#6xoRC-8+r83vq2h}pCg;S@n!k(nBj!A#B-S0dFe*QTeyD<8MmI6WLqv#*eX-ciRm7nFRfFpw=%417nb_xJP)_C#6#if|> z)u@sG$nxyKufr%>%y6R?*mNts4e&$dnRfhY;BR8!p1FN8H(E_Dq6Oz?3x4cOUh}z5 z6~m_U@gC?I=u+2oZo6syy1kHJQ#Y5nlId|buiY-gk&|VcIhWg!$t=IbPX%C>Z#k(l z`X+U{mz_Jdr4mfP$yi2eXz9HC`N$$1>nyJ zU}feH2$@Ia9rqyDInYevD9Ih z4MN~+Yo~lNK_~)E`#{mbPR{1kgss_q`VSJAH5fp@as($6tI?n9lTA5ABhVMzN^czy z5FcRO>oiQ7P9%Xbyl$yfI!g`q^8-kb5H9rtrYx7NCi1DE?W2gtLRRSoRbt6*OS${CsxTI7}@e#C=dN48rWWt$^JgOx~sxMLM(9= zyoz;Q^j7wuCK^e{=jO6jEdkS;uKpWDh=&i4J7)`Qs^scblO*P3ZyJVSw=Or`sy(viBj2acZd-<#<%dlE@<#|X~ahq~^bo}z~z(4ER`0PRQL#od#fiv4{ zfPegdMsCogryhix3;OmVr&F2?q+J3Bc&Z0KDWx$B8_=6_2g`evIjNnYS@0?%fj;fj z(GD^t>@ZOt86@`aunw5zgf8NPb#{elfM6a*e+`Q5QWWg`+mf0|a!cB4Nnu2X#^G5a zc?!Nk8a}%IewKy9XKE9RdV`1_;SHdYY^q@w=#zBp7BP|bPat+;8&ptzKn=hmA$;}J4}gZl3RIL z{Uo<$c=9v+TS}+j`=^9VQ#jEiyzN&5O~DjBxUw}tiFYc3j21Io_GdoS?>R8do&3$X z7Sg#LMmrszg@{~=H`~9N_#OEsj8-SfZsdnDi(j9Ru*J;h$TyakDr^RU?5|07F66wn zCGsWwzbfLh)>R$(42z>E6{DZ|`nfkEe$z#NfzCY>sHOUUb?{vwk^kX`0 zP&Ss7fD@b$q&}IlyXA0m4<+nGP(_lhX2s))`jSSyg>{%5Ni|q59%#p6Sj}Aenabzf zr|ZHU^QXUN$bgAiU9eR-)0g>E){FQDOXy>KXOD)a%h!n#%%5a5>N;IF@4rPzJ}XS^ z&D&Pt{QZs4L2?^|^VE86RZr3sCy6bJ+?9*srwqkDcCJA$d*@1GvRoN!9z#2!xQ zk3xFUm(XfEU3WL!jbBkG-VB!RLQTys4_lgoAIG{yBPB_T++8NXWL!UWqF(Ye8hY~; zQ(QQqz5Cx#x?_Rme?#e(6hFYyml)eGXxedU5v100Slt673}UK58tXLT06xZy0xIV- zuKw15C=rD+Ci{G{ZWs2{2*N{0OcM4l`i#~-LCb7oxd`uYK6~dP$3I~dWIwNa612ex6`ph^m z*A1TwD!P!S(^!yPRX6mv8=JG5SRi<|;q@$$i8WWfKA#BMseFbQcyn<()$hnSQ|c@( z1$xqaGod(s^^t838K!p%VgB&|>ELy{s!q)Lp}QnGvSeS1i+Jz!i^$c|cFmtEz{Z{!_rOV7>9++XEYQ&Q=>h&rKDp0Epzyyhpi29!_@9@h2{+!ho*-f%&D2C4k-k zjmR4r+|0yWb0DVGP_AGtSRCw2Kv>v>y|4e1N# z{dX)-N&$`q3X<9ZqLI(dLcAdW`&R-}Z2g%Cq`!e!hEHXE3oxsEm#0yIr_KEm^%u8kgE2q{c0Z{pr82sZ-^Aa} zCFEOt&m%NjwP-eF&D?7}%z^lmjCI?8w%NE2(!-SL7=c+RB-%b5MCk1lL>U~9%h{F* zi00m_?TfX${@EA+v|nS{f|?E>0#F5*PTe_;or2e}62Sfp-q`uu@A0R~AudbQWTDsMLc6&dL17OQ|P`0RN{ySv&>-h-v!(uP%VfJ}0v2 zeED=EMI-~^q~C`sG5V!0h`4~dOKm^cU;sp)>__s21{<}< zh5wW6`%AYNC+W<9-F!dy1pxw-Xm3PGT=C$*0yv9ZJ$tQgtx1;|M@{jN6&p4HK;W{< zc|rJQs>{ScF*q6IBl$NFk@^W<2l6>d*_`Ugb`iv&vXXld`z= zKiU$vt$$aRyvg}|#t7JwiG*}KO_ybJZ>qIPTk~(ecno@h8VUB+;&0#{4JY({w;G(u zt_1ToEEwtQ?}@9)I1Z<*Zfbg*0IscVOXICdT_VyE(mzC5R{e(W#W6!USL`n--EKHh zCfU5+CM?L-v%VUn@sDrYK{;bs(dsShy)Bne^5X%dP-xk!VQ~t}gi94dnq4b|ufBEh z+eLmg+rZqIs|A|2HmF~;0bQK%;+YSu7lXigABs4Hfa&t288qS(A z%?1>awqN^v>TM4@|4l-6peQr8Gcru?)l}o7QK*7}wZ3SSO2QN3bvbS;|C23J@6eqH z`2&h**6}9+`h0s=T|S#+Zv26hTR{saeCQDHt?i+^{OR4iS(W zmeDFCyk;s62Xo)@$J!wYk0~-8sr@5W0rP_X6ICOeRjUb6v?+ZHm#9eJKsJ!$ACy}R z)aZV`fPs=1W&p*|ruXis1H_O;i!7)5`baT+e1{1a;TEYhu_UmH*Urianv2vrNI(C5 zCPMl!)Hxhc>=_|%2Yts&?6o}AJqwtj7Wx~@MfnY%fhp2H9Sd_5MjGk29zloOfI2bx zeiLCU>W{`D&Qpk+e(ZAD*J~%B2b94C{v}|+5xeREH$`u^TH}N-R;v5+UJqmnGTZM| zRpm6)TThH;3Iad~bd680lhyYD0^g}@9?$4jktZZDl-bT|nEnKwUdXVv2sF%`Dip`B zNyWEMFf>CljFM3wS7?%PsD)yX)W!W7JDp2G&s>pTBllS@tt;uQYD&?|?n(qt!z}oo z@T~Ml^dE-SZg+|O!B;zTl2YFnplg;J7aMGh>W@l1#j@ua94uh-P_4j}mr-nzN#2pb z`>WLdtg{&z8=K8*KRb~l%x>DnlAd3{hWV>Ta;53Oj<|OAy{c(0PoOWC|CnB`h^VM9 z>aCDy>+-4!FZ7E&Jg#vc0IIEqHovn@BRR(E{v`kW+=37Z(Tb998=}z ziy!6#f72LXU?8mtplq4@z0d%p%R}bYnvIY$Mw!u8R*lbWdO2zG#-_HaS-1YN?PHrt zdHdyWAEVFH3c6$~-^kK=xF}p`o`E=aiF_u+F&dpME4R-_0eiMZWG|GWDp8SvIT7s$ z@QS{%WA}|A)zow3Ezp3muEQ=t>VWDL*&(5!7l4VfR9g5>-h6caEF&B z?juSmWAk&a*tnmCv#A0ajvrSGXx|UJ;a3;5>1KTPQt8mNHazb^5k%5VobV0cGIsF$ z5Fi5AKQ$S|xcyJlMxPY5U0#tQ(P`Y}G2>8O0a!E{U${{Nv@md^#x|z~2w^%j3QaQ~ zT@P6jbD80$ZNExOeb_Ws5)f4OpDTqs%n`e+m5f<`;1UFMFAJWEfa$Gq6^*Bz9N^Lw z*V8LX3FV5jXDJteJe{O4ZSb|`ZF0sYN3c&>2nQENdrB0v6+75|Gz#gm8|jP#tbXEvTT_(2ERLm%Ra;6o8XZ1H**953NY(+1S{)xTe$~i4}qG6MQj% z_>T98DAdS|D2NhIaoapKC%sXoGlT2^eMDrPS4;6gD9qvSe84#myX*Dp=)Y?)+bZs6 z_D)C9j=oX>I{XB-n7wIdR2=f2Bc{}j^e(^iUrEFjM!thGmtD7q?S`)6-vN#bST__9 zNKFSr{tupO@qwxwOQ^w!{k0riq9DIC6>XrxhT{>i{{cz!k18@9Aj&A&-0?5RV483S z8@su={gpK3d;-D)&1S#{aa>uiCV%h02An&CGX=RTdbmZ*Nx}6%2t|IHr39v;Vw4mI z!g`Na_aaIQ+w-aPYK(z|s&V`URH4YI#=w9+MSHisM-0DfqktsE|B$x;v6r&E!LEOx>O*ShrDBGNs*N$(U4>&h=j?ELz8D{_ulZXN9e`v5z;0D_%%Mxy| zv!y-}mI_~Pj)WlM1A@p23PuEwvM=SWoDlyJlU7)ElUzW4AWa-y1TerL8P%^@t3PpU znW>6#bQdVqKmV)*o@I3iErk0C!9PfBbti$ag8wos^%fpjP(x_|z*0!fOIPPiO>if~ z`88d+P9<^zpmh@typ?Y(Xh`vEQ7@Z|P=Y!7 z*>pY&;-rCuz?$A4hy`0wnIbhifw6}LQqRqkP# z@e!riw|$|hUwntx#LBNl-bPY|{G73g+mcSG0TG{<0wYO9Wf||E76WQa>N2Q7`fMP? zY@_2swgAw# zjDJp`d%gik_28a_ZLy37;8K`>VQK=I%@USsW?}(ukt2s)L&{f}n+0ogKdNFm6SPcq z*eO*vd7%+^IV&-X2N-Q>ST*Vmg_tmn+7|FEi?z_rMmJN67JkoB_a&4#)cp}#k0ErJ z*wX+&hDaIbVy)5BtS|mK#E7`>?%|@~T-$Bc)|?;u+yupy3UCe6mX*6u3Zh!OZ|0li z&pLG(D!xR5dgu-Y)iXK?7@U&LrPFWy!)!teQEfd{`rZnIl!28b$MAy}n|EO&IE^)g zce2llFy5H1sjvMwRLNTM~ zc8VYnpo*PO&o*ny)(cxkBm+*-$qgxL^p@NDb1kPW+++gR&kk~#2h>*Gzg z3hO0cAW~wxp;nfx-d+r$A%K3&3_kDtTHqHhb8g@QtN`S(^zy=S9*-}~d-Q>>bC7-V zWBjkCAGp6wr|j<_nnoLtFe7d5dPRf__C4N%BbVRB;^8uOmtn#T-7>oPw`pgj-K_SK z$?XE69wyj#?)&K(iaMFeP65;%hL^`qD}9>SAkaLYirJc%p-&HU7&poVJ0?|k`ONwnu(*TKb-xoozk;y??gl=Fgum zkme5$Cn+E%VX}9yQ&2peIjjo9_WG zpQmP4sAvkH)f5{7_ddxLNxfM_Sd@7RuJ+oSDh4d_c&?~0Ev*#C>$d<1r7dARuyt0Z zuY`9%=y@^f=TCQAyI;1H+~yDcID~>MFBFUz0vA&W4{u}_9%g=`1H3{@+0DYA4ow}P zve z$Lbr+`5qHL#_M$04y^3dv;15xouBEW#!C=LyrW=M=e4V*-IVtR^u|Ki>bWU3$(P zhBcc)bSQYSg>lCzvlg*PHIXYkZE=dtO1gnrb^eobw(z#m(E>Zbe-amzesXN|CE4sw zbiQ$MAcpwz_X4;3j&g>wN5_}{f0g*8C?UZ~nq$Hc5rg0mY~D7GYpDXw$!F{c)B7!7 z(=XNuKLxygW?xsvUIfK%#Yo%-FexyQ?Jpp{g;dh$I~DL6p82A@CAIO>aIIQ~a+IF- zhWFTbp_@2tjz87j8tNP`|L!~vfC3z(mVpD+64rJBwCRGr^l@s9B&-z90Ai(@anemL zX3KGFy(+BxTfE^z5IUyG)jHv=J%_XU(Qz?amahLEbl@r}lA0D%zwvF@HeniR7{h7B zf|-U2tmK2)Z~?T!9@4W+xza}jIaV*WdF_Zu6O_wJ(vTZ>s@*M^al1V)z=?1I^yG?| zx%gfj#met(P@;gFz0&DYwfNXrAa1fml?yyF4|v*yx?mtN*YXfDT(|jiRz+rwP-H4{ z=JVI-JIkr)4k$b}^PAdmiK2;&qPQTL0&!LUw+;uIB$QWL==$4P(8_9A7JG;HT1$GL zH2QTr<{p;!heW7KQ9Oh@KHX)kC%RDtfpxK2C~|~6ngbC*n5kIdGjUmYImeAdjjLs) zI8+f&p^J*M)CBLDeu_xEgy2^*s+GCKr=rC{uFqs0WTd`kGA_ zjev@?OcsQWuH%w5_P%fq1vS1ABKffy?1ZFu1da>j)DyIfwP^|qCj)!(gVYxz`F-Am zQhkhTwd5#nY;=KgrmuUx`EkiRb!fo)>J|835vX|ww_okNl}Dgl0W_)WACRVx#b}I? zKlG^0*J&5_=^}t)^@EmkMIy(!={9|K9^)v*Y@dQaFOQhD@7?7$bbu5K&F3e$XyHXj zw^h%KA{JUNVilIvzEnQl-RFEAoXKBy$;r1QfR3GxmnP!4`tw+O-M!)dSZhf5<&5Xk*f`(Zmz6u*W2$7%%)=r!Np zbAA5xA!U!`xtPEk*^6=NNB`a#>0RsT4*HC^Rjj}Y81fR-Np<3l2 zuY2Y`xik52&eI(?*Cr+$Xb#`~#PI-df2XhUDi{()-m!N#`?c}OMy_;NM{AbXC)@U> zV=l#7x+ypmZc1|PJV}F{Y^b4)yivTwq#zLSpn|ldmUzm8F749;qS?MnEl=(1^6A|a zoYn1=uGS(iH!8WMOke8z65XOTaz)Db-k5v80`7#lopCjFb>nNE;Ou)ne64L>o+9p? z3_bh(?2uJc?B4pg2jMQ);@`B4Hbx#t?MGe0MW<~tE_zs!p`?n7rITKE#FC+h81k+G z6Mcj~1I6W508@q$gn4XQo#q&T)ATbA+=Ubt1I#qnq0d7bU!0#${zN8HWTLqW@cHt60zUon zyU^tPe}#3M7Mo8Rmg|gqenYoq3NMObEn04)0&o-LMdYSeQ1l*cr%~<-{N;99fo9q# zR>sXGRrj++G8ZZ+39rkOJ!9x;B$`m&TIu@CG*3KXs5#FiR;`do?ITlc;h_yyk|V&fuHG$n#nw4mm2-pjFEX4fG< zF13?(x{7*Bb&8m(yjL z=_4I?*&_k>V`Ha!BAm>~AkaHyn*eW*g^gV?cG{4dhSq)k0!7xM3$<;lg+7oD zsbXi{0EeOcFymv`idC#|3JEANi0X15It2&j^?MYEbcJ+%ZSL zm50?BJ$c9}e)Xkqi+gj*^J<+JmO9=uc*{C`w`Hg6E5DC;i#UaRRWuud=r?c3SvxOE z+UAXq1!LbV(Wnd%yYCPd7K%6V${m$kFeU5YKT0iMx~`38Ri2p)IW+WT4n|&rK%f|r z%4d@o2TMSVdhq5TR*J9eVA_C9Q_qu?yJ~{DB6eUz?o%&}2_Bi=#ZsF$D2sDHY)Y!8 z34qLc&iD)NX1ABo1sGh+-~1BTU4Hv#*jL89u1?{2!VspcdRU*(d$_%9N9$%-98;a` zUfVgxVuPaQtU?yw8ENOHcrV}1Qq5YC_;uIz%U;%W+gIC)25F13+V(I!_gqNbP;qmP zOVSdUURSM9CqJG0c1o6_8oV?&C4^76Evn5TbLGWt2hE``=AR6tJ+ah~vFwh!Uy=8z z)m*U#o(c+Q_hn^DO3DEcPzi*tSvTmHPBTro`*Y@*XNXZGJ%Kq&9@>8kyki%5B;jga^ycu6z!wqf%tu#y= z1ghS=ZmxCJ4X({Ev10>o?H|!8H87EX__|b1M_X)Nm(hNT<<(U3Do5ogn#$ZBQi`pt za*>Mq0Xp+j)O?!Xowb!vqogv4vq8oH!k(Yr^qj*)iAP1ZZR=4y}1bRgnpBypU_YhWbJ3IFD_Bk6j2$zsv zxA${ZklC}a*s$3Anwce3*2UTfCA=Y*kg-B&gsyTY~YF0jlUHE0caQ^6m$2gXdauRl}`S8`Yci;fUeQLw(! z)#(hREFbtjx3aFl74PADjJ+8Jsnf4*vv;b@Fj|(;=*5pIub!2wVFBJ9J5x0+mT)iK zP8xGoMdt#b_u2CgLpA#YDJc5@@n=xhFzH8N1R=!kjKg*r$w zy>Q0H)SaGfBD~pXi9Dw>-kV zAtAq}gJZSo2&Mwv+R8)~^_;gdFmgPSOqQD)YR+mP&p{xwAkKq9RsgoYdHwk1ZmQ(u zYoT2H!^ZqroG||83!K_V^R^f#XJ=w$^P!IvbaZsD8XP$vb2%@jiDRXuV>Q33fJ;~R zt~>nIZrW2-sjNX7&`eLHYh`ir?u=tsImVGS%v=yGePDsa zo*vM{O9YnB`*XF0Ps#>GTC=*si3KWi?$Uw*9wq2XaOKSV2yKXANba64%QWh4zgrO> z`goV89cECw!h9aH?M~t;n_2nZYP#L0Weq2 znDR6oCPE3V+9ZlaISCc#pcEuY=o&XwWj=gC3l1!vJ5dVUhuU;v{&H_@l=U>LaCB(! z{;AqRcI1{$ombdf67Q5Y#m5JZ3gC^HRc)TO(uf4>OIF576Kdv!3mt)NxU*-7g2>=) zIw^9o;ClWGR#Q{c+bfyk8#H@z@`FFPs7HQmP9lwbuBdja^y&~hzL-rY&CVM}=64$? zy#?Va>^tD#8YJNs3UGVHF&OJ`2tV|U@<3R`aKpleXmybZEAsHrK|7N!WJ##O&CZ}r zl_`FOvQy#2cHfDa+n{=IczA1_P8yXiFHp-XuaK^3T&b%8y)uTW946YZ{%bq#xBSV0 zS{K$xH2!VsKnjm_v7!=CUkRNTv<1NW8-V?M7>px(bs8JX9s>o3JZrl)WU5gxEt)d_ zkWX(8l2gm$7csZb=bLDqQ-z>@Ao$@yac(jpxXT89%77VPUHj2}!k8%j;Jxskg=LbN zO@%&V$jFE>5!ZZYwy=t{Q>Dj2JYah-Gq>kA_p0qS>xem3RM{NcikoCq<)SC)J86bf zymeeX6F;@FR9nwVIM#V;vekCH058>cU@64>Q)j>8kyN10@2X_AbaWuzN2@sEci;EV z>9ck(ti(`cnK=B8=V$WgO0hdB1P+(6-s=x)%y%8+ zV+5+Ve+^}1W865AT3*`l+!}LJ7sudObs`n-e3r8Gl;>-vC?+;O^4YS&CAqGL)t3ki z#(Y^`y_9r6ec+UhD4e>z-}=;s`rSC@bd9&Q{|rE zs4c{M1TNQ^Uhk@?9@4sB{mRWS5~)~14eP26;T-hf>r?`7aSC>Np_>+KcEXmowoLq; zty-%>yksW+EE=DqauqFC5UJ9@?N{pX)IQ5e+%bJ=2d%MOC;zpvbxFx_3IEw%3Rzph zVF7;<^Z5fafw$KMjEPmgxZ@Xw7MsuLKopbR9eptb?qWOiH;Gn1}}$S5M%2Lj~HLY#x(|=xo5<)gSRS^0eJ+V34Xd zY@V=u1Oskn!$qyEv}wzQ!}5aX)E~S0=UsQUIIBP^d5~V_4rk?a%yJXK+mpf-9|qtM zh$|CDlsPiu>Wl~MusHoMW@s1;FY(XzAItQmXgePnq;Fwn29g2kNzB!n$~{w$^L677 z#CTDOU==epr9psTh9J(8U;6O#a|GB5$BOrzLodneXCNX)ef@=*8G>K$z+*|Fp@_f< znWLTYET)MOK^&?cUtb^|wH?S`^!>ZK(PGk$S@A`N4m{Fx9W9{66NEn{hE zS^n7i4)c9O3-NQySWc$m@ewL>_|KtvBDHMJejhghh0fXXmS}3uMBgv*x{?_F{ags9r}7amcXV)eLU8n=Uc!I`=y32OK{~_D*t4 z+RE)99gHX%TAoy!y$=UNRKa)uguLc|C#Q-9p4tNC3>a|1_xH7JwrF>U!GiJbUFLnL zg_9)wb-t(86N0Pv%TRE3OhMVR?**yFcR`Q&uRp8?KL*lfE^R*3$D&r+-rlz3$&{n? zwVEzbfx%!Er7q|UyxG<6B9&1<>||w3%qIO|>!k@(WudfSE=)QxhIW_4h0&joh^Xt& zAQ|AIS;mg9(?nIFCUokL+w#=tHY9ql=>IIDFDTyKxPlTvXtq8C$LP6iOO!$admeJO-oL$(yNnt ztGXA|q|W$WIMvON@nwbbj}=pNeO3a@Xc`gDWWYKqo%`M2obU5HEl1ja1}V`2GtH4C zhPA-UmF;h7&{UXIui29WaBD71>T)gku|m6YgI=df?-}~~iYa0@sDK1LLSSg%kVRWl zQ`5u*Xv7G0#+T8wxkxB_ctvR9ratT8xw*Lu^_e7?sIHI+#{xzj9UUS+JkB7D z5z-!kS=02KsTUf9QA)=>&N`WM5svU)o9HLEb#jFqN)32at8Kh3e&?O}xK36G!+}AM zK9Z7>%Nz^|+Iq=jZ+S79p19Zyfep~K>N!hh<_cioTBBAj5s}zTBo>r!fdAWIjWzKN zOn_N?-profb^EUhs?VdKku%c=Ra~CLzW8z~^^+9!>7@7q4-iO+ruf<9&4*b|`m#KxL!Qc~ zM${)J*Cqr5ALeQ$2M`JZ&(BR!0Id#IOn{b#KQ@n>gk9w;={M3yWS|}m_46M{>pP7L z69juUym<1sC~x{u1_fVO+^2Q#8f_VE6_D&nQ&4pFe8St?;Rxt>8u~ek#}-4`EcSiT z0r)A}%*}^a@W$D?%LwI6-N>LlsFIE4WJ{pNBaY+_dD<^CfdY(P{lh-|0!=-5!iY?F z$r4v#Z>&N&2j!_#)RY811B+*rsEhw?8%rZFCN(AHMFfTjR{~2Wf|)|FfrWBgnF7l% zLJi?N`1kx!&JQY)7p|0<9V|LUv&=4fjI`aU3f075=~PoXDW(6E+nyVE#!n7pKoig` z;-%Fx$=pvSqR^)REuW*Y!4H2%q;P|KN7R+Tj0o-|{m(7@kc7_30g$gACeCx%(_x}tm z%LIJ%|8A#BU9fm?3mlgqoqko%Venr#91HBBNR_{BqIo>iELmyyK9YsOui$!tTR`*J zD5Ybl-6J#s(ItCu@}Onx<=R ztElK(^wpr-Y9OKHIshR_CbD@1>$$GE&7c5hsWCzqPcT-fP-R}ddNtM9*tpzYalDq( zy{fMLz#l)WigK-`E*%HI57$vHp>G>6Gh0wV&2`fpWJXK;xCd!$-31dHd$q-Nvs=6~ znc=$<`~CDoxA;3nc&)5f7akoRVYRF1(T(|Fz`fj$j*gxO)-aFw@Ig*iw(I_430O#r x{U(4BA1K`;RnEc=a38PO*-e|ku+bFeN2)m|ZUvS}G*Ng36l7GTYoyFV{~N@^E2RJc literal 49869 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

*-e4~BMMY3DEvoN_xi4CQKh?QKyv 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 z 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%0A7PY-8$NXM3WDs0UrwYpB90wMS6F!g;#*fy>4lN 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

5fX-e_nkHqseC5s; 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 diff --git a/doc/tutorials/introduction/android_binary_package/images/emulator_canny.png b/doc/tutorials/introduction/android_binary_package/images/emulator_canny.png index 1bc0511318dabe84f61b9f48045e309ee3021322..d08340be9ceed6dc6cd60a2e7293561e14e6c6e2 100644 GIT binary patch literal 25443 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 GRr-d#ifTtlDiWX9z+ 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 literal 27606 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 Date: Fri, 1 Mar 2013 13:56:50 +0400 Subject: [PATCH 30/33] removing redundant picture resize --- doc/tutorials/introduction/android_binary_package/O4A_SDK.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst b/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst index e509ce8108..b37126f308 100644 --- a/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst +++ b/doc/tutorials/introduction/android_binary_package/O4A_SDK.rst @@ -329,7 +329,6 @@ Well, running samples from Eclipse is very simple: * Here is ``Sample - image-manipulations`` sample, running on top of stock camera-preview of the emulator. .. image:: images/emulator_canny.png - :height: 600px :alt: 'Sample - image-manipulations' running Canny :align: center From 65bb4250a450128980c51463ee938c27062294ed Mon Sep 17 00:00:00 2001 From: yao Date: Fri, 1 Mar 2013 18:08:53 +0800 Subject: [PATCH 31/33] Fix a bug in addWeighted x64 mode And a potential problem in remap --- modules/ocl/src/arithm.cpp | 11 +++++++---- modules/ocl/src/imgproc.cpp | 5 +++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/modules/ocl/src/arithm.cpp b/modules/ocl/src/arithm.cpp index a7e4fd90b6..4e2c819914 100644 --- a/modules/ocl/src/arithm.cpp +++ b/modules/ocl/src/arithm.cpp @@ -2123,12 +2123,16 @@ void cv::ocl::addWeighted(const oclMat &src1, double alpha, const oclMat &src2, }; int dst_step1 = dst.cols * dst.elemSize(); + int src1_step = (int) src1.step; + int src2_step = (int) src2.step; + int dst_step = (int) dst.step; + float alpha_f = alpha, beta_f = beta, gama_f = gama; vector > args; args.push_back( make_pair( sizeof(cl_mem), (void *)&src1.data )); - args.push_back( make_pair( sizeof(cl_int), (void *)&src1.step )); + args.push_back( make_pair( sizeof(cl_int), (void *)&src1_step )); args.push_back( make_pair( sizeof(cl_int), (void *)&src1.offset)); args.push_back( make_pair( sizeof(cl_mem), (void *)&src2.data )); - args.push_back( make_pair( sizeof(cl_int), (void *)&src2.step )); + args.push_back( make_pair( sizeof(cl_int), (void *)&src2_step )); args.push_back( make_pair( sizeof(cl_int), (void *)&src2.offset)); if(src1.clCxt -> impl -> double_support != 0) @@ -2139,14 +2143,13 @@ void cv::ocl::addWeighted(const oclMat &src1, double alpha, const oclMat &src2, } else { - float alpha_f = alpha, beta_f = beta, gama_f = gama; args.push_back( make_pair( sizeof(cl_float), (void *)&alpha_f )); args.push_back( make_pair( sizeof(cl_float), (void *)&beta_f )); args.push_back( make_pair( sizeof(cl_float), (void *)&gama_f )); } args.push_back( make_pair( sizeof(cl_mem), (void *)&dst.data )); - args.push_back( make_pair( sizeof(cl_int), (void *)&dst.step )); + args.push_back( make_pair( sizeof(cl_int), (void *)&dst_step )); args.push_back( make_pair( sizeof(cl_int), (void *)&dst.offset)); args.push_back( make_pair( sizeof(cl_int), (void *)&src1.rows )); args.push_back( make_pair( sizeof(cl_int), (void *)&cols )); diff --git a/modules/ocl/src/imgproc.cpp b/modules/ocl/src/imgproc.cpp index 8fbada1d33..9b6cf748c0 100644 --- a/modules/ocl/src/imgproc.cpp +++ b/modules/ocl/src/imgproc.cpp @@ -289,13 +289,14 @@ namespace cv args.push_back( make_pair(sizeof(cl_int), (void *)&map1.cols)); args.push_back( make_pair(sizeof(cl_int), (void *)&map1.rows)); args.push_back( make_pair(sizeof(cl_int), (void *)&cols)); - if(src.clCxt -> impl -> double_support != 0) + float borderFloat[4] = {(float)borderValue[0], (float)borderValue[1], (float)borderValue[2], (float)borderValue[3]}; + + if(src.clCxt -> impl -> double_support != 0) { args.push_back( make_pair(sizeof(cl_double4), (void *)&borderValue)); } else { - float borderFloat[4] = {(float)borderValue[0], (float)borderValue[1], (float)borderValue[2], (float)borderValue[3]}; args.push_back( make_pair(sizeof(cl_float4), (void *)&borderFloat)); } } From 1094179155c2524cfe6c3036e63c5e25d9ab1bd2 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Fri, 1 Mar 2013 16:50:42 +0400 Subject: [PATCH 32/33] Avoid build falure in armeabi build with Android SDK --- cmake/templates/OpenCVConfig.cmake.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/templates/OpenCVConfig.cmake.in b/cmake/templates/OpenCVConfig.cmake.in index e285eab191..7441b59d59 100644 --- a/cmake/templates/OpenCVConfig.cmake.in +++ b/cmake/templates/OpenCVConfig.cmake.in @@ -202,7 +202,7 @@ foreach(__opttype OPT DBG) #indicate that this module is also found string(TOUPPER "${__cvdep}" __cvdep) set(${__cvdep}_FOUND 1) - else() + elseif(EXISTS "${OpenCV_3RDPARTY_LIB_DIR_${__opttype}}/${OpenCV_${__cvdep}_LIBNAME_${__opttype}}") list(APPEND OpenCV_LIBS_${__opttype} "${OpenCV_3RDPARTY_LIB_DIR_${__opttype}}/${OpenCV_${__cvdep}_LIBNAME_${__opttype}}") endif() endforeach() From facab40745af0abfd7e7f9ee08f2ab0ab9c7c741 Mon Sep 17 00:00:00 2001 From: Andrey Kamaev Date: Fri, 1 Mar 2013 19:44:17 +0400 Subject: [PATCH 33/33] Disable -fomit-frame-pointer for OS X Clang as it leads to crash on exception thrown --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a649f9fb7..579312d40a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,7 +184,7 @@ OCV_OPTION(INSTALL_TO_MANGLED_PATHS "Enables mangled install paths, that help wi OCV_OPTION(ENABLE_PRECOMPILED_HEADERS "Use precompiled headers" ON IF (NOT IOS) ) OCV_OPTION(ENABLE_SOLUTION_FOLDERS "Solution folder in Visual Studio or in other IDEs" (MSVC_IDE OR CMAKE_GENERATOR MATCHES Xcode) IF (CMAKE_VERSION VERSION_GREATER "2.8.0") ) OCV_OPTION(ENABLE_PROFILING "Enable profiling in the GCC compiler (Add flags: -g -pg)" OFF IF CMAKE_COMPILER_IS_GNUCXX ) -OCV_OPTION(ENABLE_OMIT_FRAME_POINTER "Enable -fomit-frame-pointer for GCC" ON IF CMAKE_COMPILER_IS_GNUCXX ) +OCV_OPTION(ENABLE_OMIT_FRAME_POINTER "Enable -fomit-frame-pointer for GCC" ON IF CMAKE_COMPILER_IS_GNUCXX AND NOT (APPLE AND CMAKE_COMPILER_IS_CLANGCXX) ) OCV_OPTION(ENABLE_POWERPC "Enable PowerPC for GCC" ON IF (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_PROCESSOR MATCHES powerpc.*) ) OCV_OPTION(ENABLE_FAST_MATH "Enable -ffast-math (not recommended for GCC 4.6.x)" OFF IF (CMAKE_COMPILER_IS_GNUCXX AND (X86 OR X86_64)) ) OCV_OPTION(ENABLE_SSE "Enable SSE instructions" ON IF ((MSVC OR CMAKE_COMPILER_IS_GNUCXX) AND (X86 OR X86_64)) )