├── LICENSE
├── README.md
├── bower.json
├── build
├── jsfeat-min.js
└── jsfeat.js
├── cascades
├── bbf_face.js
├── eye.js
├── frontalface.js
├── handfist.js
├── handopen.js
├── mouth.js
├── profileface.js
└── upperbody.js
├── compile
├── build.xml
└── yuicompressor-2.4.2.jar
├── package.json
└── src
├── jsfeat.js
├── jsfeat_bbf.js
├── jsfeat_cache.js
├── jsfeat_export.js
├── jsfeat_fast_corners.js
├── jsfeat_haar.js
├── jsfeat_imgproc.js
├── jsfeat_linalg.js
├── jsfeat_mat_math.js
├── jsfeat_math.js
├── jsfeat_motion_estimator.js
├── jsfeat_optical_flow_lk.js
├── jsfeat_orb.js
├── jsfeat_struct.js
├── jsfeat_transform.js
├── jsfeat_yape.js
└── jsfeat_yape06.js
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2012 Eugene Zatepyakin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | jsfeat
2 | ======
3 |
4 | ### JavaScript Computer Vision library ###
5 |
6 | The project aim is to explore JS/HTML5 possibilities using modern & state-of-art computer vision algorithms.
7 |
8 | [Examples and Documentation](https://inspirit.github.io/jsfeat/)
9 |
10 | ### Features ###
11 |
12 | * Custom data structures
13 | * Basic image processing methods (grayscale, derivatives, box-blur, resample, etc.)
14 | * grayscale ([Demo](https://inspirit.github.io/jsfeat/sample_grayscale.html))
15 | * box blur ([Demo](https://inspirit.github.io/jsfeat/sample_boxblur.html))
16 | * gaussian blur ([Demo](https://inspirit.github.io/jsfeat/sample_gaussblur.html))
17 | * equalize histogram ([Demo](https://inspirit.github.io/jsfeat/sample_equalize_hist.html))
18 | * canny edges ([Demo](https://inspirit.github.io/jsfeat/sample_canny_edge.html))
19 | * sobel deriv ([Demo](https://inspirit.github.io/jsfeat/sample_sobel.html))
20 | * scharr deriv ([Demo](https://inspirit.github.io/jsfeat/sample_scharr.html))
21 | * find more at Examples and Documentation page
22 | * Linear Algebra module
23 | * LU (Gaussian elimination) solver
24 | * Cholesky solver
25 | * SVD decomposition, solver and pseudo-inverse
26 | * Eigen Vectors and Values
27 | * Multiview module ([Demo](https://inspirit.github.io/jsfeat/sample_videostab.html))
28 | * Affine2D motion kernel
29 | * Homography2D motion kernel
30 | * RANSAC motion estimator
31 | * LMEDS motion estimator
32 | * Matrix Math module for various matrix operation such as traspose, multiply etc.
33 | * Features 2D
34 | * Fast Corners feature detector ([Demo](https://inspirit.github.io/jsfeat/sample_fast_corners.html))
35 | * YAPE06 feature detector ([Demo](https://inspirit.github.io/jsfeat/sample_yape06.html))
36 | * YAPE feature detector ([Demo](https://inspirit.github.io/jsfeat/sample_yape.html))
37 | * ORB feature descriptor ([Demo](https://inspirit.github.io/jsfeat/sample_orb.html))
38 | * Lucas-Kanade optical flow ([Demo](https://inspirit.github.io/jsfeat/sample_oflow_lk.html) - click to add points)
39 | * HAAR object detector ([Demo](https://inspirit.github.io/jsfeat/sample_haar_face.html))
40 | * BBF object detector ([Demo](https://inspirit.github.io/jsfeat/sample_bbf_face.html))
41 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | "name": "jsfeat",
4 | "version" : "0.0.8",
5 | "description" : "JavaScript Computer Vision library",
6 | "author" : "Eugene Zatepyakin (http://www.inspirit.ru/)",
7 | "main" : "build/jsfeat-min.js",
8 |
9 | "ignore": [
10 | "src",
11 | "compile",
12 | "node_modules"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/cascades/handfist.js:
--------------------------------------------------------------------------------
1 | /**
2 | * this cascade is derived from https://github.com/mtschirs/js-objectdetect implementation
3 | * @author Martin Tschirsich / http://www.tu-darmstadt.de/~m_t
4 | */
5 | (function(global) {
6 | global.handfist = {complexClassifiers:[{simpleClassifiers:[{features:[[3,3,9,16,-1.],[3,7,9,8,2.]],tilted:0,threshold:-0.0223442204296589,right_val:-0.9436557292938232,left_val:0.7737345099449158},{features:[[0,9,12,5,-1.],[6,9,6,5,2.]],tilted:0,threshold:-9.3714958056807518e-003,right_val:-0.9004204869270325,left_val:0.5525149106979370}],threshold:-0.3911409080028534},{simpleClassifiers:[{features:[[12,14,12,10,-1.],[12,14,6,5,2.],[18,19,6,5,2.]],tilted:0,threshold:0.0127444602549076,right_val:0.5557708144187927,left_val:-0.7241874933242798},{features:[[2,4,16,8,-1.],[2,8,16,4,2.]],tilted:0,threshold:-0.0203973893076181,right_val:-0.9134256243705750,left_val:0.3255875110626221},{features:[[9,6,15,14,-1.],[9,13,15,7,2.]],tilted:0,threshold:1.5015050303190947e-003,right_val:0.2950277030467987,left_val:-0.8422530293464661},{features:[[0,10,10,5,-1.],[5,10,5,5,2.]],tilted:0,threshold:-9.5540005713701248e-003,right_val:-0.8186870813369751,left_val:0.2949278056621552},{features:[[8,0,16,6,-1.],[8,0,16,3,2.]],tilted:1,threshold:-9.0454015880823135e-003,right_val:0.2449316978454590,left_val:-0.9253956079483032}],threshold:-0.8027257919311523},{simpleClassifiers:[{features:[[11,9,9,6,-1.],[14,12,3,6,3.]],tilted:1,threshold:0.0339135192334652,right_val:0.5952491760253906,left_val:-0.6010565757751465},{features:[[15,1,8,10,-1.],[15,6,8,5,2.]],tilted:0,threshold:-6.3976310193538666e-003,right_val:-0.9008722901344299,left_val:0.2902083992958069},{features:[[12,23,12,1,-1.],[18,23,6,1,2.]],tilted:0,threshold:3.5964029375463724e-003,right_val:0.3585815131664276,left_val:-0.6108912825584412},{features:[[0,8,16,11,-1.],[8,8,8,11,2.]],tilted:0,threshold:3.1002631294541061e-004,right_val:-0.9231098890304565,left_val:0.2521544992923737}],threshold:-0.6695849895477295},{simpleClassifiers:[{features:[[12,22,12,2,-1.],[18,22,6,2,2.]],tilted:0,threshold:8.9982077479362488e-003,right_val:0.5311666131019592,left_val:-0.6216139197349548},{features:[[6,7,10,5,-1.],[6,7,5,5,2.]],tilted:1,threshold:5.8961678296327591e-003,right_val:-0.8741096854209900,left_val:0.3589088022708893},{features:[[10,8,3,2,-1.],[10,9,3,1,2.]],tilted:0,threshold:-7.3489747592248023e-005,right_val:-0.8340616226196289,left_val:0.2021690011024475},{features:[[15,15,3,4,-1.],[15,15,3,2,2.]],tilted:1,threshold:-1.3183970004320145e-003,right_val:0.2309758067131043,left_val:-0.8218436241149902}],threshold:-0.9460288882255554},{simpleClassifiers:[{features:[[4,18,20,6,-1.],[4,18,10,3,2.],[14,21,10,3,2.]],tilted:0,threshold:5.8955969288945198e-003,right_val:0.3239434063434601,left_val:-0.7554979920387268},{features:[[3,1,20,14,-1.],[3,1,10,7,2.],[13,8,10,7,2.]],tilted:0,threshold:8.6170788854360580e-003,right_val:0.2782224118709564,left_val:-0.7028874754905701},{features:[[2,11,3,9,-1.],[3,14,1,3,9.]],tilted:0,threshold:-1.5837070532143116e-003,right_val:0.2773326933383942,left_val:-0.7751926779747009},{features:[[0,4,12,20,-1.],[0,4,6,10,2.],[6,14,6,10,2.]],tilted:0,threshold:7.9292394220829010e-003,right_val:0.2167312055826187,left_val:-0.7723438143730164},{features:[[16,15,6,2,-1.],[16,15,6,1,2.]],tilted:1,threshold:-1.4443190302699804e-003,right_val:0.2078661024570465,left_val:-0.8843228220939636},{features:[[11,8,7,2,-1.],[11,9,7,1,2.]],tilted:0,threshold:-4.8251380212605000e-004,right_val:-0.6776664853096008,left_val:0.2337501049041748},{features:[[20,15,4,6,-1.],[22,15,2,6,2.]],tilted:0,threshold:8.0077340826392174e-003,right_val:0.5163818001747131,left_val:-0.3731102049350739}],threshold:-1.0588489770889282},{simpleClassifiers:[{features:[[14,19,1,2,-1.],[14,20,1,1,2.]],tilted:0,threshold:-5.8145709772361442e-005,right_val:-0.6792302131652832,left_val:0.3404448032379150},{features:[[0,6,2,7,-1.],[1,6,1,7,2.]],tilted:0,threshold:-1.1419489746913314e-003,right_val:-0.5890597105026245,left_val:0.3598371148109436},{features:[[8,0,10,2,-1.],[8,0,5,2,2.]],tilted:1,threshold:5.8654937893152237e-003,right_val:0.1721540987491608,left_val:-0.9622359871864319},{features:[[5,8,16,7,-1.],[13,8,8,7,2.]],tilted:0,threshold:1.1028599692508578e-004,right_val:0.2389315962791443,left_val:-0.7706093192100525},{features:[[2,9,14,12,-1.],[9,9,7,12,2.]],tilted:0,threshold:0.0145609602332115,right_val:-0.8984915018081665,left_val:0.1552716046571732}],threshold:-0.7966647148132324},{simpleClassifiers:[{features:[[2,11,6,10,-1.],[2,11,3,5,2.],[5,16,3,5,2.]],tilted:0,threshold:3.9159432053565979e-003,right_val:0.2886646091938019,left_val:-0.7370954751968384},{features:[[0,3,4,9,-1.],[2,3,2,9,2.]],tilted:0,threshold:-4.6402178704738617e-003,right_val:-0.5601897239685059,left_val:0.3129867017269135},{features:[[7,10,10,8,-1.],[12,10,5,8,2.]],tilted:0,threshold:-4.2656981386244297e-003,right_val:0.2132489979267120,left_val:-0.8286197781562805},{features:[[8,16,16,8,-1.],[8,16,8,4,2.],[16,20,8,4,2.]],tilted:0,threshold:7.9925684258341789e-003,right_val:0.2340082973241806,left_val:-0.6752548217773438},{features:[[4,13,6,3,-1.],[6,15,2,3,3.]],tilted:1,threshold:-6.2725958414375782e-003,right_val:0.2019792944192886,left_val:-0.7839264273643494},{features:[[13,3,11,18,-1.],[13,12,11,9,2.]],tilted:0,threshold:-0.0288890209048986,right_val:0.1651563942432404,left_val:-0.7889788150787354},{features:[[10,7,5,4,-1.],[10,9,5,2,2.]],tilted:0,threshold:-1.5122259501367807e-003,right_val:-0.7596625089645386,left_val:0.1971655040979385},{features:[[11,17,6,3,-1.],[13,18,2,1,9.]],tilted:0,threshold:4.3620187789201736e-003,right_val:-0.9309347271919251,left_val:0.1344974040985107},{features:[[12,7,12,17,-1.],[15,7,6,17,2.]],tilted:0,threshold:-3.2192119397222996e-003,right_val:-0.6044244170188904,left_val:0.2437663972377777}],threshold:-1.0856239795684814},{simpleClassifiers:[{features:[[14,18,1,2,-1.],[14,19,1,1,2.]],tilted:0,threshold:-4.3883759644813836e-005,right_val:-0.6793813705444336,left_val:0.3130159080028534},{features:[[3,11,6,12,-1.],[3,11,3,6,2.],[6,17,3,6,2.]],tilted:0,threshold:6.2022951897233725e-004,right_val:0.1801322996616364,left_val:-0.8423554897308350},{features:[[22,13,2,7,-1.],[23,13,1,7,2.]],tilted:0,threshold:1.0972339659929276e-003,right_val:0.3450973927974701,left_val:-0.4771775007247925},{features:[[16,15,1,2,-1.],[16,15,1,1,2.]],tilted:1,threshold:-2.6349889230914414e-004,right_val:0.2153723984956741,left_val:-0.7629253864288330},{features:[[0,5,22,18,-1.],[0,14,22,9,2.]],tilted:0,threshold:-0.0542980991303921,right_val:0.1730009019374847,left_val:-0.8849576711654663},{features:[[13,19,3,3,-1.],[14,20,1,1,9.]],tilted:0,threshold:-2.1721520461142063e-003,right_val:0.1638997048139572,left_val:-0.8367894887924194},{features:[[15,0,5,2,-1.],[15,1,5,1,2.]],tilted:0,threshold:-1.6347350319847465e-003,right_val:-0.4079189002513886,left_val:0.3731253147125244},{features:[[5,15,4,5,-1.],[5,15,2,5,2.]],tilted:1,threshold:-2.9642079025506973e-003,right_val:0.1886135041713715,left_val:-0.7973154187202454}],threshold:-0.8849025964736939},{simpleClassifiers:[{features:[[12,16,2,8,-1.],[12,20,2,4,2.]],tilted:0,threshold:-2.6686030905693769e-003,right_val:-0.6534382104873657,left_val:0.2950133979320526},{features:[[0,18,2,4,-1.],[1,18,1,4,2.]],tilted:0,threshold:-7.9764809925109148e-004,right_val:-0.4435322880744934,left_val:0.3938421010971069},{features:[[8,3,12,4,-1.],[8,3,12,2,2.]],tilted:1,threshold:-5.1704752258956432e-003,right_val:0.2110860049724579,left_val:-0.7686781883239746},{features:[[6,17,3,2,-1.],[7,18,1,2,3.]],tilted:1,threshold:-1.5294969780370593e-003,right_val:0.1583137959241867,left_val:-0.8944628238677979},{features:[[1,0,10,6,-1.],[6,0,5,6,2.]],tilted:0,threshold:-6.3780639320611954e-003,right_val:-0.4529472887516022,left_val:0.3393965959548950},{features:[[12,9,3,2,-1.],[12,10,3,1,2.]],tilted:0,threshold:-2.6243639877066016e-004,right_val:-0.4983885884284973,left_val:0.2850841879844666},{features:[[11,1,12,11,-1.],[11,1,6,11,2.]],tilted:1,threshold:0.0361888185143471,right_val:-0.7394319772720337,left_val:0.2132015973329544},{features:[[21,13,2,10,-1.],[21,18,2,5,2.]],tilted:0,threshold:7.7682351693511009e-003,right_val:0.4112299978733063,left_val:-0.4052247107028961},{features:[[15,16,1,2,-1.],[15,16,1,1,2.]],tilted:1,threshold:-2.3738530580885708e-004,right_val:0.1911296993494034,left_val:-0.7753518819808960},{features:[[0,11,8,8,-1.],[0,11,4,4,2.],[4,15,4,4,2.]],tilted:0,threshold:4.2231627739965916e-003,right_val:0.1739158928394318,left_val:-0.7229338884353638}],threshold:-1.0250910520553589},{simpleClassifiers:[{features:[[11,11,7,6,-1.],[11,13,7,2,3.]],tilted:0,threshold:2.9137390665709972e-003,right_val:0.3337337076663971,left_val:-0.5349493026733398},{features:[[12,17,3,3,-1.],[13,18,1,1,9.]],tilted:0,threshold:-1.6270120395347476e-003,right_val:0.1722342073917389,left_val:-0.8804692029953003},{features:[[0,9,2,2,-1.],[1,9,1,2,2.]],tilted:0,threshold:-2.9037619242444634e-004,right_val:-0.5733091235160828,left_val:0.2734786868095398},{features:[[13,17,1,2,-1.],[13,18,1,1,2.]],tilted:0,threshold:-1.4552129869116470e-005,right_val:-0.5995762944221497,left_val:0.2491019070148468},{features:[[7,0,17,18,-1.],[7,9,17,9,2.]],tilted:0,threshold:0.0141834802925587,right_val:-0.8961830139160156,left_val:0.1507173925638199},{features:[[8,11,8,2,-1.],[8,11,8,1,2.]],tilted:1,threshold:-5.8600129705155268e-005,right_val:-0.7106314897537231,left_val:0.1771630048751831},{features:[[18,17,6,7,-1.],[21,17,3,7,2.]],tilted:0,threshold:7.3492531664669514e-003,right_val:0.2574213147163391,left_val:-0.5106546878814697},{features:[[2,19,8,1,-1.],[6,19,4,1,2.]],tilted:0,threshold:-1.7738100141286850e-003,right_val:0.1460683941841126,left_val:-0.8705360293388367}],threshold:-0.9740471243858337},{simpleClassifiers:[{features:[[12,10,10,6,-1.],[12,10,5,3,2.],[17,13,5,3,2.]],tilted:0,threshold:-8.5521116852760315e-003,right_val:-0.4556924998760223,left_val:0.3413020968437195},{features:[[5,20,18,4,-1.],[5,20,9,2,2.],[14,22,9,2,2.]],tilted:0,threshold:2.9570560436695814e-003,right_val:0.2246744036674500,left_val:-0.5616099834442139},{features:[[1,10,22,5,-1.],[12,10,11,5,2.]],tilted:0,threshold:-0.0195402801036835,right_val:0.1363316029310226,left_val:-0.8423789739608765},{features:[[1,11,12,1,-1.],[1,11,6,1,2.]],tilted:1,threshold:-3.2073149923235178e-003,right_val:0.1883326023817062,left_val:-0.7569847702980042},{features:[[12,0,12,24,-1.],[12,6,12,12,2.]],tilted:0,threshold:-8.4488727152347565e-003,right_val:-0.8026102185249329,left_val:0.1382011026144028},{features:[[4,15,5,6,-1.],[4,17,5,2,3.]],tilted:0,threshold:1.1350389831932262e-004,right_val:0.1435786038637161,left_val:-0.7027189135551453},{features:[[12,2,6,4,-1.],[14,4,2,4,3.]],tilted:1,threshold:-5.8187649119645357e-004,right_val:0.2510882019996643,left_val:-0.4507982134819031},{features:[[0,7,2,17,-1.],[1,7,1,17,2.]],tilted:0,threshold:-0.0161978900432587,right_val:-0.2079977989196777,left_val:0.6447368860244751},{features:[[13,15,3,9,-1.],[14,15,1,9,3.]],tilted:0,threshold:6.6894508199766278e-004,right_val:-0.7483944892883301,left_val:0.1998561024665833},{features:[[13,18,3,3,-1.],[14,19,1,1,9.]],tilted:0,threshold:-1.8372290069237351e-003,right_val:0.1146014034748077,left_val:-0.8788912892341614},{features:[[17,17,1,2,-1.],[17,18,1,1,2.]],tilted:0,threshold:-4.3397278204793110e-005,right_val:-0.5028128027915955,left_val:0.2129840999841690}],threshold:-1.4024209976196289},{simpleClassifiers:[{features:[[10,11,4,12,-1.],[10,11,2,6,2.],[12,17,2,6,2.]],tilted:0,threshold:-2.0713880658149719e-003,right_val:-0.5756726861000061,left_val:0.2486661970615387},{features:[[12,23,12,1,-1.],[18,23,6,1,2.]],tilted:0,threshold:3.6768750287592411e-003,right_val:0.2280506044626236,left_val:-0.5755078196525574},{features:[[13,10,3,4,-1.],[13,10,3,2,2.]],tilted:1,threshold:-3.0887479078955948e-004,right_val:-0.6454687118530273,left_val:0.2362288981676102},{features:[[0,0,24,24,-1.],[0,0,12,12,2.],[12,12,12,12,2.]],tilted:0,threshold:-0.0257820300757885,right_val:0.1617882996797562,left_val:-0.7496209144592285},{features:[[2,10,2,6,-1.],[2,13,2,3,2.]],tilted:0,threshold:-1.2850989587605000e-003,right_val:0.1440877020359039,left_val:-0.7813286781311035},{features:[[0,11,2,6,-1.],[0,14,2,3,2.]],tilted:0,threshold:3.3493789378553629e-003,right_val:-0.7505543231964111,left_val:0.1375873982906342},{features:[[0,1,24,1,-1.],[8,1,8,1,3.]],tilted:0,threshold:-2.6788329705595970e-003,right_val:-0.4255296885967255,left_val:0.2596372067928314},{features:[[13,7,4,2,-1.],[13,8,4,1,2.]],tilted:0,threshold:-2.8834199838456698e-005,right_val:-0.7050843238830566,left_val:0.1635348945856094},{features:[[0,13,3,10,-1.],[1,13,1,10,3.]],tilted:0,threshold:-1.6196980141103268e-003,right_val:-0.3415850102901459,left_val:0.3419960141181946},{features:[[1,10,10,10,-1.],[6,10,5,10,2.]],tilted:0,threshold:1.0517919436097145e-003,right_val:-0.7929052114486694,left_val:0.1479195058345795},{features:[[9,0,4,6,-1.],[9,0,4,3,2.]],tilted:1,threshold:-2.4886541068553925e-003,right_val:0.1043419018387795,left_val:-0.8937227129936218}],threshold:-1.1141099929809570},{simpleClassifiers:[{features:[[16,18,1,2,-1.],[16,19,1,1,2.]],tilted:0,threshold:-5.7590808864915743e-005,right_val:-0.6426038742065430,left_val:0.2734906971454620},{features:[[21,14,2,8,-1.],[22,14,1,8,2.]],tilted:0,threshold:7.1206100983545184e-004,right_val:0.2552855014801025,left_val:-0.5435984134674072},{features:[[0,7,21,9,-1.],[7,10,7,3,9.]],tilted:0,threshold:-0.3888005912303925,right_val:-0.1862079948186874,left_val:0.6930956840515137},{features:[[16,16,1,4,-1.],[16,17,1,2,2.]],tilted:0,threshold:2.5288251345045865e-004,right_val:-0.5620415806770325,left_val:0.2914173901081085},{features:[[19,15,2,6,-1.],[17,17,2,2,3.]],tilted:1,threshold:-2.1006830502301455e-003,right_val:0.1185996010899544,left_val:-0.6822040081024170},{features:[[6,0,15,4,-1.],[6,1,15,2,2.]],tilted:0,threshold:-3.2310429960489273e-003,right_val:-0.2774995863437653,left_val:0.3972072899341583},{features:[[9,16,1,4,-1.],[9,17,1,2,2.]],tilted:0,threshold:1.4478569937637076e-005,right_val:0.2119608968496323,left_val:-0.5476933717727661},{features:[[8,20,8,2,-1.],[8,20,4,1,2.],[12,21,4,1,2.]],tilted:0,threshold:-9.0244162129238248e-004,right_val:0.1194489970803261,left_val:-0.8646997213363648},{features:[[0,9,3,14,-1.],[1,9,1,14,3.]],tilted:0,threshold:-1.5906910412013531e-003,right_val:-0.3928124904632568,left_val:0.2919914126396179},{features:[[11,1,11,4,-1.],[11,1,11,2,2.]],tilted:1,threshold:7.4913240969181061e-003,right_val:-0.4020768105983734,left_val:0.2679530084133148}],threshold:-1.0776710510253906},{simpleClassifiers:[{features:[[15,20,1,2,-1.],[15,21,1,1,2.]],tilted:0,threshold:-7.1240079705603421e-005,right_val:-0.4779424071311951,left_val:0.2823083102703095},{features:[[2,18,1,2,-1.],[2,18,1,1,2.]],tilted:1,threshold:-2.6417701155878603e-004,right_val:-0.4036655128002167,left_val:0.3084900975227356},{features:[[0,14,12,6,-1.],[0,16,12,2,3.]],tilted:0,threshold:5.2890321239829063e-004,right_val:0.1605536937713623,left_val:-0.7423822879791260},{features:[[4,10,2,14,-1.],[4,10,1,7,2.],[5,17,1,7,2.]],tilted:0,threshold:3.8283021422103047e-004,right_val:0.1794416010379791,left_val:-0.6108828783035278},{features:[[22,3,2,15,-1.],[23,3,1,15,2.]],tilted:0,threshold:5.4077422246336937e-003,right_val:0.4017147123813629,left_val:-0.2767061889171600},{features:[[4,17,3,1,-1.],[5,18,1,1,3.]],tilted:1,threshold:-8.2620367174968123e-004,right_val:0.1641048043966293,left_val:-0.8456827998161316},{features:[[21,6,3,9,-1.],[21,9,3,3,3.]],tilted:0,threshold:-8.9606801047921181e-003,right_val:0.1270485967397690,left_val:-0.6698572039604187},{features:[[1,7,23,4,-1.],[1,9,23,2,2.]],tilted:0,threshold:-3.0286349356174469e-003,right_val:-0.7880274057388306,left_val:0.1227105036377907},{features:[[4,3,20,20,-1.],[4,13,20,10,2.]],tilted:0,threshold:-0.0262723900377750,right_val:0.1347829997539520,left_val:-0.7226560711860657},{features:[[14,13,7,4,-1.],[14,15,7,2,2.]],tilted:0,threshold:-5.0153239862993360e-004,right_val:-0.3537223935127258,left_val:0.2890014052391052},{features:[[2,6,2,2,-1.],[2,6,2,1,2.]],tilted:1,threshold:-1.9847620569635183e-004,right_val:-0.4667024016380310,left_val:0.2491115033626556}],threshold:-1.1201709508895874},{simpleClassifiers:[{features:[[13,15,6,4,-1.],[13,17,6,2,2.]],tilted:0,threshold:-1.6098109772428870e-003,right_val:-0.5425583124160767,left_val:0.2436411976814270},{features:[[17,0,7,24,-1.],[17,8,7,8,3.]],tilted:0,threshold:3.0391800682991743e-003,right_val:-0.7677937150001526,left_val:0.1427879035472870},{features:[[3,7,20,8,-1.],[13,7,10,8,2.]],tilted:0,threshold:-0.0111625995486975,right_val:0.1309580951929092,left_val:-0.7964649796485901},{features:[[0,7,22,1,-1.],[11,7,11,1,2.]],tilted:0,threshold:-1.6689340118318796e-003,right_val:-0.4947401881217957,left_val:0.2306797951459885},{features:[[7,9,8,2,-1.],[7,10,8,1,2.]],tilted:0,threshold:-8.8481552666053176e-004,right_val:-0.5158239006996155,left_val:0.2005017995834351},{features:[[2,0,3,18,-1.],[2,6,3,6,3.]],tilted:0,threshold:-2.6040559168905020e-003,right_val:-0.7818121910095215,left_val:0.1298092007637024},{features:[[2,13,3,5,-1.],[3,13,1,5,3.]],tilted:0,threshold:-2.3444599355570972e-004,right_val:0.1478334069252014,left_val:-0.5695487260818481},{features:[[14,16,3,4,-1.],[15,16,1,4,3.]],tilted:0,threshold:8.4604357834905386e-004,right_val:-0.8308842182159424,left_val:0.1037243008613586},{features:[[10,0,12,3,-1.],[10,1,12,1,3.]],tilted:0,threshold:-2.4807569570839405e-003,right_val:-0.2719523906707764,left_val:0.3425926864147186},{features:[[15,16,3,1,-1.],[16,17,1,1,3.]],tilted:1,threshold:-1.1127090547233820e-003,right_val:0.1176175028085709,left_val:-0.8275328278541565},{features:[[22,13,2,5,-1.],[23,13,1,5,2.]],tilted:0,threshold:1.4298419700935483e-003,right_val:0.2652699053287506,left_val:-0.3477616012096405},{features:[[11,14,4,6,-1.],[11,16,4,2,3.]],tilted:0,threshold:-1.4572150539606810e-003,right_val:0.1092033982276917,left_val:-0.8802363276481628}],threshold:-1.0063530206680298},{simpleClassifiers:[{features:[[14,15,1,2,-1.],[14,16,1,1,2.]],tilted:0,threshold:-1.4507149899145588e-005,right_val:-0.4580149054527283,left_val:0.2605004012584686},{features:[[6,3,6,5,-1.],[6,3,3,5,2.]],tilted:1,threshold:0.0136784398928285,right_val:0.1477705985307694,left_val:-0.7149971723556519},{features:[[2,8,1,2,-1.],[2,8,1,1,2.]],tilted:1,threshold:-7.3151881224475801e-005,right_val:-0.4995836019515991,left_val:0.2058611065149307},{features:[[9,17,4,4,-1.],[9,18,4,2,2.]],tilted:0,threshold:-6.7043182207271457e-004,right_val:0.1358278989791870,left_val:-0.7319483757019043},{features:[[10,6,4,5,-1.],[11,6,2,5,2.]],tilted:0,threshold:-1.1992789804935455e-003,right_val:-0.2521241009235382,left_val:0.4456472992897034},{features:[[2,21,12,2,-1.],[8,21,6,2,2.]],tilted:0,threshold:-0.0117351496592164,right_val:0.1424607038497925,left_val:-0.7972438931465149},{features:[[12,8,12,15,-1.],[16,8,4,15,3.]],tilted:0,threshold:-4.7361929900944233e-003,right_val:-0.5223402976989746,left_val:0.1624221056699753},{features:[[0,3,20,20,-1.],[0,13,20,10,2.]],tilted:0,threshold:-0.1084595024585724,right_val:0.1265926957130432,left_val:-0.7962973713874817},{features:[[16,17,4,2,-1.],[16,17,4,1,2.]],tilted:1,threshold:-3.2293208641931415e-004,right_val:0.0899520069360733,left_val:-0.7129234075546265},{features:[[21,14,2,5,-1.],[21,14,1,5,2.]],tilted:1,threshold:2.5980910286307335e-003,right_val:0.3197942078113556,left_val:-0.2800100147724152},{features:[[12,0,12,8,-1.],[12,0,12,4,2.]],tilted:1,threshold:-7.5798099860548973e-003,right_val:0.1406804025173187,left_val:-0.7153301239013672},{features:[[17,0,7,24,-1.],[17,6,7,12,2.]],tilted:0,threshold:-8.4003582596778870e-003,right_val:-0.6506950259208679,left_val:0.1168404966592789},{features:[[13,10,3,6,-1.],[13,12,3,2,3.]],tilted:0,threshold:3.6820198874920607e-003,right_val:0.3865979909896851,left_val:-0.2631436884403229}],threshold:-1.0373339653015137},{simpleClassifiers:[{features:[[8,11,9,9,-1.],[11,14,3,3,9.]],tilted:0,threshold:0.0240733902901411,right_val:0.2617827057838440,left_val:-0.4794333875179291},{features:[[17,18,7,6,-1.],[17,21,7,3,2.]],tilted:0,threshold:1.9582170061767101e-003,right_val:0.2301298975944519,left_val:-0.4434475898742676},{features:[[9,8,4,2,-1.],[9,9,4,1,2.]],tilted:0,threshold:-2.0559200493153185e-004,right_val:-0.7277694940567017,left_val:0.1224080994725227},{features:[[7,7,7,6,-1.],[7,9,7,2,3.]],tilted:0,threshold:1.0637210216373205e-003,right_val:0.6447200775146484,left_val:-0.1582341045141220},{features:[[2,9,1,9,-1.],[2,12,1,3,3.]],tilted:0,threshold:-3.5040560760535300e-004,right_val:0.2033808976411820,left_val:-0.5160586237907410},{features:[[1,0,1,20,-1.],[1,10,1,10,2.]],tilted:0,threshold:-1.5382179990410805e-003,right_val:-0.5412080287933350,left_val:0.2029495984315872},{features:[[5,11,4,3,-1.],[5,11,2,3,2.]],tilted:1,threshold:4.2215911671519279e-003,right_val:-0.6884710788726807,left_val:0.1420246958732605},{features:[[1,6,14,13,-1.],[8,6,7,13,2.]],tilted:0,threshold:4.0536639280617237e-003,right_val:-0.8890265226364136,left_val:0.0946411192417145},{features:[[11,6,6,4,-1.],[13,6,2,4,3.]],tilted:0,threshold:3.9104130119085312e-003,right_val:0.4553441107273102,left_val:-0.2211245000362396},{features:[[15,20,2,2,-1.],[15,20,2,1,2.]],tilted:1,threshold:-5.8839347911998630e-004,right_val:0.1466006040573120,left_val:-0.7423400878906250},{features:[[11,7,11,2,-1.],[11,8,11,1,2.]],tilted:0,threshold:4.7331111272796988e-004,right_val:-0.8416292071342468,left_val:0.0803736001253128},{features:[[14,0,7,4,-1.],[14,1,7,2,2.]],tilted:0,threshold:-1.4589539496228099e-003,right_val:-0.2989330887794495,left_val:0.2730404138565064}],threshold:-0.9257612824440002}],size:[24,24],tilted:true};
7 | })(jsfeat.haar);
--------------------------------------------------------------------------------
/compile/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/compile/yuicompressor-2.4.2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/inspirit/jsfeat/4c7b336bbeeb26e6cd4cdf3c7d414abe273846f3/compile/yuicompressor-2.4.2.jar
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "jsfeat",
3 | "version" : "0.0.8",
4 | "description" : "JavaScript Computer Vision library",
5 | "author" : "Eugene Zatepyakin (http://www.inspirit.ru/)",
6 | "files" : "build/jsfeat.js",
7 | "main" : "build/jsfeat"
8 | }
9 |
--------------------------------------------------------------------------------
/src/jsfeat.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | */
4 |
5 | // namespace ?
6 | var jsfeat = jsfeat || { REVISION: 'ALPHA' };
7 |
--------------------------------------------------------------------------------
/src/jsfeat_bbf.js:
--------------------------------------------------------------------------------
1 | /**
2 | * BBF: Brightness Binary Feature
3 | *
4 | * @author Eugene Zatepyakin / http://inspirit.ru/
5 | *
6 | * this code is a rewrite from https://github.com/liuliu/ccv implementation
7 | * @author Liu Liu / http://liuliu.me/
8 | *
9 | * The original paper refers to: YEF∗ Real-Time Object Detection, Yotam Abramson and Bruno Steux
10 | */
11 |
12 | (function(global) {
13 | "use strict";
14 | //
15 | var bbf = (function() {
16 |
17 | var _group_func = function(r1, r2) {
18 | var distance = (r1.width * 0.25 + 0.5)|0;
19 |
20 | return r2.x <= r1.x + distance &&
21 | r2.x >= r1.x - distance &&
22 | r2.y <= r1.y + distance &&
23 | r2.y >= r1.y - distance &&
24 | r2.width <= (r1.width * 1.5 + 0.5)|0 &&
25 | (r2.width * 1.5 + 0.5)|0 >= r1.width;
26 | }
27 |
28 | var img_pyr = new jsfeat.pyramid_t(1);
29 |
30 | return {
31 |
32 | interval: 4,
33 | scale: 1.1486,
34 | next: 5,
35 | scale_to: 1,
36 |
37 | // make features local copy
38 | // to avoid array allocation with each scale
39 | // this is strange but array works faster than Int32 version???
40 | prepare_cascade: function(cascade) {
41 | var sn = cascade.stage_classifier.length;
42 | for (var j = 0; j < sn; j++) {
43 | var orig_feature = cascade.stage_classifier[j].feature;
44 | var f_cnt = cascade.stage_classifier[j].count;
45 | var feature = cascade.stage_classifier[j]._feature = new Array(f_cnt);
46 | for (var k = 0; k < f_cnt; k++) {
47 | feature[k] = {"size" : orig_feature[k].size,
48 | "px" : new Array(orig_feature[k].size),
49 | "pz" : new Array(orig_feature[k].size),
50 | "nx" : new Array(orig_feature[k].size),
51 | "nz" : new Array(orig_feature[k].size)};
52 | }
53 | }
54 | },
55 |
56 | build_pyramid: function(src, min_width, min_height, interval) {
57 | if (typeof interval === "undefined") { interval = 4; }
58 |
59 | var sw=src.cols,sh=src.rows;
60 | var i=0,nw=0,nh=0;
61 | var new_pyr=false;
62 | var src0=src,src1=src;
63 | var data_type = jsfeat.U8_t | jsfeat.C1_t;
64 |
65 | this.interval = interval;
66 | this.scale = Math.pow(2, 1 / (this.interval + 1));
67 | this.next = (this.interval + 1)|0;
68 | this.scale_to = (Math.log(Math.min(sw / min_width, sh / min_height)) / Math.log(this.scale))|0;
69 |
70 | var pyr_l = ((this.scale_to + this.next * 2) * 4) | 0;
71 | if(img_pyr.levels != pyr_l) {
72 | img_pyr.levels = pyr_l;
73 | img_pyr.data = new Array(pyr_l);
74 | new_pyr = true;
75 | img_pyr.data[0] = src; // first is src
76 | }
77 |
78 | for (i = 1; i <= this.interval; ++i) {
79 | nw = (sw / Math.pow(this.scale, i))|0;
80 | nh = (sh / Math.pow(this.scale, i))|0;
81 | src0 = img_pyr.data[i<<2];
82 | if(new_pyr || nw != src0.cols || nh != src0.rows) {
83 | img_pyr.data[i<<2] = new jsfeat.matrix_t(nw, nh, data_type);
84 | src0 = img_pyr.data[i<<2];
85 | }
86 | jsfeat.imgproc.resample(src, src0, nw, nh);
87 | }
88 | for (i = this.next; i < this.scale_to + this.next * 2; ++i) {
89 | src1 = img_pyr.data[(i << 2) - (this.next << 2)];
90 | src0 = img_pyr.data[i<<2];
91 | nw = src1.cols >> 1;
92 | nh = src1.rows >> 1;
93 | if(new_pyr || nw != src0.cols || nh != src0.rows) {
94 | img_pyr.data[i<<2] = new jsfeat.matrix_t(nw, nh, data_type);
95 | src0 = img_pyr.data[i<<2];
96 | }
97 | jsfeat.imgproc.pyrdown(src1, src0);
98 | }
99 | for (i = this.next * 2; i < this.scale_to + this.next * 2; ++i) {
100 | src1 = img_pyr.data[(i << 2) - (this.next << 2)];
101 | nw = src1.cols >> 1;
102 | nh = src1.rows >> 1;
103 | src0 = img_pyr.data[(i<<2)+1];
104 | if(new_pyr || nw != src0.cols || nh != src0.rows) {
105 | img_pyr.data[(i<<2)+1] = new jsfeat.matrix_t(nw, nh, data_type);
106 | src0 = img_pyr.data[(i<<2)+1];
107 | }
108 | jsfeat.imgproc.pyrdown(src1, src0, 1, 0);
109 | //
110 | src0 = img_pyr.data[(i<<2)+2];
111 | if(new_pyr || nw != src0.cols || nh != src0.rows) {
112 | img_pyr.data[(i<<2)+2] = new jsfeat.matrix_t(nw, nh, data_type);
113 | src0 = img_pyr.data[(i<<2)+2];
114 | }
115 | jsfeat.imgproc.pyrdown(src1, src0, 0, 1);
116 | //
117 | src0 = img_pyr.data[(i<<2)+3];
118 | if(new_pyr || nw != src0.cols || nh != src0.rows) {
119 | img_pyr.data[(i<<2)+3] = new jsfeat.matrix_t(nw, nh, data_type);
120 | src0 = img_pyr.data[(i<<2)+3];
121 | }
122 | jsfeat.imgproc.pyrdown(src1, src0, 1, 1);
123 | }
124 | return img_pyr;
125 | },
126 |
127 | detect: function(pyramid, cascade) {
128 | var interval = this.interval;
129 | var scale = this.scale;
130 | var next = this.next;
131 | var scale_upto = this.scale_to;
132 | var i=0,j=0,k=0,n=0,x=0,y=0,q=0,sn=0,f_cnt=0,q_cnt=0,p=0,pmin=0,nmax=0,f=0,i4=0,qw=0,qh=0;
133 | var sum=0.0, alpha, feature, orig_feature, feature_k, feature_o, flag = true, shortcut=true;
134 | var scale_x = 1.0, scale_y = 1.0;
135 | var dx = [0, 1, 0, 1];
136 | var dy = [0, 0, 1, 1];
137 | var seq = [];
138 | var pyr=pyramid.data, bpp = 1, bpp2 = 2, bpp4 = 4;
139 |
140 | var u8 = [], u8o = [0,0,0];
141 | var step = [0,0,0];
142 | var paddings = [0,0,0];
143 |
144 | for (i = 0; i < scale_upto; i++) {
145 | i4 = (i<<2);
146 | qw = pyr[i4 + (next << 3)].cols - (cascade.width >> 2);
147 | qh = pyr[i4 + (next << 3)].rows - (cascade.height >> 2);
148 | step[0] = pyr[i4].cols * bpp;
149 | step[1] = pyr[i4 + (next << 2)].cols * bpp;
150 | step[2] = pyr[i4 + (next << 3)].cols * bpp;
151 | paddings[0] = (pyr[i4].cols * bpp4) - (qw * bpp4);
152 | paddings[1] = (pyr[i4 + (next << 2)].cols * bpp2) - (qw * bpp2);
153 | paddings[2] = (pyr[i4 + (next << 3)].cols * bpp) - (qw * bpp);
154 | sn = cascade.stage_classifier.length;
155 | for (j = 0; j < sn; j++) {
156 | orig_feature = cascade.stage_classifier[j].feature;
157 | feature = cascade.stage_classifier[j]._feature;
158 | f_cnt = cascade.stage_classifier[j].count;
159 | for (k = 0; k < f_cnt; k++) {
160 | feature_k = feature[k];
161 | feature_o = orig_feature[k];
162 | q_cnt = feature_o.size|0;
163 | for (q = 0; q < q_cnt; q++) {
164 | feature_k.px[q] = (feature_o.px[q] * bpp) + feature_o.py[q] * step[feature_o.pz[q]];
165 | feature_k.pz[q] = feature_o.pz[q];
166 | feature_k.nx[q] = (feature_o.nx[q] * bpp) + feature_o.ny[q] * step[feature_o.nz[q]];
167 | feature_k.nz[q] = feature_o.nz[q];
168 | }
169 | }
170 | }
171 | u8[0] = pyr[i4].data; u8[1] = pyr[i4 + (next<<2)].data;
172 | for (q = 0; q < 4; q++) {
173 | u8[2] = pyr[i4 + (next<<3) + q].data;
174 | u8o[0] = (dx[q]*bpp2) + dy[q] * (pyr[i4].cols*bpp2);
175 | u8o[1] = (dx[q]*bpp) + dy[q] * (pyr[i4 + (next<<2)].cols*bpp);
176 | u8o[2] = 0;
177 | for (y = 0; y < qh; y++) {
178 | for (x = 0; x < qw; x++) {
179 | sum = 0;
180 | flag = true;
181 | sn = cascade.stage_classifier.length;
182 | for (j = 0; j < sn; j++) {
183 | sum = 0;
184 | alpha = cascade.stage_classifier[j].alpha;
185 | feature = cascade.stage_classifier[j]._feature;
186 | f_cnt = cascade.stage_classifier[j].count;
187 | for (k = 0; k < f_cnt; k++) {
188 | feature_k = feature[k];
189 | pmin = u8[feature_k.pz[0]][u8o[feature_k.pz[0]] + feature_k.px[0]];
190 | nmax = u8[feature_k.nz[0]][u8o[feature_k.nz[0]] + feature_k.nx[0]];
191 | if (pmin <= nmax) {
192 | sum += alpha[k << 1];
193 | } else {
194 | shortcut = true;
195 | q_cnt = feature_k.size;
196 | for (f = 1; f < q_cnt; f++) {
197 | if (feature_k.pz[f] >= 0) {
198 | p = u8[feature_k.pz[f]][u8o[feature_k.pz[f]] + feature_k.px[f]];
199 | if (p < pmin) {
200 | if (p <= nmax) {
201 | shortcut = false;
202 | break;
203 | }
204 | pmin = p;
205 | }
206 | }
207 | if (feature_k.nz[f] >= 0) {
208 | n = u8[feature_k.nz[f]][u8o[feature_k.nz[f]] + feature_k.nx[f]];
209 | if (n > nmax) {
210 | if (pmin <= n) {
211 | shortcut = false;
212 | break;
213 | }
214 | nmax = n;
215 | }
216 | }
217 | }
218 | sum += (shortcut) ? alpha[(k << 1) + 1] : alpha[k << 1];
219 | }
220 | }
221 | if (sum < cascade.stage_classifier[j].threshold) {
222 | flag = false;
223 | break;
224 | }
225 | }
226 | if (flag) {
227 | seq.push({"x" : (x * 4 + dx[q] * 2) * scale_x,
228 | "y" : (y * 4 + dy[q] * 2) * scale_y,
229 | "width" : cascade.width * scale_x,
230 | "height" : cascade.height * scale_y,
231 | "neighbor" : 1,
232 | "confidence" : sum});
233 | ++x;
234 | u8o[0] += bpp4;
235 | u8o[1] += bpp2;
236 | u8o[2] += bpp;
237 | }
238 | u8o[0] += bpp4;
239 | u8o[1] += bpp2;
240 | u8o[2] += bpp;
241 | }
242 | u8o[0] += paddings[0];
243 | u8o[1] += paddings[1];
244 | u8o[2] += paddings[2];
245 | }
246 | }
247 | scale_x *= scale;
248 | scale_y *= scale;
249 | }
250 |
251 | return seq;
252 | },
253 |
254 | // OpenCV method to group detected rectangles
255 | group_rectangles: function(rects, min_neighbors) {
256 | if (typeof min_neighbors === "undefined") { min_neighbors = 1; }
257 | var i, j, n = rects.length;
258 | var node = [];
259 | for (i = 0; i < n; ++i) {
260 | node[i] = {"parent" : -1,
261 | "element" : rects[i],
262 | "rank" : 0};
263 | }
264 | for (i = 0; i < n; ++i) {
265 | if (!node[i].element)
266 | continue;
267 | var root = i;
268 | while (node[root].parent != -1)
269 | root = node[root].parent;
270 | for (j = 0; j < n; ++j) {
271 | if( i != j && node[j].element && _group_func(node[i].element, node[j].element)) {
272 | var root2 = j;
273 |
274 | while (node[root2].parent != -1)
275 | root2 = node[root2].parent;
276 |
277 | if(root2 != root) {
278 | if(node[root].rank > node[root2].rank)
279 | node[root2].parent = root;
280 | else {
281 | node[root].parent = root2;
282 | if (node[root].rank == node[root2].rank)
283 | node[root2].rank++;
284 | root = root2;
285 | }
286 |
287 | /* compress path from node2 to the root: */
288 | var temp, node2 = j;
289 | while (node[node2].parent != -1) {
290 | temp = node2;
291 | node2 = node[node2].parent;
292 | node[temp].parent = root;
293 | }
294 |
295 | /* compress path from node to the root: */
296 | node2 = i;
297 | while (node[node2].parent != -1) {
298 | temp = node2;
299 | node2 = node[node2].parent;
300 | node[temp].parent = root;
301 | }
302 | }
303 | }
304 | }
305 | }
306 | var idx_seq = [];
307 | var class_idx = 0;
308 | for(i = 0; i < n; i++) {
309 | j = -1;
310 | var node1 = i;
311 | if(node[node1].element) {
312 | while (node[node1].parent != -1)
313 | node1 = node[node1].parent;
314 | if(node[node1].rank >= 0)
315 | node[node1].rank = ~class_idx++;
316 | j = ~node[node1].rank;
317 | }
318 | idx_seq[i] = j;
319 | }
320 |
321 | var comps = [];
322 | for (i = 0; i < class_idx+1; ++i) {
323 | comps[i] = {"neighbors" : 0,
324 | "x" : 0,
325 | "y" : 0,
326 | "width" : 0,
327 | "height" : 0,
328 | "confidence" : 0};
329 | }
330 |
331 | // count number of neighbors
332 | for(i = 0; i < n; ++i) {
333 | var r1 = rects[i];
334 | var idx = idx_seq[i];
335 |
336 | if (comps[idx].neighbors == 0)
337 | comps[idx].confidence = r1.confidence;
338 |
339 | ++comps[idx].neighbors;
340 |
341 | comps[idx].x += r1.x;
342 | comps[idx].y += r1.y;
343 | comps[idx].width += r1.width;
344 | comps[idx].height += r1.height;
345 | comps[idx].confidence = Math.max(comps[idx].confidence, r1.confidence);
346 | }
347 |
348 | var seq2 = [];
349 | // calculate average bounding box
350 | for(i = 0; i < class_idx; ++i) {
351 | n = comps[i].neighbors;
352 | if (n >= min_neighbors)
353 | seq2.push({"x" : (comps[i].x * 2 + n) / (2 * n),
354 | "y" : (comps[i].y * 2 + n) / (2 * n),
355 | "width" : (comps[i].width * 2 + n) / (2 * n),
356 | "height" : (comps[i].height * 2 + n) / (2 * n),
357 | "neighbors" : comps[i].neighbors,
358 | "confidence" : comps[i].confidence});
359 | }
360 |
361 | var result_seq = [];
362 | n = seq2.length;
363 | // filter out small face rectangles inside large face rectangles
364 | for(i = 0; i < n; ++i) {
365 | var r1 = seq2[i];
366 | var flag = true;
367 | for(j = 0; j < n; ++j) {
368 | var r2 = seq2[j];
369 | var distance = (r2.width * 0.25 + 0.5)|0;
370 |
371 | if(i != j &&
372 | r1.x >= r2.x - distance &&
373 | r1.y >= r2.y - distance &&
374 | r1.x + r1.width <= r2.x + r2.width + distance &&
375 | r1.y + r1.height <= r2.y + r2.height + distance &&
376 | (r2.neighbors > Math.max(3, r1.neighbors) || r1.neighbors < 3)) {
377 | flag = false;
378 | break;
379 | }
380 | }
381 |
382 | if(flag)
383 | result_seq.push(r1);
384 | }
385 | return result_seq;
386 | }
387 |
388 | };
389 |
390 | })();
391 |
392 | global.bbf = bbf;
393 |
394 | })(jsfeat);
395 |
--------------------------------------------------------------------------------
/src/jsfeat_cache.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | */
4 |
5 | (function(global) {
6 | "use strict";
7 | //
8 |
9 | var cache = (function() {
10 |
11 | // very primitive array cache, still need testing if it helps
12 | // of course V8 has its own powerful cache sys but i'm not sure
13 | // it caches several multichannel 640x480 buffer creations each frame
14 |
15 | var _pool_node_t = (function () {
16 | function _pool_node_t(size_in_bytes) {
17 | this.next = null;
18 | this.data = new jsfeat.data_t(size_in_bytes);
19 | this.size = this.data.size;
20 | this.buffer = this.data.buffer;
21 | this.u8 = this.data.u8;
22 | this.i32 = this.data.i32;
23 | this.f32 = this.data.f32;
24 | this.f64 = this.data.f64;
25 | }
26 | _pool_node_t.prototype.resize = function(size_in_bytes) {
27 | delete this.data;
28 | this.data = new jsfeat.data_t(size_in_bytes);
29 | this.size = this.data.size;
30 | this.buffer = this.data.buffer;
31 | this.u8 = this.data.u8;
32 | this.i32 = this.data.i32;
33 | this.f32 = this.data.f32;
34 | this.f64 = this.data.f64;
35 | }
36 | return _pool_node_t;
37 | })();
38 |
39 | var _pool_head, _pool_tail;
40 | var _pool_size = 0;
41 |
42 | return {
43 |
44 | allocate: function(capacity, data_size) {
45 | _pool_head = _pool_tail = new _pool_node_t(data_size);
46 | for (var i = 0; i < capacity; ++i) {
47 | var node = new _pool_node_t(data_size);
48 | _pool_tail = _pool_tail.next = node;
49 |
50 | _pool_size++;
51 | }
52 | },
53 |
54 | get_buffer: function(size_in_bytes) {
55 | // assume we have enough free nodes
56 | var node = _pool_head;
57 | _pool_head = _pool_head.next;
58 | _pool_size--;
59 |
60 | if(size_in_bytes > node.size) {
61 | node.resize(size_in_bytes);
62 | }
63 |
64 | return node;
65 | },
66 |
67 | put_buffer: function(node) {
68 | _pool_tail = _pool_tail.next = node;
69 | _pool_size++;
70 | }
71 | };
72 | })();
73 |
74 | global.cache = cache;
75 | // for now we dont need more than 30 buffers
76 | // if having cache sys really helps we can add auto extending sys
77 | cache.allocate(30, 640*4);
78 |
79 | })(jsfeat);
80 |
--------------------------------------------------------------------------------
/src/jsfeat_export.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | */
4 |
5 | (function(lib) {
6 | "use strict";
7 |
8 | if (typeof module === "undefined" || typeof module.exports === "undefined") {
9 | // in a browser, define its namespaces in global
10 | window.jsfeat = lib;
11 | } else {
12 | // in commonjs, or when AMD wrapping has been applied, define its namespaces as exports
13 | module.exports = lib;
14 | }
15 | })(jsfeat);
16 |
--------------------------------------------------------------------------------
/src/jsfeat_fast_corners.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | *
4 | * This is FAST corner detector, contributed to OpenCV by the author, Edward Rosten.
5 | */
6 |
7 | /*
8 | The references are:
9 | * Machine learning for high-speed corner detection,
10 | E. Rosten and T. Drummond, ECCV 2006
11 | * Faster and better: A machine learning approach to corner detection
12 | E. Rosten, R. Porter and T. Drummond, PAMI, 2009
13 | */
14 |
15 | (function(global) {
16 | "use strict";
17 | //
18 | var fast_corners = (function() {
19 |
20 | var offsets16 = new Int32Array([0, 3, 1, 3, 2, 2, 3, 1, 3, 0, 3, -1, 2, -2, 1, -3, 0, -3, -1, -3, -2, -2, -3, -1, -3, 0, -3, 1, -2, 2, -1, 3]);
21 |
22 | var threshold_tab = new Uint8Array(512);
23 | var pixel_off = new Int32Array(25);
24 | var score_diff = new Int32Array(25);
25 |
26 | // private functions
27 | var _cmp_offsets = function(pixel, step, pattern_size) {
28 | var k = 0;
29 | var offsets = offsets16;
30 | for( ; k < pattern_size; ++k ) {
31 | pixel[k] = offsets[k<<1] + offsets[(k<<1)+1] * step;
32 | }
33 | for( ; k < 25; ++k ) {
34 | pixel[k] = pixel[k - pattern_size];
35 | }
36 | },
37 |
38 | _cmp_score_16 = function(src, off, pixel, d, threshold) {
39 | var N = 25, k = 0, v = src[off];
40 | var a0 = threshold,a=0,b0=0,b=0;
41 |
42 | for( ; k < N; ++k ) {
43 | d[k] = v - src[off+pixel[k]];
44 | }
45 |
46 | for( k = 0; k < 16; k += 2 ) {
47 | a = Math.min(d[k+1], d[k+2]);
48 | a = Math.min(a, d[k+3]);
49 |
50 | if( a <= a0 ) continue;
51 |
52 | a = Math.min(a, d[k+4]);
53 | a = Math.min(a, d[k+5]);
54 | a = Math.min(a, d[k+6]);
55 | a = Math.min(a, d[k+7]);
56 | a = Math.min(a, d[k+8]);
57 | a0 = Math.max(a0, Math.min(a, d[k]));
58 | a0 = Math.max(a0, Math.min(a, d[k+9]));
59 | }
60 |
61 | b0 = -a0;
62 | for( k = 0; k < 16; k += 2 ) {
63 | b = Math.max(d[k+1], d[k+2]);
64 | b = Math.max(b, d[k+3]);
65 | b = Math.max(b, d[k+4]);
66 | b = Math.max(b, d[k+5]);
67 |
68 | if( b >= b0 ) continue;
69 | b = Math.max(b, d[k+6]);
70 | b = Math.max(b, d[k+7]);
71 | b = Math.max(b, d[k+8]);
72 | b0 = Math.min(b0, Math.max(b, d[k]));
73 | b0 = Math.min(b0, Math.max(b, d[k+9]));
74 | }
75 |
76 | return -b0-1;
77 | };
78 |
79 | var _threshold = 20;
80 |
81 | return {
82 | set_threshold: function(threshold) {
83 | _threshold = Math.min(Math.max(threshold, 0), 255);
84 | for (var i = -255; i <= 255; ++i) {
85 | threshold_tab[(i + 255)] = (i < -_threshold ? 1 : (i > _threshold ? 2 : 0));
86 | }
87 | return _threshold;
88 | },
89 |
90 | detect: function(src, corners, border) {
91 | if (typeof border === "undefined") { border = 3; }
92 |
93 | var K = 8, N = 25;
94 | var img = src.data, w = src.cols, h = src.rows;
95 | var i=0, j=0, k=0, vt=0, x=0, m3=0;
96 | var buf_node = jsfeat.cache.get_buffer(3 * w);
97 | var cpbuf_node = jsfeat.cache.get_buffer(((w+1)*3)<<2);
98 | var buf = buf_node.u8;
99 | var cpbuf = cpbuf_node.i32;
100 | var pixel = pixel_off;
101 | var sd = score_diff;
102 | var sy = Math.max(3, border);
103 | var ey = Math.min((h-2), (h-border));
104 | var sx = Math.max(3, border);
105 | var ex = Math.min((w - 3), (w - border));
106 | var _count = 0, corners_cnt = 0, pt;
107 | var score_func = _cmp_score_16;
108 | var thresh_tab = threshold_tab;
109 | var threshold = _threshold;
110 |
111 | var v=0,tab=0,d=0,ncorners=0,cornerpos=0,curr=0,ptr=0,prev=0,pprev=0;
112 | var jp1=0,jm1=0,score=0;
113 |
114 | _cmp_offsets(pixel, w, 16);
115 |
116 | // local vars are faster?
117 | var pixel0 = pixel[0];
118 | var pixel1 = pixel[1];
119 | var pixel2 = pixel[2];
120 | var pixel3 = pixel[3];
121 | var pixel4 = pixel[4];
122 | var pixel5 = pixel[5];
123 | var pixel6 = pixel[6];
124 | var pixel7 = pixel[7];
125 | var pixel8 = pixel[8];
126 | var pixel9 = pixel[9];
127 | var pixel10 = pixel[10];
128 | var pixel11 = pixel[11];
129 | var pixel12 = pixel[12];
130 | var pixel13 = pixel[13];
131 | var pixel14 = pixel[14];
132 | var pixel15 = pixel[15];
133 |
134 | for(i = 0; i < w*3; ++i) {
135 | buf[i] = 0;
136 | }
137 |
138 | for(i = sy; i < ey; ++i) {
139 | ptr = ((i * w) + sx)|0;
140 | m3 = (i - 3)%3;
141 | curr = (m3*w)|0;
142 | cornerpos = (m3*(w+1))|0;
143 | for (j = 0; j < w; ++j) buf[curr+j] = 0;
144 | ncorners = 0;
145 |
146 | if( i < (ey - 1) ) {
147 | j = sx;
148 |
149 | for( ; j < ex; ++j, ++ptr ) {
150 | v = img[ptr];
151 | tab = ( - v + 255 );
152 | d = ( thresh_tab[tab+img[ptr+pixel0]] | thresh_tab[tab+img[ptr+pixel8]] );
153 |
154 | if( d == 0 ) {
155 | continue;
156 | }
157 |
158 | d &= ( thresh_tab[tab+img[ptr+pixel2]] | thresh_tab[tab+img[ptr+pixel10]] );
159 | d &= ( thresh_tab[tab+img[ptr+pixel4]] | thresh_tab[tab+img[ptr+pixel12]] );
160 | d &= ( thresh_tab[tab+img[ptr+pixel6]] | thresh_tab[tab+img[ptr+pixel14]] );
161 |
162 | if( d == 0 ) {
163 | continue;
164 | }
165 |
166 | d &= ( thresh_tab[tab+img[ptr+pixel1]] | thresh_tab[tab+img[ptr+pixel9]] );
167 | d &= ( thresh_tab[tab+img[ptr+pixel3]] | thresh_tab[tab+img[ptr+pixel11]] );
168 | d &= ( thresh_tab[tab+img[ptr+pixel5]] | thresh_tab[tab+img[ptr+pixel13]] );
169 | d &= ( thresh_tab[tab+img[ptr+pixel7]] | thresh_tab[tab+img[ptr+pixel15]] );
170 |
171 | if( d & 1 ) {
172 | vt = (v - threshold);
173 | _count = 0;
174 |
175 | for( k = 0; k < N; ++k ) {
176 | x = img[(ptr+pixel[k])];
177 | if(x < vt) {
178 | ++_count;
179 | if( _count > K ) {
180 | ++ncorners;
181 | cpbuf[cornerpos+ncorners] = j;
182 | buf[curr+j] = score_func(img, ptr, pixel, sd, threshold);
183 | break;
184 | }
185 | }
186 | else {
187 | _count = 0;
188 | }
189 | }
190 | }
191 |
192 | if( d & 2 ) {
193 | vt = (v + threshold);
194 | _count = 0;
195 |
196 | for( k = 0; k < N; ++k ) {
197 | x = img[(ptr+pixel[k])];
198 | if(x > vt) {
199 | ++_count;
200 | if( _count > K ) {
201 | ++ncorners;
202 | cpbuf[cornerpos+ncorners] = j;
203 | buf[curr+j] = score_func(img, ptr, pixel, sd, threshold);
204 | break;
205 | }
206 | }
207 | else {
208 | _count = 0;
209 | }
210 | }
211 | }
212 | }
213 | }
214 |
215 | cpbuf[cornerpos+w] = ncorners;
216 |
217 | if ( i == sy ) {
218 | continue;
219 | }
220 |
221 | m3 = (i - 4 + 3)%3;
222 | prev = (m3*w)|0;
223 | cornerpos = (m3*(w+1))|0;
224 | m3 = (i - 5 + 3)%3;
225 | pprev = (m3*w)|0;
226 |
227 | ncorners = cpbuf[cornerpos+w];
228 |
229 | for( k = 0; k < ncorners; ++k ) {
230 | j = cpbuf[cornerpos+k];
231 | jp1 = (j+1)|0;
232 | jm1 = (j-1)|0;
233 | score = buf[prev+j];
234 | if( (score > buf[prev+jp1] && score > buf[prev+jm1] &&
235 | score > buf[pprev+jm1] && score > buf[pprev+j] && score > buf[pprev+jp1] &&
236 | score > buf[curr+jm1] && score > buf[curr+j] && score > buf[curr+jp1]) ) {
237 | // save corner
238 | pt = corners[corners_cnt];
239 | pt.x = j, pt.y = (i-1), pt.score = score;
240 | corners_cnt++;
241 | }
242 | }
243 | } // y loop
244 | jsfeat.cache.put_buffer(buf_node);
245 | jsfeat.cache.put_buffer(cpbuf_node);
246 | return corners_cnt;
247 | }
248 | };
249 | })();
250 |
251 | global.fast_corners = fast_corners;
252 | fast_corners.set_threshold(20); // set default
253 |
254 | })(jsfeat);
255 |
--------------------------------------------------------------------------------
/src/jsfeat_haar.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | *
4 | * this code is a rewrite from https://github.com/mtschirs/js-objectdetect implementation
5 | * @author Martin Tschirsich / http://www.tu-darmstadt.de/~m_t
6 | */
7 |
8 | (function(global) {
9 | "use strict";
10 | //
11 | var haar = (function() {
12 |
13 | var _group_func = function(r1, r2) {
14 | var distance = (r1.width * 0.25 + 0.5)|0;
15 |
16 | return r2.x <= r1.x + distance &&
17 | r2.x >= r1.x - distance &&
18 | r2.y <= r1.y + distance &&
19 | r2.y >= r1.y - distance &&
20 | r2.width <= (r1.width * 1.5 + 0.5)|0 &&
21 | (r2.width * 1.5 + 0.5)|0 >= r1.width;
22 | }
23 |
24 | return {
25 |
26 | edges_density: 0.07,
27 |
28 | detect_single_scale: function(int_sum, int_sqsum, int_tilted, int_canny_sum, width, height, scale, classifier) {
29 | var win_w = (classifier.size[0] * scale)|0,
30 | win_h = (classifier.size[1] * scale)|0,
31 | step_x = (0.5 * scale + 1.5)|0,
32 | step_y = step_x;
33 | var i,j,k,x,y,ex=(width-win_w)|0,ey=(height-win_h)|0;
34 | var w1=(width+1)|0,edge_dens,mean,variance,std;
35 | var inv_area = 1.0 / (win_w * win_h);
36 | var stages,stage,trees,tree,sn,tn,fn,found=true,stage_thresh,stage_sum,tree_sum,feature,features;
37 | var fi_a,fi_b,fi_c,fi_d,fw,fh;
38 |
39 | var ii_a=0,ii_b=win_w,ii_c=win_h*w1,ii_d=ii_c+win_w;
40 | var edges_thresh = ((win_w*win_h) * 0xff * this.edges_density)|0;
41 | // if too much gradient we also can skip
42 | //var edges_thresh_high = ((win_w*win_h) * 0xff * 0.3)|0;
43 |
44 | var rects = [];
45 | for(y = 0; y < ey; y += step_y) {
46 | ii_a = y * w1;
47 | for(x = 0; x < ex; x += step_x, ii_a += step_x) {
48 |
49 | mean = int_sum[ii_a]
50 | - int_sum[ii_a+ii_b]
51 | - int_sum[ii_a+ii_c]
52 | + int_sum[ii_a+ii_d];
53 |
54 | // canny prune
55 | if(int_canny_sum) {
56 | edge_dens = (int_canny_sum[ii_a]
57 | - int_canny_sum[ii_a+ii_b]
58 | - int_canny_sum[ii_a+ii_c]
59 | + int_canny_sum[ii_a+ii_d]);
60 | if(edge_dens < edges_thresh || mean < 20) {
61 | x += step_x, ii_a += step_x;
62 | continue;
63 | }
64 | }
65 |
66 | mean *= inv_area;
67 | variance = (int_sqsum[ii_a]
68 | - int_sqsum[ii_a+ii_b]
69 | - int_sqsum[ii_a+ii_c]
70 | + int_sqsum[ii_a+ii_d]) * inv_area - mean * mean;
71 |
72 | std = variance > 0. ? Math.sqrt(variance) : 1;
73 |
74 | stages = classifier.complexClassifiers;
75 | sn = stages.length;
76 | found = true;
77 | for(i = 0; i < sn; ++i) {
78 | stage = stages[i];
79 | stage_thresh = stage.threshold;
80 | trees = stage.simpleClassifiers;
81 | tn = trees.length;
82 | stage_sum = 0;
83 | for(j = 0; j < tn; ++j) {
84 | tree = trees[j];
85 | tree_sum = 0;
86 | features = tree.features;
87 | fn = features.length;
88 | if(tree.tilted === 1) {
89 | for(k=0; k < fn; ++k) {
90 | feature = features[k];
91 | fi_a = ~~(x + feature[0] * scale) + ~~(y + feature[1] * scale) * w1;
92 | fw = ~~(feature[2] * scale);
93 | fh = ~~(feature[3] * scale);
94 | fi_b = fw * w1;
95 | fi_c = fh * w1;
96 |
97 | tree_sum += (int_tilted[fi_a]
98 | - int_tilted[fi_a + fw + fi_b]
99 | - int_tilted[fi_a - fh + fi_c]
100 | + int_tilted[fi_a + fw - fh + fi_b + fi_c]) * feature[4];
101 | }
102 | } else {
103 | for(k=0; k < fn; ++k) {
104 | feature = features[k];
105 | fi_a = ~~(x + feature[0] * scale) + ~~(y + feature[1] * scale) * w1;
106 | fw = ~~(feature[2] * scale);
107 | fh = ~~(feature[3] * scale);
108 | fi_c = fh * w1;
109 |
110 | tree_sum += (int_sum[fi_a]
111 | - int_sum[fi_a+fw]
112 | - int_sum[fi_a+fi_c]
113 | + int_sum[fi_a+fi_c+fw]) * feature[4];
114 | }
115 | }
116 | stage_sum += (tree_sum * inv_area < tree.threshold * std) ? tree.left_val : tree.right_val;
117 | }
118 | if (stage_sum < stage_thresh) {
119 | found = false;
120 | break;
121 | }
122 | }
123 |
124 | if(found) {
125 | rects.push({"x" : x,
126 | "y" : y,
127 | "width" : win_w,
128 | "height" : win_h,
129 | "neighbor" : 1,
130 | "confidence" : stage_sum});
131 | x += step_x, ii_a += step_x;
132 | }
133 | }
134 | }
135 | return rects;
136 | },
137 |
138 | detect_multi_scale: function(int_sum, int_sqsum, int_tilted, int_canny_sum, width, height, classifier, scale_factor, scale_min) {
139 | if (typeof scale_factor === "undefined") { scale_factor = 1.2; }
140 | if (typeof scale_min === "undefined") { scale_min = 1.0; }
141 | var win_w = classifier.size[0];
142 | var win_h = classifier.size[1];
143 | var rects = [];
144 | while (scale_min * win_w < width && scale_min * win_h < height) {
145 | rects = rects.concat(this.detect_single_scale(int_sum, int_sqsum, int_tilted, int_canny_sum, width, height, scale_min, classifier));
146 | scale_min *= scale_factor;
147 | }
148 | return rects;
149 | },
150 |
151 | // OpenCV method to group detected rectangles
152 | group_rectangles: function(rects, min_neighbors) {
153 | if (typeof min_neighbors === "undefined") { min_neighbors = 1; }
154 | var i, j, n = rects.length;
155 | var node = [];
156 | for (i = 0; i < n; ++i) {
157 | node[i] = {"parent" : -1,
158 | "element" : rects[i],
159 | "rank" : 0};
160 | }
161 | for (i = 0; i < n; ++i) {
162 | if (!node[i].element)
163 | continue;
164 | var root = i;
165 | while (node[root].parent != -1)
166 | root = node[root].parent;
167 | for (j = 0; j < n; ++j) {
168 | if( i != j && node[j].element && _group_func(node[i].element, node[j].element)) {
169 | var root2 = j;
170 |
171 | while (node[root2].parent != -1)
172 | root2 = node[root2].parent;
173 |
174 | if(root2 != root) {
175 | if(node[root].rank > node[root2].rank)
176 | node[root2].parent = root;
177 | else {
178 | node[root].parent = root2;
179 | if (node[root].rank == node[root2].rank)
180 | node[root2].rank++;
181 | root = root2;
182 | }
183 |
184 | /* compress path from node2 to the root: */
185 | var temp, node2 = j;
186 | while (node[node2].parent != -1) {
187 | temp = node2;
188 | node2 = node[node2].parent;
189 | node[temp].parent = root;
190 | }
191 |
192 | /* compress path from node to the root: */
193 | node2 = i;
194 | while (node[node2].parent != -1) {
195 | temp = node2;
196 | node2 = node[node2].parent;
197 | node[temp].parent = root;
198 | }
199 | }
200 | }
201 | }
202 | }
203 | var idx_seq = [];
204 | var class_idx = 0;
205 | for(i = 0; i < n; i++) {
206 | j = -1;
207 | var node1 = i;
208 | if(node[node1].element) {
209 | while (node[node1].parent != -1)
210 | node1 = node[node1].parent;
211 | if(node[node1].rank >= 0)
212 | node[node1].rank = ~class_idx++;
213 | j = ~node[node1].rank;
214 | }
215 | idx_seq[i] = j;
216 | }
217 |
218 | var comps = [];
219 | for (i = 0; i < class_idx+1; ++i) {
220 | comps[i] = {"neighbors" : 0,
221 | "x" : 0,
222 | "y" : 0,
223 | "width" : 0,
224 | "height" : 0,
225 | "confidence" : 0};
226 | }
227 |
228 | // count number of neighbors
229 | for(i = 0; i < n; ++i) {
230 | var r1 = rects[i];
231 | var idx = idx_seq[i];
232 |
233 | if (comps[idx].neighbors == 0)
234 | comps[idx].confidence = r1.confidence;
235 |
236 | ++comps[idx].neighbors;
237 |
238 | comps[idx].x += r1.x;
239 | comps[idx].y += r1.y;
240 | comps[idx].width += r1.width;
241 | comps[idx].height += r1.height;
242 | comps[idx].confidence = Math.max(comps[idx].confidence, r1.confidence);
243 | }
244 |
245 | var seq2 = [];
246 | // calculate average bounding box
247 | for(i = 0; i < class_idx; ++i) {
248 | n = comps[i].neighbors;
249 | if (n >= min_neighbors)
250 | seq2.push({"x" : (comps[i].x * 2 + n) / (2 * n),
251 | "y" : (comps[i].y * 2 + n) / (2 * n),
252 | "width" : (comps[i].width * 2 + n) / (2 * n),
253 | "height" : (comps[i].height * 2 + n) / (2 * n),
254 | "neighbors" : comps[i].neighbors,
255 | "confidence" : comps[i].confidence});
256 | }
257 |
258 | var result_seq = [];
259 | n = seq2.length;
260 | // filter out small face rectangles inside large face rectangles
261 | for(i = 0; i < n; ++i) {
262 | var r1 = seq2[i];
263 | var flag = true;
264 | for(j = 0; j < n; ++j) {
265 | var r2 = seq2[j];
266 | var distance = (r2.width * 0.25 + 0.5)|0;
267 |
268 | if(i != j &&
269 | r1.x >= r2.x - distance &&
270 | r1.y >= r2.y - distance &&
271 | r1.x + r1.width <= r2.x + r2.width + distance &&
272 | r1.y + r1.height <= r2.y + r2.height + distance &&
273 | (r2.neighbors > Math.max(3, r1.neighbors) || r1.neighbors < 3)) {
274 | flag = false;
275 | break;
276 | }
277 | }
278 |
279 | if(flag)
280 | result_seq.push(r1);
281 | }
282 | return result_seq;
283 | }
284 | };
285 |
286 | })();
287 |
288 | global.haar = haar;
289 |
290 | })(jsfeat);
291 |
--------------------------------------------------------------------------------
/src/jsfeat_linalg.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | *
4 | */
5 |
6 | (function(global) {
7 | "use strict";
8 | //
9 |
10 | var linalg = (function() {
11 |
12 | var swap = function(A, i0, i1, t) {
13 | t = A[i0];
14 | A[i0] = A[i1];
15 | A[i1] = t;
16 | }
17 |
18 | var hypot = function(a, b) {
19 | a = Math.abs(a);
20 | b = Math.abs(b);
21 | if( a > b ) {
22 | b /= a;
23 | return a*Math.sqrt(1.0 + b*b);
24 | }
25 | if( b > 0 ) {
26 | a /= b;
27 | return b*Math.sqrt(1.0 + a*a);
28 | }
29 | return 0.0;
30 | }
31 |
32 | var JacobiImpl = function(A, astep, W, V, vstep, n) {
33 | var eps = jsfeat.EPSILON;
34 | var i=0,j=0,k=0,m=0,l=0,idx=0,_in=0,_in2=0;
35 | var iters=0,max_iter=n*n*30;
36 | var mv=0.0,val=0.0,p=0.0,y=0.0,t=0.0,s=0.0,c=0.0,a0=0.0,b0=0.0;
37 |
38 | var indR_buff = jsfeat.cache.get_buffer(n<<2);
39 | var indC_buff = jsfeat.cache.get_buffer(n<<2);
40 | var indR = indR_buff.i32;
41 | var indC = indC_buff.i32;
42 |
43 | if(V) {
44 | for(; i < n; i++) {
45 | k = i*vstep;
46 | for(j = 0; j < n; j++) {
47 | V[k + j] = 0.0;
48 | }
49 | V[k + i] = 1.0;
50 | }
51 | }
52 |
53 | for(k = 0; k < n; k++) {
54 | W[k] = A[(astep + 1)*k];
55 | if(k < n - 1) {
56 | for(m = k+1, mv = Math.abs(A[astep*k + m]), i = k+2; i < n; i++) {
57 | val = Math.abs(A[astep*k+i]);
58 | if(mv < val)
59 | mv = val, m = i;
60 | }
61 | indR[k] = m;
62 | }
63 | if(k > 0) {
64 | for(m = 0, mv = Math.abs(A[k]), i = 1; i < k; i++) {
65 | val = Math.abs(A[astep*i+k]);
66 | if(mv < val)
67 | mv = val, m = i;
68 | }
69 | indC[k] = m;
70 | }
71 | }
72 |
73 | if(n > 1) for( ; iters < max_iter; iters++) {
74 | // find index (k,l) of pivot p
75 | for(k = 0, mv = Math.abs(A[indR[0]]), i = 1; i < n-1; i++) {
76 | val = Math.abs(A[astep*i + indR[i]]);
77 | if( mv < val )
78 | mv = val, k = i;
79 | }
80 | l = indR[k];
81 | for(i = 1; i < n; i++) {
82 | val = Math.abs(A[astep*indC[i] + i]);
83 | if( mv < val )
84 | mv = val, k = indC[i], l = i;
85 | }
86 |
87 | p = A[astep*k + l];
88 |
89 | if(Math.abs(p) <= eps) break;
90 |
91 | y = (W[l] - W[k])*0.5;
92 | t = Math.abs(y) + hypot(p, y);
93 | s = hypot(p, t);
94 | c = t/s;
95 | s = p/s; t = (p/t)*p;
96 | if(y < 0)
97 | s = -s, t = -t;
98 | A[astep*k + l] = 0;
99 |
100 | W[k] -= t;
101 | W[l] += t;
102 |
103 | // rotate rows and columns k and l
104 | for (i = 0; i < k; i++) {
105 | _in = (astep * i + k);
106 | _in2 = (astep * i + l);
107 | a0 = A[_in];
108 | b0 = A[_in2];
109 | A[_in] = a0 * c - b0 * s;
110 | A[_in2] = a0 * s + b0 * c;
111 | }
112 | for (i = (k + 1); i < l; i++) {
113 | _in = (astep * k + i);
114 | _in2 = (astep * i + l);
115 | a0 = A[_in];
116 | b0 = A[_in2];
117 | A[_in] = a0 * c - b0 * s;
118 | A[_in2] = a0 * s + b0 * c;
119 | }
120 | i = l + 1;
121 | _in = (astep * k + i);
122 | _in2 = (astep * l + i);
123 | for (; i < n; i++, _in++, _in2++) {
124 | a0 = A[_in];
125 | b0 = A[_in2];
126 | A[_in] = a0 * c - b0 * s;
127 | A[_in2] = a0 * s + b0 * c;
128 | }
129 |
130 | // rotate eigenvectors
131 | if (V) {
132 | _in = vstep * k;
133 | _in2 = vstep * l;
134 | for (i = 0; i < n; i++, _in++, _in2++) {
135 | a0 = V[_in];
136 | b0 = V[_in2];
137 | V[_in] = a0 * c - b0 * s;
138 | V[_in2] = a0 * s + b0 * c;
139 | }
140 | }
141 |
142 | for(j = 0; j < 2; j++) {
143 | idx = j == 0 ? k : l;
144 | if(idx < n - 1) {
145 | for(m = idx+1, mv = Math.abs(A[astep*idx + m]), i = idx+2; i < n; i++) {
146 | val = Math.abs(A[astep*idx+i]);
147 | if( mv < val )
148 | mv = val, m = i;
149 | }
150 | indR[idx] = m;
151 | }
152 | if(idx > 0) {
153 | for(m = 0, mv = Math.abs(A[idx]), i = 1; i < idx; i++) {
154 | val = Math.abs(A[astep*i+idx]);
155 | if( mv < val )
156 | mv = val, m = i;
157 | }
158 | indC[idx] = m;
159 | }
160 | }
161 | }
162 |
163 | // sort eigenvalues & eigenvectors
164 | for(k = 0; k < n-1; k++) {
165 | m = k;
166 | for(i = k+1; i < n; i++) {
167 | if(W[m] < W[i])
168 | m = i;
169 | }
170 | if(k != m) {
171 | swap(W, m, k, mv);
172 | if(V) {
173 | for(i = 0; i < n; i++) {
174 | swap(V, vstep*m + i, vstep*k + i, mv);
175 | }
176 | }
177 | }
178 | }
179 |
180 |
181 | jsfeat.cache.put_buffer(indR_buff);
182 | jsfeat.cache.put_buffer(indC_buff);
183 | }
184 |
185 | var JacobiSVDImpl = function(At, astep, _W, Vt, vstep, m, n, n1) {
186 | var eps = jsfeat.EPSILON * 2.0;
187 | var minval = jsfeat.FLT_MIN;
188 | var i=0,j=0,k=0,iter=0,max_iter=Math.max(m, 30);
189 | var Ai=0,Aj=0,Vi=0,Vj=0,changed=0;
190 | var c=0.0, s=0.0, t=0.0;
191 | var t0=0.0,t1=0.0,sd=0.0,beta=0.0,gamma=0.0,delta=0.0,a=0.0,p=0.0,b=0.0;
192 | var seed = 0x1234;
193 | var val=0.0,val0=0.0,asum=0.0;
194 |
195 | var W_buff = jsfeat.cache.get_buffer(n<<3);
196 | var W = W_buff.f64;
197 |
198 | for(; i < n; i++) {
199 | for(k = 0, sd = 0; k < m; k++) {
200 | t = At[i*astep + k];
201 | sd += t*t;
202 | }
203 | W[i] = sd;
204 |
205 | if(Vt) {
206 | for(k = 0; k < n; k++) {
207 | Vt[i*vstep + k] = 0;
208 | }
209 | Vt[i*vstep + i] = 1;
210 | }
211 | }
212 |
213 | for(; iter < max_iter; iter++) {
214 | changed = 0;
215 |
216 | for(i = 0; i < n-1; i++) {
217 | for(j = i+1; j < n; j++) {
218 | Ai = (i*astep)|0, Aj = (j*astep)|0;
219 | a = W[i], p = 0, b = W[j];
220 |
221 | k = 2;
222 | p += At[Ai]*At[Aj];
223 | p += At[Ai+1]*At[Aj+1];
224 |
225 | for(; k < m; k++)
226 | p += At[Ai+k]*At[Aj+k];
227 |
228 | if(Math.abs(p) <= eps*Math.sqrt(a*b)) continue;
229 |
230 | p *= 2.0;
231 | beta = a - b, gamma = hypot(p, beta);
232 | if( beta < 0 ) {
233 | delta = (gamma - beta)*0.5;
234 | s = Math.sqrt(delta/gamma);
235 | c = (p/(gamma*s*2.0));
236 | } else {
237 | c = Math.sqrt((gamma + beta)/(gamma*2.0));
238 | s = (p/(gamma*c*2.0));
239 | }
240 |
241 | a=0.0, b=0.0;
242 |
243 | k = 2; // unroll
244 | t0 = c*At[Ai] + s*At[Aj];
245 | t1 = -s*At[Ai] + c*At[Aj];
246 | At[Ai] = t0; At[Aj] = t1;
247 | a += t0*t0; b += t1*t1;
248 |
249 | t0 = c*At[Ai+1] + s*At[Aj+1];
250 | t1 = -s*At[Ai+1] + c*At[Aj+1];
251 | At[Ai+1] = t0; At[Aj+1] = t1;
252 | a += t0*t0; b += t1*t1;
253 |
254 | for( ; k < m; k++ )
255 | {
256 | t0 = c*At[Ai+k] + s*At[Aj+k];
257 | t1 = -s*At[Ai+k] + c*At[Aj+k];
258 | At[Ai+k] = t0; At[Aj+k] = t1;
259 |
260 | a += t0*t0; b += t1*t1;
261 | }
262 |
263 | W[i] = a; W[j] = b;
264 |
265 | changed = 1;
266 |
267 | if(Vt) {
268 | Vi = (i*vstep)|0, Vj = (j*vstep)|0;
269 |
270 | k = 2;
271 | t0 = c*Vt[Vi] + s*Vt[Vj];
272 | t1 = -s*Vt[Vi] + c*Vt[Vj];
273 | Vt[Vi] = t0; Vt[Vj] = t1;
274 |
275 | t0 = c*Vt[Vi+1] + s*Vt[Vj+1];
276 | t1 = -s*Vt[Vi+1] + c*Vt[Vj+1];
277 | Vt[Vi+1] = t0; Vt[Vj+1] = t1;
278 |
279 | for(; k < n; k++) {
280 | t0 = c*Vt[Vi+k] + s*Vt[Vj+k];
281 | t1 = -s*Vt[Vi+k] + c*Vt[Vj+k];
282 | Vt[Vi+k] = t0; Vt[Vj+k] = t1;
283 | }
284 | }
285 | }
286 | }
287 | if(changed == 0) break;
288 | }
289 |
290 | for(i = 0; i < n; i++) {
291 | for(k = 0, sd = 0; k < m; k++) {
292 | t = At[i*astep + k];
293 | sd += t*t;
294 | }
295 | W[i] = Math.sqrt(sd);
296 | }
297 |
298 | for(i = 0; i < n-1; i++) {
299 | j = i;
300 | for(k = i+1; k < n; k++) {
301 | if(W[j] < W[k])
302 | j = k;
303 | }
304 | if(i != j) {
305 | swap(W, i, j, sd);
306 | if(Vt) {
307 | for(k = 0; k < m; k++) {
308 | swap(At, i*astep + k, j*astep + k, t);
309 | }
310 |
311 | for(k = 0; k < n; k++) {
312 | swap(Vt, i*vstep + k, j*vstep + k, t);
313 | }
314 | }
315 | }
316 | }
317 |
318 | for(i = 0; i < n; i++) {
319 | _W[i] = W[i];
320 | }
321 |
322 | if(!Vt) {
323 | jsfeat.cache.put_buffer(W_buff);
324 | return;
325 | }
326 |
327 | for(i = 0; i < n1; i++) {
328 |
329 | sd = i < n ? W[i] : 0;
330 |
331 | while(sd <= minval) {
332 | // if we got a zero singular value, then in order to get the corresponding left singular vector
333 | // we generate a random vector, project it to the previously computed left singular vectors,
334 | // subtract the projection and normalize the difference.
335 | val0 = (1.0/m);
336 | for(k = 0; k < m; k++) {
337 | seed = (seed * 214013 + 2531011);
338 | val = (((seed >> 16) & 0x7fff) & 256) != 0 ? val0 : -val0;
339 | At[i*astep + k] = val;
340 | }
341 | for(iter = 0; iter < 2; iter++) {
342 | for(j = 0; j < i; j++) {
343 | sd = 0;
344 | for(k = 0; k < m; k++) {
345 | sd += At[i*astep + k]*At[j*astep + k];
346 | }
347 | asum = 0.0;
348 | for(k = 0; k < m; k++) {
349 | t = (At[i*astep + k] - sd*At[j*astep + k]);
350 | At[i*astep + k] = t;
351 | asum += Math.abs(t);
352 | }
353 | asum = asum ? 1.0/asum : 0;
354 | for(k = 0; k < m; k++) {
355 | At[i*astep + k] *= asum;
356 | }
357 | }
358 | }
359 | sd = 0;
360 | for(k = 0; k < m; k++) {
361 | t = At[i*astep + k];
362 | sd += t*t;
363 | }
364 | sd = Math.sqrt(sd);
365 | }
366 |
367 | s = (1.0/sd);
368 | for(k = 0; k < m; k++) {
369 | At[i*astep + k] *= s;
370 | }
371 | }
372 |
373 | jsfeat.cache.put_buffer(W_buff);
374 | }
375 |
376 | return {
377 |
378 | lu_solve: function(A, B) {
379 | var i=0,j=0,k=0,p=1,astep=A.cols;
380 | var ad=A.data, bd=B.data;
381 | var t,alpha,d,s;
382 |
383 | for(i = 0; i < astep; i++) {
384 | k = i;
385 | for(j = i+1; j < astep; j++) {
386 | if(Math.abs(ad[j*astep + i]) > Math.abs(ad[k*astep+i])) {
387 | k = j;
388 | }
389 | }
390 |
391 | if(Math.abs(ad[k*astep+i]) < jsfeat.EPSILON) {
392 | return 0; // FAILED
393 | }
394 |
395 | if(k != i) {
396 | for(j = i; j < astep; j++ ) {
397 | swap(ad, i*astep+j, k*astep+j, t);
398 | }
399 |
400 | swap(bd, i, k, t);
401 | p = -p;
402 | }
403 |
404 | d = -1.0/ad[i*astep+i];
405 |
406 | for(j = i+1; j < astep; j++) {
407 | alpha = ad[j*astep+i]*d;
408 |
409 | for(k = i+1; k < astep; k++) {
410 | ad[j*astep+k] += alpha*ad[i*astep+k];
411 | }
412 |
413 | bd[j] += alpha*bd[i];
414 | }
415 |
416 | ad[i*astep+i] = -d;
417 | }
418 |
419 | for(i = astep-1; i >= 0; i--) {
420 | s = bd[i];
421 | for(k = i+1; k < astep; k++) {
422 | s -= ad[i*astep+k]*bd[k];
423 | }
424 | bd[i] = s*ad[i*astep+i];
425 | }
426 |
427 | return 1; // OK
428 | },
429 |
430 | cholesky_solve: function(A, B) {
431 | var col=0,row=0,col2=0,cs=0,rs=0,i=0,j=0;
432 | var size = A.cols;
433 | var ad=A.data, bd=B.data;
434 | var val,inv_diag;
435 |
436 | for (col = 0; col < size; col++) {
437 | inv_diag = 1.0;
438 | cs = (col * size);
439 | rs = cs;
440 | for (row = col; row < size; row++)
441 | {
442 | // correct for the parts of cholesky already computed
443 | val = ad[(rs+col)];
444 | for (col2 = 0; col2 < col; col2++) {
445 | val -= ad[(col2*size+col)] * ad[(rs+col2)];
446 | }
447 | if (row == col) {
448 | // this is the diagonal element so don't divide
449 | ad[(rs+col)] = val;
450 | if(val == 0) {
451 | return 0;
452 | }
453 | inv_diag = 1.0 / val;
454 | } else {
455 | // cache the value without division in the upper half
456 | ad[(cs+row)] = val;
457 | // divide my the diagonal element for all others
458 | ad[(rs+col)] = val * inv_diag;
459 | }
460 | rs = (rs + size);
461 | }
462 | }
463 |
464 | // first backsub through L
465 | cs = 0;
466 | for (i = 0; i < size; i++) {
467 | val = bd[i];
468 | for (j = 0; j < i; j++) {
469 | val -= ad[(cs+j)] * bd[j];
470 | }
471 | bd[i] = val;
472 | cs = (cs + size);
473 | }
474 | // backsub through diagonal
475 | cs = 0;
476 | for (i = 0; i < size; i++) {
477 | bd[i] /= ad[(cs + i)];
478 | cs = (cs + size);
479 | }
480 | // backsub through L Transpose
481 | i = (size-1);
482 | for (; i >= 0; i--) {
483 | val = bd[i];
484 | j = (i + 1);
485 | cs = (j * size);
486 | for (; j < size; j++) {
487 | val -= ad[(cs + i)] * bd[j];
488 | cs = (cs + size);
489 | }
490 | bd[i] = val;
491 | }
492 |
493 | return 1;
494 | },
495 |
496 | svd_decompose: function(A, W, U, V, options) {
497 | if (typeof options === "undefined") { options = 0; };
498 | var at=0,i=0,j=0,_m=A.rows,_n=A.cols,m=_m,n=_n;
499 | var dt = A.type | jsfeat.C1_t; // we only work with single channel
500 |
501 | if(m < n) {
502 | at = 1;
503 | i = m;
504 | m = n;
505 | n = i;
506 | }
507 |
508 | var a_buff = jsfeat.cache.get_buffer((m*m)<<3);
509 | var w_buff = jsfeat.cache.get_buffer(n<<3);
510 | var v_buff = jsfeat.cache.get_buffer((n*n)<<3);
511 |
512 | var a_mt = new jsfeat.matrix_t(m, m, dt, a_buff.data);
513 | var w_mt = new jsfeat.matrix_t(1, n, dt, w_buff.data);
514 | var v_mt = new jsfeat.matrix_t(n, n, dt, v_buff.data);
515 |
516 | if(at == 0) {
517 | // transpose
518 | jsfeat.matmath.transpose(a_mt, A);
519 | } else {
520 | for(i = 0; i < _n*_m; i++) {
521 | a_mt.data[i] = A.data[i];
522 | }
523 | for(; i < n*m; i++) {
524 | a_mt.data[i] = 0;
525 | }
526 | }
527 |
528 | JacobiSVDImpl(a_mt.data, m, w_mt.data, v_mt.data, n, m, n, m);
529 |
530 | if(W) {
531 | for(i=0; i < n; i++) {
532 | W.data[i] = w_mt.data[i];
533 | }
534 | for(; i < _n; i++) {
535 | W.data[i] = 0;
536 | }
537 | }
538 |
539 | if (at == 0) {
540 | if(U && (options & jsfeat.SVD_U_T)) {
541 | i = m*m;
542 | while(--i >= 0) {
543 | U.data[i] = a_mt.data[i];
544 | }
545 | } else if(U) {
546 | jsfeat.matmath.transpose(U, a_mt);
547 | }
548 |
549 | if(V && (options & jsfeat.SVD_V_T)) {
550 | i = n*n;
551 | while(--i >= 0) {
552 | V.data[i] = v_mt.data[i];
553 | }
554 | } else if(V) {
555 | jsfeat.matmath.transpose(V, v_mt);
556 | }
557 | } else {
558 | if(U && (options & jsfeat.SVD_U_T)) {
559 | i = n*n;
560 | while(--i >= 0) {
561 | U.data[i] = v_mt.data[i];
562 | }
563 | } else if(U) {
564 | jsfeat.matmath.transpose(U, v_mt);
565 | }
566 |
567 | if(V && (options & jsfeat.SVD_V_T)) {
568 | i = m*m;
569 | while(--i >= 0) {
570 | V.data[i] = a_mt.data[i];
571 | }
572 | } else if(V) {
573 | jsfeat.matmath.transpose(V, a_mt);
574 | }
575 | }
576 |
577 | jsfeat.cache.put_buffer(a_buff);
578 | jsfeat.cache.put_buffer(w_buff);
579 | jsfeat.cache.put_buffer(v_buff);
580 |
581 | },
582 |
583 | svd_solve: function(A, X, B) {
584 | var i=0,j=0,k=0;
585 | var pu=0,pv=0;
586 | var nrows=A.rows,ncols=A.cols;
587 | var sum=0.0,xsum=0.0,tol=0.0;
588 | var dt = A.type | jsfeat.C1_t;
589 |
590 | var u_buff = jsfeat.cache.get_buffer((nrows*nrows)<<3);
591 | var w_buff = jsfeat.cache.get_buffer(ncols<<3);
592 | var v_buff = jsfeat.cache.get_buffer((ncols*ncols)<<3);
593 |
594 | var u_mt = new jsfeat.matrix_t(nrows, nrows, dt, u_buff.data);
595 | var w_mt = new jsfeat.matrix_t(1, ncols, dt, w_buff.data);
596 | var v_mt = new jsfeat.matrix_t(ncols, ncols, dt, v_buff.data);
597 |
598 | var bd = B.data, ud = u_mt.data, wd = w_mt.data, vd = v_mt.data;
599 |
600 | this.svd_decompose(A, w_mt, u_mt, v_mt, 0);
601 |
602 | tol = jsfeat.EPSILON * wd[0] * ncols;
603 |
604 | for (; i < ncols; i++, pv += ncols) {
605 | xsum = 0.0;
606 | for(j = 0; j < ncols; j++) {
607 | if(wd[j] > tol) {
608 | for(k = 0, sum = 0.0, pu = 0; k < nrows; k++, pu += ncols) {
609 | sum += ud[pu + j] * bd[k];
610 | }
611 | xsum += sum * vd[pv + j] / wd[j];
612 | }
613 | }
614 | X.data[i] = xsum;
615 | }
616 |
617 | jsfeat.cache.put_buffer(u_buff);
618 | jsfeat.cache.put_buffer(w_buff);
619 | jsfeat.cache.put_buffer(v_buff);
620 | },
621 |
622 | svd_invert: function(Ai, A) {
623 | var i=0,j=0,k=0;
624 | var pu=0,pv=0,pa=0;
625 | var nrows=A.rows,ncols=A.cols;
626 | var sum=0.0,tol=0.0;
627 | var dt = A.type | jsfeat.C1_t;
628 |
629 | var u_buff = jsfeat.cache.get_buffer((nrows*nrows)<<3);
630 | var w_buff = jsfeat.cache.get_buffer(ncols<<3);
631 | var v_buff = jsfeat.cache.get_buffer((ncols*ncols)<<3);
632 |
633 | var u_mt = new jsfeat.matrix_t(nrows, nrows, dt, u_buff.data);
634 | var w_mt = new jsfeat.matrix_t(1, ncols, dt, w_buff.data);
635 | var v_mt = new jsfeat.matrix_t(ncols, ncols, dt, v_buff.data);
636 |
637 | var id = Ai.data, ud = u_mt.data, wd = w_mt.data, vd = v_mt.data;
638 |
639 | this.svd_decompose(A, w_mt, u_mt, v_mt, 0);
640 |
641 | tol = jsfeat.EPSILON * wd[0] * ncols;
642 |
643 | for (; i < ncols; i++, pv += ncols) {
644 | for (j = 0, pu = 0; j < nrows; j++, pa++) {
645 | for (k = 0, sum = 0.0; k < ncols; k++, pu++) {
646 | if (wd[k] > tol) sum += vd[pv + k] * ud[pu] / wd[k];
647 | }
648 | id[pa] = sum;
649 | }
650 | }
651 |
652 | jsfeat.cache.put_buffer(u_buff);
653 | jsfeat.cache.put_buffer(w_buff);
654 | jsfeat.cache.put_buffer(v_buff);
655 | },
656 |
657 | eigenVV: function(A, vects, vals) {
658 | var n=A.cols,i=n*n;
659 | var dt = A.type | jsfeat.C1_t;
660 |
661 | var a_buff = jsfeat.cache.get_buffer((n*n)<<3);
662 | var w_buff = jsfeat.cache.get_buffer(n<<3);
663 | var a_mt = new jsfeat.matrix_t(n, n, dt, a_buff.data);
664 | var w_mt = new jsfeat.matrix_t(1, n, dt, w_buff.data);
665 |
666 | while(--i >= 0) {
667 | a_mt.data[i] = A.data[i];
668 | }
669 |
670 | JacobiImpl(a_mt.data, n, w_mt.data, vects ? vects.data : null, n, n);
671 |
672 | if(vals) {
673 | while(--n >= 0) {
674 | vals.data[n] = w_mt.data[n];
675 | }
676 | }
677 |
678 | jsfeat.cache.put_buffer(a_buff);
679 | jsfeat.cache.put_buffer(w_buff);
680 | }
681 |
682 | };
683 |
684 | })();
685 |
686 | global.linalg = linalg;
687 |
688 | })(jsfeat);
--------------------------------------------------------------------------------
/src/jsfeat_mat_math.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | *
4 | */
5 |
6 | (function(global) {
7 | "use strict";
8 | //
9 |
10 | var matmath = (function() {
11 |
12 | return {
13 | identity: function(M, value) {
14 | if (typeof value === "undefined") { value=1; }
15 | var src=M.data;
16 | var rows=M.rows, cols=M.cols, cols_1=(cols+1)|0;
17 | var len = rows * cols;
18 | var k = len;
19 | while(--len >= 0) src[len] = 0.0;
20 | len = k;
21 | k = 0;
22 | while(k < len) {
23 | src[k] = value;
24 | k = k + cols_1;
25 | }
26 | },
27 |
28 | transpose: function(At, A) {
29 | var i=0,j=0,nrows=A.rows,ncols=A.cols;
30 | var Ai=0,Ati=0,pAt=0;
31 | var ad=A.data,atd=At.data;
32 |
33 | for (; i < nrows; Ati += 1, Ai += ncols, i++) {
34 | pAt = Ati;
35 | for (j = 0; j < ncols; pAt += nrows, j++) atd[pAt] = ad[Ai+j];
36 | }
37 | },
38 |
39 | // C = A * B
40 | multiply: function(C, A, B) {
41 | var i=0,j=0,k=0;
42 | var Ap=0,pA=0,pB=0,p_B=0,Cp=0;
43 | var ncols=A.cols,nrows=A.rows,mcols=B.cols;
44 | var ad=A.data,bd=B.data,cd=C.data;
45 | var sum=0.0;
46 |
47 | for (; i < nrows; Ap += ncols, i++) {
48 | for (p_B = 0, j = 0; j < mcols; Cp++, p_B++, j++) {
49 | pB = p_B;
50 | pA = Ap;
51 | sum = 0.0;
52 | for (k = 0; k < ncols; pA++, pB += mcols, k++) {
53 | sum += ad[pA] * bd[pB];
54 | }
55 | cd[Cp] = sum;
56 | }
57 | }
58 | },
59 |
60 | // C = A * B'
61 | multiply_ABt: function(C, A, B) {
62 | var i=0,j=0,k=0;
63 | var Ap=0,pA=0,pB=0,Cp=0;
64 | var ncols=A.cols,nrows=A.rows,mrows=B.rows;
65 | var ad=A.data,bd=B.data,cd=C.data;
66 | var sum=0.0;
67 |
68 | for (; i < nrows; Ap += ncols, i++) {
69 | for (pB = 0, j = 0; j < mrows; Cp++, j++) {
70 | pA = Ap;
71 | sum = 0.0;
72 | for (k = 0; k < ncols; pA++, pB++, k++) {
73 | sum += ad[pA] * bd[pB];
74 | }
75 | cd[Cp] = sum;
76 | }
77 | }
78 | },
79 |
80 | // C = A' * B
81 | multiply_AtB: function(C, A, B) {
82 | var i=0,j=0,k=0;
83 | var Ap=0,pA=0,pB=0,p_B=0,Cp=0;
84 | var ncols=A.cols,nrows=A.rows,mcols=B.cols;
85 | var ad=A.data,bd=B.data,cd=C.data;
86 | var sum=0.0;
87 |
88 | for (; i < ncols; Ap++, i++) {
89 | for (p_B = 0, j = 0; j < mcols; Cp++, p_B++, j++) {
90 | pB = p_B;
91 | pA = Ap;
92 | sum = 0.0;
93 | for (k = 0; k < nrows; pA += ncols, pB += mcols, k++) {
94 | sum += ad[pA] * bd[pB];
95 | }
96 | cd[Cp] = sum;
97 | }
98 | }
99 | },
100 |
101 | // C = A * A'
102 | multiply_AAt: function(C, A) {
103 | var i=0,j=0,k=0;
104 | var pCdiag=0,p_A=0,pA=0,pB=0,pC=0,pCt=0;
105 | var ncols=A.cols,nrows=A.rows;
106 | var ad=A.data,cd=C.data;
107 | var sum=0.0;
108 |
109 | for (; i < nrows; pCdiag += nrows + 1, p_A = pA, i++) {
110 | pC = pCdiag;
111 | pCt = pCdiag;
112 | pB = p_A;
113 | for (j = i; j < nrows; pC++, pCt += nrows, j++) {
114 | pA = p_A;
115 | sum = 0.0;
116 | for (k = 0; k < ncols; k++) {
117 | sum += ad[pA++] * ad[pB++];
118 | }
119 | cd[pC] = sum
120 | cd[pCt] = sum;
121 | }
122 | }
123 | },
124 |
125 | // C = A' * A
126 | multiply_AtA: function(C, A) {
127 | var i=0,j=0,k=0;
128 | var p_A=0,pA=0,pB=0,p_C=0,pC=0,p_CC=0;
129 | var ncols=A.cols,nrows=A.rows;
130 | var ad=A.data,cd=C.data;
131 | var sum=0.0;
132 |
133 | for (; i < ncols; p_C += ncols, i++) {
134 | p_A = i;
135 | p_CC = p_C + i;
136 | pC = p_CC;
137 | for (j = i; j < ncols; pC++, p_CC += ncols, j++) {
138 | pA = p_A;
139 | pB = j;
140 | sum = 0.0;
141 | for (k = 0; k < nrows; pA += ncols, pB += ncols, k++) {
142 | sum += ad[pA] * ad[pB];
143 | }
144 | cd[pC] = sum
145 | cd[p_CC] = sum;
146 | }
147 | }
148 | },
149 |
150 | // various small matrix operations
151 | identity_3x3: function(M, value) {
152 | if (typeof value === "undefined") { value=1; }
153 | var dt=M.data;
154 | dt[0] = dt[4] = dt[8] = value;
155 | dt[1] = dt[2] = dt[3] = 0;
156 | dt[5] = dt[6] = dt[7] = 0;
157 | },
158 |
159 | invert_3x3: function(from, to) {
160 | var A = from.data, invA = to.data;
161 | var t1 = A[4];
162 | var t2 = A[8];
163 | var t4 = A[5];
164 | var t5 = A[7];
165 | var t8 = A[0];
166 |
167 | var t9 = t8*t1;
168 | var t11 = t8*t4;
169 | var t13 = A[3];
170 | var t14 = A[1];
171 | var t15 = t13*t14;
172 | var t17 = A[2];
173 | var t18 = t13*t17;
174 | var t20 = A[6];
175 | var t21 = t20*t14;
176 | var t23 = t20*t17;
177 | var t26 = 1.0/(t9*t2-t11*t5-t15*t2+t18*t5+t21*t4-t23*t1);
178 | invA[0] = (t1*t2-t4*t5)*t26;
179 | invA[1] = -(t14*t2-t17*t5)*t26;
180 | invA[2] = -(-t14*t4+t17*t1)*t26;
181 | invA[3] = -(t13*t2-t4*t20)*t26;
182 | invA[4] = (t8*t2-t23)*t26;
183 | invA[5] = -(t11-t18)*t26;
184 | invA[6] = -(-t13*t5+t1*t20)*t26;
185 | invA[7] = -(t8*t5-t21)*t26;
186 | invA[8] = (t9-t15)*t26;
187 | },
188 | // C = A * B
189 | multiply_3x3: function(C, A, B) {
190 | var Cd=C.data, Ad=A.data, Bd=B.data;
191 | var m1_0 = Ad[0], m1_1 = Ad[1], m1_2 = Ad[2];
192 | var m1_3 = Ad[3], m1_4 = Ad[4], m1_5 = Ad[5];
193 | var m1_6 = Ad[6], m1_7 = Ad[7], m1_8 = Ad[8];
194 |
195 | var m2_0 = Bd[0], m2_1 = Bd[1], m2_2 = Bd[2];
196 | var m2_3 = Bd[3], m2_4 = Bd[4], m2_5 = Bd[5];
197 | var m2_6 = Bd[6], m2_7 = Bd[7], m2_8 = Bd[8];
198 |
199 | Cd[0] = m1_0 * m2_0 + m1_1 * m2_3 + m1_2 * m2_6;
200 | Cd[1] = m1_0 * m2_1 + m1_1 * m2_4 + m1_2 * m2_7;
201 | Cd[2] = m1_0 * m2_2 + m1_1 * m2_5 + m1_2 * m2_8;
202 | Cd[3] = m1_3 * m2_0 + m1_4 * m2_3 + m1_5 * m2_6;
203 | Cd[4] = m1_3 * m2_1 + m1_4 * m2_4 + m1_5 * m2_7;
204 | Cd[5] = m1_3 * m2_2 + m1_4 * m2_5 + m1_5 * m2_8;
205 | Cd[6] = m1_6 * m2_0 + m1_7 * m2_3 + m1_8 * m2_6;
206 | Cd[7] = m1_6 * m2_1 + m1_7 * m2_4 + m1_8 * m2_7;
207 | Cd[8] = m1_6 * m2_2 + m1_7 * m2_5 + m1_8 * m2_8;
208 | },
209 |
210 | mat3x3_determinant: function(M) {
211 | var md=M.data;
212 | return md[0] * md[4] * md[8] -
213 | md[0] * md[5] * md[7] -
214 | md[3] * md[1] * md[8] +
215 | md[3] * md[2] * md[7] +
216 | md[6] * md[1] * md[5] -
217 | md[6] * md[2] * md[4];
218 | },
219 |
220 | determinant_3x3: function(M11, M12, M13,
221 | M21, M22, M23,
222 | M31, M32, M33) {
223 | return M11 * M22 * M33 - M11 * M23 * M32 -
224 | M21 * M12 * M33 + M21 * M13 * M32 +
225 | M31 * M12 * M23 - M31 * M13 * M22;
226 | }
227 | };
228 |
229 | })();
230 |
231 | global.matmath = matmath;
232 |
233 | })(jsfeat);
--------------------------------------------------------------------------------
/src/jsfeat_math.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | */
4 |
5 | (function(global) {
6 | "use strict";
7 | //
8 |
9 | var math = (function() {
10 |
11 | var qsort_stack = new Int32Array(48*2);
12 |
13 | return {
14 | get_gaussian_kernel: function(size, sigma, kernel, data_type) {
15 | var i=0,x=0.0,t=0.0,sigma_x=0.0,scale_2x=0.0;
16 | var sum = 0.0;
17 | var kern_node = jsfeat.cache.get_buffer(size<<2);
18 | var _kernel = kern_node.f32;//new Float32Array(size);
19 |
20 | if((size&1) == 1 && size <= 7 && sigma <= 0) {
21 | switch(size>>1) {
22 | case 0:
23 | _kernel[0] = 1.0;
24 | sum = 1.0;
25 | break;
26 | case 1:
27 | _kernel[0] = 0.25, _kernel[1] = 0.5, _kernel[2] = 0.25;
28 | sum = 0.25+0.5+0.25;
29 | break;
30 | case 2:
31 | _kernel[0] = 0.0625, _kernel[1] = 0.25, _kernel[2] = 0.375,
32 | _kernel[3] = 0.25, _kernel[4] = 0.0625;
33 | sum = 0.0625+0.25+0.375+0.25+0.0625;
34 | break;
35 | case 3:
36 | _kernel[0] = 0.03125, _kernel[1] = 0.109375, _kernel[2] = 0.21875,
37 | _kernel[3] = 0.28125, _kernel[4] = 0.21875, _kernel[5] = 0.109375, _kernel[6] = 0.03125;
38 | sum = 0.03125+0.109375+0.21875+0.28125+0.21875+0.109375+0.03125;
39 | break;
40 | }
41 | } else {
42 | sigma_x = sigma > 0 ? sigma : ((size-1)*0.5 - 1.0)*0.3 + 0.8;
43 | scale_2x = -0.5/(sigma_x*sigma_x);
44 |
45 | for( ; i < size; ++i )
46 | {
47 | x = i - (size-1)*0.5;
48 | t = Math.exp(scale_2x*x*x);
49 |
50 | _kernel[i] = t;
51 | sum += t;
52 | }
53 | }
54 |
55 | if(data_type & jsfeat.U8_t) {
56 | // int based kernel
57 | sum = 256.0/sum;
58 | for (i = 0; i < size; ++i) {
59 | kernel[i] = (_kernel[i] * sum + 0.5)|0;
60 | }
61 | } else {
62 | // classic kernel
63 | sum = 1.0/sum;
64 | for (i = 0; i < size; ++i) {
65 | kernel[i] = _kernel[i] * sum;
66 | }
67 | }
68 |
69 | jsfeat.cache.put_buffer(kern_node);
70 | },
71 |
72 | // model is 3x3 matrix_t
73 | perspective_4point_transform: function(model, src_x0, src_y0, dst_x0, dst_y0,
74 | src_x1, src_y1, dst_x1, dst_y1,
75 | src_x2, src_y2, dst_x2, dst_y2,
76 | src_x3, src_y3, dst_x3, dst_y3) {
77 | var t1 = src_x0;
78 | var t2 = src_x2;
79 | var t4 = src_y1;
80 | var t5 = t1 * t2 * t4;
81 | var t6 = src_y3;
82 | var t7 = t1 * t6;
83 | var t8 = t2 * t7;
84 | var t9 = src_y2;
85 | var t10 = t1 * t9;
86 | var t11 = src_x1;
87 | var t14 = src_y0;
88 | var t15 = src_x3;
89 | var t16 = t14 * t15;
90 | var t18 = t16 * t11;
91 | var t20 = t15 * t11 * t9;
92 | var t21 = t15 * t4;
93 | var t24 = t15 * t9;
94 | var t25 = t2 * t4;
95 | var t26 = t6 * t2;
96 | var t27 = t6 * t11;
97 | var t28 = t9 * t11;
98 | var t30 = 1.0 / (t21-t24 - t25 + t26 - t27 + t28);
99 | var t32 = t1 * t15;
100 | var t35 = t14 * t11;
101 | var t41 = t4 * t1;
102 | var t42 = t6 * t41;
103 | var t43 = t14 * t2;
104 | var t46 = t16 * t9;
105 | var t48 = t14 * t9 * t11;
106 | var t51 = t4 * t6 * t2;
107 | var t55 = t6 * t14;
108 | var Hr0 = -(t8-t5 + t10 * t11 - t11 * t7 - t16 * t2 + t18 - t20 + t21 * t2) * t30;
109 | var Hr1 = (t5 - t8 - t32 * t4 + t32 * t9 + t18 - t2 * t35 + t27 * t2 - t20) * t30;
110 | var Hr2 = t1;
111 | var Hr3 = (-t9 * t7 + t42 + t43 * t4 - t16 * t4 + t46 - t48 + t27 * t9 - t51) * t30;
112 | var Hr4 = (-t42 + t41 * t9 - t55 * t2 + t46 - t48 + t55 * t11 + t51 - t21 * t9) * t30;
113 | var Hr5 = t14;
114 | var Hr6 = (-t10 + t41 + t43 - t35 + t24 - t21 - t26 + t27) * t30;
115 | var Hr7 = (-t7 + t10 + t16 - t43 + t27 - t28 - t21 + t25) * t30;
116 |
117 | t1 = dst_x0;
118 | t2 = dst_x2;
119 | t4 = dst_y1;
120 | t5 = t1 * t2 * t4;
121 | t6 = dst_y3;
122 | t7 = t1 * t6;
123 | t8 = t2 * t7;
124 | t9 = dst_y2;
125 | t10 = t1 * t9;
126 | t11 = dst_x1;
127 | t14 = dst_y0;
128 | t15 = dst_x3;
129 | t16 = t14 * t15;
130 | t18 = t16 * t11;
131 | t20 = t15 * t11 * t9;
132 | t21 = t15 * t4;
133 | t24 = t15 * t9;
134 | t25 = t2 * t4;
135 | t26 = t6 * t2;
136 | t27 = t6 * t11;
137 | t28 = t9 * t11;
138 | t30 = 1.0 / (t21-t24 - t25 + t26 - t27 + t28);
139 | t32 = t1 * t15;
140 | t35 = t14 * t11;
141 | t41 = t4 * t1;
142 | t42 = t6 * t41;
143 | t43 = t14 * t2;
144 | t46 = t16 * t9;
145 | t48 = t14 * t9 * t11;
146 | t51 = t4 * t6 * t2;
147 | t55 = t6 * t14;
148 | var Hl0 = -(t8-t5 + t10 * t11 - t11 * t7 - t16 * t2 + t18 - t20 + t21 * t2) * t30;
149 | var Hl1 = (t5 - t8 - t32 * t4 + t32 * t9 + t18 - t2 * t35 + t27 * t2 - t20) * t30;
150 | var Hl2 = t1;
151 | var Hl3 = (-t9 * t7 + t42 + t43 * t4 - t16 * t4 + t46 - t48 + t27 * t9 - t51) * t30;
152 | var Hl4 = (-t42 + t41 * t9 - t55 * t2 + t46 - t48 + t55 * t11 + t51 - t21 * t9) * t30;
153 | var Hl5 = t14;
154 | var Hl6 = (-t10 + t41 + t43 - t35 + t24 - t21 - t26 + t27) * t30;
155 | var Hl7 = (-t7 + t10 + t16 - t43 + t27 - t28 - t21 + t25) * t30;
156 |
157 | // the following code computes R = Hl * inverse Hr
158 | t2 = Hr4-Hr7*Hr5;
159 | t4 = Hr0*Hr4;
160 | t5 = Hr0*Hr5;
161 | t7 = Hr3*Hr1;
162 | t8 = Hr2*Hr3;
163 | t10 = Hr1*Hr6;
164 | var t12 = Hr2*Hr6;
165 | t15 = 1.0 / (t4-t5*Hr7-t7+t8*Hr7+t10*Hr5-t12*Hr4);
166 | t18 = -Hr3+Hr5*Hr6;
167 | var t23 = -Hr3*Hr7+Hr4*Hr6;
168 | t28 = -Hr1+Hr2*Hr7;
169 | var t31 = Hr0-t12;
170 | t35 = Hr0*Hr7-t10;
171 | t41 = -Hr1*Hr5+Hr2*Hr4;
172 | var t44 = t5-t8;
173 | var t47 = t4-t7;
174 | t48 = t2*t15;
175 | var t49 = t28*t15;
176 | var t50 = t41*t15;
177 | var mat = model.data;
178 | mat[0] = Hl0*t48+Hl1*(t18*t15)-Hl2*(t23*t15);
179 | mat[1] = Hl0*t49+Hl1*(t31*t15)-Hl2*(t35*t15);
180 | mat[2] = -Hl0*t50-Hl1*(t44*t15)+Hl2*(t47*t15);
181 | mat[3] = Hl3*t48+Hl4*(t18*t15)-Hl5*(t23*t15);
182 | mat[4] = Hl3*t49+Hl4*(t31*t15)-Hl5*(t35*t15);
183 | mat[5] = -Hl3*t50-Hl4*(t44*t15)+Hl5*(t47*t15);
184 | mat[6] = Hl6*t48+Hl7*(t18*t15)-t23*t15;
185 | mat[7] = Hl6*t49+Hl7*(t31*t15)-t35*t15;
186 | mat[8] = -Hl6*t50-Hl7*(t44*t15)+t47*t15;
187 | },
188 |
189 | // The current implementation was derived from *BSD system qsort():
190 | // Copyright (c) 1992, 1993
191 | // The Regents of the University of California. All rights reserved.
192 | qsort: function(array, low, high, cmp) {
193 | var isort_thresh = 7;
194 | var t,ta,tb,tc;
195 | var sp = 0,left=0,right=0,i=0,n=0,m=0,ptr=0,ptr2=0,d=0;
196 | var left0=0,left1=0,right0=0,right1=0,pivot=0,a=0,b=0,c=0,swap_cnt=0;
197 |
198 | var stack = qsort_stack;
199 |
200 | if( (high-low+1) <= 1 ) return;
201 |
202 | stack[0] = low;
203 | stack[1] = high;
204 |
205 | while( sp >= 0 ) {
206 |
207 | left = stack[sp<<1];
208 | right = stack[(sp<<1)+1];
209 | sp--;
210 |
211 | for(;;) {
212 | n = (right - left) + 1;
213 |
214 | if( n <= isort_thresh ) {
215 | //insert_sort:
216 | for( ptr = left + 1; ptr <= right; ptr++ ) {
217 | for( ptr2 = ptr; ptr2 > left && cmp(array[ptr2],array[ptr2-1]); ptr2--) {
218 | t = array[ptr2];
219 | array[ptr2] = array[ptr2-1];
220 | array[ptr2-1] = t;
221 | }
222 | }
223 | break;
224 | } else {
225 | swap_cnt = 0;
226 |
227 | left0 = left;
228 | right0 = right;
229 | pivot = left + (n>>1);
230 |
231 | if( n > 40 ) {
232 | d = n >> 3;
233 | a = left, b = left + d, c = left + (d<<1);
234 | ta = array[a],tb = array[b],tc = array[c];
235 | left = cmp(ta, tb) ? (cmp(tb, tc) ? b : (cmp(ta, tc) ? c : a))
236 | : (cmp(tc, tb) ? b : (cmp(ta, tc) ? a : c));
237 |
238 | a = pivot - d, b = pivot, c = pivot + d;
239 | ta = array[a],tb = array[b],tc = array[c];
240 | pivot = cmp(ta, tb) ? (cmp(tb, tc) ? b : (cmp(ta, tc) ? c : a))
241 | : (cmp(tc, tb) ? b : (cmp(ta, tc) ? a : c));
242 |
243 | a = right - (d<<1), b = right - d, c = right;
244 | ta = array[a],tb = array[b],tc = array[c];
245 | right = cmp(ta, tb) ? (cmp(tb, tc) ? b : (cmp(ta, tc) ? c : a))
246 | : (cmp(tc, tb) ? b : (cmp(ta, tc) ? a : c));
247 | }
248 |
249 | a = left, b = pivot, c = right;
250 | ta = array[a],tb = array[b],tc = array[c];
251 | pivot = cmp(ta, tb) ? (cmp(tb, tc) ? b : (cmp(ta, tc) ? c : a))
252 | : (cmp(tc, tb) ? b : (cmp(ta, tc) ? a : c));
253 | if( pivot != left0 ) {
254 | t = array[pivot];
255 | array[pivot] = array[left0];
256 | array[left0] = t;
257 | pivot = left0;
258 | }
259 | left = left1 = left0 + 1;
260 | right = right1 = right0;
261 |
262 | ta = array[pivot];
263 | for(;;) {
264 | while( left <= right && !cmp(ta, array[left]) ) {
265 | if( !cmp(array[left], ta) ) {
266 | if( left > left1 ) {
267 | t = array[left1];
268 | array[left1] = array[left];
269 | array[left] = t;
270 | }
271 | swap_cnt = 1;
272 | left1++;
273 | }
274 | left++;
275 | }
276 |
277 | while( left <= right && !cmp(array[right], ta) ) {
278 | if( !cmp(ta, array[right]) ) {
279 | if( right < right1 ) {
280 | t = array[right1];
281 | array[right1] = array[right];
282 | array[right] = t;
283 | }
284 | swap_cnt = 1;
285 | right1--;
286 | }
287 | right--;
288 | }
289 |
290 | if( left > right ) break;
291 |
292 | t = array[left];
293 | array[left] = array[right];
294 | array[right] = t;
295 | swap_cnt = 1;
296 | left++;
297 | right--;
298 | }
299 |
300 | if( swap_cnt == 0 ) {
301 | left = left0, right = right0;
302 | //goto insert_sort;
303 | for( ptr = left + 1; ptr <= right; ptr++ ) {
304 | for( ptr2 = ptr; ptr2 > left && cmp(array[ptr2],array[ptr2-1]); ptr2--) {
305 | t = array[ptr2];
306 | array[ptr2] = array[ptr2-1];
307 | array[ptr2-1] = t;
308 | }
309 | }
310 | break;
311 | }
312 |
313 | n = Math.min( (left1 - left0), (left - left1) );
314 | m = (left-n)|0;
315 | for( i = 0; i < n; ++i,++m ) {
316 | t = array[left0+i];
317 | array[left0+i] = array[m];
318 | array[m] = t;
319 | }
320 |
321 | n = Math.min( (right0 - right1), (right1 - right) );
322 | m = (right0-n+1)|0;
323 | for( i = 0; i < n; ++i,++m ) {
324 | t = array[left+i];
325 | array[left+i] = array[m];
326 | array[m] = t;
327 | }
328 | n = (left - left1);
329 | m = (right1 - right);
330 | if( n > 1 ) {
331 | if( m > 1 ) {
332 | if( n > m ) {
333 | ++sp;
334 | stack[sp<<1] = left0;
335 | stack[(sp<<1)+1] = left0 + n - 1;
336 | left = right0 - m + 1, right = right0;
337 | } else {
338 | ++sp;
339 | stack[sp<<1] = right0 - m + 1;
340 | stack[(sp<<1)+1] = right0;
341 | left = left0, right = left0 + n - 1;
342 | }
343 | } else {
344 | left = left0, right = left0 + n - 1;
345 | }
346 | }
347 | else if( m > 1 )
348 | left = right0 - m + 1, right = right0;
349 | else
350 | break;
351 | }
352 | }
353 | }
354 | },
355 |
356 | median: function(array, low, high) {
357 | var w;
358 | var middle=0,ll=0,hh=0,median=(low+high)>>1;
359 | for (;;) {
360 | if (high <= low) return array[median];
361 | if (high == (low + 1)) {
362 | if (array[low] > array[high]) {
363 | w = array[low];
364 | array[low] = array[high];
365 | array[high] = w;
366 | }
367 | return array[median];
368 | }
369 | middle = ((low + high) >> 1);
370 | if (array[middle] > array[high]) {
371 | w = array[middle];
372 | array[middle] = array[high];
373 | array[high] = w;
374 | }
375 | if (array[low] > array[high]) {
376 | w = array[low];
377 | array[low] = array[high];
378 | array[high] = w;
379 | }
380 | if (array[middle] > array[low]) {
381 | w = array[middle];
382 | array[middle] = array[low];
383 | array[low] = w;
384 | }
385 | ll = (low + 1);
386 | w = array[middle];
387 | array[middle] = array[ll];
388 | array[ll] = w;
389 | hh = high;
390 | for (;;) {
391 | do ++ll; while (array[low] > array[ll]);
392 | do --hh; while (array[hh] > array[low]);
393 | if (hh < ll) break;
394 | w = array[ll];
395 | array[ll] = array[hh];
396 | array[hh] = w;
397 | }
398 | w = array[low];
399 | array[low] = array[hh];
400 | array[hh] = w;
401 | if (hh <= median)
402 | low = ll;
403 | else if (hh >= median)
404 | high = (hh - 1);
405 | }
406 | return 0;
407 | }
408 | };
409 |
410 | })();
411 |
412 | global.math = math;
413 |
414 | })(jsfeat);
415 |
--------------------------------------------------------------------------------
/src/jsfeat_motion_estimator.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | *
4 | */
5 |
6 | (function(global) {
7 | "use strict";
8 | //
9 |
10 | var motion_model = (function() {
11 |
12 | var sqr = function(x) {
13 | return x*x;
14 | }
15 |
16 | // does isotropic normalization
17 | var iso_normalize_points = function(from, to, T0, T1, count) {
18 | var i=0;
19 | var cx0=0.0, cy0=0.0, d0=0.0, s0=0.0;
20 | var cx1=0.0, cy1=0.0, d1=0.0, s1=0.0;
21 | var dx=0.0,dy=0.0;
22 |
23 | for (; i < count; ++i) {
24 | cx0 += from[i].x;
25 | cy0 += from[i].y;
26 | cx1 += to[i].x;
27 | cy1 += to[i].y;
28 | }
29 |
30 | cx0 /= count; cy0 /= count;
31 | cx1 /= count; cy1 /= count;
32 |
33 | for (i = 0; i < count; ++i) {
34 | dx = from[i].x - cx0;
35 | dy = from[i].y - cy0;
36 | d0 += Math.sqrt(dx*dx + dy*dy);
37 | dx = to[i].x - cx1;
38 | dy = to[i].y - cy1;
39 | d1 += Math.sqrt(dx*dx + dy*dy);
40 | }
41 |
42 | d0 /= count; d1 /= count;
43 |
44 | s0 = Math.SQRT2 / d0; s1 = Math.SQRT2 / d1;
45 |
46 | T0[0] = T0[4] = s0;
47 | T0[2] = -cx0*s0;
48 | T0[5] = -cy0*s0;
49 | T0[1] = T0[3] = T0[6] = T0[7] = 0.0;
50 | T0[8] = 1.0;
51 |
52 | T1[0] = T1[4] = s1;
53 | T1[2] = -cx1*s1;
54 | T1[5] = -cy1*s1;
55 | T1[1] = T1[3] = T1[6] = T1[7] = 0.0;
56 | T1[8] = 1.0;
57 | }
58 |
59 | var have_collinear_points = function(points, count) {
60 | var j=0,k=0,i=(count-1)|0;
61 | var dx1=0.0,dy1=0.0,dx2=0.0,dy2=0.0;
62 |
63 | // check that the i-th selected point does not belong
64 | // to a line connecting some previously selected points
65 | for(; j < i; ++j) {
66 | dx1 = points[j].x - points[i].x;
67 | dy1 = points[j].y - points[i].y;
68 | for(k = 0; k < j; ++k) {
69 | dx2 = points[k].x - points[i].x;
70 | dy2 = points[k].y - points[i].y;
71 | if( Math.abs(dx2*dy1 - dy2*dx1) <= jsfeat.EPSILON*(Math.abs(dx1) + Math.abs(dy1) + Math.abs(dx2) + Math.abs(dy2)))
72 | return true;
73 | }
74 | }
75 | return false;
76 | }
77 |
78 | var T0 = new jsfeat.matrix_t(3, 3, jsfeat.F32_t|jsfeat.C1_t);
79 | var T1 = new jsfeat.matrix_t(3, 3, jsfeat.F32_t|jsfeat.C1_t);
80 | var AtA = new jsfeat.matrix_t(6, 6, jsfeat.F32_t|jsfeat.C1_t);
81 | var AtB = new jsfeat.matrix_t(6, 1, jsfeat.F32_t|jsfeat.C1_t);
82 |
83 | var affine2d = (function () {
84 |
85 | function affine2d() {
86 | // empty constructor
87 | }
88 |
89 | affine2d.prototype.run = function(from, to, model, count) {
90 | var i=0,j=0;
91 | var dt=model.type|jsfeat.C1_t;
92 | var md=model.data, t0d=T0.data, t1d=T1.data;
93 | var pt0,pt1,px=0.0,py=0.0;
94 |
95 | iso_normalize_points(from, to, t0d, t1d, count);
96 |
97 | var a_buff = jsfeat.cache.get_buffer((2*count*6)<<3);
98 | var b_buff = jsfeat.cache.get_buffer((2*count)<<3);
99 |
100 | var a_mt = new jsfeat.matrix_t(6, 2*count, dt, a_buff.data);
101 | var b_mt = new jsfeat.matrix_t(1, 2*count, dt, b_buff.data);
102 | var ad=a_mt.data, bd=b_mt.data;
103 |
104 | for (; i < count; ++i) {
105 | pt0 = from[i];
106 | pt1 = to[i];
107 |
108 | px = t0d[0]*pt0.x + t0d[1]*pt0.y + t0d[2];
109 | py = t0d[3]*pt0.x + t0d[4]*pt0.y + t0d[5];
110 |
111 | j = i*2*6;
112 | ad[j]=px, ad[j+1]=py, ad[j+2]=1.0, ad[j+3]=0.0, ad[j+4]=0.0, ad[j+5]=0.0;
113 |
114 | j += 6;
115 | ad[j]=0.0, ad[j+1]=0.0, ad[j+2]=0.0, ad[j+3]=px, ad[j+4]=py, ad[j+5]=1.0;
116 |
117 | bd[i<<1] = t1d[0]*pt1.x + t1d[1]*pt1.y + t1d[2];
118 | bd[(i<<1)+1] = t1d[3]*pt1.x + t1d[4]*pt1.y + t1d[5];
119 | }
120 |
121 | jsfeat.matmath.multiply_AtA(AtA, a_mt);
122 | jsfeat.matmath.multiply_AtB(AtB, a_mt, b_mt);
123 |
124 | jsfeat.linalg.lu_solve(AtA, AtB);
125 |
126 | md[0] = AtB.data[0], md[1]=AtB.data[1], md[2]=AtB.data[2];
127 | md[3] = AtB.data[3], md[4]=AtB.data[4], md[5]=AtB.data[5];
128 | md[6] = 0.0, md[7] = 0.0, md[8] = 1.0; // fill last row
129 |
130 | // denormalize
131 | jsfeat.matmath.invert_3x3(T1, T1);
132 | jsfeat.matmath.multiply_3x3(model, T1, model);
133 | jsfeat.matmath.multiply_3x3(model, model, T0);
134 |
135 | // free buffer
136 | jsfeat.cache.put_buffer(a_buff);
137 | jsfeat.cache.put_buffer(b_buff);
138 |
139 | return 1;
140 | }
141 |
142 | affine2d.prototype.error = function(from, to, model, err, count) {
143 | var i=0;
144 | var pt0,pt1;
145 | var m=model.data;
146 |
147 | for (; i < count; ++i) {
148 | pt0 = from[i];
149 | pt1 = to[i];
150 |
151 | err[i] = sqr(pt1.x - m[0]*pt0.x - m[1]*pt0.y - m[2]) +
152 | sqr(pt1.y - m[3]*pt0.x - m[4]*pt0.y - m[5]);
153 | }
154 | }
155 |
156 | affine2d.prototype.check_subset = function(from, to, count) {
157 | return true; // all good
158 | }
159 |
160 | return affine2d;
161 | })();
162 |
163 | var mLtL = new jsfeat.matrix_t(9, 9, jsfeat.F32_t|jsfeat.C1_t);
164 | var Evec = new jsfeat.matrix_t(9, 9, jsfeat.F32_t|jsfeat.C1_t);
165 |
166 | var homography2d = (function () {
167 |
168 | function homography2d() {
169 | // empty constructor
170 | //this.T0 = new jsfeat.matrix_t(3, 3, jsfeat.F32_t|jsfeat.C1_t);
171 | //this.T1 = new jsfeat.matrix_t(3, 3, jsfeat.F32_t|jsfeat.C1_t);
172 | //this.mLtL = new jsfeat.matrix_t(9, 9, jsfeat.F32_t|jsfeat.C1_t);
173 | //this.Evec = new jsfeat.matrix_t(9, 9, jsfeat.F32_t|jsfeat.C1_t);
174 | }
175 |
176 | homography2d.prototype.run = function(from, to, model, count) {
177 | var i=0,j=0;
178 | var md=model.data, t0d=T0.data, t1d=T1.data;
179 | var LtL=mLtL.data, evd=Evec.data;
180 | var x=0.0,y=0.0,X=0.0,Y=0.0;
181 |
182 | // norm
183 | var smx=0.0, smy=0.0, cmx=0.0, cmy=0.0, sMx=0.0, sMy=0.0, cMx=0.0, cMy=0.0;
184 |
185 | for(; i < count; ++i) {
186 | cmx += to[i].x;
187 | cmy += to[i].y;
188 | cMx += from[i].x;
189 | cMy += from[i].y;
190 | }
191 |
192 | cmx /= count; cmy /= count;
193 | cMx /= count; cMy /= count;
194 |
195 | for(i = 0; i < count; ++i)
196 | {
197 | smx += Math.abs(to[i].x - cmx);
198 | smy += Math.abs(to[i].y - cmy);
199 | sMx += Math.abs(from[i].x - cMx);
200 | sMy += Math.abs(from[i].y - cMy);
201 | }
202 |
203 | if( Math.abs(smx) < jsfeat.EPSILON
204 | || Math.abs(smy) < jsfeat.EPSILON
205 | || Math.abs(sMx) < jsfeat.EPSILON
206 | || Math.abs(sMy) < jsfeat.EPSILON ) return 0;
207 |
208 | smx = count/smx; smy = count/smy;
209 | sMx = count/sMx; sMy = count/sMy;
210 |
211 | t0d[0] = sMx; t0d[1] = 0; t0d[2] = -cMx*sMx;
212 | t0d[3] = 0; t0d[4] = sMy; t0d[5] = -cMy*sMy;
213 | t0d[6] = 0; t0d[7] = 0; t0d[8] = 1;
214 |
215 | t1d[0] = 1.0/smx; t1d[1] = 0; t1d[2] = cmx;
216 | t1d[3] = 0; t1d[4] = 1.0/smy; t1d[5] = cmy;
217 | t1d[6] = 0; t1d[7] = 0; t1d[8] = 1;
218 | //
219 |
220 | // construct system
221 | i = 81;
222 | while(--i >= 0) {
223 | LtL[i] = 0.0;
224 | }
225 | for(i = 0; i < count; ++i) {
226 | x = (to[i].x - cmx) * smx;
227 | y = (to[i].y - cmy) * smy;
228 | X = (from[i].x - cMx) * sMx;
229 | Y = (from[i].y - cMy) * sMy;
230 |
231 | LtL[0] += X*X;
232 | LtL[1] += X*Y;
233 | LtL[2] += X;
234 |
235 | LtL[6] += X*-x*X;
236 | LtL[7] += X*-x*Y;
237 | LtL[8] += X*-x;
238 | LtL[10] += Y*Y;
239 | LtL[11] += Y;
240 |
241 | LtL[15] += Y*-x*X;
242 | LtL[16] += Y*-x*Y;
243 | LtL[17] += Y*-x;
244 | LtL[20] += 1.0;
245 |
246 | LtL[24] += -x*X;
247 | LtL[25] += -x*Y;
248 | LtL[26] += -x;
249 | LtL[30] += X*X;
250 | LtL[31] += X*Y;
251 | LtL[32] += X;
252 | LtL[33] += X*-y*X;
253 | LtL[34] += X*-y*Y;
254 | LtL[35] += X*-y;
255 | LtL[40] += Y*Y;
256 | LtL[41] += Y;
257 | LtL[42] += Y*-y*X;
258 | LtL[43] += Y*-y*Y;
259 | LtL[44] += Y*-y;
260 | LtL[50] += 1.0;
261 | LtL[51] += -y*X;
262 | LtL[52] += -y*Y;
263 | LtL[53] += -y;
264 | LtL[60] += -x*X*-x*X + -y*X*-y*X;
265 | LtL[61] += -x*X*-x*Y + -y*X*-y*Y;
266 | LtL[62] += -x*X*-x + -y*X*-y;
267 | LtL[70] += -x*Y*-x*Y + -y*Y*-y*Y;
268 | LtL[71] += -x*Y*-x + -y*Y*-y;
269 | LtL[80] += -x*-x + -y*-y;
270 | }
271 | //
272 |
273 | // symmetry
274 | for(i = 0; i < 9; ++i) {
275 | for(j = 0; j < i; ++j)
276 | LtL[i*9+j] = LtL[j*9+i];
277 | }
278 |
279 | jsfeat.linalg.eigenVV(mLtL, Evec);
280 |
281 | md[0]=evd[72], md[1]=evd[73], md[2]=evd[74];
282 | md[3]=evd[75], md[4]=evd[76], md[5]=evd[77];
283 | md[6]=evd[78], md[7]=evd[79], md[8]=evd[80];
284 |
285 | // denormalize
286 | jsfeat.matmath.multiply_3x3(model, T1, model);
287 | jsfeat.matmath.multiply_3x3(model, model, T0);
288 |
289 | // set bottom right to 1.0
290 | x = 1.0/md[8];
291 | md[0] *= x; md[1] *= x; md[2] *= x;
292 | md[3] *= x; md[4] *= x; md[5] *= x;
293 | md[6] *= x; md[7] *= x; md[8] = 1.0;
294 |
295 | return 1;
296 | }
297 |
298 | homography2d.prototype.error = function(from, to, model, err, count) {
299 | var i=0;
300 | var pt0,pt1,ww=0.0,dx=0.0,dy=0.0;
301 | var m=model.data;
302 |
303 | for (; i < count; ++i) {
304 | pt0 = from[i];
305 | pt1 = to[i];
306 |
307 | ww = 1.0/(m[6]*pt0.x + m[7]*pt0.y + 1.0);
308 | dx = (m[0]*pt0.x + m[1]*pt0.y + m[2])*ww - pt1.x;
309 | dy = (m[3]*pt0.x + m[4]*pt0.y + m[5])*ww - pt1.y;
310 | err[i] = (dx*dx + dy*dy);
311 | }
312 | }
313 |
314 | homography2d.prototype.check_subset = function(from, to, count) {
315 | // seems to reject good subsets actually
316 | //if( have_collinear_points(from, count) || have_collinear_points(to, count) ) {
317 | //return false;
318 | //}
319 | if( count == 4 ) {
320 | var negative = 0;
321 |
322 | var fp0=from[0],fp1=from[1],fp2=from[2],fp3=from[3];
323 | var tp0=to[0],tp1=to[1],tp2=to[2],tp3=to[3];
324 |
325 | // set1
326 | var A11=fp0.x, A12=fp0.y, A13=1.0;
327 | var A21=fp1.x, A22=fp1.y, A23=1.0;
328 | var A31=fp2.x, A32=fp2.y, A33=1.0;
329 |
330 | var B11=tp0.x, B12=tp0.y, B13=1.0;
331 | var B21=tp1.x, B22=tp1.y, B23=1.0;
332 | var B31=tp2.x, B32=tp2.y, B33=1.0;
333 |
334 | var detA = jsfeat.matmath.determinant_3x3(A11,A12,A13, A21,A22,A23, A31,A32,A33);
335 | var detB = jsfeat.matmath.determinant_3x3(B11,B12,B13, B21,B22,B23, B31,B32,B33);
336 |
337 | if(detA*detB < 0) negative++;
338 |
339 | // set2
340 | A11=fp1.x, A12=fp1.y;
341 | A21=fp2.x, A22=fp2.y;
342 | A31=fp3.x, A32=fp3.y;
343 |
344 | B11=tp1.x, B12=tp1.y;
345 | B21=tp2.x, B22=tp2.y;
346 | B31=tp3.x, B32=tp3.y;
347 |
348 | detA = jsfeat.matmath.determinant_3x3(A11,A12,A13, A21,A22,A23, A31,A32,A33);
349 | detB = jsfeat.matmath.determinant_3x3(B11,B12,B13, B21,B22,B23, B31,B32,B33);
350 |
351 | if(detA*detB < 0) negative++;
352 |
353 | // set3
354 | A11=fp0.x, A12=fp0.y;
355 | A21=fp2.x, A22=fp2.y;
356 | A31=fp3.x, A32=fp3.y;
357 |
358 | B11=tp0.x, B12=tp0.y;
359 | B21=tp2.x, B22=tp2.y;
360 | B31=tp3.x, B32=tp3.y;
361 |
362 | detA = jsfeat.matmath.determinant_3x3(A11,A12,A13, A21,A22,A23, A31,A32,A33);
363 | detB = jsfeat.matmath.determinant_3x3(B11,B12,B13, B21,B22,B23, B31,B32,B33);
364 |
365 | if(detA*detB < 0) negative++;
366 |
367 | // set4
368 | A11=fp0.x, A12=fp0.y;
369 | A21=fp1.x, A22=fp1.y;
370 | A31=fp3.x, A32=fp3.y;
371 |
372 | B11=tp0.x, B12=tp0.y;
373 | B21=tp1.x, B22=tp1.y;
374 | B31=tp3.x, B32=tp3.y;
375 |
376 | detA = jsfeat.matmath.determinant_3x3(A11,A12,A13, A21,A22,A23, A31,A32,A33);
377 | detB = jsfeat.matmath.determinant_3x3(B11,B12,B13, B21,B22,B23, B31,B32,B33);
378 |
379 | if(detA*detB < 0) negative++;
380 |
381 | if(negative != 0 && negative != 4) {
382 | return false;
383 | }
384 | }
385 | return true; // all good
386 | }
387 |
388 | return homography2d;
389 | })();
390 |
391 | return {
392 |
393 | affine2d:affine2d,
394 | homography2d:homography2d
395 |
396 | };
397 |
398 | })();
399 |
400 | var ransac_params_t = (function () {
401 | function ransac_params_t(size, thresh, eps, prob) {
402 | if (typeof size === "undefined") { size=0; }
403 | if (typeof thresh === "undefined") { thresh=0.5; }
404 | if (typeof eps === "undefined") { eps=0.5; }
405 | if (typeof prob === "undefined") { prob=0.99; }
406 |
407 | this.size = size;
408 | this.thresh = thresh;
409 | this.eps = eps;
410 | this.prob = prob;
411 | };
412 | ransac_params_t.prototype.update_iters = function(_eps, max_iters) {
413 | var num = Math.log(1 - this.prob);
414 | var denom = Math.log(1 - Math.pow(1 - _eps, this.size));
415 | return (denom >= 0 || -num >= max_iters*(-denom) ? max_iters : Math.round(num/denom))|0;
416 | };
417 | return ransac_params_t;
418 | })();
419 |
420 | var motion_estimator = (function() {
421 |
422 | var get_subset = function(kernel, from, to, need_cnt, max_cnt, from_sub, to_sub) {
423 | var max_try = 1000;
424 | var indices = [];
425 | var i=0, j=0, ssiter=0, idx_i=0, ok=false;
426 | for(; ssiter < max_try; ++ssiter) {
427 | i = 0;
428 | for (; i < need_cnt && ssiter < max_try;) {
429 | ok = false;
430 | idx_i = 0;
431 | while (!ok) {
432 | ok = true;
433 | idx_i = indices[i] = Math.floor(Math.random() * max_cnt)|0;
434 | for (j = 0; j < i; ++j) {
435 | if (idx_i == indices[j])
436 | { ok = false; break; }
437 | }
438 | }
439 | from_sub[i] = from[idx_i];
440 | to_sub[i] = to[idx_i];
441 | if( !kernel.check_subset( from_sub, to_sub, i+1 ) ) {
442 | ssiter++;
443 | continue;
444 | }
445 | ++i;
446 | }
447 | break;
448 | }
449 |
450 | return (i == need_cnt && ssiter < max_try);
451 | }
452 |
453 | var find_inliers = function(kernel, model, from, to, count, thresh, err, mask) {
454 | var numinliers = 0, i=0, f=0;
455 | var t = thresh*thresh;
456 |
457 | kernel.error(from, to, model, err, count);
458 |
459 | for(; i < count; ++i) {
460 | f = err[i] <= t;
461 | mask[i] = f;
462 | numinliers += f;
463 | }
464 | return numinliers;
465 | }
466 |
467 | return {
468 |
469 | ransac: function(params, kernel, from, to, count, model, mask, max_iters) {
470 | if (typeof max_iters === "undefined") { max_iters=1000; }
471 |
472 | if(count < params.size) return false;
473 |
474 | var model_points = params.size;
475 | var niters = max_iters, iter=0;
476 | var result = false;
477 |
478 | var subset0 = [];
479 | var subset1 = [];
480 | var found = false;
481 |
482 | var mc=model.cols,mr=model.rows;
483 | var dt = model.type | jsfeat.C1_t;
484 |
485 | var m_buff = jsfeat.cache.get_buffer((mc*mr)<<3);
486 | var ms_buff = jsfeat.cache.get_buffer(count);
487 | var err_buff = jsfeat.cache.get_buffer(count<<2);
488 | var M = new jsfeat.matrix_t(mc, mr, dt, m_buff.data);
489 | var curr_mask = new jsfeat.matrix_t(count, 1, jsfeat.U8C1_t, ms_buff.data);
490 |
491 | var inliers_max = -1, numinliers=0;
492 | var nmodels = 0;
493 |
494 | var err = err_buff.f32;
495 |
496 | // special case
497 | if(count == model_points) {
498 | if(kernel.run(from, to, M, count) <= 0) {
499 | jsfeat.cache.put_buffer(m_buff);
500 | jsfeat.cache.put_buffer(ms_buff);
501 | jsfeat.cache.put_buffer(err_buff);
502 | return false;
503 | }
504 |
505 | M.copy_to(model);
506 | if(mask) {
507 | while(--count >= 0) {
508 | mask.data[count] = 1;
509 | }
510 | }
511 | jsfeat.cache.put_buffer(m_buff);
512 | jsfeat.cache.put_buffer(ms_buff);
513 | jsfeat.cache.put_buffer(err_buff);
514 | return true;
515 | }
516 |
517 | for (; iter < niters; ++iter) {
518 | // generate subset
519 | found = get_subset(kernel, from, to, model_points, count, subset0, subset1);
520 | if(!found) {
521 | if(iter == 0) {
522 | jsfeat.cache.put_buffer(m_buff);
523 | jsfeat.cache.put_buffer(ms_buff);
524 | jsfeat.cache.put_buffer(err_buff);
525 | return false;
526 | }
527 | break;
528 | }
529 |
530 | nmodels = kernel.run( subset0, subset1, M, model_points );
531 | if(nmodels <= 0)
532 | continue;
533 |
534 | // TODO handle multimodel output
535 |
536 | numinliers = find_inliers(kernel, M, from, to, count, params.thresh, err, curr_mask.data);
537 |
538 | if( numinliers > Math.max(inliers_max, model_points-1) ) {
539 | M.copy_to(model);
540 | inliers_max = numinliers;
541 | if(mask) curr_mask.copy_to(mask);
542 | niters = params.update_iters((count - numinliers)/count, niters);
543 | result = true;
544 | }
545 | }
546 |
547 | jsfeat.cache.put_buffer(m_buff);
548 | jsfeat.cache.put_buffer(ms_buff);
549 | jsfeat.cache.put_buffer(err_buff);
550 |
551 | return result;
552 | },
553 |
554 | lmeds: function(params, kernel, from, to, count, model, mask, max_iters) {
555 | if (typeof max_iters === "undefined") { max_iters=1000; }
556 |
557 | if(count < params.size) return false;
558 |
559 | var model_points = params.size;
560 | var niters = max_iters, iter=0;
561 | var result = false;
562 |
563 | var subset0 = [];
564 | var subset1 = [];
565 | var found = false;
566 |
567 | var mc=model.cols,mr=model.rows;
568 | var dt = model.type | jsfeat.C1_t;
569 |
570 | var m_buff = jsfeat.cache.get_buffer((mc*mr)<<3);
571 | var ms_buff = jsfeat.cache.get_buffer(count);
572 | var err_buff = jsfeat.cache.get_buffer(count<<2);
573 | var M = new jsfeat.matrix_t(mc, mr, dt, m_buff.data);
574 | var curr_mask = new jsfeat.matrix_t(count, 1, jsfeat.U8_t|jsfeat.C1_t, ms_buff.data);
575 |
576 | var numinliers=0;
577 | var nmodels = 0;
578 |
579 | var err = err_buff.f32;
580 | var min_median = 1000000000.0, sigma=0.0, median=0.0;
581 |
582 | params.eps = 0.45;
583 | niters = params.update_iters(params.eps, niters);
584 |
585 | // special case
586 | if(count == model_points) {
587 | if(kernel.run(from, to, M, count) <= 0) {
588 | jsfeat.cache.put_buffer(m_buff);
589 | jsfeat.cache.put_buffer(ms_buff);
590 | jsfeat.cache.put_buffer(err_buff);
591 | return false;
592 | }
593 |
594 | M.copy_to(model);
595 | if(mask) {
596 | while(--count >= 0) {
597 | mask.data[count] = 1;
598 | }
599 | }
600 | jsfeat.cache.put_buffer(m_buff);
601 | jsfeat.cache.put_buffer(ms_buff);
602 | jsfeat.cache.put_buffer(err_buff);
603 | return true;
604 | }
605 |
606 | for (; iter < niters; ++iter) {
607 | // generate subset
608 | found = get_subset(kernel, from, to, model_points, count, subset0, subset1);
609 | if(!found) {
610 | if(iter == 0) {
611 | jsfeat.cache.put_buffer(m_buff);
612 | jsfeat.cache.put_buffer(ms_buff);
613 | jsfeat.cache.put_buffer(err_buff);
614 | return false;
615 | }
616 | break;
617 | }
618 |
619 | nmodels = kernel.run( subset0, subset1, M, model_points );
620 | if(nmodels <= 0)
621 | continue;
622 |
623 | // TODO handle multimodel output
624 |
625 | kernel.error(from, to, M, err, count);
626 | median = jsfeat.math.median(err, 0, count-1);
627 |
628 | if(median < min_median) {
629 | min_median = median;
630 | M.copy_to(model);
631 | result = true;
632 | }
633 | }
634 |
635 | if(result) {
636 | sigma = 2.5*1.4826*(1 + 5.0/(count - model_points))*Math.sqrt(min_median);
637 | sigma = Math.max(sigma, 0.001);
638 |
639 | numinliers = find_inliers(kernel, model, from, to, count, sigma, err, curr_mask.data);
640 | if(mask) curr_mask.copy_to(mask);
641 |
642 | result = numinliers >= model_points;
643 | }
644 |
645 | jsfeat.cache.put_buffer(m_buff);
646 | jsfeat.cache.put_buffer(ms_buff);
647 | jsfeat.cache.put_buffer(err_buff);
648 |
649 | return result;
650 | }
651 |
652 | };
653 |
654 | })();
655 |
656 | global.ransac_params_t = ransac_params_t;
657 | global.motion_model = motion_model;
658 | global.motion_estimator = motion_estimator;
659 |
660 | })(jsfeat);
661 |
--------------------------------------------------------------------------------
/src/jsfeat_optical_flow_lk.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | *
4 | * this code is a rewrite from OpenCV's Lucas-Kanade optical flow implementation
5 | */
6 |
7 | (function(global) {
8 | "use strict";
9 | //
10 | var optical_flow_lk = (function() {
11 |
12 | // short link to shar deriv
13 | var scharr_deriv = jsfeat.imgproc.scharr_derivatives;
14 |
15 | return {
16 | track: function(prev_pyr, curr_pyr, prev_xy, curr_xy, count, win_size, max_iter, status, eps, min_eigen_threshold) {
17 | if (typeof max_iter === "undefined") { max_iter = 30; }
18 | if (typeof status === "undefined") { status = new Uint8Array(count); }
19 | if (typeof eps === "undefined") { eps = 0.01; }
20 | if (typeof min_eigen_threshold === "undefined") { min_eigen_threshold = 0.0001; }
21 |
22 | var half_win = (win_size-1)*0.5;
23 | var win_area = (win_size*win_size)|0;
24 | var win_area2 = win_area << 1;
25 | var prev_imgs = prev_pyr.data, next_imgs = curr_pyr.data;
26 | var img_prev=prev_imgs[0].data,img_next=next_imgs[0].data;
27 | var w0 = prev_imgs[0].cols, h0 = prev_imgs[0].rows,lw=0,lh=0;
28 |
29 | var iwin_node = jsfeat.cache.get_buffer(win_area<<2);
30 | var deriv_iwin_node = jsfeat.cache.get_buffer(win_area2<<2);
31 | var deriv_lev_node = jsfeat.cache.get_buffer((h0*(w0<<1))<<2);
32 |
33 | var deriv_m = new jsfeat.matrix_t(w0, h0, jsfeat.S32C2_t, deriv_lev_node.data);
34 |
35 | var iwin_buf = iwin_node.i32;
36 | var deriv_iwin = deriv_iwin_node.i32;
37 | var deriv_lev = deriv_lev_node.i32;
38 |
39 | var dstep=0,src=0,dsrc=0,iptr=0,diptr=0,jptr=0;
40 | var lev_sc=0.0,prev_x=0.0,prev_y=0.0,next_x=0.0,next_y=0.0;
41 | var prev_delta_x=0.0,prev_delta_y=0.0,delta_x=0.0,delta_y=0.0;
42 | var iprev_x=0,iprev_y=0,inext_x=0,inext_y=0;
43 | var i=0,j=0,x=0,y=0,level=0,ptid=0,iter=0;
44 | var brd_tl=0,brd_r=0,brd_b=0;
45 | var a=0.0,b=0.0,b1=0.0,b2=0.0;
46 |
47 | // fixed point math
48 | var W_BITS14 = 14;
49 | var W_BITS4 = 14;
50 | var W_BITS1m5 = W_BITS4 - 5;
51 | var W_BITS1m51 = (1 << ((W_BITS1m5) - 1));
52 | var W_BITS14_ = (1 << W_BITS14);
53 | var W_BITS41 = (1 << ((W_BITS4) - 1));
54 | var FLT_SCALE = 1.0/(1 << 20);
55 | var iw00=0,iw01=0,iw10=0,iw11=0,ival=0,ixval=0,iyval=0;
56 | var A11=0.0,A12=0.0,A22=0.0,D=0.0,min_eig=0.0;
57 |
58 | var FLT_EPSILON = 0.00000011920929;
59 | eps *= eps;
60 |
61 | // reset status
62 | for(; i < count; ++i) {
63 | status[i] = 1;
64 | }
65 |
66 | var max_level = (prev_pyr.levels - 1)|0;
67 | level = max_level;
68 |
69 | for(; level >= 0; --level) {
70 | lev_sc = (1.0/(1 << level));
71 | lw = w0 >> level;
72 | lh = h0 >> level;
73 | dstep = lw << 1;
74 | img_prev = prev_imgs[level].data;
75 | img_next = next_imgs[level].data;
76 |
77 | brd_r = (lw - win_size)|0;
78 | brd_b = (lh - win_size)|0;
79 |
80 | // calculate level derivatives
81 | scharr_deriv(prev_imgs[level], deriv_m);
82 |
83 | // iterate through points
84 | for(ptid = 0; ptid < count; ++ptid) {
85 | i = ptid << 1;
86 | j = i + 1;
87 | prev_x = prev_xy[i]*lev_sc;
88 | prev_y = prev_xy[j]*lev_sc;
89 |
90 | if( level == max_level ) {
91 | next_x = prev_x;
92 | next_y = prev_y;
93 | } else {
94 | next_x = curr_xy[i]*2.0;
95 | next_y = curr_xy[j]*2.0;
96 | }
97 | curr_xy[i] = next_x;
98 | curr_xy[j] = next_y;
99 |
100 | prev_x -= half_win;
101 | prev_y -= half_win;
102 | iprev_x = prev_x|0;
103 | iprev_y = prev_y|0;
104 |
105 | // border check
106 | x = (iprev_x <= brd_tl)|(iprev_x >= brd_r)|(iprev_y <= brd_tl)|(iprev_y >= brd_b);
107 | if( x != 0 ) {
108 | if( level == 0 ) {
109 | status[ptid] = 0;
110 | }
111 | continue;
112 | }
113 |
114 | a = prev_x - iprev_x;
115 | b = prev_y - iprev_y;
116 | iw00 = (((1.0 - a)*(1.0 - b)*W_BITS14_) + 0.5)|0;
117 | iw01 = ((a*(1.0 - b)*W_BITS14_) + 0.5)|0;
118 | iw10 = (((1.0 - a)*b*W_BITS14_) + 0.5)|0;
119 | iw11 = (W_BITS14_ - iw00 - iw01 - iw10);
120 |
121 | A11 = 0.0, A12 = 0.0, A22 = 0.0;
122 |
123 | // extract the patch from the first image, compute covariation matrix of derivatives
124 | for( y = 0; y < win_size; ++y ) {
125 | src = ( (y + iprev_y)*lw + iprev_x )|0;
126 | dsrc = src << 1;
127 |
128 | iptr = (y*win_size)|0;
129 | diptr = iptr << 1;
130 | for(x = 0 ; x < win_size; ++x, ++src, ++iptr, dsrc += 2) {
131 | ival = ( (img_prev[src])*iw00 + (img_prev[src+1])*iw01 +
132 | (img_prev[src+lw])*iw10 + (img_prev[src+lw+1])*iw11 );
133 | ival = (((ival) + W_BITS1m51) >> (W_BITS1m5));
134 |
135 | ixval = ( deriv_lev[dsrc]*iw00 + deriv_lev[dsrc+2]*iw01 +
136 | deriv_lev[dsrc+dstep]*iw10 + deriv_lev[dsrc+dstep+2]*iw11 );
137 | ixval = (((ixval) + W_BITS41) >> (W_BITS4));
138 |
139 | iyval = ( deriv_lev[dsrc+1]*iw00 + deriv_lev[dsrc+3]*iw01 + deriv_lev[dsrc+dstep+1]*iw10 +
140 | deriv_lev[dsrc+dstep+3]*iw11 );
141 | iyval = (((iyval) + W_BITS41) >> (W_BITS4));
142 |
143 | iwin_buf[iptr] = ival;
144 | deriv_iwin[diptr++] = ixval;
145 | deriv_iwin[diptr++] = iyval;
146 |
147 | A11 += ixval*ixval;
148 | A12 += ixval*iyval;
149 | A22 += iyval*iyval;
150 | }
151 | }
152 |
153 | A11 *= FLT_SCALE; A12 *= FLT_SCALE; A22 *= FLT_SCALE;
154 |
155 | D = A11*A22 - A12*A12;
156 | min_eig = (A22 + A11 - Math.sqrt((A11-A22)*(A11-A22) + 4.0*A12*A12)) / win_area2;
157 |
158 | if( min_eig < min_eigen_threshold || D < FLT_EPSILON )
159 | {
160 | if( level == 0 ) {
161 | status[ptid] = 0;
162 | }
163 | continue;
164 | }
165 |
166 | D = 1.0/D;
167 |
168 | next_x -= half_win;
169 | next_y -= half_win;
170 | prev_delta_x = 0.0;
171 | prev_delta_y = 0.0;
172 |
173 | for( iter = 0; iter < max_iter; ++iter ) {
174 | inext_x = next_x|0;
175 | inext_y = next_y|0;
176 |
177 | x = (inext_x <= brd_tl)|(inext_x >= brd_r)|(inext_y <= brd_tl)|(inext_y >= brd_b);
178 | if( x != 0 ) {
179 | if( level == 0 ) {
180 | status[ptid] = 0;
181 | }
182 | break;
183 | }
184 |
185 | a = next_x - inext_x;
186 | b = next_y - inext_y;
187 | iw00 = (((1.0 - a)*(1.0 - b)*W_BITS14_) + 0.5)|0;
188 | iw01 = ((a*(1.0 - b)*W_BITS14_) + 0.5)|0;
189 | iw10 = (((1.0 - a)*b*W_BITS14_) + 0.5)|0;
190 | iw11 = (W_BITS14_ - iw00 - iw01 - iw10);
191 | b1 = 0.0, b2 = 0.0;
192 |
193 | for( y = 0; y < win_size; ++y ) {
194 | jptr = ( (y + inext_y)*lw + inext_x )|0;
195 |
196 | iptr = (y*win_size)|0;
197 | diptr = iptr << 1;
198 | for( x = 0 ; x < win_size; ++x, ++jptr, ++iptr ) {
199 | ival = ( (img_next[jptr])*iw00 + (img_next[jptr+1])*iw01 +
200 | (img_next[jptr+lw])*iw10 + (img_next[jptr+lw+1])*iw11 );
201 | ival = (((ival) + W_BITS1m51) >> (W_BITS1m5));
202 | ival = (ival - iwin_buf[iptr]);
203 |
204 | b1 += ival * deriv_iwin[diptr++];
205 | b2 += ival * deriv_iwin[diptr++];
206 | }
207 | }
208 |
209 | b1 *= FLT_SCALE;
210 | b2 *= FLT_SCALE;
211 |
212 | delta_x = ((A12*b2 - A22*b1) * D);
213 | delta_y = ((A12*b1 - A11*b2) * D);
214 |
215 | next_x += delta_x;
216 | next_y += delta_y;
217 | curr_xy[i] = next_x + half_win;
218 | curr_xy[j] = next_y + half_win;
219 |
220 | if( delta_x*delta_x + delta_y*delta_y <= eps ) {
221 | break;
222 | }
223 |
224 | if( iter > 0 && Math.abs(delta_x + prev_delta_x) < 0.01 &&
225 | Math.abs(delta_y + prev_delta_y) < 0.01 ) {
226 | curr_xy[i] -= delta_x*0.5;
227 | curr_xy[j] -= delta_y*0.5;
228 | break;
229 | }
230 |
231 | prev_delta_x = delta_x;
232 | prev_delta_y = delta_y;
233 | }
234 | } // points loop
235 | } // levels loop
236 |
237 | jsfeat.cache.put_buffer(iwin_node);
238 | jsfeat.cache.put_buffer(deriv_iwin_node);
239 | jsfeat.cache.put_buffer(deriv_lev_node);
240 | }
241 | };
242 | })();
243 |
244 | global.optical_flow_lk = optical_flow_lk;
245 |
246 | })(jsfeat);
247 |
--------------------------------------------------------------------------------
/src/jsfeat_orb.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | *
4 | * Original implementation derived from OpenCV,
5 | * @authors Ethan Rublee, Vincent Rabaud, Gary Bradski
6 | */
7 |
8 | (function(global) {
9 | "use strict";
10 | //
11 |
12 | var orb = (function() {
13 |
14 | var bit_pattern_31_ = new Int32Array([
15 | 8,-3, 9,5/*mean (0), correlation (0)*/,
16 | 4,2, 7,-12/*mean (1.12461e-05), correlation (0.0437584)*/,
17 | -11,9, -8,2/*mean (3.37382e-05), correlation (0.0617409)*/,
18 | 7,-12, 12,-13/*mean (5.62303e-05), correlation (0.0636977)*/,
19 | 2,-13, 2,12/*mean (0.000134953), correlation (0.085099)*/,
20 | 1,-7, 1,6/*mean (0.000528565), correlation (0.0857175)*/,
21 | -2,-10, -2,-4/*mean (0.0188821), correlation (0.0985774)*/,
22 | -13,-13, -11,-8/*mean (0.0363135), correlation (0.0899616)*/,
23 | -13,-3, -12,-9/*mean (0.121806), correlation (0.099849)*/,
24 | 10,4, 11,9/*mean (0.122065), correlation (0.093285)*/,
25 | -13,-8, -8,-9/*mean (0.162787), correlation (0.0942748)*/,
26 | -11,7, -9,12/*mean (0.21561), correlation (0.0974438)*/,
27 | 7,7, 12,6/*mean (0.160583), correlation (0.130064)*/,
28 | -4,-5, -3,0/*mean (0.228171), correlation (0.132998)*/,
29 | -13,2, -12,-3/*mean (0.00997526), correlation (0.145926)*/,
30 | -9,0, -7,5/*mean (0.198234), correlation (0.143636)*/,
31 | 12,-6, 12,-1/*mean (0.0676226), correlation (0.16689)*/,
32 | -3,6, -2,12/*mean (0.166847), correlation (0.171682)*/,
33 | -6,-13, -4,-8/*mean (0.101215), correlation (0.179716)*/,
34 | 11,-13, 12,-8/*mean (0.200641), correlation (0.192279)*/,
35 | 4,7, 5,1/*mean (0.205106), correlation (0.186848)*/,
36 | 5,-3, 10,-3/*mean (0.234908), correlation (0.192319)*/,
37 | 3,-7, 6,12/*mean (0.0709964), correlation (0.210872)*/,
38 | -8,-7, -6,-2/*mean (0.0939834), correlation (0.212589)*/,
39 | -2,11, -1,-10/*mean (0.127778), correlation (0.20866)*/,
40 | -13,12, -8,10/*mean (0.14783), correlation (0.206356)*/,
41 | -7,3, -5,-3/*mean (0.182141), correlation (0.198942)*/,
42 | -4,2, -3,7/*mean (0.188237), correlation (0.21384)*/,
43 | -10,-12, -6,11/*mean (0.14865), correlation (0.23571)*/,
44 | 5,-12, 6,-7/*mean (0.222312), correlation (0.23324)*/,
45 | 5,-6, 7,-1/*mean (0.229082), correlation (0.23389)*/,
46 | 1,0, 4,-5/*mean (0.241577), correlation (0.215286)*/,
47 | 9,11, 11,-13/*mean (0.00338507), correlation (0.251373)*/,
48 | 4,7, 4,12/*mean (0.131005), correlation (0.257622)*/,
49 | 2,-1, 4,4/*mean (0.152755), correlation (0.255205)*/,
50 | -4,-12, -2,7/*mean (0.182771), correlation (0.244867)*/,
51 | -8,-5, -7,-10/*mean (0.186898), correlation (0.23901)*/,
52 | 4,11, 9,12/*mean (0.226226), correlation (0.258255)*/,
53 | 0,-8, 1,-13/*mean (0.0897886), correlation (0.274827)*/,
54 | -13,-2, -8,2/*mean (0.148774), correlation (0.28065)*/,
55 | -3,-2, -2,3/*mean (0.153048), correlation (0.283063)*/,
56 | -6,9, -4,-9/*mean (0.169523), correlation (0.278248)*/,
57 | 8,12, 10,7/*mean (0.225337), correlation (0.282851)*/,
58 | 0,9, 1,3/*mean (0.226687), correlation (0.278734)*/,
59 | 7,-5, 11,-10/*mean (0.00693882), correlation (0.305161)*/,
60 | -13,-6, -11,0/*mean (0.0227283), correlation (0.300181)*/,
61 | 10,7, 12,1/*mean (0.125517), correlation (0.31089)*/,
62 | -6,-3, -6,12/*mean (0.131748), correlation (0.312779)*/,
63 | 10,-9, 12,-4/*mean (0.144827), correlation (0.292797)*/,
64 | -13,8, -8,-12/*mean (0.149202), correlation (0.308918)*/,
65 | -13,0, -8,-4/*mean (0.160909), correlation (0.310013)*/,
66 | 3,3, 7,8/*mean (0.177755), correlation (0.309394)*/,
67 | 5,7, 10,-7/*mean (0.212337), correlation (0.310315)*/,
68 | -1,7, 1,-12/*mean (0.214429), correlation (0.311933)*/,
69 | 3,-10, 5,6/*mean (0.235807), correlation (0.313104)*/,
70 | 2,-4, 3,-10/*mean (0.00494827), correlation (0.344948)*/,
71 | -13,0, -13,5/*mean (0.0549145), correlation (0.344675)*/,
72 | -13,-7, -12,12/*mean (0.103385), correlation (0.342715)*/,
73 | -13,3, -11,8/*mean (0.134222), correlation (0.322922)*/,
74 | -7,12, -4,7/*mean (0.153284), correlation (0.337061)*/,
75 | 6,-10, 12,8/*mean (0.154881), correlation (0.329257)*/,
76 | -9,-1, -7,-6/*mean (0.200967), correlation (0.33312)*/,
77 | -2,-5, 0,12/*mean (0.201518), correlation (0.340635)*/,
78 | -12,5, -7,5/*mean (0.207805), correlation (0.335631)*/,
79 | 3,-10, 8,-13/*mean (0.224438), correlation (0.34504)*/,
80 | -7,-7, -4,5/*mean (0.239361), correlation (0.338053)*/,
81 | -3,-2, -1,-7/*mean (0.240744), correlation (0.344322)*/,
82 | 2,9, 5,-11/*mean (0.242949), correlation (0.34145)*/,
83 | -11,-13, -5,-13/*mean (0.244028), correlation (0.336861)*/,
84 | -1,6, 0,-1/*mean (0.247571), correlation (0.343684)*/,
85 | 5,-3, 5,2/*mean (0.000697256), correlation (0.357265)*/,
86 | -4,-13, -4,12/*mean (0.00213675), correlation (0.373827)*/,
87 | -9,-6, -9,6/*mean (0.0126856), correlation (0.373938)*/,
88 | -12,-10, -8,-4/*mean (0.0152497), correlation (0.364237)*/,
89 | 10,2, 12,-3/*mean (0.0299933), correlation (0.345292)*/,
90 | 7,12, 12,12/*mean (0.0307242), correlation (0.366299)*/,
91 | -7,-13, -6,5/*mean (0.0534975), correlation (0.368357)*/,
92 | -4,9, -3,4/*mean (0.099865), correlation (0.372276)*/,
93 | 7,-1, 12,2/*mean (0.117083), correlation (0.364529)*/,
94 | -7,6, -5,1/*mean (0.126125), correlation (0.369606)*/,
95 | -13,11, -12,5/*mean (0.130364), correlation (0.358502)*/,
96 | -3,7, -2,-6/*mean (0.131691), correlation (0.375531)*/,
97 | 7,-8, 12,-7/*mean (0.160166), correlation (0.379508)*/,
98 | -13,-7, -11,-12/*mean (0.167848), correlation (0.353343)*/,
99 | 1,-3, 12,12/*mean (0.183378), correlation (0.371916)*/,
100 | 2,-6, 3,0/*mean (0.228711), correlation (0.371761)*/,
101 | -4,3, -2,-13/*mean (0.247211), correlation (0.364063)*/,
102 | -1,-13, 1,9/*mean (0.249325), correlation (0.378139)*/,
103 | 7,1, 8,-6/*mean (0.000652272), correlation (0.411682)*/,
104 | 1,-1, 3,12/*mean (0.00248538), correlation (0.392988)*/,
105 | 9,1, 12,6/*mean (0.0206815), correlation (0.386106)*/,
106 | -1,-9, -1,3/*mean (0.0364485), correlation (0.410752)*/,
107 | -13,-13, -10,5/*mean (0.0376068), correlation (0.398374)*/,
108 | 7,7, 10,12/*mean (0.0424202), correlation (0.405663)*/,
109 | 12,-5, 12,9/*mean (0.0942645), correlation (0.410422)*/,
110 | 6,3, 7,11/*mean (0.1074), correlation (0.413224)*/,
111 | 5,-13, 6,10/*mean (0.109256), correlation (0.408646)*/,
112 | 2,-12, 2,3/*mean (0.131691), correlation (0.416076)*/,
113 | 3,8, 4,-6/*mean (0.165081), correlation (0.417569)*/,
114 | 2,6, 12,-13/*mean (0.171874), correlation (0.408471)*/,
115 | 9,-12, 10,3/*mean (0.175146), correlation (0.41296)*/,
116 | -8,4, -7,9/*mean (0.183682), correlation (0.402956)*/,
117 | -11,12, -4,-6/*mean (0.184672), correlation (0.416125)*/,
118 | 1,12, 2,-8/*mean (0.191487), correlation (0.386696)*/,
119 | 6,-9, 7,-4/*mean (0.192668), correlation (0.394771)*/,
120 | 2,3, 3,-2/*mean (0.200157), correlation (0.408303)*/,
121 | 6,3, 11,0/*mean (0.204588), correlation (0.411762)*/,
122 | 3,-3, 8,-8/*mean (0.205904), correlation (0.416294)*/,
123 | 7,8, 9,3/*mean (0.213237), correlation (0.409306)*/,
124 | -11,-5, -6,-4/*mean (0.243444), correlation (0.395069)*/,
125 | -10,11, -5,10/*mean (0.247672), correlation (0.413392)*/,
126 | -5,-8, -3,12/*mean (0.24774), correlation (0.411416)*/,
127 | -10,5, -9,0/*mean (0.00213675), correlation (0.454003)*/,
128 | 8,-1, 12,-6/*mean (0.0293635), correlation (0.455368)*/,
129 | 4,-6, 6,-11/*mean (0.0404971), correlation (0.457393)*/,
130 | -10,12, -8,7/*mean (0.0481107), correlation (0.448364)*/,
131 | 4,-2, 6,7/*mean (0.050641), correlation (0.455019)*/,
132 | -2,0, -2,12/*mean (0.0525978), correlation (0.44338)*/,
133 | -5,-8, -5,2/*mean (0.0629667), correlation (0.457096)*/,
134 | 7,-6, 10,12/*mean (0.0653846), correlation (0.445623)*/,
135 | -9,-13, -8,-8/*mean (0.0858749), correlation (0.449789)*/,
136 | -5,-13, -5,-2/*mean (0.122402), correlation (0.450201)*/,
137 | 8,-8, 9,-13/*mean (0.125416), correlation (0.453224)*/,
138 | -9,-11, -9,0/*mean (0.130128), correlation (0.458724)*/,
139 | 1,-8, 1,-2/*mean (0.132467), correlation (0.440133)*/,
140 | 7,-4, 9,1/*mean (0.132692), correlation (0.454)*/,
141 | -2,1, -1,-4/*mean (0.135695), correlation (0.455739)*/,
142 | 11,-6, 12,-11/*mean (0.142904), correlation (0.446114)*/,
143 | -12,-9, -6,4/*mean (0.146165), correlation (0.451473)*/,
144 | 3,7, 7,12/*mean (0.147627), correlation (0.456643)*/,
145 | 5,5, 10,8/*mean (0.152901), correlation (0.455036)*/,
146 | 0,-4, 2,8/*mean (0.167083), correlation (0.459315)*/,
147 | -9,12, -5,-13/*mean (0.173234), correlation (0.454706)*/,
148 | 0,7, 2,12/*mean (0.18312), correlation (0.433855)*/,
149 | -1,2, 1,7/*mean (0.185504), correlation (0.443838)*/,
150 | 5,11, 7,-9/*mean (0.185706), correlation (0.451123)*/,
151 | 3,5, 6,-8/*mean (0.188968), correlation (0.455808)*/,
152 | -13,-4, -8,9/*mean (0.191667), correlation (0.459128)*/,
153 | -5,9, -3,-3/*mean (0.193196), correlation (0.458364)*/,
154 | -4,-7, -3,-12/*mean (0.196536), correlation (0.455782)*/,
155 | 6,5, 8,0/*mean (0.1972), correlation (0.450481)*/,
156 | -7,6, -6,12/*mean (0.199438), correlation (0.458156)*/,
157 | -13,6, -5,-2/*mean (0.211224), correlation (0.449548)*/,
158 | 1,-10, 3,10/*mean (0.211718), correlation (0.440606)*/,
159 | 4,1, 8,-4/*mean (0.213034), correlation (0.443177)*/,
160 | -2,-2, 2,-13/*mean (0.234334), correlation (0.455304)*/,
161 | 2,-12, 12,12/*mean (0.235684), correlation (0.443436)*/,
162 | -2,-13, 0,-6/*mean (0.237674), correlation (0.452525)*/,
163 | 4,1, 9,3/*mean (0.23962), correlation (0.444824)*/,
164 | -6,-10, -3,-5/*mean (0.248459), correlation (0.439621)*/,
165 | -3,-13, -1,1/*mean (0.249505), correlation (0.456666)*/,
166 | 7,5, 12,-11/*mean (0.00119208), correlation (0.495466)*/,
167 | 4,-2, 5,-7/*mean (0.00372245), correlation (0.484214)*/,
168 | -13,9, -9,-5/*mean (0.00741116), correlation (0.499854)*/,
169 | 7,1, 8,6/*mean (0.0208952), correlation (0.499773)*/,
170 | 7,-8, 7,6/*mean (0.0220085), correlation (0.501609)*/,
171 | -7,-4, -7,1/*mean (0.0233806), correlation (0.496568)*/,
172 | -8,11, -7,-8/*mean (0.0236505), correlation (0.489719)*/,
173 | -13,6, -12,-8/*mean (0.0268781), correlation (0.503487)*/,
174 | 2,4, 3,9/*mean (0.0323324), correlation (0.501938)*/,
175 | 10,-5, 12,3/*mean (0.0399235), correlation (0.494029)*/,
176 | -6,-5, -6,7/*mean (0.0420153), correlation (0.486579)*/,
177 | 8,-3, 9,-8/*mean (0.0548021), correlation (0.484237)*/,
178 | 2,-12, 2,8/*mean (0.0616622), correlation (0.496642)*/,
179 | -11,-2, -10,3/*mean (0.0627755), correlation (0.498563)*/,
180 | -12,-13, -7,-9/*mean (0.0829622), correlation (0.495491)*/,
181 | -11,0, -10,-5/*mean (0.0843342), correlation (0.487146)*/,
182 | 5,-3, 11,8/*mean (0.0929937), correlation (0.502315)*/,
183 | -2,-13, -1,12/*mean (0.113327), correlation (0.48941)*/,
184 | -1,-8, 0,9/*mean (0.132119), correlation (0.467268)*/,
185 | -13,-11, -12,-5/*mean (0.136269), correlation (0.498771)*/,
186 | -10,-2, -10,11/*mean (0.142173), correlation (0.498714)*/,
187 | -3,9, -2,-13/*mean (0.144141), correlation (0.491973)*/,
188 | 2,-3, 3,2/*mean (0.14892), correlation (0.500782)*/,
189 | -9,-13, -4,0/*mean (0.150371), correlation (0.498211)*/,
190 | -4,6, -3,-10/*mean (0.152159), correlation (0.495547)*/,
191 | -4,12, -2,-7/*mean (0.156152), correlation (0.496925)*/,
192 | -6,-11, -4,9/*mean (0.15749), correlation (0.499222)*/,
193 | 6,-3, 6,11/*mean (0.159211), correlation (0.503821)*/,
194 | -13,11, -5,5/*mean (0.162427), correlation (0.501907)*/,
195 | 11,11, 12,6/*mean (0.16652), correlation (0.497632)*/,
196 | 7,-5, 12,-2/*mean (0.169141), correlation (0.484474)*/,
197 | -1,12, 0,7/*mean (0.169456), correlation (0.495339)*/,
198 | -4,-8, -3,-2/*mean (0.171457), correlation (0.487251)*/,
199 | -7,1, -6,7/*mean (0.175), correlation (0.500024)*/,
200 | -13,-12, -8,-13/*mean (0.175866), correlation (0.497523)*/,
201 | -7,-2, -6,-8/*mean (0.178273), correlation (0.501854)*/,
202 | -8,5, -6,-9/*mean (0.181107), correlation (0.494888)*/,
203 | -5,-1, -4,5/*mean (0.190227), correlation (0.482557)*/,
204 | -13,7, -8,10/*mean (0.196739), correlation (0.496503)*/,
205 | 1,5, 5,-13/*mean (0.19973), correlation (0.499759)*/,
206 | 1,0, 10,-13/*mean (0.204465), correlation (0.49873)*/,
207 | 9,12, 10,-1/*mean (0.209334), correlation (0.49063)*/,
208 | 5,-8, 10,-9/*mean (0.211134), correlation (0.503011)*/,
209 | -1,11, 1,-13/*mean (0.212), correlation (0.499414)*/,
210 | -9,-3, -6,2/*mean (0.212168), correlation (0.480739)*/,
211 | -1,-10, 1,12/*mean (0.212731), correlation (0.502523)*/,
212 | -13,1, -8,-10/*mean (0.21327), correlation (0.489786)*/,
213 | 8,-11, 10,-6/*mean (0.214159), correlation (0.488246)*/,
214 | 2,-13, 3,-6/*mean (0.216993), correlation (0.50287)*/,
215 | 7,-13, 12,-9/*mean (0.223639), correlation (0.470502)*/,
216 | -10,-10, -5,-7/*mean (0.224089), correlation (0.500852)*/,
217 | -10,-8, -8,-13/*mean (0.228666), correlation (0.502629)*/,
218 | 4,-6, 8,5/*mean (0.22906), correlation (0.498305)*/,
219 | 3,12, 8,-13/*mean (0.233378), correlation (0.503825)*/,
220 | -4,2, -3,-3/*mean (0.234323), correlation (0.476692)*/,
221 | 5,-13, 10,-12/*mean (0.236392), correlation (0.475462)*/,
222 | 4,-13, 5,-1/*mean (0.236842), correlation (0.504132)*/,
223 | -9,9, -4,3/*mean (0.236977), correlation (0.497739)*/,
224 | 0,3, 3,-9/*mean (0.24314), correlation (0.499398)*/,
225 | -12,1, -6,1/*mean (0.243297), correlation (0.489447)*/,
226 | 3,2, 4,-8/*mean (0.00155196), correlation (0.553496)*/,
227 | -10,-10, -10,9/*mean (0.00239541), correlation (0.54297)*/,
228 | 8,-13, 12,12/*mean (0.0034413), correlation (0.544361)*/,
229 | -8,-12, -6,-5/*mean (0.003565), correlation (0.551225)*/,
230 | 2,2, 3,7/*mean (0.00835583), correlation (0.55285)*/,
231 | 10,6, 11,-8/*mean (0.00885065), correlation (0.540913)*/,
232 | 6,8, 8,-12/*mean (0.0101552), correlation (0.551085)*/,
233 | -7,10, -6,5/*mean (0.0102227), correlation (0.533635)*/,
234 | -3,-9, -3,9/*mean (0.0110211), correlation (0.543121)*/,
235 | -1,-13, -1,5/*mean (0.0113473), correlation (0.550173)*/,
236 | -3,-7, -3,4/*mean (0.0140913), correlation (0.554774)*/,
237 | -8,-2, -8,3/*mean (0.017049), correlation (0.55461)*/,
238 | 4,2, 12,12/*mean (0.01778), correlation (0.546921)*/,
239 | 2,-5, 3,11/*mean (0.0224022), correlation (0.549667)*/,
240 | 6,-9, 11,-13/*mean (0.029161), correlation (0.546295)*/,
241 | 3,-1, 7,12/*mean (0.0303081), correlation (0.548599)*/,
242 | 11,-1, 12,4/*mean (0.0355151), correlation (0.523943)*/,
243 | -3,0, -3,6/*mean (0.0417904), correlation (0.543395)*/,
244 | 4,-11, 4,12/*mean (0.0487292), correlation (0.542818)*/,
245 | 2,-4, 2,1/*mean (0.0575124), correlation (0.554888)*/,
246 | -10,-6, -8,1/*mean (0.0594242), correlation (0.544026)*/,
247 | -13,7, -11,1/*mean (0.0597391), correlation (0.550524)*/,
248 | -13,12, -11,-13/*mean (0.0608974), correlation (0.55383)*/,
249 | 6,0, 11,-13/*mean (0.065126), correlation (0.552006)*/,
250 | 0,-1, 1,4/*mean (0.074224), correlation (0.546372)*/,
251 | -13,3, -9,-2/*mean (0.0808592), correlation (0.554875)*/,
252 | -9,8, -6,-3/*mean (0.0883378), correlation (0.551178)*/,
253 | -13,-6, -8,-2/*mean (0.0901035), correlation (0.548446)*/,
254 | 5,-9, 8,10/*mean (0.0949843), correlation (0.554694)*/,
255 | 2,7, 3,-9/*mean (0.0994152), correlation (0.550979)*/,
256 | -1,-6, -1,-1/*mean (0.10045), correlation (0.552714)*/,
257 | 9,5, 11,-2/*mean (0.100686), correlation (0.552594)*/,
258 | 11,-3, 12,-8/*mean (0.101091), correlation (0.532394)*/,
259 | 3,0, 3,5/*mean (0.101147), correlation (0.525576)*/,
260 | -1,4, 0,10/*mean (0.105263), correlation (0.531498)*/,
261 | 3,-6, 4,5/*mean (0.110785), correlation (0.540491)*/,
262 | -13,0, -10,5/*mean (0.112798), correlation (0.536582)*/,
263 | 5,8, 12,11/*mean (0.114181), correlation (0.555793)*/,
264 | 8,9, 9,-6/*mean (0.117431), correlation (0.553763)*/,
265 | 7,-4, 8,-12/*mean (0.118522), correlation (0.553452)*/,
266 | -10,4, -10,9/*mean (0.12094), correlation (0.554785)*/,
267 | 7,3, 12,4/*mean (0.122582), correlation (0.555825)*/,
268 | 9,-7, 10,-2/*mean (0.124978), correlation (0.549846)*/,
269 | 7,0, 12,-2/*mean (0.127002), correlation (0.537452)*/,
270 | -1,-6, 0,-11/*mean (0.127148), correlation (0.547401)*/
271 | ]);
272 |
273 | var H = new jsfeat.matrix_t(3, 3, jsfeat.F32_t|jsfeat.C1_t);
274 | var patch_img = new jsfeat.matrix_t(32, 32, jsfeat.U8_t|jsfeat.C1_t);
275 |
276 | var rectify_patch = function(src, dst, angle, px, py, psize) {
277 | var cosine = Math.cos(angle);
278 | var sine = Math.sin(angle);
279 |
280 | H.data[0] = cosine, H.data[1] = -sine, H.data[2] = (-cosine + sine ) * psize*0.5 + px,
281 | H.data[3] = sine, H.data[4] = cosine, H.data[5] = (-sine - cosine) * psize*0.5 + py;
282 |
283 | jsfeat.imgproc.warp_affine(src, dst, H, 128);
284 | }
285 |
286 | return {
287 |
288 | describe: function(src, corners, count, descriptors) {
289 | var DESCR_SIZE = 32; // bytes;
290 | var i=0,b=0,px=0.0,py=0.0,angle=0.0;
291 | var t0=0, t1=0, val=0;
292 | var img = src.data, w = src.cols, h = src.rows;
293 | var patch_d = patch_img.data;
294 | var patch_off = 16*32 + 16; // center of patch
295 | var patt=0;
296 |
297 | if(!(descriptors.type&jsfeat.U8_t)) {
298 | // relocate to U8 type
299 | descriptors.type = jsfeat.U8_t;
300 | descriptors.cols = DESCR_SIZE;
301 | descriptors.rows = count;
302 | descriptors.channel = 1;
303 | descriptors.allocate();
304 | } else {
305 | descriptors.resize(DESCR_SIZE, count, 1);
306 | }
307 |
308 | var descr_d = descriptors.data;
309 | var descr_off = 0;
310 |
311 | for(i = 0; i < count; ++i) {
312 | px = corners[i].x;
313 | py = corners[i].y;
314 | angle = corners[i].angle;
315 |
316 | rectify_patch(src, patch_img, angle, px, py, 32);
317 |
318 | // describe the patch
319 | patt = 0;
320 | for (b = 0; b < DESCR_SIZE; ++b) {
321 |
322 | t0 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
323 | t1 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
324 | val = (t0 < t1)|0;
325 |
326 | t0 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
327 | t1 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
328 | val |= (t0 < t1) << 1;
329 |
330 | t0 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
331 | t1 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
332 | val |= (t0 < t1) << 2;
333 |
334 | t0 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
335 | t1 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
336 | val |= (t0 < t1) << 3;
337 |
338 | t0 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
339 | t1 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
340 | val |= (t0 < t1) << 4;
341 |
342 | t0 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
343 | t1 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
344 | val |= (t0 < t1) << 5;
345 |
346 | t0 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
347 | t1 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
348 | val |= (t0 < t1) << 6;
349 |
350 | t0 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
351 | t1 = patch_d[patch_off + bit_pattern_31_[patt+1] * 32 + bit_pattern_31_[patt]]; patt += 2
352 | val |= (t0 < t1) << 7;
353 |
354 | descr_d[descr_off+b] = val;
355 | }
356 | descr_off += DESCR_SIZE;
357 | }
358 | }
359 | };
360 | })();
361 |
362 | global.orb = orb;
363 |
364 | })(jsfeat);
365 |
--------------------------------------------------------------------------------
/src/jsfeat_struct.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | */
4 |
5 | (function(global) {
6 | "use strict";
7 | //
8 |
9 | // CONSTANTS
10 | var EPSILON = 0.0000001192092896;
11 | var FLT_MIN = 1E-37;
12 |
13 | // implementation from CCV project
14 | // currently working only with u8,s32,f32
15 | var U8_t = 0x0100,
16 | S32_t = 0x0200,
17 | F32_t = 0x0400,
18 | S64_t = 0x0800,
19 | F64_t = 0x1000;
20 |
21 | var C1_t = 0x01,
22 | C2_t = 0x02,
23 | C3_t = 0x03,
24 | C4_t = 0x04;
25 |
26 | var _data_type_size = new Int32Array([ -1, 1, 4, -1, 4, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1, 8 ]);
27 |
28 | var get_data_type = (function () {
29 | return function(type) {
30 | return (type & 0xFF00);
31 | }
32 | })();
33 |
34 | var get_channel = (function () {
35 | return function(type) {
36 | return (type & 0xFF);
37 | }
38 | })();
39 |
40 | var get_data_type_size = (function () {
41 | return function(type) {
42 | return _data_type_size[(type & 0xFF00) >> 8];
43 | }
44 | })();
45 |
46 | // color conversion
47 | var COLOR_RGBA2GRAY = 0;
48 | var COLOR_RGB2GRAY = 1;
49 | var COLOR_BGRA2GRAY = 2;
50 | var COLOR_BGR2GRAY = 3;
51 |
52 | // box blur option
53 | var BOX_BLUR_NOSCALE = 0x01;
54 | // svd options
55 | var SVD_U_T = 0x01;
56 | var SVD_V_T = 0x02;
57 |
58 | var data_t = (function () {
59 | function data_t(size_in_bytes, buffer) {
60 | // we need align size to multiple of 8
61 | this.size = ((size_in_bytes + 7) | 0) & -8;
62 | if (typeof buffer === "undefined") {
63 | this.buffer = new ArrayBuffer(this.size);
64 | } else {
65 | this.buffer = buffer;
66 | this.size = buffer.length;
67 | }
68 | this.u8 = new Uint8Array(this.buffer);
69 | this.i32 = new Int32Array(this.buffer);
70 | this.f32 = new Float32Array(this.buffer);
71 | this.f64 = new Float64Array(this.buffer);
72 | }
73 | return data_t;
74 | })();
75 |
76 | var matrix_t = (function () {
77 | // columns, rows, data_type
78 | function matrix_t(c, r, data_type, data_buffer) {
79 | this.type = get_data_type(data_type)|0;
80 | this.channel = get_channel(data_type)|0;
81 | this.cols = c|0;
82 | this.rows = r|0;
83 | if (typeof data_buffer === "undefined") {
84 | this.allocate();
85 | } else {
86 | this.buffer = data_buffer;
87 | // data user asked for
88 | this.data = this.type&U8_t ? this.buffer.u8 : (this.type&S32_t ? this.buffer.i32 : (this.type&F32_t ? this.buffer.f32 : this.buffer.f64));
89 | }
90 | }
91 | matrix_t.prototype.allocate = function() {
92 | // clear references
93 | delete this.data;
94 | delete this.buffer;
95 | //
96 | this.buffer = new data_t((this.cols * get_data_type_size(this.type) * this.channel) * this.rows);
97 | this.data = this.type&U8_t ? this.buffer.u8 : (this.type&S32_t ? this.buffer.i32 : (this.type&F32_t ? this.buffer.f32 : this.buffer.f64));
98 | }
99 | matrix_t.prototype.copy_to = function(other) {
100 | var od = other.data, td = this.data;
101 | var i = 0, n = (this.cols*this.rows*this.channel)|0;
102 | for(; i < n-4; i+=4) {
103 | od[i] = td[i];
104 | od[i+1] = td[i+1];
105 | od[i+2] = td[i+2];
106 | od[i+3] = td[i+3];
107 | }
108 | for(; i < n; ++i) {
109 | od[i] = td[i];
110 | }
111 | }
112 | matrix_t.prototype.resize = function(c, r, ch) {
113 | if (typeof ch === "undefined") { ch = this.channel; }
114 | // relocate buffer only if new size doesnt fit
115 | var new_size = (c * get_data_type_size(this.type) * ch) * r;
116 | if(new_size > this.buffer.size) {
117 | this.cols = c;
118 | this.rows = r;
119 | this.channel = ch;
120 | this.allocate();
121 | } else {
122 | this.cols = c;
123 | this.rows = r;
124 | this.channel = ch;
125 | }
126 | }
127 |
128 | return matrix_t;
129 | })();
130 |
131 | var pyramid_t = (function () {
132 |
133 | function pyramid_t(levels) {
134 | this.levels = levels|0;
135 | this.data = new Array(levels);
136 | this.pyrdown = jsfeat.imgproc.pyrdown;
137 | }
138 |
139 | pyramid_t.prototype.allocate = function(start_w, start_h, data_type) {
140 | var i = this.levels;
141 | while(--i >= 0) {
142 | this.data[i] = new matrix_t(start_w >> i, start_h >> i, data_type);
143 | }
144 | }
145 |
146 | pyramid_t.prototype.build = function(input, skip_first_level) {
147 | if (typeof skip_first_level === "undefined") { skip_first_level = true; }
148 | // just copy data to first level
149 | var i = 2, a = input, b = this.data[0];
150 | if(!skip_first_level) {
151 | var j=input.cols*input.rows;
152 | while(--j >= 0) {
153 | b.data[j] = input.data[j];
154 | }
155 | }
156 | b = this.data[1];
157 | this.pyrdown(a, b);
158 | for(; i < this.levels; ++i) {
159 | a = b;
160 | b = this.data[i];
161 | this.pyrdown(a, b);
162 | }
163 | }
164 |
165 | return pyramid_t;
166 | })();
167 |
168 | var keypoint_t = (function () {
169 | function keypoint_t(x,y,score,level,angle) {
170 | if (typeof x === "undefined") { x=0; }
171 | if (typeof y === "undefined") { y=0; }
172 | if (typeof score === "undefined") { score=0; }
173 | if (typeof level === "undefined") { level=0; }
174 | if (typeof angle === "undefined") { angle=-1.0; }
175 |
176 | this.x = x;
177 | this.y = y;
178 | this.score = score;
179 | this.level = level;
180 | this.angle = angle;
181 | }
182 | return keypoint_t;
183 | })();
184 |
185 |
186 | // data types
187 | global.U8_t = U8_t;
188 | global.S32_t = S32_t;
189 | global.F32_t = F32_t;
190 | global.S64_t = S64_t;
191 | global.F64_t = F64_t;
192 | // data channels
193 | global.C1_t = C1_t;
194 | global.C2_t = C2_t;
195 | global.C3_t = C3_t;
196 | global.C4_t = C4_t;
197 |
198 | // popular formats
199 | global.U8C1_t = U8_t | C1_t;
200 | global.U8C3_t = U8_t | C3_t;
201 | global.U8C4_t = U8_t | C4_t;
202 |
203 | global.F32C1_t = F32_t | C1_t;
204 | global.F32C2_t = F32_t | C2_t;
205 | global.S32C1_t = S32_t | C1_t;
206 | global.S32C2_t = S32_t | C2_t;
207 |
208 | // constants
209 | global.EPSILON = EPSILON;
210 | global.FLT_MIN = FLT_MIN;
211 |
212 | // color convert
213 | global.COLOR_RGBA2GRAY = COLOR_RGBA2GRAY;
214 | global.COLOR_RGB2GRAY = COLOR_RGB2GRAY;
215 | global.COLOR_BGRA2GRAY = COLOR_BGRA2GRAY;
216 | global.COLOR_BGR2GRAY = COLOR_BGR2GRAY;
217 |
218 | // options
219 | global.BOX_BLUR_NOSCALE = BOX_BLUR_NOSCALE;
220 | global.SVD_U_T = SVD_U_T;
221 | global.SVD_V_T = SVD_V_T;
222 |
223 | global.get_data_type = get_data_type;
224 | global.get_channel = get_channel;
225 | global.get_data_type_size = get_data_type_size;
226 |
227 | global.data_t = data_t;
228 | global.matrix_t = matrix_t;
229 | global.pyramid_t = pyramid_t;
230 | global.keypoint_t = keypoint_t;
231 |
232 | })(jsfeat);
233 |
--------------------------------------------------------------------------------
/src/jsfeat_transform.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | */
4 |
5 | (function(global) {
6 | "use strict";
7 | //
8 |
9 | var transform = (function() {
10 | //
11 | return {
12 | affine_3point_transform: function(mat, src_x0, src_y0, dst_x0, dst_y0,
13 | src_x1, src_y1, dst_x1, dst_y1,
14 | src_x2, src_y2, dst_x2, dst_y2) {
15 | // we need linear algebra module first
16 | },
17 |
18 | perspective_4point_transform: function(mat, src_x0, src_y0, dst_x0, dst_y0,
19 | src_x1, src_y1, dst_x1, dst_y1,
20 | src_x2, src_y2, dst_x2, dst_y2,
21 | src_x3, src_y3, dst_x3, dst_y3) {
22 | var t1 = src_x0;
23 | var t2 = src_x2;
24 | var t4 = src_y1;
25 | var t5 = t1 * t2 * t4;
26 | var t6 = src_y3;
27 | var t7 = t1 * t6;
28 | var t8 = t2 * t7;
29 | var t9 = src_y2;
30 | var t10 = t1 * t9;
31 | var t11 = src_x1;
32 | var t14 = src_y0;
33 | var t15 = src_x3;
34 | var t16 = t14 * t15;
35 | var t18 = t16 * t11;
36 | var t20 = t15 * t11 * t9;
37 | var t21 = t15 * t4;
38 | var t24 = t15 * t9;
39 | var t25 = t2 * t4;
40 | var t26 = t6 * t2;
41 | var t27 = t6 * t11;
42 | var t28 = t9 * t11;
43 | var t30 = 1.0 / (t21-t24 - t25 + t26 - t27 + t28);
44 | var t32 = t1 * t15;
45 | var t35 = t14 * t11;
46 | var t41 = t4 * t1;
47 | var t42 = t6 * t41;
48 | var t43 = t14 * t2;
49 | var t46 = t16 * t9;
50 | var t48 = t14 * t9 * t11;
51 | var t51 = t4 * t6 * t2;
52 | var t55 = t6 * t14;
53 | var Hr0 = -(t8-t5 + t10 * t11 - t11 * t7 - t16 * t2 + t18 - t20 + t21 * t2) * t30;
54 | var Hr1 = (t5 - t8 - t32 * t4 + t32 * t9 + t18 - t2 * t35 + t27 * t2 - t20) * t30;
55 | var Hr2 = t1;
56 | var Hr3 = (-t9 * t7 + t42 + t43 * t4 - t16 * t4 + t46 - t48 + t27 * t9 - t51) * t30;
57 | var Hr4 = (-t42 + t41 * t9 - t55 * t2 + t46 - t48 + t55 * t11 + t51 - t21 * t9) * t30;
58 | var Hr5 = t14;
59 | var Hr6 = (-t10 + t41 + t43 - t35 + t24 - t21 - t26 + t27) * t30;
60 | var Hr7 = (-t7 + t10 + t16 - t43 + t27 - t28 - t21 + t25) * t30;
61 |
62 | t1 = dst_x0;
63 | t2 = dst_x2;
64 | t4 = dst_y1;
65 | t5 = t1 * t2 * t4;
66 | t6 = dst_y3;
67 | t7 = t1 * t6;
68 | t8 = t2 * t7;
69 | t9 = dst_y2;
70 | t10 = t1 * t9;
71 | t11 = dst_x1;
72 | t14 = dst_y0;
73 | t15 = dst_x3;
74 | t16 = t14 * t15;
75 | t18 = t16 * t11;
76 | t20 = t15 * t11 * t9;
77 | t21 = t15 * t4;
78 | t24 = t15 * t9;
79 | t25 = t2 * t4;
80 | t26 = t6 * t2;
81 | t27 = t6 * t11;
82 | t28 = t9 * t11;
83 | t30 = 1.0 / (t21-t24 - t25 + t26 - t27 + t28);
84 | t32 = t1 * t15;
85 | t35 = t14 * t11;
86 | t41 = t4 * t1;
87 | t42 = t6 * t41;
88 | t43 = t14 * t2;
89 | t46 = t16 * t9;
90 | t48 = t14 * t9 * t11;
91 | t51 = t4 * t6 * t2;
92 | t55 = t6 * t14;
93 | var Hl0 = -(t8-t5 + t10 * t11 - t11 * t7 - t16 * t2 + t18 - t20 + t21 * t2) * t30;
94 | var Hl1 = (t5 - t8 - t32 * t4 + t32 * t9 + t18 - t2 * t35 + t27 * t2 - t20) * t30;
95 | var Hl2 = t1;
96 | var Hl3 = (-t9 * t7 + t42 + t43 * t4 - t16 * t4 + t46 - t48 + t27 * t9 - t51) * t30;
97 | var Hl4 = (-t42 + t41 * t9 - t55 * t2 + t46 - t48 + t55 * t11 + t51 - t21 * t9) * t30;
98 | var Hl5 = t14;
99 | var Hl6 = (-t10 + t41 + t43 - t35 + t24 - t21 - t26 + t27) * t30;
100 | var Hl7 = (-t7 + t10 + t16 - t43 + t27 - t28 - t21 + t25) * t30;
101 |
102 | // the following code computes R = Hl * inverse Hr
103 | t2 = Hr4-Hr7*Hr5;
104 | t4 = Hr0*Hr4;
105 | t5 = Hr0*Hr5;
106 | t7 = Hr3*Hr1;
107 | t8 = Hr2*Hr3;
108 | t10 = Hr1*Hr6;
109 | var t12 = Hr2*Hr6;
110 | t15 = 1.0 / (t4-t5*Hr7-t7+t8*Hr7+t10*Hr5-t12*Hr4);
111 | t18 = -Hr3+Hr5*Hr6;
112 | var t23 = -Hr3*Hr7+Hr4*Hr6;
113 | t28 = -Hr1+Hr2*Hr7;
114 | var t31 = Hr0-t12;
115 | t35 = Hr0*Hr7-t10;
116 | t41 = -Hr1*Hr5+Hr2*Hr4;
117 | var t44 = t5-t8;
118 | var t47 = t4-t7;
119 | t48 = t2*t15;
120 | var t49 = t28*t15;
121 | var t50 = t41*t15;
122 | mat[0] = Hl0*t48+Hl1*(t18*t15)-Hl2*(t23*t15);
123 | mat[1] = Hl0*t49+Hl1*(t31*t15)-Hl2*(t35*t15);
124 | mat[2] = -Hl0*t50-Hl1*(t44*t15)+Hl2*(t47*t15);
125 | mat[3] = Hl3*t48+Hl4*(t18*t15)-Hl5*(t23*t15);
126 | mat[4] = Hl3*t49+Hl4*(t31*t15)-Hl5*(t35*t15);
127 | mat[5] = -Hl3*t50-Hl4*(t44*t15)+Hl5*(t47*t15);
128 | mat[6] = Hl6*t48+Hl7*(t18*t15)-t23*t15;
129 | mat[7] = Hl6*t49+Hl7*(t31*t15)-t35*t15;
130 | mat[8] = -Hl6*t50-Hl7*(t44*t15)+t47*t15;
131 | },
132 |
133 | invert_affine_transform: function(src, dst) {
134 | var m11 = src[0], m12 = src[1], m13 = src[2];
135 | var m21 = src[3], m22 = src[4], m23 = src[5];
136 |
137 | var det = 1.0 / (m11 * m22 - m12 * m21);
138 |
139 | dst[0] = det * m22;
140 | dst[1] = det * -m12;
141 | dst[2] = det * (m12*m23 - m13*m22);
142 |
143 | dst[3] = det * -m21;
144 | dst[4] = det * m11;
145 | dst[5] = det * (m13*m21 - m11*m23);
146 | },
147 |
148 | invert_perspective_transform: function(src, dst) {
149 | var m11 = src[0], m12 = src[1], m13 = src[2];
150 | var m21 = src[3], m22 = src[4], m23 = src[5];
151 | var m31 = src[6], m32 = src[7], m33 = src[8];
152 |
153 | var det = 1.0 / (m11 * (m22*m33 - m23*m32) - m12 * (m21*m33 - m23*m31) + m13 * (m21*m32 - m22*m31));
154 |
155 | dst[0] = det * (m22*m33 - m23*m32);
156 | dst[1] = det * (m13*m32 - m12*m33);
157 | dst[2] = det * (m12*m23 - m13*m22);
158 |
159 | dst[3] = det * (m23*m31 - m21*m33);
160 | dst[4] = det * (m11*m33 - m13*m31);
161 | dst[5] = det * (m13*m21 - m11*m23);
162 |
163 | dst[6] = det * (m21*m32 - m22*m31);
164 | dst[7] = det * (m12*m31 - m11*m32);
165 | dst[8] = det * (m11*m22 - m12*m21);
166 | }
167 | };
168 | })();
169 |
170 | global.transform = transform;
171 |
172 | })(jsfeat);
--------------------------------------------------------------------------------
/src/jsfeat_yape.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | *
4 | * Copyright 2007 Computer Vision Lab,
5 | * Ecole Polytechnique Federale de Lausanne (EPFL), Switzerland.
6 | */
7 |
8 | (function(global) {
9 | "use strict";
10 | //
11 |
12 | var yape = (function() {
13 |
14 | var precompute_directions = function(step, dirs, R) {
15 | var i = 0;
16 | var x, y;
17 |
18 | x = R;
19 | for(y = 0; y < x; y++, i++)
20 | {
21 | x = (Math.sqrt((R * R - y * y)) + 0.5)|0;
22 | dirs[i] = (x + step * y);
23 | }
24 | for(x-- ; x < y && x >= 0; x--, i++)
25 | {
26 | y = (Math.sqrt((R * R - x * x)) + 0.5)|0;
27 | dirs[i] = (x + step * y);
28 | }
29 | for( ; -x < y; x--, i++)
30 | {
31 | y = (Math.sqrt((R * R - x * x)) + 0.5)|0;
32 | dirs[i] = (x + step * y);
33 | }
34 | for(y-- ; y >= 0; y--, i++)
35 | {
36 | x = (-Math.sqrt((R * R - y * y)) - 0.5)|0;
37 | dirs[i] = (x + step * y);
38 | }
39 | for(; y > x; y--, i++)
40 | {
41 | x = (-Math.sqrt((R * R - y * y)) - 0.5)|0;
42 | dirs[i] = (x + step * y);
43 | }
44 | for(x++ ; x <= 0; x++, i++)
45 | {
46 | y = (-Math.sqrt((R * R - x * x)) - 0.5)|0;
47 | dirs[i] = (x + step * y);
48 | }
49 | for( ; x < -y; x++, i++)
50 | {
51 | y = (-Math.sqrt((R * R - x * x)) - 0.5)|0;
52 | dirs[i] = (x + step * y);
53 | }
54 | for(y++ ; y < 0; y++, i++)
55 | {
56 | x = (Math.sqrt((R * R - y * y)) + 0.5)|0;
57 | dirs[i] = (x + step * y);
58 | }
59 |
60 | dirs[i] = dirs[0];
61 | dirs[i + 1] = dirs[1];
62 | return i;
63 | }
64 |
65 | var third_check = function (Sb, off, step) {
66 | var n = 0;
67 | if(Sb[off+1] != 0) n++;
68 | if(Sb[off-1] != 0) n++;
69 | if(Sb[off+step] != 0) n++;
70 | if(Sb[off+step+1] != 0) n++;
71 | if(Sb[off+step-1] != 0) n++;
72 | if(Sb[off-step] != 0) n++;
73 | if(Sb[off-step+1] != 0) n++;
74 | if(Sb[off-step-1] != 0) n++;
75 |
76 | return n;
77 | }
78 |
79 | var is_local_maxima = function(p, off, v, step, neighborhood) {
80 | var x, y;
81 |
82 | if (v > 0) {
83 | off -= step*neighborhood;
84 | for (y= -neighborhood; y<=neighborhood; ++y) {
85 | for (x= -neighborhood; x<=neighborhood; ++x) {
86 | if (p[off+x] > v) return false;
87 | }
88 | off += step;
89 | }
90 | } else {
91 | off -= step*neighborhood;
92 | for (y= -neighborhood; y<=neighborhood; ++y) {
93 | for (x= -neighborhood; x<=neighborhood; ++x) {
94 | if (p[off+x] < v) return false;
95 | }
96 | off += step;
97 | }
98 | }
99 | return true;
100 | }
101 |
102 | var perform_one_point = function(I, x, Scores, Im, Ip, dirs, opposite, dirs_nb) {
103 | var score = 0;
104 | var a = 0, b = (opposite - 1)|0;
105 | var A=0, B0=0, B1=0, B2=0;
106 | var state=0;
107 |
108 | // WE KNOW THAT NOT(A ~ I0 & B1 ~ I0):
109 | A = I[x+dirs[a]];
110 | if ((A <= Ip)) {
111 | if ((A >= Im)) { // A ~ I0
112 | B0 = I[x+dirs[b]];
113 | if ((B0 <= Ip)) {
114 | if ((B0 >= Im)) { Scores[x] = 0; return; }
115 | else {
116 | b++; B1 = I[x+dirs[b]];
117 | if ((B1 > Ip)) {
118 | b++; B2 = I[x+dirs[b]];
119 | if ((B2 > Ip)) state = 3;
120 | else if ((B2 < Im)) state = 6;
121 | else { Scores[x] = 0; return; } // A ~ I0, B2 ~ I0
122 | }
123 | else/* if ((B1 < Im))*/ {
124 | b++; B2 = I[x+dirs[b]];
125 | if ((B2 > Ip)) state = 7;
126 | else if ((B2 < Im)) state = 2;
127 | else { Scores[x] = 0; return; } // A ~ I0, B2 ~ I0
128 | }
129 | //else { Scores[x] = 0; return; } // A ~ I0, B1 ~ I0
130 | }
131 | }
132 | else { // B0 < I0
133 | b++; B1 = I[x+dirs[b]];
134 | if ((B1 > Ip)) {
135 | b++; B2 = I[x+dirs[b]];
136 | if ((B2 > Ip)) state = 3;
137 | else if ((B2 < Im)) state = 6;
138 | else { Scores[x] = 0; return; } // A ~ I0, B2 ~ I0
139 | }
140 | else if ((B1 < Im)) {
141 | b++; B2 = I[x+dirs[b]];
142 | if ((B2 > Ip)) state = 7;
143 | else if ((B2 < Im)) state = 2;
144 | else { Scores[x] = 0; return; } // A ~ I0, B2 ~ I0
145 | }
146 | else { Scores[x] = 0; return; } // A ~ I0, B1 ~ I0
147 | }
148 | }
149 | else { // A > I0
150 | B0 = I[x+dirs[b]];
151 | if ((B0 > Ip)) { Scores[x] = 0; return; }
152 | b++; B1 = I[x+dirs[b]];
153 | if ((B1 > Ip)) { Scores[x] = 0; return; }
154 | b++; B2 = I[x+dirs[b]];
155 | if ((B2 > Ip)) { Scores[x] = 0; return; }
156 | state = 1;
157 | }
158 | }
159 | else // A < I0
160 | {
161 | B0 = I[x+dirs[b]];
162 | if ((B0 < Im)) { Scores[x] = 0; return; }
163 | b++; B1 = I[x+dirs[b]];
164 | if ((B1 < Im)) { Scores[x] = 0; return; }
165 | b++; B2 = I[x+dirs[b]];
166 | if ((B2 < Im)) { Scores[x] = 0; return; }
167 | state = 0;
168 | }
169 |
170 | for(a = 1; a <= opposite; a++)
171 | {
172 | A = I[x+dirs[a]];
173 |
174 | switch(state)
175 | {
176 | case 0:
177 | if ((A > Ip)) {
178 | B1 = B2; b++; B2 = I[x+dirs[b]];
179 | if ((B2 < Im)) { Scores[x] = 0; return; }
180 | { score -= A + B1; state = 0; break; };
181 | }
182 | if ((A < Im)) {
183 | if ((B1 > Ip)) { Scores[x] = 0; return; }
184 | if ((B2 > Ip)) { Scores[x] = 0; return; }
185 | B1 = B2; b++; B2 = I[x+dirs[b]];
186 | if ((B2 > Ip)) { Scores[x] = 0; return; }
187 | { score -= A + B1; state = 8; break; };
188 | }
189 | // A ~ I0
190 | if ((B1 <= Ip)) { Scores[x] = 0; return; }
191 | if ((B2 <= Ip)) { Scores[x] = 0; return; }
192 | B1 = B2; b++; B2 = I[x+dirs[b]];
193 | if ((B2 > Ip)) { score -= A + B1; state = 3; break; };
194 | if ((B2 < Im)) { score -= A + B1; state = 6; break; };
195 | { Scores[x] = 0; return; }
196 |
197 | case 1:
198 | if ((A < Im)) {
199 | B1 = B2; b++; B2 = I[x+dirs[b]];
200 | if ((B2 > Ip)) { Scores[x] = 0; return; }
201 | { score -= A + B1; state = 1; break; };
202 | }
203 | if ((A > Ip)) {
204 | if ((B1 < Im)) { Scores[x] = 0; return; }
205 | if ((B2 < Im)) { Scores[x] = 0; return; }
206 | B1 = B2; b++; B2 = I[x+dirs[b]];
207 | if ((B2 < Im)) { Scores[x] = 0; return; }
208 | { score -= A + B1; state = 9; break; };
209 | }
210 | // A ~ I0
211 | if ((B1 >= Im)) { Scores[x] = 0; return; }
212 | if ((B2 >= Im)) { Scores[x] = 0; return; }
213 | B1 = B2; b++; B2 = I[x+dirs[b]];
214 | if ((B2 < Im)) { score -= A + B1; state = 2; break; };
215 | if ((B2 > Ip)) { score -= A + B1; state = 7; break; };
216 | { Scores[x] = 0; return; }
217 |
218 | case 2:
219 | if ((A > Ip)) { Scores[x] = 0; return; }
220 | B1 = B2; b++; B2 = I[x+dirs[b]];
221 | if ((A < Im))
222 | {
223 | if ((B2 > Ip)) { Scores[x] = 0; return; }
224 | { score -= A + B1; state = 4; break; };
225 | }
226 | // A ~ I0
227 | if ((B2 > Ip)) { score -= A + B1; state = 7; break; };
228 | if ((B2 < Im)) { score -= A + B1; state = 2; break; };
229 | { Scores[x] = 0; return; } // A ~ I0, B2 ~ I0
230 |
231 | case 3:
232 | if ((A < Im)) { Scores[x] = 0; return; }
233 | B1 = B2; b++; B2 = I[x+dirs[b]];
234 | if ((A > Ip)) {
235 | if ((B2 < Im)) { Scores[x] = 0; return; }
236 | { score -= A + B1; state = 5; break; };
237 | }
238 | // A ~ I0
239 | if ((B2 > Ip)) { score -= A + B1; state = 3; break; };
240 | if ((B2 < Im)) { score -= A + B1; state = 6; break; };
241 | { Scores[x] = 0; return; }
242 |
243 | case 4:
244 | if ((A > Ip)) { Scores[x] = 0; return; }
245 | if ((A < Im)) {
246 | B1 = B2; b++; B2 = I[x+dirs[b]];
247 | if ((B2 > Ip)) { Scores[x] = 0; return; }
248 | { score -= A + B1; state = 1; break; };
249 | }
250 | if ((B2 >= Im)) { Scores[x] = 0; return; }
251 | B1 = B2; b++; B2 = I[x+dirs[b]];
252 | if ((B2 < Im)) { score -= A + B1; state = 2; break; };
253 | if ((B2 > Ip)) { score -= A + B1; state = 7; break; };
254 | { Scores[x] = 0; return; }
255 |
256 | case 5:
257 | if ((A < Im)) { Scores[x] = 0; return; }
258 | if ((A > Ip)) {
259 | B1 = B2; b++; B2 = I[x+dirs[b]];
260 | if ((B2 < Im)) { Scores[x] = 0; return; }
261 | { score -= A + B1; state = 0; break; };
262 | }
263 | // A ~ I0
264 | if ((B2 <= Ip)) { Scores[x] = 0; return; }
265 | B1 = B2; b++; B2 = I[x+dirs[b]];
266 | if ((B2 > Ip)) { score -= A + B1; state = 3; break; };
267 | if ((B2 < Im)) { score -= A + B1; state = 6; break; };
268 | { Scores[x] = 0; return; }
269 |
270 | case 7:
271 | if ((A > Ip)) { Scores[x] = 0; return; }
272 | if ((A < Im)) { Scores[x] = 0; return; }
273 | B1 = B2; b++; B2 = I[x+dirs[b]];
274 | // A ~ I0
275 | if ((B2 > Ip)) { score -= A + B1; state = 3; break; };
276 | if ((B2 < Im)) { score -= A + B1; state = 6; break; };
277 | { Scores[x] = 0; return; } // A ~ I0, B2 ~ I0
278 |
279 | case 6:
280 | if ((A > Ip)) { Scores[x] = 0; return; }
281 | if ((A < Im)) { Scores[x] = 0; return; }
282 | B1 = B2; b++; B2 = I[x+dirs[b]];
283 | // A ~ I0
284 | if ((B2 < Im)) { score -= A + B1; state = 2; break; };
285 | if ((B2 > Ip)) { score -= A + B1; state = 7; break; };
286 | { Scores[x] = 0; return; } // A ~ I0, B2 ~ I0
287 |
288 | case 8:
289 | if ((A > Ip)) {
290 | if ((B2 < Im)) { Scores[x] = 0; return; }
291 | B1 = B2; b++; B2 = I[x+dirs[b]];
292 | if ((B2 < Im)) { Scores[x] = 0; return; }
293 | { score -= A + B1; state = 9; break; };
294 | }
295 | if ((A < Im)) {
296 | B1 = B2; b++; B2 = I[x+dirs[b]];
297 | if ((B2 > Ip)) { Scores[x] = 0; return; }
298 | { score -= A + B1; state = 1; break; };
299 | }
300 | { Scores[x] = 0; return; }
301 |
302 | case 9:
303 | if ((A < Im)) {
304 | if ((B2 > Ip)) { Scores[x] = 0; return; }
305 | B1 = B2; b++; B2 = I[x+dirs[b]];
306 | if ((B2 > Ip)) { Scores[x] = 0; return; }
307 | { score -= A + B1; state = 8; break; };
308 | }
309 | if ((A > Ip)) {
310 | B1 = B2; b++; B2 = I[x+dirs[b]];
311 | if ((B2 < Im)) { Scores[x] = 0; return; }
312 | { score -= A + B1; state = 0; break; };
313 | }
314 | { Scores[x] = 0; return; }
315 |
316 | default:
317 | //"PB default";
318 | break;
319 | } // switch(state)
320 | } // for(a...)
321 |
322 | Scores[x] = (score + dirs_nb * I[x]);
323 | }
324 |
325 | var lev_table_t = (function () {
326 | function lev_table_t(w, h, r) {
327 | this.dirs = new Int32Array(1024);
328 | this.dirs_count = precompute_directions(w, this.dirs, r)|0;
329 | this.scores = new Int32Array(w*h);
330 | this.radius = r|0;
331 | }
332 | return lev_table_t;
333 | })();
334 |
335 | return {
336 |
337 | level_tables: [],
338 | tau: 7,
339 |
340 | init: function(width, height, radius, pyramid_levels) {
341 | if (typeof pyramid_levels === "undefined") { pyramid_levels = 1; }
342 | var i;
343 | radius = Math.min(radius, 7);
344 | radius = Math.max(radius, 3);
345 | for(i = 0; i < pyramid_levels; ++i) {
346 | this.level_tables[i] = new lev_table_t(width>>i, height>>i, radius);
347 | }
348 | },
349 |
350 | detect: function(src, points, border) {
351 | if (typeof border === "undefined") { border = 4; }
352 | var t = this.level_tables[0];
353 | var R = t.radius|0, Rm1 = (R-1)|0;
354 | var dirs = t.dirs;
355 | var dirs_count = t.dirs_count|0;
356 | var opposite = dirs_count >> 1;
357 | var img = src.data, w=src.cols|0, h=src.rows|0,hw=w>>1;
358 | var scores = t.scores;
359 | var x=0,y=0,row=0,rowx=0,ip=0,im=0,abs_score=0, score=0;
360 | var tau = this.tau|0;
361 | var number_of_points = 0, pt;
362 |
363 | var sx = Math.max(R+1, border)|0;
364 | var sy = Math.max(R+1, border)|0;
365 | var ex = Math.min(w-R-2, w-border)|0;
366 | var ey = Math.min(h-R-2, h-border)|0;
367 |
368 | row = (sy*w+sx)|0;
369 | for(y = sy; y < ey; ++y, row+=w) {
370 | for(x = sx, rowx = row; x < ex; ++x, ++rowx) {
371 | ip = img[rowx] + tau, im = img[rowx] - tau;
372 |
373 | if (im
= 3 && is_local_maxima(scores, rowx, score, hw, R)) {
392 | pt = points[number_of_points];
393 | pt.x = x, pt.y = y, pt.score = abs_score;
394 | ++number_of_points;
395 |
396 | x += Rm1, rowx += Rm1;
397 | }
398 | }
399 | }
400 | }
401 |
402 | return number_of_points;
403 | }
404 | };
405 |
406 | })();
407 |
408 | global.yape = yape;
409 |
410 | })(jsfeat);
--------------------------------------------------------------------------------
/src/jsfeat_yape06.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Eugene Zatepyakin / http://inspirit.ru/
3 | *
4 | * Copyright 2007 Computer Vision Lab,
5 | * Ecole Polytechnique Federale de Lausanne (EPFL), Switzerland.
6 | * @author Vincent Lepetit (http://cvlab.epfl.ch/~lepetit)
7 | */
8 |
9 | (function(global) {
10 | "use strict";
11 | //
12 |
13 | var yape06 = (function() {
14 |
15 | var compute_laplacian = function(src, dst, w, h, Dxx, Dyy, sx,sy, ex,ey) {
16 | var y=0,x=0,yrow=(sy*w+sx)|0,row=yrow;
17 |
18 | for(y = sy; y < ey; ++y, yrow+=w, row = yrow) {
19 | for(x = sx; x < ex; ++x, ++row) {
20 | dst[row] = -4 * src[row] + src[row+Dxx] + src[row-Dxx] + src[row+Dyy] + src[row-Dyy];
21 | }
22 | }
23 | }
24 |
25 | var hessian_min_eigen_value = function(src, off, tr, Dxx, Dyy, Dxy, Dyx) {
26 | var Ixx = -2 * src[off] + src[off + Dxx] + src[off - Dxx];
27 | var Iyy = -2 * src[off] + src[off + Dyy] + src[off - Dyy];
28 | var Ixy = src[off + Dxy] + src[off - Dxy] - src[off + Dyx] - src[off - Dyx];
29 | var sqrt_delta = ( Math.sqrt(((Ixx - Iyy) * (Ixx - Iyy) + 4 * Ixy * Ixy) ) )|0;
30 |
31 | return Math.min(Math.abs(tr - sqrt_delta), Math.abs(-(tr + sqrt_delta)));
32 | }
33 |
34 | return {
35 |
36 | laplacian_threshold: 30,
37 | min_eigen_value_threshold: 25,
38 |
39 | detect: function(src, points, border) {
40 | if (typeof border === "undefined") { border = 5; }
41 | var x=0,y=0;
42 | var w=src.cols, h=src.rows, srd_d=src.data;
43 | var Dxx = 5, Dyy = (5 * w)|0;
44 | var Dxy = (3 + 3 * w)|0, Dyx = (3 - 3 * w)|0;
45 | var lap_buf = jsfeat.cache.get_buffer((w*h)<<2);
46 | var laplacian = lap_buf.i32;
47 | var lv=0, row=0,rowx=0,min_eigen_value=0,pt;
48 | var number_of_points = 0;
49 | var lap_thresh = this.laplacian_threshold;
50 | var eigen_thresh = this.min_eigen_value_threshold;
51 |
52 | var sx = Math.max(5, border)|0;
53 | var sy = Math.max(3, border)|0;
54 | var ex = Math.min(w-5, w-border)|0;
55 | var ey = Math.min(h-3, h-border)|0;
56 |
57 | x = w*h;
58 | while(--x>=0) {laplacian[x]=0;}
59 | compute_laplacian(srd_d, laplacian, w, h, Dxx, Dyy, sx,sy, ex,ey);
60 |
61 | row = (sy*w+sx)|0;
62 | for(y = sy; y < ey; ++y, row += w) {
63 | for(x = sx, rowx=row; x < ex; ++x, ++rowx) {
64 |
65 | lv = laplacian[rowx];
66 | if ((lv < -lap_thresh &&
67 | lv < laplacian[rowx - 1] && lv < laplacian[rowx + 1] &&
68 | lv < laplacian[rowx - w] && lv < laplacian[rowx + w] &&
69 | lv < laplacian[rowx - w - 1] && lv < laplacian[rowx + w - 1] &&
70 | lv < laplacian[rowx - w + 1] && lv < laplacian[rowx + w + 1])
71 | ||
72 | (lv > lap_thresh &&
73 | lv > laplacian[rowx - 1] && lv > laplacian[rowx + 1] &&
74 | lv > laplacian[rowx - w] && lv > laplacian[rowx + w] &&
75 | lv > laplacian[rowx - w - 1] && lv > laplacian[rowx + w - 1] &&
76 | lv > laplacian[rowx - w + 1] && lv > laplacian[rowx + w + 1])
77 | ) {
78 |
79 | min_eigen_value = hessian_min_eigen_value(srd_d, rowx, lv, Dxx, Dyy, Dxy, Dyx);
80 | if (min_eigen_value > eigen_thresh) {
81 | pt = points[number_of_points];
82 | pt.x = x, pt.y = y, pt.score = min_eigen_value;
83 | ++number_of_points;
84 | ++x, ++rowx; // skip next pixel since this is maxima in 3x3
85 | }
86 | }
87 | }
88 | }
89 |
90 | jsfeat.cache.put_buffer(lap_buf);
91 |
92 | return number_of_points;
93 | }
94 |
95 | };
96 | })();
97 |
98 | global.yape06 = yape06;
99 |
100 | })(jsfeat);
101 |
--------------------------------------------------------------------------------