| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111 | 
							- /**
 
-  * tracking - A modern approach for Computer Vision on the web.
 
-  * @author Eduardo Lundgren <edu@rdo.io>
 
-  * @version v1.1.3
 
-  * @link http://trackingjs.com
 
-  * @license BSD
 
-  */
 
- (function(window, undefined) {
 
-   window.tracking = window.tracking || {};
 
-   /**
 
-    * Inherit the prototype methods from one constructor into another.
 
-    *
 
-    * Usage:
 
-    * <pre>
 
-    * function ParentClass(a, b) { }
 
-    * ParentClass.prototype.foo = function(a) { }
 
-    *
 
-    * function ChildClass(a, b, c) {
 
-    *   tracking.base(this, a, b);
 
-    * }
 
-    * tracking.inherits(ChildClass, ParentClass);
 
-    *
 
-    * var child = new ChildClass('a', 'b', 'c');
 
-    * child.foo();
 
-    * </pre>
 
-    *
 
-    * @param {Function} childCtor Child class.
 
-    * @param {Function} parentCtor Parent class.
 
-    */
 
-   tracking.inherits = function(childCtor, parentCtor) {
 
-     function TempCtor() {
 
-     }
 
-     TempCtor.prototype = parentCtor.prototype;
 
-     childCtor.superClass_ = parentCtor.prototype;
 
-     childCtor.prototype = new TempCtor();
 
-     childCtor.prototype.constructor = childCtor;
 
-     /**
 
-      * Calls superclass constructor/method.
 
-      *
 
-      * This function is only available if you use tracking.inherits to express
 
-      * inheritance relationships between classes.
 
-      *
 
-      * @param {!object} me Should always be "this".
 
-      * @param {string} methodName The method name to call. Calling superclass
 
-      *     constructor can be done with the special string 'constructor'.
 
-      * @param {...*} var_args The arguments to pass to superclass
 
-      *     method/constructor.
 
-      * @return {*} The return value of the superclass method/constructor.
 
-      */
 
-     childCtor.base = function(me, methodName) {
 
-       var args = Array.prototype.slice.call(arguments, 2);
 
-       return parentCtor.prototype[methodName].apply(me, args);
 
-     };
 
-   };
 
-   /**
 
-    * Captures the user camera when tracking a video element and set its source
 
-    * to the camera stream.
 
-    * @param {HTMLVideoElement} element Canvas element to track.
 
-    * @param {object} opt_options Optional configuration to the tracker.
 
-    */
 
-   tracking.initUserMedia_ = function(element, opt_options) {
 
-     window.navigator.mediaDevices.getUserMedia({
 
-       video: true,
 
-       audio: (opt_options && opt_options.audio) ? true : false,
 
-     }).then(function(stream) {
 
-       element.srcObject = stream;
 
-     }).catch(function(err) {
 
-       throw Error('Cannot capture user camera.');
 
-     });
 
-   };
 
-   /**
 
-    * Tests whether the object is a dom node.
 
-    * @param {object} o Object to be tested.
 
-    * @return {boolean} True if the object is a dom node.
 
-    */
 
-   tracking.isNode = function(o) {
 
-     return o.nodeType || this.isWindow(o);
 
-   };
 
-   /**
 
-    * Tests whether the object is the `window` object.
 
-    * @param {object} o Object to be tested.
 
-    * @return {boolean} True if the object is the `window` object.
 
-    */
 
-   tracking.isWindow = function(o) {
 
-     return !!(o && o.alert && o.document);
 
-   };
 
-   /**
 
-    * Selects a dom node from a CSS3 selector using `document.querySelector`.
 
-    * @param {string} selector
 
-    * @param {object} opt_element The root element for the query. When not
 
-    *     specified `document` is used as root element.
 
-    * @return {HTMLElement} The first dom element that matches to the selector.
 
-    *     If not found, returns `null`.
 
-    */
 
-   tracking.one = function(selector, opt_element) {
 
-     if (this.isNode(selector)) {
 
-       return selector;
 
-     }
 
-     return (opt_element || document).querySelector(selector);
 
-   };
 
-   /**
 
-    * Tracks a canvas, image or video element based on the specified `tracker`
 
-    * instance. This method extract the pixel information of the input element
 
-    * to pass to the `tracker` instance. When tracking a video, the
 
-    * `tracker.track(pixels, width, height)` will be in a
 
-    * `requestAnimationFrame` loop in order to track all video frames.
 
-    *
 
-    * Example:
 
-    * var tracker = new tracking.ColorTracker();
 
-    *
 
-    * tracking.track('#video', tracker);
 
-    * or
 
-    * tracking.track('#video', tracker, { camera: true });
 
-    *
 
-    * tracker.on('track', function(event) {
 
-    *   // console.log(event.data[0].x, event.data[0].y)
 
-    * });
 
-    *
 
-    * @param {HTMLElement} element The element to track, canvas, image or
 
-    *     video.
 
-    * @param {tracking.Tracker} tracker The tracker instance used to track the
 
-    *     element.
 
-    * @param {object} opt_options Optional configuration to the tracker.
 
-    */
 
-   tracking.track = function(element, tracker, opt_options) {
 
-     element = tracking.one(element);
 
-     if (!element) {
 
-       throw new Error('Element not found, try a different element or selector.');
 
-     }
 
-     if (!tracker) {
 
-       throw new Error('Tracker not specified, try `tracking.track(element, new tracking.FaceTracker())`.');
 
-     }
 
-     switch (element.nodeName.toLowerCase()) {
 
-       case 'canvas':
 
-         return this.trackCanvas_(element, tracker, opt_options);
 
-       case 'img':
 
-         return this.trackImg_(element, tracker, opt_options);
 
-       case 'video':
 
-         if (opt_options) {
 
-           if (opt_options.camera) {
 
-             this.initUserMedia_(element, opt_options);
 
-           }
 
-         }
 
-         return this.trackVideo_(element, tracker, opt_options);
 
-       default:
 
-         throw new Error('Element not supported, try in a canvas, img, or video.');
 
-     }
 
-   };
 
-   /**
 
-    * Tracks a canvas element based on the specified `tracker` instance and
 
-    * returns a `TrackerTask` for this track.
 
-    * @param {HTMLCanvasElement} element Canvas element to track.
 
-    * @param {tracking.Tracker} tracker The tracker instance used to track the
 
-    *     element.
 
-    * @param {object} opt_options Optional configuration to the tracker.
 
-    * @return {tracking.TrackerTask}
 
-    * @private
 
-    */
 
-   tracking.trackCanvas_ = function(element, tracker) {
 
-     var self = this;
 
-     var task = new tracking.TrackerTask(tracker);
 
-     task.on('run', function() {
 
-       self.trackCanvasInternal_(element, tracker);
 
-     });
 
-     return task.run();
 
-   };
 
-   /**
 
-    * Tracks a canvas element based on the specified `tracker` instance. This
 
-    * method extract the pixel information of the input element to pass to the
 
-    * `tracker` instance.
 
-    * @param {HTMLCanvasElement} element Canvas element to track.
 
-    * @param {tracking.Tracker} tracker The tracker instance used to track the
 
-    *     element.
 
-    * @param {object} opt_options Optional configuration to the tracker.
 
-    * @private
 
-    */
 
-   tracking.trackCanvasInternal_ = function(element, tracker) {
 
-     var width = element.width;
 
-     var height = element.height;
 
-     var context = element.getContext('2d');
 
-     var imageData = context.getImageData(0, 0, width, height);
 
-     tracker.track(imageData.data, width, height);
 
-   };
 
-   /**
 
-    * Tracks a image element based on the specified `tracker` instance. This
 
-    * method extract the pixel information of the input element to pass to the
 
-    * `tracker` instance.
 
-    * @param {HTMLImageElement} element Canvas element to track.
 
-    * @param {tracking.Tracker} tracker The tracker instance used to track the
 
-    *     element.
 
-    * @param {object} opt_options Optional configuration to the tracker.
 
-    * @private
 
-    */
 
-   tracking.trackImg_ = function(element, tracker) {
 
-     var width = element.width;
 
-     var height = element.height;
 
-     var canvas = document.createElement('canvas');
 
-     canvas.width = width;
 
-     canvas.height = height;
 
-     var task = new tracking.TrackerTask(tracker);
 
-     task.on('run', function() {
 
-       tracking.Canvas.loadImage(canvas, element.src, 0, 0, width, height, function() {
 
-         tracking.trackCanvasInternal_(canvas, tracker);
 
-       });
 
-     });
 
-     return task.run();
 
-   };
 
-   /**
 
-    * Tracks a video element based on the specified `tracker` instance. This
 
-    * method extract the pixel information of the input element to pass to the
 
-    * `tracker` instance. The `tracker.track(pixels, width, height)` will be in
 
-    * a `requestAnimationFrame` loop in order to track all video frames.
 
-    * @param {HTMLVideoElement} element Canvas element to track.
 
-    * @param {tracking.Tracker} tracker The tracker instance used to track the
 
-    *     element.
 
-    * @param {object} opt_options Optional configuration to the tracker.
 
-    * @private
 
-    */
 
-   tracking.trackVideo_ = function(element, tracker) {
 
-     var canvas = document.createElement('canvas');
 
-     var context = canvas.getContext('2d');
 
-     var width;
 
-     var height;
 
-     var resizeCanvas_ = function() {
 
-       width = element.offsetWidth;
 
-       height = element.offsetHeight;
 
-       canvas.width = width;
 
-       canvas.height = height;
 
-     };
 
-     resizeCanvas_();
 
-     element.addEventListener('resize', resizeCanvas_);
 
-     var requestId;
 
-     var requestAnimationFrame_ = function() {
 
-       requestId = window.requestAnimationFrame(function() {
 
-         if (element.readyState === element.HAVE_ENOUGH_DATA) {
 
-           try {
 
-             // Firefox v~30.0 gets confused with the video readyState firing an
 
-             // erroneous HAVE_ENOUGH_DATA just before HAVE_CURRENT_DATA state,
 
-             // hence keep trying to read it until resolved.
 
-             context.drawImage(element, 0, 0, width, height);
 
-           } catch (err) {}
 
-           tracking.trackCanvasInternal_(canvas, tracker);
 
-         }
 
-         requestAnimationFrame_();
 
-       });
 
-     };
 
-     var task = new tracking.TrackerTask(tracker);
 
-     task.on('stop', function() {
 
-       window.cancelAnimationFrame(requestId);
 
-     });
 
-     task.on('run', function() {
 
-       requestAnimationFrame_();
 
-     });
 
-     return task.run();
 
-   };
 
-   // Browser polyfills
 
-   //===================
 
-   if (!window.URL) {
 
-     window.URL = window.URL || window.webkitURL || window.msURL || window.oURL;
 
-   }
 
-   if (!navigator.getUserMedia) {
 
-     navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia ||
 
-     navigator.mozGetUserMedia || navigator.msGetUserMedia;
 
-   }
 
- }(window));
 
- (function() {
 
-   /**
 
-    * EventEmitter utility.
 
-    * @constructor
 
-    */
 
-   tracking.EventEmitter = function() {};
 
-   /**
 
-    * Holds event listeners scoped by event type.
 
-    * @type {object}
 
-    * @private
 
-    */
 
-   tracking.EventEmitter.prototype.events_ = null;
 
-   /**
 
-    * Adds a listener to the end of the listeners array for the specified event.
 
-    * @param {string} event
 
-    * @param {function} listener
 
-    * @return {object} Returns emitter, so calls can be chained.
 
-    */
 
-   tracking.EventEmitter.prototype.addListener = function(event, listener) {
 
-     if (typeof listener !== 'function') {
 
-       throw new TypeError('Listener must be a function');
 
-     }
 
-     if (!this.events_) {
 
-       this.events_ = {};
 
-     }
 
-     this.emit('newListener', event, listener);
 
-     if (!this.events_[event]) {
 
-       this.events_[event] = [];
 
-     }
 
-     this.events_[event].push(listener);
 
-     return this;
 
-   };
 
-   /**
 
-    * Returns an array of listeners for the specified event.
 
-    * @param {string} event
 
-    * @return {array} Array of listeners.
 
-    */
 
-   tracking.EventEmitter.prototype.listeners = function(event) {
 
-     return this.events_ && this.events_[event];
 
-   };
 
-   /**
 
-    * Execute each of the listeners in order with the supplied arguments.
 
-    * @param {string} event
 
-    * @param {*} opt_args [arg1], [arg2], [...]
 
-    * @return {boolean} Returns true if event had listeners, false otherwise.
 
-    */
 
-   tracking.EventEmitter.prototype.emit = function(event) {
 
-     var listeners = this.listeners(event);
 
-     if (listeners) {
 
-       var args = Array.prototype.slice.call(arguments, 1);
 
-       for (var i = 0; i < listeners.length; i++) {
 
-         if (listeners[i]) {
 
-           listeners[i].apply(this, args);
 
-         }
 
-       }
 
-       return true;
 
-     }
 
-     return false;
 
-   };
 
-   /**
 
-    * Adds a listener to the end of the listeners array for the specified event.
 
-    * @param {string} event
 
-    * @param {function} listener
 
-    * @return {object} Returns emitter, so calls can be chained.
 
-    */
 
-   tracking.EventEmitter.prototype.on = tracking.EventEmitter.prototype.addListener;
 
-   /**
 
-    * Adds a one time listener for the event. This listener is invoked only the
 
-    * next time the event is fired, after which it is removed.
 
-    * @param {string} event
 
-    * @param {function} listener
 
-    * @return {object} Returns emitter, so calls can be chained.
 
-    */
 
-   tracking.EventEmitter.prototype.once = function(event, listener) {
 
-     var self = this;
 
-     self.on(event, function handlerInternal() {
 
-       self.removeListener(event, handlerInternal);
 
-       listener.apply(this, arguments);
 
-     });
 
-   };
 
-   /**
 
-    * Removes all listeners, or those of the specified event. It's not a good
 
-    * idea to remove listeners that were added elsewhere in the code,
 
-    * especially when it's on an emitter that you didn't create.
 
-    * @param {string} event
 
-    * @return {object} Returns emitter, so calls can be chained.
 
-    */
 
-   tracking.EventEmitter.prototype.removeAllListeners = function(opt_event) {
 
-     if (!this.events_) {
 
-       return this;
 
-     }
 
-     if (opt_event) {
 
-       delete this.events_[opt_event];
 
-     } else {
 
-       delete this.events_;
 
-     }
 
-     return this;
 
-   };
 
-   /**
 
-    * Remove a listener from the listener array for the specified event.
 
-    * Caution: changes array indices in the listener array behind the listener.
 
-    * @param {string} event
 
-    * @param {function} listener
 
-    * @return {object} Returns emitter, so calls can be chained.
 
-    */
 
-   tracking.EventEmitter.prototype.removeListener = function(event, listener) {
 
-     if (typeof listener !== 'function') {
 
-       throw new TypeError('Listener must be a function');
 
-     }
 
-     if (!this.events_) {
 
-       return this;
 
-     }
 
-     var listeners = this.listeners(event);
 
-     if (Array.isArray(listeners)) {
 
-       var i = listeners.indexOf(listener);
 
-       if (i < 0) {
 
-         return this;
 
-       }
 
-       listeners.splice(i, 1);
 
-     }
 
-     return this;
 
-   };
 
-   /**
 
-    * By default EventEmitters will print a warning if more than 10 listeners
 
-    * are added for a particular event. This is a useful default which helps
 
-    * finding memory leaks. Obviously not all Emitters should be limited to 10.
 
-    * This function allows that to be increased. Set to zero for unlimited.
 
-    * @param {number} n The maximum number of listeners.
 
-    */
 
-   tracking.EventEmitter.prototype.setMaxListeners = function() {
 
-     throw new Error('Not implemented');
 
-   };
 
- }());
 
- (function() {
 
-   /**
 
-    * Canvas utility.
 
-    * @static
 
-    * @constructor
 
-    */
 
-   tracking.Canvas = {};
 
-   /**
 
-    * Loads an image source into the canvas.
 
-    * @param {HTMLCanvasElement} canvas The canvas dom element.
 
-    * @param {string} src The image source.
 
-    * @param {number} x The canvas horizontal coordinate to load the image.
 
-    * @param {number} y The canvas vertical coordinate to load the image.
 
-    * @param {number} width The image width.
 
-    * @param {number} height The image height.
 
-    * @param {function} opt_callback Callback that fires when the image is loaded
 
-    *     into the canvas.
 
-    * @static
 
-    */
 
-   tracking.Canvas.loadImage = function(canvas, src, x, y, width, height, opt_callback) {
 
-     var instance = this;
 
-     var img = new window.Image();
 
-     img.crossOrigin = '*';
 
-     img.onload = function() {
 
-       var context = canvas.getContext('2d');
 
-       canvas.width = width;
 
-       canvas.height = height;
 
-       context.drawImage(img, x, y, width, height);
 
-       if (opt_callback) {
 
-         opt_callback.call(instance);
 
-       }
 
-       img = null;
 
-     };
 
-     img.src = src;
 
-   };
 
- }());
 
- (function() {
 
-   /**
 
-    * DisjointSet utility with path compression. Some applications involve
 
-    * grouping n distinct objects into a collection of disjoint sets. Two
 
-    * important operations are then finding which set a given object belongs to
 
-    * and uniting the two sets. A disjoint set data structure maintains a
 
-    * collection S={ S1 , S2 ,..., Sk } of disjoint dynamic sets. Each set is
 
-    * identified by a representative, which usually is a member in the set.
 
-    * @static
 
-    * @constructor
 
-    */
 
-   tracking.DisjointSet = function(length) {
 
-     if (length === undefined) {
 
-       throw new Error('DisjointSet length not specified.');
 
-     }
 
-     this.length = length;
 
-     this.parent = new Uint32Array(length);
 
-     for (var i = 0; i < length; i++) {
 
-       this.parent[i] = i;
 
-     }
 
-   };
 
-   /**
 
-    * Holds the length of the internal set.
 
-    * @type {number}
 
-    */
 
-   tracking.DisjointSet.prototype.length = null;
 
-   /**
 
-    * Holds the set containing the representative values.
 
-    * @type {Array.<number>}
 
-    */
 
-   tracking.DisjointSet.prototype.parent = null;
 
-   /**
 
-    * Finds a pointer to the representative of the set containing i.
 
-    * @param {number} i
 
-    * @return {number} The representative set of i.
 
-    */
 
-   tracking.DisjointSet.prototype.find = function(i) {
 
-     if (this.parent[i] === i) {
 
-       return i;
 
-     } else {
 
-       return (this.parent[i] = this.find(this.parent[i]));
 
-     }
 
-   };
 
-   /**
 
-    * Unites two dynamic sets containing objects i and j, say Si and Sj, into
 
-    * a new set that Si ∪ Sj, assuming that Si ∩ Sj = ∅;
 
-    * @param {number} i
 
-    * @param {number} j
 
-    */
 
-   tracking.DisjointSet.prototype.union = function(i, j) {
 
-     var iRepresentative = this.find(i);
 
-     var jRepresentative = this.find(j);
 
-     this.parent[iRepresentative] = jRepresentative;
 
-   };
 
- }());
 
- (function() {
 
-   /**
 
-    * Image utility.
 
-    * @static
 
-    * @constructor
 
-    */
 
-   tracking.Image = {};
 
-   /**
 
-    * Computes gaussian blur. Adapted from
 
-    * https://github.com/kig/canvasfilters.
 
-    * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
 
-    * @param {number} width The image width.
 
-    * @param {number} height The image height.
 
-    * @param {number} diameter Gaussian blur diameter, must be greater than 1.
 
-    * @return {array} The edge pixels in a linear [r,g,b,a,...] array.
 
-    */
 
-   tracking.Image.blur = function(pixels, width, height, diameter) {
 
-     diameter = Math.abs(diameter);
 
-     if (diameter <= 1) {
 
-       throw new Error('Diameter should be greater than 1.');
 
-     }
 
-     var radius = diameter / 2;
 
-     var len = Math.ceil(diameter) + (1 - (Math.ceil(diameter) % 2));
 
-     var weights = new Float32Array(len);
 
-     var rho = (radius + 0.5) / 3;
 
-     var rhoSq = rho * rho;
 
-     var gaussianFactor = 1 / Math.sqrt(2 * Math.PI * rhoSq);
 
-     var rhoFactor = -1 / (2 * rho * rho);
 
-     var wsum = 0;
 
-     var middle = Math.floor(len / 2);
 
-     for (var i = 0; i < len; i++) {
 
-       var x = i - middle;
 
-       var gx = gaussianFactor * Math.exp(x * x * rhoFactor);
 
-       weights[i] = gx;
 
-       wsum += gx;
 
-     }
 
-     for (var j = 0; j < weights.length; j++) {
 
-       weights[j] /= wsum;
 
-     }
 
-     return this.separableConvolve(pixels, width, height, weights, weights, false);
 
-   };
 
-   /**
 
-    * Computes the integral image for summed, squared, rotated and sobel pixels.
 
-    * @param {array} pixels The pixels in a linear [r,g,b,a,...] array to loop
 
-    *     through.
 
-    * @param {number} width The image width.
 
-    * @param {number} height The image height.
 
-    * @param {array} opt_integralImage Empty array of size `width * height` to
 
-    *     be filled with the integral image values. If not specified compute sum
 
-    *     values will be skipped.
 
-    * @param {array} opt_integralImageSquare Empty array of size `width *
 
-    *     height` to be filled with the integral image squared values. If not
 
-    *     specified compute squared values will be skipped.
 
-    * @param {array} opt_tiltedIntegralImage Empty array of size `width *
 
-    *     height` to be filled with the rotated integral image values. If not
 
-    *     specified compute sum values will be skipped.
 
-    * @param {array} opt_integralImageSobel Empty array of size `width *
 
-    *     height` to be filled with the integral image of sobel values. If not
 
-    *     specified compute sobel filtering will be skipped.
 
-    * @static
 
-    */
 
-   tracking.Image.computeIntegralImage = function(pixels, width, height, opt_integralImage, opt_integralImageSquare, opt_tiltedIntegralImage, opt_integralImageSobel) {
 
-     if (arguments.length < 4) {
 
-       throw new Error('You should specify at least one output array in the order: sum, square, tilted, sobel.');
 
-     }
 
-     var pixelsSobel;
 
-     if (opt_integralImageSobel) {
 
-       pixelsSobel = tracking.Image.sobel(pixels, width, height);
 
-     }
 
-     for (var i = 0; i < height; i++) {
 
-       for (var j = 0; j < width; j++) {
 
-         var w = i * width * 4 + j * 4;
 
-         var pixel = ~~(pixels[w] * 0.299 + pixels[w + 1] * 0.587 + pixels[w + 2] * 0.114);
 
-         if (opt_integralImage) {
 
-           this.computePixelValueSAT_(opt_integralImage, width, i, j, pixel);
 
-         }
 
-         if (opt_integralImageSquare) {
 
-           this.computePixelValueSAT_(opt_integralImageSquare, width, i, j, pixel * pixel);
 
-         }
 
-         if (opt_tiltedIntegralImage) {
 
-           var w1 = w - width * 4;
 
-           var pixelAbove = ~~(pixels[w1] * 0.299 + pixels[w1 + 1] * 0.587 + pixels[w1 + 2] * 0.114);
 
-           this.computePixelValueRSAT_(opt_tiltedIntegralImage, width, i, j, pixel, pixelAbove || 0);
 
-         }
 
-         if (opt_integralImageSobel) {
 
-           this.computePixelValueSAT_(opt_integralImageSobel, width, i, j, pixelsSobel[w]);
 
-         }
 
-       }
 
-     }
 
-   };
 
-   /**
 
-    * Helper method to compute the rotated summed area table (RSAT) by the
 
-    * formula:
 
-    *
 
-    * RSAT(x, y) = RSAT(x-1, y-1) + RSAT(x+1, y-1) - RSAT(x, y-2) + I(x, y) + I(x, y-1)
 
-    *
 
-    * @param {number} width The image width.
 
-    * @param {array} RSAT Empty array of size `width * height` to be filled with
 
-    *     the integral image values. If not specified compute sum values will be
 
-    *     skipped.
 
-    * @param {number} i Vertical position of the pixel to be evaluated.
 
-    * @param {number} j Horizontal position of the pixel to be evaluated.
 
-    * @param {number} pixel Pixel value to be added to the integral image.
 
-    * @static
 
-    * @private
 
-    */
 
-   tracking.Image.computePixelValueRSAT_ = function(RSAT, width, i, j, pixel, pixelAbove) {
 
-     var w = i * width + j;
 
-     RSAT[w] = (RSAT[w - width - 1] || 0) + (RSAT[w - width + 1] || 0) - (RSAT[w - width - width] || 0) + pixel + pixelAbove;
 
-   };
 
-   /**
 
-    * Helper method to compute the summed area table (SAT) by the formula:
 
-    *
 
-    * SAT(x, y) = SAT(x, y-1) + SAT(x-1, y) + I(x, y) - SAT(x-1, y-1)
 
-    *
 
-    * @param {number} width The image width.
 
-    * @param {array} SAT Empty array of size `width * height` to be filled with
 
-    *     the integral image values. If not specified compute sum values will be
 
-    *     skipped.
 
-    * @param {number} i Vertical position of the pixel to be evaluated.
 
-    * @param {number} j Horizontal position of the pixel to be evaluated.
 
-    * @param {number} pixel Pixel value to be added to the integral image.
 
-    * @static
 
-    * @private
 
-    */
 
-   tracking.Image.computePixelValueSAT_ = function(SAT, width, i, j, pixel) {
 
-     var w = i * width + j;
 
-     SAT[w] = (SAT[w - width] || 0) + (SAT[w - 1] || 0) + pixel - (SAT[w - width - 1] || 0);
 
-   };
 
-   /**
 
-    * Converts a color from a colorspace based on an RGB color model to a
 
-    * grayscale representation of its luminance. The coefficients represent the
 
-    * measured intensity perception of typical trichromat humans, in
 
-    * particular, human vision is most sensitive to green and least sensitive
 
-    * to blue.
 
-    * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
 
-    * @param {number} width The image width.
 
-    * @param {number} height The image height.
 
-    * @param {boolean} fillRGBA If the result should fill all RGBA values with the gray scale
 
-    *  values, instead of returning a single value per pixel.
 
-    * @param {Uint8ClampedArray} The grayscale pixels in a linear array ([p,p,p,a,...] if fillRGBA
 
-    *  is true and [p1, p2, p3, ...] if fillRGBA is false).
 
-    * @static
 
-    */
 
-   tracking.Image.grayscale = function(pixels, width, height, fillRGBA) {
 
-     var gray = new Uint8ClampedArray(fillRGBA ? pixels.length : pixels.length >> 2);
 
-     var p = 0;
 
-     var w = 0;
 
-     for (var i = 0; i < height; i++) {
 
-       for (var j = 0; j < width; j++) {
 
-         var value = pixels[w] * 0.299 + pixels[w + 1] * 0.587 + pixels[w + 2] * 0.114;
 
-         gray[p++] = value;
 
-         if (fillRGBA) {
 
-           gray[p++] = value;
 
-           gray[p++] = value;
 
-           gray[p++] = pixels[w + 3];
 
-         }
 
-         w += 4;
 
-       }
 
-     }
 
-     return gray;
 
-   };
 
-   /**
 
-    * Fast horizontal separable convolution. A point spread function (PSF) is
 
-    * said to be separable if it can be broken into two one-dimensional
 
-    * signals: a vertical and a horizontal projection. The convolution is
 
-    * performed by sliding the kernel over the image, generally starting at the
 
-    * top left corner, so as to move the kernel through all the positions where
 
-    * the kernel fits entirely within the boundaries of the image. Adapted from
 
-    * https://github.com/kig/canvasfilters.
 
-    * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
 
-    * @param {number} width The image width.
 
-    * @param {number} height The image height.
 
-    * @param {array} weightsVector The weighting vector, e.g [-1,0,1].
 
-    * @param {number} opaque
 
-    * @return {array} The convoluted pixels in a linear [r,g,b,a,...] array.
 
-    */
 
-   tracking.Image.horizontalConvolve = function(pixels, width, height, weightsVector, opaque) {
 
-     var side = weightsVector.length;
 
-     var halfSide = Math.floor(side / 2);
 
-     var output = new Float32Array(width * height * 4);
 
-     var alphaFac = opaque ? 1 : 0;
 
-     for (var y = 0; y < height; y++) {
 
-       for (var x = 0; x < width; x++) {
 
-         var sy = y;
 
-         var sx = x;
 
-         var offset = (y * width + x) * 4;
 
-         var r = 0;
 
-         var g = 0;
 
-         var b = 0;
 
-         var a = 0;
 
-         for (var cx = 0; cx < side; cx++) {
 
-           var scy = sy;
 
-           var scx = Math.min(width - 1, Math.max(0, sx + cx - halfSide));
 
-           var poffset = (scy * width + scx) * 4;
 
-           var wt = weightsVector[cx];
 
-           r += pixels[poffset] * wt;
 
-           g += pixels[poffset + 1] * wt;
 
-           b += pixels[poffset + 2] * wt;
 
-           a += pixels[poffset + 3] * wt;
 
-         }
 
-         output[offset] = r;
 
-         output[offset + 1] = g;
 
-         output[offset + 2] = b;
 
-         output[offset + 3] = a + alphaFac * (255 - a);
 
-       }
 
-     }
 
-     return output;
 
-   };
 
-   /**
 
-    * Fast vertical separable convolution. A point spread function (PSF) is
 
-    * said to be separable if it can be broken into two one-dimensional
 
-    * signals: a vertical and a horizontal projection. The convolution is
 
-    * performed by sliding the kernel over the image, generally starting at the
 
-    * top left corner, so as to move the kernel through all the positions where
 
-    * the kernel fits entirely within the boundaries of the image. Adapted from
 
-    * https://github.com/kig/canvasfilters.
 
-    * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
 
-    * @param {number} width The image width.
 
-    * @param {number} height The image height.
 
-    * @param {array} weightsVector The weighting vector, e.g [-1,0,1].
 
-    * @param {number} opaque
 
-    * @return {array} The convoluted pixels in a linear [r,g,b,a,...] array.
 
-    */
 
-   tracking.Image.verticalConvolve = function(pixels, width, height, weightsVector, opaque) {
 
-     var side = weightsVector.length;
 
-     var halfSide = Math.floor(side / 2);
 
-     var output = new Float32Array(width * height * 4);
 
-     var alphaFac = opaque ? 1 : 0;
 
-     for (var y = 0; y < height; y++) {
 
-       for (var x = 0; x < width; x++) {
 
-         var sy = y;
 
-         var sx = x;
 
-         var offset = (y * width + x) * 4;
 
-         var r = 0;
 
-         var g = 0;
 
-         var b = 0;
 
-         var a = 0;
 
-         for (var cy = 0; cy < side; cy++) {
 
-           var scy = Math.min(height - 1, Math.max(0, sy + cy - halfSide));
 
-           var scx = sx;
 
-           var poffset = (scy * width + scx) * 4;
 
-           var wt = weightsVector[cy];
 
-           r += pixels[poffset] * wt;
 
-           g += pixels[poffset + 1] * wt;
 
-           b += pixels[poffset + 2] * wt;
 
-           a += pixels[poffset + 3] * wt;
 
-         }
 
-         output[offset] = r;
 
-         output[offset + 1] = g;
 
-         output[offset + 2] = b;
 
-         output[offset + 3] = a + alphaFac * (255 - a);
 
-       }
 
-     }
 
-     return output;
 
-   };
 
-   /**
 
-    * Fast separable convolution. A point spread function (PSF) is said to be
 
-    * separable if it can be broken into two one-dimensional signals: a
 
-    * vertical and a horizontal projection. The convolution is performed by
 
-    * sliding the kernel over the image, generally starting at the top left
 
-    * corner, so as to move the kernel through all the positions where the
 
-    * kernel fits entirely within the boundaries of the image. Adapted from
 
-    * https://github.com/kig/canvasfilters.
 
-    * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
 
-    * @param {number} width The image width.
 
-    * @param {number} height The image height.
 
-    * @param {array} horizWeights The horizontal weighting vector, e.g [-1,0,1].
 
-    * @param {array} vertWeights The vertical vector, e.g [-1,0,1].
 
-    * @param {number} opaque
 
-    * @return {array} The convoluted pixels in a linear [r,g,b,a,...] array.
 
-    */
 
-   tracking.Image.separableConvolve = function(pixels, width, height, horizWeights, vertWeights, opaque) {
 
-     var vertical = this.verticalConvolve(pixels, width, height, vertWeights, opaque);
 
-     return this.horizontalConvolve(vertical, width, height, horizWeights, opaque);
 
-   };
 
-   /**
 
-    * Compute image edges using Sobel operator. Computes the vertical and
 
-    * horizontal gradients of the image and combines the computed images to
 
-    * find edges in the image. The way we implement the Sobel filter here is by
 
-    * first grayscaling the image, then taking the horizontal and vertical
 
-    * gradients and finally combining the gradient images to make up the final
 
-    * image. Adapted from https://github.com/kig/canvasfilters.
 
-    * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
 
-    * @param {number} width The image width.
 
-    * @param {number} height The image height.
 
-    * @return {array} The edge pixels in a linear [r,g,b,a,...] array.
 
-    */
 
-   tracking.Image.sobel = function(pixels, width, height) {
 
-     pixels = this.grayscale(pixels, width, height, true);
 
-     var output = new Float32Array(width * height * 4);
 
-     var sobelSignVector = new Float32Array([-1, 0, 1]);
 
-     var sobelScaleVector = new Float32Array([1, 2, 1]);
 
-     var vertical = this.separableConvolve(pixels, width, height, sobelSignVector, sobelScaleVector);
 
-     var horizontal = this.separableConvolve(pixels, width, height, sobelScaleVector, sobelSignVector);
 
-     for (var i = 0; i < output.length; i += 4) {
 
-       var v = vertical[i];
 
-       var h = horizontal[i];
 
-       var p = Math.sqrt(h * h + v * v);
 
-       output[i] = p;
 
-       output[i + 1] = p;
 
-       output[i + 2] = p;
 
-       output[i + 3] = 255;
 
-     }
 
-     return output;
 
-   };
 
-   /**
 
-    * Equalizes the histogram of a grayscale image, normalizing the
 
-    * brightness and increasing the contrast of the image.
 
-    * @param {pixels} pixels The grayscale pixels in a linear array.
 
-    * @param {number} width The image width.
 
-    * @param {number} height The image height.
 
-    * @return {array} The equalized grayscale pixels in a linear array.
 
-    */
 
-   tracking.Image.equalizeHist = function(pixels, width, height){
 
-     var equalized = new Uint8ClampedArray(pixels.length);
 
-     var histogram = new Array(256);
 
-     for(var i=0; i < 256; i++) histogram[i] = 0;
 
-     for(var i=0; i < pixels.length; i++){
 
-       equalized[i] = pixels[i];
 
-       histogram[pixels[i]]++;
 
-     }
 
-     var prev = histogram[0];
 
-     for(var i=0; i < 256; i++){
 
-       histogram[i] += prev;
 
-       prev = histogram[i];
 
-     }
 
-     var norm = 255 / pixels.length;
 
-     for(var i=0; i < pixels.length; i++)
 
-       equalized[i] = (histogram[pixels[i]] * norm + 0.5) | 0;
 
-     return equalized;
 
-   }
 
- }());
 
- (function() {
 
-   /**
 
-    * ViolaJones utility.
 
-    * @static
 
-    * @constructor
 
-    */
 
-   tracking.ViolaJones = {};
 
-   /**
 
-    * Holds the minimum area of intersection that defines when a rectangle is
 
-    * from the same group. Often when a face is matched multiple rectangles are
 
-    * classified as possible rectangles to represent the face, when they
 
-    * intersects they are grouped as one face.
 
-    * @type {number}
 
-    * @default 0.5
 
-    * @static
 
-    */
 
-   tracking.ViolaJones.REGIONS_OVERLAP = 0.5;
 
-   /**
 
-    * Holds the HAAR cascade classifiers converted from OpenCV training.
 
-    * @type {array}
 
-    * @static
 
-    */
 
-   tracking.ViolaJones.classifiers = {};
 
-   /**
 
-    * Detects through the HAAR cascade data rectangles matches.
 
-    * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
 
-    * @param {number} width The image width.
 
-    * @param {number} height The image height.
 
-    * @param {number} initialScale The initial scale to start the block
 
-    *     scaling.
 
-    * @param {number} scaleFactor The scale factor to scale the feature block.
 
-    * @param {number} stepSize The block step size.
 
-    * @param {number} edgesDensity Percentage density edges inside the
 
-    *     classifier block. Value from [0.0, 1.0], defaults to 0.2. If specified
 
-    *     edge detection will be applied to the image to prune dead areas of the
 
-    *     image, this can improve significantly performance.
 
-    * @param {number} data The HAAR cascade data.
 
-    * @return {array} Found rectangles.
 
-    * @static
 
-    */
 
-   tracking.ViolaJones.detect = function(pixels, width, height, initialScale, scaleFactor, stepSize, edgesDensity, data) {
 
-     var total = 0;
 
-     var rects = [];
 
-     var integralImage = new Int32Array(width * height);
 
-     var integralImageSquare = new Int32Array(width * height);
 
-     var tiltedIntegralImage = new Int32Array(width * height);
 
-     var integralImageSobel;
 
-     if (edgesDensity > 0) {
 
-       integralImageSobel = new Int32Array(width * height);
 
-     }
 
-     tracking.Image.computeIntegralImage(pixels, width, height, integralImage, integralImageSquare, tiltedIntegralImage, integralImageSobel);
 
-     var minWidth = data[0];
 
-     var minHeight = data[1];
 
-     var scale = initialScale * scaleFactor;
 
-     var blockWidth = (scale * minWidth) | 0;
 
-     var blockHeight = (scale * minHeight) | 0;
 
-     while (blockWidth < width && blockHeight < height) {
 
-       var step = (scale * stepSize + 0.5) | 0;
 
-       for (var i = 0; i < (height - blockHeight); i += step) {
 
-         for (var j = 0; j < (width - blockWidth); j += step) {
 
-           if (edgesDensity > 0) {
 
-             if (this.isTriviallyExcluded(edgesDensity, integralImageSobel, i, j, width, blockWidth, blockHeight)) {
 
-               continue;
 
-             }
 
-           }
 
-           if (this.evalStages_(data, integralImage, integralImageSquare, tiltedIntegralImage, i, j, width, blockWidth, blockHeight, scale)) {
 
-             rects[total++] = {
 
-               width: blockWidth,
 
-               height: blockHeight,
 
-               x: j,
 
-               y: i
 
-             };
 
-           }
 
-         }
 
-       }
 
-       scale *= scaleFactor;
 
-       blockWidth = (scale * minWidth) | 0;
 
-       blockHeight = (scale * minHeight) | 0;
 
-     }
 
-     return this.mergeRectangles_(rects);
 
-   };
 
-   /**
 
-    * Fast check to test whether the edges density inside the block is greater
 
-    * than a threshold, if true it tests the stages. This can improve
 
-    * significantly performance.
 
-    * @param {number} edgesDensity Percentage density edges inside the
 
-    *     classifier block.
 
-    * @param {array} integralImageSobel The integral image of a sobel image.
 
-    * @param {number} i Vertical position of the pixel to be evaluated.
 
-    * @param {number} j Horizontal position of the pixel to be evaluated.
 
-    * @param {number} width The image width.
 
-    * @return {boolean} True whether the block at position i,j can be skipped,
 
-    *     false otherwise.
 
-    * @static
 
-    * @protected
 
-    */
 
-   tracking.ViolaJones.isTriviallyExcluded = function(edgesDensity, integralImageSobel, i, j, width, blockWidth, blockHeight) {
 
-     var wbA = i * width + j;
 
-     var wbB = wbA + blockWidth;
 
-     var wbD = wbA + blockHeight * width;
 
-     var wbC = wbD + blockWidth;
 
-     var blockEdgesDensity = (integralImageSobel[wbA] - integralImageSobel[wbB] - integralImageSobel[wbD] + integralImageSobel[wbC]) / (blockWidth * blockHeight * 255);
 
-     if (blockEdgesDensity < edgesDensity) {
 
-       return true;
 
-     }
 
-     return false;
 
-   };
 
-   /**
 
-    * Evaluates if the block size on i,j position is a valid HAAR cascade
 
-    * stage.
 
-    * @param {number} data The HAAR cascade data.
 
-    * @param {number} i Vertical position of the pixel to be evaluated.
 
-    * @param {number} j Horizontal position of the pixel to be evaluated.
 
-    * @param {number} width The image width.
 
-    * @param {number} blockSize The block size.
 
-    * @param {number} scale The scale factor of the block size and its original
 
-    *     size.
 
-    * @param {number} inverseArea The inverse area of the block size.
 
-    * @return {boolean} Whether the region passes all the stage tests.
 
-    * @private
 
-    * @static
 
-    */
 
-   tracking.ViolaJones.evalStages_ = function(data, integralImage, integralImageSquare, tiltedIntegralImage, i, j, width, blockWidth, blockHeight, scale) {
 
-     var inverseArea = 1.0 / (blockWidth * blockHeight);
 
-     var wbA = i * width + j;
 
-     var wbB = wbA + blockWidth;
 
-     var wbD = wbA + blockHeight * width;
 
-     var wbC = wbD + blockWidth;
 
-     var mean = (integralImage[wbA] - integralImage[wbB] - integralImage[wbD] + integralImage[wbC]) * inverseArea;
 
-     var variance = (integralImageSquare[wbA] - integralImageSquare[wbB] - integralImageSquare[wbD] + integralImageSquare[wbC]) * inverseArea - mean * mean;
 
-     var standardDeviation = 1;
 
-     if (variance > 0) {
 
-       standardDeviation = Math.sqrt(variance);
 
-     }
 
-     var length = data.length;
 
-     for (var w = 2; w < length; ) {
 
-       var stageSum = 0;
 
-       var stageThreshold = data[w++];
 
-       var nodeLength = data[w++];
 
-       while (nodeLength--) {
 
-         var rectsSum = 0;
 
-         var tilted = data[w++];
 
-         var rectsLength = data[w++];
 
-         for (var r = 0; r < rectsLength; r++) {
 
-           var rectLeft = (j + data[w++] * scale + 0.5) | 0;
 
-           var rectTop = (i + data[w++] * scale + 0.5) | 0;
 
-           var rectWidth = (data[w++] * scale + 0.5) | 0;
 
-           var rectHeight = (data[w++] * scale + 0.5) | 0;
 
-           var rectWeight = data[w++];
 
-           var w1;
 
-           var w2;
 
-           var w3;
 
-           var w4;
 
-           if (tilted) {
 
-             // RectSum(r) = RSAT(x-h+w, y+w+h-1) + RSAT(x, y-1) - RSAT(x-h, y+h-1) - RSAT(x+w, y+w-1)
 
-             w1 = (rectLeft - rectHeight + rectWidth) + (rectTop + rectWidth + rectHeight - 1) * width;
 
-             w2 = rectLeft + (rectTop - 1) * width;
 
-             w3 = (rectLeft - rectHeight) + (rectTop + rectHeight - 1) * width;
 
-             w4 = (rectLeft + rectWidth) + (rectTop + rectWidth - 1) * width;
 
-             rectsSum += (tiltedIntegralImage[w1] + tiltedIntegralImage[w2] - tiltedIntegralImage[w3] - tiltedIntegralImage[w4]) * rectWeight;
 
-           } else {
 
-             // RectSum(r) = SAT(x-1, y-1) + SAT(x+w-1, y+h-1) - SAT(x-1, y+h-1) - SAT(x+w-1, y-1)
 
-             w1 = rectTop * width + rectLeft;
 
-             w2 = w1 + rectWidth;
 
-             w3 = w1 + rectHeight * width;
 
-             w4 = w3 + rectWidth;
 
-             rectsSum += (integralImage[w1] - integralImage[w2] - integralImage[w3] + integralImage[w4]) * rectWeight;
 
-             // TODO: Review the code below to analyze performance when using it instead.
 
-             // w1 = (rectLeft - 1) + (rectTop - 1) * width;
 
-             // w2 = (rectLeft + rectWidth - 1) + (rectTop + rectHeight - 1) * width;
 
-             // w3 = (rectLeft - 1) + (rectTop + rectHeight - 1) * width;
 
-             // w4 = (rectLeft + rectWidth - 1) + (rectTop - 1) * width;
 
-             // rectsSum += (integralImage[w1] + integralImage[w2] - integralImage[w3] - integralImage[w4]) * rectWeight;
 
-           }
 
-         }
 
-         var nodeThreshold = data[w++];
 
-         var nodeLeft = data[w++];
 
-         var nodeRight = data[w++];
 
-         if (rectsSum * inverseArea < nodeThreshold * standardDeviation) {
 
-           stageSum += nodeLeft;
 
-         } else {
 
-           stageSum += nodeRight;
 
-         }
 
-       }
 
-       if (stageSum < stageThreshold) {
 
-         return false;
 
-       }
 
-     }
 
-     return true;
 
-   };
 
-   /**
 
-    * Postprocess the detected sub-windows in order to combine overlapping
 
-    * detections into a single detection.
 
-    * @param {array} rects
 
-    * @return {array}
 
-    * @private
 
-    * @static
 
-    */
 
-   tracking.ViolaJones.mergeRectangles_ = function(rects) {
 
-     var disjointSet = new tracking.DisjointSet(rects.length);
 
-     for (var i = 0; i < rects.length; i++) {
 
-       var r1 = rects[i];
 
-       for (var j = 0; j < rects.length; j++) {
 
-         var r2 = rects[j];
 
-         if (tracking.Math.intersectRect(r1.x, r1.y, r1.x + r1.width, r1.y + r1.height, r2.x, r2.y, r2.x + r2.width, r2.y + r2.height)) {
 
-           var x1 = Math.max(r1.x, r2.x);
 
-           var y1 = Math.max(r1.y, r2.y);
 
-           var x2 = Math.min(r1.x + r1.width, r2.x + r2.width);
 
-           var y2 = Math.min(r1.y + r1.height, r2.y + r2.height);
 
-           var overlap = (x1 - x2) * (y1 - y2);
 
-           var area1 = (r1.width * r1.height);
 
-           var area2 = (r2.width * r2.height);
 
-           if ((overlap / (area1 * (area1 / area2)) >= this.REGIONS_OVERLAP) &&
 
-             (overlap / (area2 * (area1 / area2)) >= this.REGIONS_OVERLAP)) {
 
-             disjointSet.union(i, j);
 
-           }
 
-         }
 
-       }
 
-     }
 
-     var map = {};
 
-     for (var k = 0; k < disjointSet.length; k++) {
 
-       var rep = disjointSet.find(k);
 
-       if (!map[rep]) {
 
-         map[rep] = {
 
-           total: 1,
 
-           width: rects[k].width,
 
-           height: rects[k].height,
 
-           x: rects[k].x,
 
-           y: rects[k].y
 
-         };
 
-         continue;
 
-       }
 
-       map[rep].total++;
 
-       map[rep].width += rects[k].width;
 
-       map[rep].height += rects[k].height;
 
-       map[rep].x += rects[k].x;
 
-       map[rep].y += rects[k].y;
 
-     }
 
-     var result = [];
 
-     Object.keys(map).forEach(function(key) {
 
-       var rect = map[key];
 
-       result.push({
 
-         total: rect.total,
 
-         width: (rect.width / rect.total + 0.5) | 0,
 
-         height: (rect.height / rect.total + 0.5) | 0,
 
-         x: (rect.x / rect.total + 0.5) | 0,
 
-         y: (rect.y / rect.total + 0.5) | 0
 
-       });
 
-     });
 
-     return result;
 
-   };
 
- }());
 
- (function() {
 
-   /**
 
-    * Brief intends for "Binary Robust Independent Elementary Features".This
 
-    * method generates a binary string for each keypoint found by an extractor
 
-    * method.
 
-    * @static
 
-    * @constructor
 
-    */
 
-   tracking.Brief = {};
 
-   /**
 
-    * The set of binary tests is defined by the nd (x,y)-location pairs
 
-    * uniquely chosen during the initialization. Values could vary between N =
 
-    * 128,256,512. N=128 yield good compromises between speed, storage
 
-    * efficiency, and recognition rate.
 
-    * @type {number}
 
-    */
 
-   tracking.Brief.N = 512;
 
-   /**
 
-    * Caches coordinates values of (x,y)-location pairs uniquely chosen during
 
-    * the initialization.
 
-    * @type {Object.<number, Int32Array>}
 
-    * @private
 
-    * @static
 
-    */
 
-   tracking.Brief.randomImageOffsets_ = {};
 
-   /**
 
-    * Caches delta values of (x,y)-location pairs uniquely chosen during
 
-    * the initialization.
 
-    * @type {Int32Array}
 
-    * @private
 
-    * @static
 
-    */
 
-   tracking.Brief.randomWindowOffsets_ = null;
 
-   /**
 
-    * Generates a binary string for each found keypoints extracted using an
 
-    * extractor method.
 
-    * @param {array} The grayscale pixels in a linear [p1,p2,...] array.
 
-    * @param {number} width The image width.
 
-    * @param {array} keypoints
 
-    * @return {Int32Array} Returns an array where for each four sequence int
 
-    *     values represent the descriptor binary string (128 bits) necessary
 
-    *     to describe the corner, e.g. [0,0,0,0, 0,0,0,0, ...].
 
-    * @static
 
-    */
 
-   tracking.Brief.getDescriptors = function(pixels, width, keypoints) {
 
-     // Optimizing divide by 32 operation using binary shift
 
-     // (this.N >> 5) === this.N/32.
 
-     var descriptors = new Int32Array((keypoints.length >> 1) * (this.N >> 5));
 
-     var descriptorWord = 0;
 
-     var offsets = this.getRandomOffsets_(width);
 
-     var position = 0;
 
-     for (var i = 0; i < keypoints.length; i += 2) {
 
-       var w = width * keypoints[i + 1] + keypoints[i];
 
-       var offsetsPosition = 0;
 
-       for (var j = 0, n = this.N; j < n; j++) {
 
-         if (pixels[offsets[offsetsPosition++] + w] < pixels[offsets[offsetsPosition++] + w]) {
 
-           // The bit in the position `j % 32` of descriptorWord should be set to 1. We do
 
-           // this by making an OR operation with a binary number that only has the bit
 
-           // in that position set to 1. That binary number is obtained by shifting 1 left by
 
-           // `j % 32` (which is the same as `j & 31` left) positions.
 
-           descriptorWord |= 1 << (j & 31);
 
-         }
 
-         // If the next j is a multiple of 32, we will need to use a new descriptor word to hold
 
-         // the next results.
 
-         if (!((j + 1) & 31)) {
 
-           descriptors[position++] = descriptorWord;
 
-           descriptorWord = 0;
 
-         }
 
-       }
 
-     }
 
-     return descriptors;
 
-   };
 
-   /**
 
-    * Matches sets of features {mi} and {m′j} extracted from two images taken
 
-    * from similar, and often successive, viewpoints. A classical procedure
 
-    * runs as follows. For each point {mi} in the first image, search in a
 
-    * region of the second image around location {mi} for point {m′j}. The
 
-    * search is based on the similarity of the local image windows, also known
 
-    * as kernel windows, centered on the points, which strongly characterizes
 
-    * the points when the images are sufficiently close. Once each keypoint is
 
-    * described with its binary string, they need to be compared with the
 
-    * closest matching point. Distance metric is critical to the performance of
 
-    * in- trusion detection systems. Thus using binary strings reduces the size
 
-    * of the descriptor and provides an interesting data structure that is fast
 
-    * to operate whose similarity can be measured by the Hamming distance.
 
-    * @param {array} keypoints1
 
-    * @param {array} descriptors1
 
-    * @param {array} keypoints2
 
-    * @param {array} descriptors2
 
-    * @return {Int32Array} Returns an array where the index is the corner1
 
-    *     index coordinate, and the value is the corresponding match index of
 
-    *     corner2, e.g. keypoints1=[x0,y0,x1,y1,...] and
 
-    *     keypoints2=[x'0,y'0,x'1,y'1,...], if x0 matches x'1 and x1 matches x'0,
 
-    *     the return array would be [3,0].
 
-    * @static
 
-    */
 
-   tracking.Brief.match = function(keypoints1, descriptors1, keypoints2, descriptors2) {
 
-     var len1 = keypoints1.length >> 1;
 
-     var len2 = keypoints2.length >> 1;
 
-     var matches = new Array(len1);
 
-     for (var i = 0; i < len1; i++) {
 
-       var min = Infinity;
 
-       var minj = 0;
 
-       for (var j = 0; j < len2; j++) {
 
-         var dist = 0;
 
-         // Optimizing divide by 32 operation using binary shift
 
-         // (this.N >> 5) === this.N/32.
 
-         for (var k = 0, n = this.N >> 5; k < n; k++) {
 
-           dist += tracking.Math.hammingWeight(descriptors1[i * n + k] ^ descriptors2[j * n + k]);
 
-         }
 
-         if (dist < min) {
 
-           min = dist;
 
-           minj = j;
 
-         }
 
-       }
 
-       matches[i] = {
 
-         index1: i,
 
-         index2: minj,
 
-         keypoint1: [keypoints1[2 * i], keypoints1[2 * i + 1]],
 
-         keypoint2: [keypoints2[2 * minj], keypoints2[2 * minj + 1]],
 
-         confidence: 1 - min / this.N
 
-       };
 
-     }
 
-     return matches;
 
-   };
 
-   /**
 
-    * Removes matches outliers by testing matches on both directions.
 
-    * @param {array} keypoints1
 
-    * @param {array} descriptors1
 
-    * @param {array} keypoints2
 
-    * @param {array} descriptors2
 
-    * @return {Int32Array} Returns an array where the index is the corner1
 
-    *     index coordinate, and the value is the corresponding match index of
 
-    *     corner2, e.g. keypoints1=[x0,y0,x1,y1,...] and
 
-    *     keypoints2=[x'0,y'0,x'1,y'1,...], if x0 matches x'1 and x1 matches x'0,
 
-    *     the return array would be [3,0].
 
-    * @static
 
-    */
 
-   tracking.Brief.reciprocalMatch = function(keypoints1, descriptors1, keypoints2, descriptors2) {
 
-     var matches = [];
 
-     if (keypoints1.length === 0 || keypoints2.length === 0) {
 
-       return matches;
 
-     }
 
-     var matches1 = tracking.Brief.match(keypoints1, descriptors1, keypoints2, descriptors2);
 
-     var matches2 = tracking.Brief.match(keypoints2, descriptors2, keypoints1, descriptors1);
 
-     for (var i = 0; i < matches1.length; i++) {
 
-       if (matches2[matches1[i].index2].index2 === i) {
 
-         matches.push(matches1[i]);
 
-       }
 
-     }
 
-     return matches;
 
-   };
 
-   /**
 
-    * Gets the coordinates values of (x,y)-location pairs uniquely chosen
 
-    * during the initialization.
 
-    * @return {array} Array with the random offset values.
 
-    * @private
 
-    */
 
-   tracking.Brief.getRandomOffsets_ = function(width) {
 
-     if (!this.randomWindowOffsets_) {
 
-       var windowPosition = 0;
 
-       var windowOffsets = new Int32Array(4 * this.N);
 
-       for (var i = 0; i < this.N; i++) {
 
-         windowOffsets[windowPosition++] = Math.round(tracking.Math.uniformRandom(-15, 16));
 
-         windowOffsets[windowPosition++] = Math.round(tracking.Math.uniformRandom(-15, 16));
 
-         windowOffsets[windowPosition++] = Math.round(tracking.Math.uniformRandom(-15, 16));
 
-         windowOffsets[windowPosition++] = Math.round(tracking.Math.uniformRandom(-15, 16));
 
-       }
 
-       this.randomWindowOffsets_ = windowOffsets;
 
-     }
 
-     if (!this.randomImageOffsets_[width]) {
 
-       var imagePosition = 0;
 
-       var imageOffsets = new Int32Array(2 * this.N);
 
-       for (var j = 0; j < this.N; j++) {
 
-         imageOffsets[imagePosition++] = this.randomWindowOffsets_[4 * j] * width + this.randomWindowOffsets_[4 * j + 1];
 
-         imageOffsets[imagePosition++] = this.randomWindowOffsets_[4 * j + 2] * width + this.randomWindowOffsets_[4 * j + 3];
 
-       }
 
-       this.randomImageOffsets_[width] = imageOffsets;
 
-     }
 
-     return this.randomImageOffsets_[width];
 
-   };
 
- }());
 
- (function() {
 
-   /**
 
-    * FAST intends for "Features from Accelerated Segment Test". This method
 
-    * performs a point segment test corner detection. The segment test
 
-    * criterion operates by considering a circle of sixteen pixels around the
 
-    * corner candidate p. The detector classifies p as a corner if there exists
 
-    * a set of n contiguous pixelsin the circle which are all brighter than the
 
-    * intensity of the candidate pixel Ip plus a threshold t, or all darker
 
-    * than Ip − t.
 
-    *
 
-    *       15 00 01
 
-    *    14          02
 
-    * 13                03
 
-    * 12       []       04
 
-    * 11                05
 
-    *    10          06
 
-    *       09 08 07
 
-    *
 
-    * For more reference:
 
-    * http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.60.3991&rep=rep1&type=pdf
 
-    * @static
 
-    * @constructor
 
-    */
 
-   tracking.Fast = {};
 
-   /**
 
-    * Holds the threshold to determine whether the tested pixel is brighter or
 
-    * darker than the corner candidate p.
 
-    * @type {number}
 
-    * @default 40
 
-    * @static
 
-    */
 
-   tracking.Fast.THRESHOLD = 40;
 
-   /**
 
-    * Caches coordinates values of the circle surrounding the pixel candidate p.
 
-    * @type {Object.<number, Int32Array>}
 
-    * @private
 
-    * @static
 
-    */
 
-   tracking.Fast.circles_ = {};
 
-   /**
 
-    * Finds corners coordinates on the graysacaled image.
 
-    * @param {array} The grayscale pixels in a linear [p1,p2,...] array.
 
-    * @param {number} width The image width.
 
-    * @param {number} height The image height.
 
-    * @param {number} threshold to determine whether the tested pixel is brighter or
 
-    *     darker than the corner candidate p. Default value is 40.
 
-    * @return {array} Array containing the coordinates of all found corners,
 
-    *     e.g. [x0,y0,x1,y1,...], where P(x0,y0) represents a corner coordinate.
 
-    * @static
 
-    */
 
-   tracking.Fast.findCorners = function(pixels, width, height, opt_threshold) {
 
-     var circleOffsets = this.getCircleOffsets_(width);
 
-     var circlePixels = new Int32Array(16);
 
-     var corners = [];
 
-     if (opt_threshold === undefined) {
 
-       opt_threshold = this.THRESHOLD;
 
-     }
 
-     // When looping through the image pixels, skips the first three lines from
 
-     // the image boundaries to constrain the surrounding circle inside the image
 
-     // area.
 
-     for (var i = 3; i < height - 3; i++) {
 
-       for (var j = 3; j < width - 3; j++) {
 
-         var w = i * width + j;
 
-         var p = pixels[w];
 
-         // Loops the circle offsets to read the pixel value for the sixteen
 
-         // surrounding pixels.
 
-         for (var k = 0; k < 16; k++) {
 
-           circlePixels[k] = pixels[w + circleOffsets[k]];
 
-         }
 
-         if (this.isCorner(p, circlePixels, opt_threshold)) {
 
-           // The pixel p is classified as a corner, as optimization increment j
 
-           // by the circle radius 3 to skip the neighbor pixels inside the
 
-           // surrounding circle. This can be removed without compromising the
 
-           // result.
 
-           corners.push(j, i);
 
-           j += 3;
 
-         }
 
-       }
 
-     }
 
-     return corners;
 
-   };
 
-   /**
 
-    * Checks if the circle pixel is brighter than the candidate pixel p by
 
-    * a threshold.
 
-    * @param {number} circlePixel The circle pixel value.
 
-    * @param {number} p The value of the candidate pixel p.
 
-    * @param {number} threshold
 
-    * @return {Boolean}
 
-    * @static
 
-    */
 
-   tracking.Fast.isBrighter = function(circlePixel, p, threshold) {
 
-     return circlePixel - p > threshold;
 
-   };
 
-   /**
 
-    * Checks if the circle pixel is within the corner of the candidate pixel p
 
-    * by a threshold.
 
-    * @param {number} p The value of the candidate pixel p.
 
-    * @param {number} circlePixel The circle pixel value.
 
-    * @param {number} threshold
 
-    * @return {Boolean}
 
-    * @static
 
-    */
 
-   tracking.Fast.isCorner = function(p, circlePixels, threshold) {
 
-     if (this.isTriviallyExcluded(circlePixels, p, threshold)) {
 
-       return false;
 
-     }
 
-     for (var x = 0; x < 16; x++) {
 
-       var darker = true;
 
-       var brighter = true;
 
-       for (var y = 0; y < 9; y++) {
 
-         var circlePixel = circlePixels[(x + y) & 15];
 
-         if (!this.isBrighter(p, circlePixel, threshold)) {
 
-           brighter = false;
 
-           if (darker === false) {
 
-             break;
 
-           }
 
-         }
 
-         if (!this.isDarker(p, circlePixel, threshold)) {
 
-           darker = false;
 
-           if (brighter === false) {
 
-             break;
 
-           }
 
-         }
 
-       }
 
-       if (brighter || darker) {
 
-         return true;
 
-       }
 
-     }
 
-     return false;
 
-   };
 
-   /**
 
-    * Checks if the circle pixel is darker than the candidate pixel p by
 
-    * a threshold.
 
-    * @param {number} circlePixel The circle pixel value.
 
-    * @param {number} p The value of the candidate pixel p.
 
-    * @param {number} threshold
 
-    * @return {Boolean}
 
-    * @static
 
-    */
 
-   tracking.Fast.isDarker = function(circlePixel, p, threshold) {
 
-     return p - circlePixel > threshold;
 
-   };
 
-   /**
 
-    * Fast check to test if the candidate pixel is a trivially excluded value.
 
-    * In order to be a corner, the candidate pixel value should be darker or
 
-    * brighter than 9-12 surrounding pixels, when at least three of the top,
 
-    * bottom, left and right pixels are brighter or darker it can be
 
-    * automatically excluded improving the performance.
 
-    * @param {number} circlePixel The circle pixel value.
 
-    * @param {number} p The value of the candidate pixel p.
 
-    * @param {number} threshold
 
-    * @return {Boolean}
 
-    * @static
 
-    * @protected
 
-    */
 
-   tracking.Fast.isTriviallyExcluded = function(circlePixels, p, threshold) {
 
-     var count = 0;
 
-     var circleBottom = circlePixels[8];
 
-     var circleLeft = circlePixels[12];
 
-     var circleRight = circlePixels[4];
 
-     var circleTop = circlePixels[0];
 
-     if (this.isBrighter(circleTop, p, threshold)) {
 
-       count++;
 
-     }
 
-     if (this.isBrighter(circleRight, p, threshold)) {
 
-       count++;
 
-     }
 
-     if (this.isBrighter(circleBottom, p, threshold)) {
 
-       count++;
 
-     }
 
-     if (this.isBrighter(circleLeft, p, threshold)) {
 
-       count++;
 
-     }
 
-     if (count < 3) {
 
-       count = 0;
 
-       if (this.isDarker(circleTop, p, threshold)) {
 
-         count++;
 
-       }
 
-       if (this.isDarker(circleRight, p, threshold)) {
 
-         count++;
 
-       }
 
-       if (this.isDarker(circleBottom, p, threshold)) {
 
-         count++;
 
-       }
 
-       if (this.isDarker(circleLeft, p, threshold)) {
 
-         count++;
 
-       }
 
-       if (count < 3) {
 
-         return true;
 
-       }
 
-     }
 
-     return false;
 
-   };
 
-   /**
 
-    * Gets the sixteen offset values of the circle surrounding pixel.
 
-    * @param {number} width The image width.
 
-    * @return {array} Array with the sixteen offset values of the circle
 
-    *     surrounding pixel.
 
-    * @private
 
-    */
 
-   tracking.Fast.getCircleOffsets_ = function(width) {
 
-     if (this.circles_[width]) {
 
-       return this.circles_[width];
 
-     }
 
-     var circle = new Int32Array(16);
 
-     circle[0] = -width - width - width;
 
-     circle[1] = circle[0] + 1;
 
-     circle[2] = circle[1] + width + 1;
 
-     circle[3] = circle[2] + width + 1;
 
-     circle[4] = circle[3] + width;
 
-     circle[5] = circle[4] + width;
 
-     circle[6] = circle[5] + width - 1;
 
-     circle[7] = circle[6] + width - 1;
 
-     circle[8] = circle[7] - 1;
 
-     circle[9] = circle[8] - 1;
 
-     circle[10] = circle[9] - width - 1;
 
-     circle[11] = circle[10] - width - 1;
 
-     circle[12] = circle[11] - width;
 
-     circle[13] = circle[12] - width;
 
-     circle[14] = circle[13] - width + 1;
 
-     circle[15] = circle[14] - width + 1;
 
-     this.circles_[width] = circle;
 
-     return circle;
 
-   };
 
- }());
 
- (function() {
 
-   /**
 
-    * Math utility.
 
-    * @static
 
-    * @constructor
 
-    */
 
-   tracking.Math = {};
 
-   /**
 
-    * Euclidean distance between two points P(x0, y0) and P(x1, y1).
 
-    * @param {number} x0 Horizontal coordinate of P0.
 
-    * @param {number} y0 Vertical coordinate of P0.
 
-    * @param {number} x1 Horizontal coordinate of P1.
 
-    * @param {number} y1 Vertical coordinate of P1.
 
-    * @return {number} The euclidean distance.
 
-    */
 
-   tracking.Math.distance = function(x0, y0, x1, y1) {
 
-     var dx = x1 - x0;
 
-     var dy = y1 - y0;
 
-     return Math.sqrt(dx * dx + dy * dy);
 
-   };
 
-   /**
 
-    * Calculates the Hamming weight of a string, which is the number of symbols that are
 
-    * different from the zero-symbol of the alphabet used. It is thus
 
-    * equivalent to the Hamming distance from the all-zero string of the same
 
-    * length. For the most typical case, a string of bits, this is the number
 
-    * of 1's in the string.
 
-    *
 
-    * Example:
 
-    *
 
-    * <pre>
 
-    *  Binary string     Hamming weight
 
-    *   11101                 4
 
-    *   11101010              5
 
-    * </pre>
 
-    *
 
-    * @param {number} i Number that holds the binary string to extract the hamming weight.
 
-    * @return {number} The hamming weight.
 
-    */
 
-   tracking.Math.hammingWeight = function(i) {
 
-     i = i - ((i >> 1) & 0x55555555);
 
-     i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
 
-     return ((i + (i >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
 
-   };
 
-   /**
 
-    * Generates a random number between [a, b] interval.
 
-    * @param {number} a
 
-    * @param {number} b
 
-    * @return {number}
 
-    */
 
-   tracking.Math.uniformRandom = function(a, b) {
 
-     return a + Math.random() * (b - a);
 
-   };
 
-   /**
 
-    * Tests if a rectangle intersects with another.
 
-    *
 
-    *  <pre>
 
-    *  x0y0 --------       x2y2 --------
 
-    *      |       |           |       |
 
-    *      -------- x1y1       -------- x3y3
 
-    * </pre>
 
-    *
 
-    * @param {number} x0 Horizontal coordinate of P0.
 
-    * @param {number} y0 Vertical coordinate of P0.
 
-    * @param {number} x1 Horizontal coordinate of P1.
 
-    * @param {number} y1 Vertical coordinate of P1.
 
-    * @param {number} x2 Horizontal coordinate of P2.
 
-    * @param {number} y2 Vertical coordinate of P2.
 
-    * @param {number} x3 Horizontal coordinate of P3.
 
-    * @param {number} y3 Vertical coordinate of P3.
 
-    * @return {boolean}
 
-    */
 
-   tracking.Math.intersectRect = function(x0, y0, x1, y1, x2, y2, x3, y3) {
 
-     return !(x2 > x1 || x3 < x0 || y2 > y1 || y3 < y0);
 
-   };
 
- }());
 
- (function() {
 
-   /**
 
-    * Matrix utility.
 
-    * @static
 
-    * @constructor
 
-    */
 
-   tracking.Matrix = {};
 
-   /**
 
-    * Loops the array organized as major-row order and executes `fn` callback
 
-    * for each iteration. The `fn` callback receives the following parameters:
 
-    * `(r,g,b,a,index,i,j)`, where `r,g,b,a` represents the pixel color with
 
-    * alpha channel, `index` represents the position in the major-row order
 
-    * array and `i,j` the respective indexes positions in two dimensions.
 
-    * @param {array} pixels The pixels in a linear [r,g,b,a,...] array to loop
 
-    *     through.
 
-    * @param {number} width The image width.
 
-    * @param {number} height The image height.
 
-    * @param {function} fn The callback function for each pixel.
 
-    * @param {number} opt_jump Optional jump for the iteration, by default it
 
-    *     is 1, hence loops all the pixels of the array.
 
-    * @static
 
-    */
 
-   tracking.Matrix.forEach = function(pixels, width, height, fn, opt_jump) {
 
-     opt_jump = opt_jump || 1;
 
-     for (var i = 0; i < height; i += opt_jump) {
 
-       for (var j = 0; j < width; j += opt_jump) {
 
-         var w = i * width * 4 + j * 4;
 
-         fn.call(this, pixels[w], pixels[w + 1], pixels[w + 2], pixels[w + 3], w, i, j);
 
-       }
 
-     }
 
-   };
 
-   /**
 
-    * Calculates the per-element subtraction of two NxM matrices and returns a 
 
-    * new NxM matrix as the result.
 
-    * @param {matrix} a The first matrix.
 
-    * @param {matrix} a The second matrix.
 
-    * @static
 
-    */
 
-   tracking.Matrix.sub = function(a, b){
 
-     var res = tracking.Matrix.clone(a);
 
-     for(var i=0; i < res.length; i++){
 
-       for(var j=0; j < res[i].length; j++){
 
-         res[i][j] -= b[i][j]; 
 
-       }
 
-     }
 
-     return res;
 
-   }
 
-   /**
 
-    * Calculates the per-element sum of two NxM matrices and returns a new NxM
 
-    * NxM matrix as the result.
 
-    * @param {matrix} a The first matrix.
 
-    * @param {matrix} a The second matrix.
 
-    * @static
 
-    */
 
-   tracking.Matrix.add = function(a, b){
 
-     var res = tracking.Matrix.clone(a);
 
-     for(var i=0; i < res.length; i++){
 
-       for(var j=0; j < res[i].length; j++){
 
-         res[i][j] += b[i][j]; 
 
-       }
 
-     }
 
-     return res;
 
-   }
 
-   /**
 
-    * Clones a matrix (or part of it) and returns a new matrix as the result.
 
-    * @param {matrix} src The matrix to be cloned.
 
-    * @param {number} width The second matrix.
 
-    * @static
 
-    */
 
-   tracking.Matrix.clone = function(src, width, height){
 
-     width = width || src[0].length;
 
-     height = height || src.length;
 
-     var temp = new Array(height);
 
-     var i = height;
 
-     while(i--){
 
-       temp[i] = new Array(width);
 
-       var j = width;
 
-       while(j--) temp[i][j] = src[i][j];
 
-     } 
 
-     return temp;
 
-   }
 
-   /**
 
-    * Multiply a matrix by a scalar and returns a new matrix as the result.
 
-    * @param {number} scalar The scalar to multiply the matrix by.
 
-    * @param {matrix} src The matrix to be multiplied.
 
-    * @static
 
-    */
 
-   tracking.Matrix.mulScalar = function(scalar, src){
 
-     var res = tracking.Matrix.clone(src);
 
-     for(var i=0; i < src.length; i++){
 
-       for(var j=0; j < src[i].length; j++){
 
-         res[i][j] *= scalar;
 
-       }
 
-     }
 
-     return res;
 
-   }
 
-   /**
 
-    * Transpose a matrix and returns a new matrix as the result.
 
-    * @param {matrix} src The matrix to be transposed.
 
-    * @static
 
-    */
 
-   tracking.Matrix.transpose = function(src){
 
-     var transpose = new Array(src[0].length);
 
-     for(var i=0; i < src[0].length; i++){
 
-       transpose[i] = new Array(src.length);
 
-       for(var j=0; j < src.length; j++){
 
-         transpose[i][j] = src[j][i];
 
-       }
 
-     }
 
-     return transpose;
 
-   }
 
-   /**
 
-    * Multiply an MxN matrix with an NxP matrix and returns a new MxP matrix
 
-    * as the result.
 
-    * @param {matrix} a The first matrix.
 
-    * @param {matrix} b The second matrix.
 
-    * @static
 
-    */
 
-   tracking.Matrix.mul = function(a, b) {
 
-     var res = new Array(a.length);
 
-     for (var i = 0; i < a.length; i++) {
 
-       res[i] = new Array(b[0].length);
 
-       for (var j = 0; j < b[0].length; j++) {
 
-         res[i][j] = 0;            
 
-         for (var k = 0; k < a[0].length; k++) {
 
-           res[i][j] += a[i][k] * b[k][j];
 
-         }
 
-       }
 
-     }
 
-     return res;
 
-   }
 
-   /**
 
-    * Calculates the absolute norm of a matrix.
 
-    * @param {matrix} src The matrix which norm will be calculated.
 
-    * @static
 
-    */
 
-   tracking.Matrix.norm = function(src){
 
-     var res = 0;
 
-     for(var i=0; i < src.length; i++){
 
-       for(var j=0; j < src[i].length; j++){
 
-         res += src[i][j]*src[i][j];
 
-       }
 
-     }
 
-     return Math.sqrt(res);
 
-   }
 
-   /**
 
-    * Calculates and returns the covariance matrix of a set of vectors as well
 
-    * as the mean of the matrix.
 
-    * @param {matrix} src The matrix which covariance matrix will be calculated.
 
-    * @static
 
-    */
 
-   tracking.Matrix.calcCovarMatrix = function(src){
 
-     var mean = new Array(src.length);
 
-     for(var i=0; i < src.length; i++){
 
-       mean[i] = [0.0];
 
-       for(var j=0; j < src[i].length; j++){
 
-         mean[i][0] += src[i][j]/src[i].length;
 
-       }
 
-     }
 
-     var deltaFull = tracking.Matrix.clone(mean);
 
-     for(var i=0; i < deltaFull.length; i++){
 
-       for(var j=0; j < src[0].length - 1; j++){
 
-         deltaFull[i].push(deltaFull[i][0]);
 
-       }
 
-     }
 
-     var a = tracking.Matrix.sub(src, deltaFull);
 
-     var b = tracking.Matrix.transpose(a);
 
-     var covar = tracking.Matrix.mul(b,a); 
 
-     return [covar, mean];
 
-   }
 
- }());
 
- (function() {
 
-   /**
 
-    * EPnp utility.
 
-    * @static
 
-    * @constructor
 
-    */
 
-   tracking.EPnP = {};
 
-   tracking.EPnP.solve = function(objectPoints, imagePoints, cameraMatrix) {};
 
- }());
 
- (function() {
 
-   /**
 
-    * Tracker utility.
 
-    * @constructor
 
-    * @extends {tracking.EventEmitter}
 
-    */
 
-   tracking.Tracker = function() {
 
-     tracking.Tracker.base(this, 'constructor');
 
-   };
 
-   tracking.inherits(tracking.Tracker, tracking.EventEmitter);
 
-   /**
 
-    * Tracks the pixels on the array. This method is called for each video
 
-    * frame in order to emit `track` event.
 
-    * @param {Uint8ClampedArray} pixels The pixels data to track.
 
-    * @param {number} width The pixels canvas width.
 
-    * @param {number} height The pixels canvas height.
 
-    */
 
-   tracking.Tracker.prototype.track = function() {};
 
- }());
 
- (function() {
 
-   /**
 
-    * TrackerTask utility.
 
-    * @constructor
 
-    * @extends {tracking.EventEmitter}
 
-    */
 
-   tracking.TrackerTask = function(tracker) {
 
-     tracking.TrackerTask.base(this, 'constructor');
 
-     if (!tracker) {
 
-       throw new Error('Tracker instance not specified.');
 
-     }
 
-     this.setTracker(tracker);
 
-   };
 
-   tracking.inherits(tracking.TrackerTask, tracking.EventEmitter);
 
-   /**
 
-    * Holds the tracker instance managed by this task.
 
-    * @type {tracking.Tracker}
 
-    * @private
 
-    */
 
-   tracking.TrackerTask.prototype.tracker_ = null;
 
-   /**
 
-    * Holds if the tracker task is in running.
 
-    * @type {boolean}
 
-    * @private
 
-    */
 
-   tracking.TrackerTask.prototype.running_ = false;
 
-   /**
 
-    * Gets the tracker instance managed by this task.
 
-    * @return {tracking.Tracker}
 
-    */
 
-   tracking.TrackerTask.prototype.getTracker = function() {
 
-     return this.tracker_;
 
-   };
 
-   /**
 
-    * Returns true if the tracker task is in running, false otherwise.
 
-    * @return {boolean}
 
-    * @private
 
-    */
 
-   tracking.TrackerTask.prototype.inRunning = function() {
 
-     return this.running_;
 
-   };
 
-   /**
 
-    * Sets if the tracker task is in running.
 
-    * @param {boolean} running
 
-    * @private
 
-    */
 
-   tracking.TrackerTask.prototype.setRunning = function(running) {
 
-     this.running_ = running;
 
-   };
 
-   /**
 
-    * Sets the tracker instance managed by this task.
 
-    * @return {tracking.Tracker}
 
-    */
 
-   tracking.TrackerTask.prototype.setTracker = function(tracker) {
 
-     this.tracker_ = tracker;
 
-   };
 
-   /**
 
-    * Emits a `run` event on the tracker task for the implementers to run any
 
-    * child action, e.g. `requestAnimationFrame`.
 
-    * @return {object} Returns itself, so calls can be chained.
 
-    */
 
-   tracking.TrackerTask.prototype.run = function() {
 
-     var self = this;
 
-     if (this.inRunning()) {
 
-       return;
 
-     }
 
-     this.setRunning(true);
 
-     this.reemitTrackEvent_ = function(event) {
 
-       self.emit('track', event);
 
-     };
 
-     this.tracker_.on('track', this.reemitTrackEvent_);
 
-     this.emit('run');
 
-     return this;
 
-   };
 
-   /**
 
-    * Emits a `stop` event on the tracker task for the implementers to stop any
 
-    * child action being done, e.g. `requestAnimationFrame`.
 
-    * @return {object} Returns itself, so calls can be chained.
 
-    */
 
-   tracking.TrackerTask.prototype.stop = function() {
 
-     if (!this.inRunning()) {
 
-       return;
 
-     }
 
-     this.setRunning(false);
 
-     this.emit('stop');
 
-     this.tracker_.removeListener('track', this.reemitTrackEvent_);
 
-     return this;
 
-   };
 
- }());
 
- (function() {
 
-   /**
 
-    * ColorTracker utility to track colored blobs in a frame using color
 
-    * difference evaluation.
 
-    * @constructor
 
-    * @param {string|Array.<string>} opt_colors Optional colors to track.
 
-    * @extends {tracking.Tracker}
 
-    */
 
-   tracking.ColorTracker = function(opt_colors) {
 
-     tracking.ColorTracker.base(this, 'constructor');
 
-     if (typeof opt_colors === 'string') {
 
-       opt_colors = [opt_colors];
 
-     }
 
-     if (opt_colors) {
 
-       opt_colors.forEach(function(color) {
 
-         if (!tracking.ColorTracker.getColor(color)) {
 
-           throw new Error('Color not valid, try `new tracking.ColorTracker("magenta")`.');
 
-         }
 
-       });
 
-       this.setColors(opt_colors);
 
-     }
 
-   };
 
-   tracking.inherits(tracking.ColorTracker, tracking.Tracker);
 
-   /**
 
-    * Holds the known colors.
 
-    * @type {Object.<string, function>}
 
-    * @private
 
-    * @static
 
-    */
 
-   tracking.ColorTracker.knownColors_ = {};
 
-   /**
 
-    * Caches coordinates values of the neighbours surrounding a pixel.
 
-    * @type {Object.<number, Int32Array>}
 
-    * @private
 
-    * @static
 
-    */
 
-   tracking.ColorTracker.neighbours_ = {};
 
-   /**
 
-    * Registers a color as known color.
 
-    * @param {string} name The color name.
 
-    * @param {function} fn The color function to test if the passed (r,g,b) is
 
-    *     the desired color.
 
-    * @static
 
-    */
 
-   tracking.ColorTracker.registerColor = function(name, fn) {
 
-     tracking.ColorTracker.knownColors_[name] = fn;
 
-   };
 
-   /**
 
-    * Gets the known color function that is able to test whether an (r,g,b) is
 
-    * the desired color.
 
-    * @param {string} name The color name.
 
-    * @return {function} The known color test function.
 
-    * @static
 
-    */
 
-   tracking.ColorTracker.getColor = function(name) {
 
-     return tracking.ColorTracker.knownColors_[name];
 
-   };
 
-   /**
 
-    * Holds the colors to be tracked by the `ColorTracker` instance.
 
-    * @default ['magenta']
 
-    * @type {Array.<string>}
 
-    */
 
-   tracking.ColorTracker.prototype.colors = ['magenta'];
 
-   /**
 
-    * Holds the minimum dimension to classify a rectangle.
 
-    * @default 20
 
-    * @type {number}
 
-    */
 
-   tracking.ColorTracker.prototype.minDimension = 20;
 
-   /**
 
-    * Holds the maximum dimension to classify a rectangle.
 
-    * @default Infinity
 
-    * @type {number}
 
-    */
 
-   tracking.ColorTracker.prototype.maxDimension = Infinity;
 
-   /**
 
-    * Holds the minimum group size to be classified as a rectangle.
 
-    * @default 30
 
-    * @type {number}
 
-    */
 
-   tracking.ColorTracker.prototype.minGroupSize = 30;
 
-   /**
 
-    * Calculates the central coordinate from the cloud points. The cloud points
 
-    * are all points that matches the desired color.
 
-    * @param {Array.<number>} cloud Major row order array containing all the
 
-    *     points from the desired color, e.g. [x1, y1, c2, y2, ...].
 
-    * @param {number} total Total numbers of pixels of the desired color.
 
-    * @return {object} Object containing the x, y and estimated z coordinate of
 
-    *     the blog extracted from the cloud points.
 
-    * @private
 
-    */
 
-   tracking.ColorTracker.prototype.calculateDimensions_ = function(cloud, total) {
 
-     var maxx = -1;
 
-     var maxy = -1;
 
-     var minx = Infinity;
 
-     var miny = Infinity;
 
-     for (var c = 0; c < total; c += 2) {
 
-       var x = cloud[c];
 
-       var y = cloud[c + 1];
 
-       if (x < minx) {
 
-         minx = x;
 
-       }
 
-       if (x > maxx) {
 
-         maxx = x;
 
-       }
 
-       if (y < miny) {
 
-         miny = y;
 
-       }
 
-       if (y > maxy) {
 
-         maxy = y;
 
-       }
 
-     }
 
-     return {
 
-       width: maxx - minx,
 
-       height: maxy - miny,
 
-       x: minx,
 
-       y: miny
 
-     };
 
-   };
 
-   /**
 
-    * Gets the colors being tracked by the `ColorTracker` instance.
 
-    * @return {Array.<string>}
 
-    */
 
-   tracking.ColorTracker.prototype.getColors = function() {
 
-     return this.colors;
 
-   };
 
-   /**
 
-    * Gets the minimum dimension to classify a rectangle.
 
-    * @return {number}
 
-    */
 
-   tracking.ColorTracker.prototype.getMinDimension = function() {
 
-     return this.minDimension;
 
-   };
 
-   /**
 
-    * Gets the maximum dimension to classify a rectangle.
 
-    * @return {number}
 
-    */
 
-   tracking.ColorTracker.prototype.getMaxDimension = function() {
 
-     return this.maxDimension;
 
-   };
 
-   /**
 
-    * Gets the minimum group size to be classified as a rectangle.
 
-    * @return {number}
 
-    */
 
-   tracking.ColorTracker.prototype.getMinGroupSize = function() {
 
-     return this.minGroupSize;
 
-   };
 
-   /**
 
-    * Gets the eight offset values of the neighbours surrounding a pixel.
 
-    * @param {number} width The image width.
 
-    * @return {array} Array with the eight offset values of the neighbours
 
-    *     surrounding a pixel.
 
-    * @private
 
-    */
 
-   tracking.ColorTracker.prototype.getNeighboursForWidth_ = function(width) {
 
-     if (tracking.ColorTracker.neighbours_[width]) {
 
-       return tracking.ColorTracker.neighbours_[width];
 
-     }
 
-     var neighbours = new Int32Array(8);
 
-     neighbours[0] = -width * 4;
 
-     neighbours[1] = -width * 4 + 4;
 
-     neighbours[2] = 4;
 
-     neighbours[3] = width * 4 + 4;
 
-     neighbours[4] = width * 4;
 
-     neighbours[5] = width * 4 - 4;
 
-     neighbours[6] = -4;
 
-     neighbours[7] = -width * 4 - 4;
 
-     tracking.ColorTracker.neighbours_[width] = neighbours;
 
-     return neighbours;
 
-   };
 
-   /**
 
-    * Unites groups whose bounding box intersect with each other.
 
-    * @param {Array.<Object>} rects
 
-    * @private
 
-    */
 
-   tracking.ColorTracker.prototype.mergeRectangles_ = function(rects) {
 
-     var intersects;
 
-     var results = [];
 
-     var minDimension = this.getMinDimension();
 
-     var maxDimension = this.getMaxDimension();
 
-     for (var r = 0; r < rects.length; r++) {
 
-       var r1 = rects[r];
 
-       intersects = true;
 
-       for (var s = r + 1; s < rects.length; s++) {
 
-         var r2 = rects[s];
 
-         if (tracking.Math.intersectRect(r1.x, r1.y, r1.x + r1.width, r1.y + r1.height, r2.x, r2.y, r2.x + r2.width, r2.y + r2.height)) {
 
-           intersects = false;
 
-           var x1 = Math.min(r1.x, r2.x);
 
-           var y1 = Math.min(r1.y, r2.y);
 
-           var x2 = Math.max(r1.x + r1.width, r2.x + r2.width);
 
-           var y2 = Math.max(r1.y + r1.height, r2.y + r2.height);
 
-           r2.height = y2 - y1;
 
-           r2.width = x2 - x1;
 
-           r2.x = x1;
 
-           r2.y = y1;
 
-           break;
 
-         }
 
-       }
 
-       if (intersects) {
 
-         if (r1.width >= minDimension && r1.height >= minDimension) {
 
-           if (r1.width <= maxDimension && r1.height <= maxDimension) {
 
-             results.push(r1);
 
-           }
 
-         }
 
-       }
 
-     }
 
-     return results;
 
-   };
 
-   /**
 
-    * Sets the colors to be tracked by the `ColorTracker` instance.
 
-    * @param {Array.<string>} colors
 
-    */
 
-   tracking.ColorTracker.prototype.setColors = function(colors) {
 
-     this.colors = colors;
 
-   };
 
-   /**
 
-    * Sets the minimum dimension to classify a rectangle.
 
-    * @param {number} minDimension
 
-    */
 
-   tracking.ColorTracker.prototype.setMinDimension = function(minDimension) {
 
-     this.minDimension = minDimension;
 
-   };
 
-   /**
 
-    * Sets the maximum dimension to classify a rectangle.
 
-    * @param {number} maxDimension
 
-    */
 
-   tracking.ColorTracker.prototype.setMaxDimension = function(maxDimension) {
 
-     this.maxDimension = maxDimension;
 
-   };
 
-   /**
 
-    * Sets the minimum group size to be classified as a rectangle.
 
-    * @param {number} minGroupSize
 
-    */
 
-   tracking.ColorTracker.prototype.setMinGroupSize = function(minGroupSize) {
 
-     this.minGroupSize = minGroupSize;
 
-   };
 
-   /**
 
-    * Tracks the `Video` frames. This method is called for each video frame in
 
-    * order to emit `track` event.
 
-    * @param {Uint8ClampedArray} pixels The pixels data to track.
 
-    * @param {number} width The pixels canvas width.
 
-    * @param {number} height The pixels canvas height.
 
-    */
 
-   tracking.ColorTracker.prototype.track = function(pixels, width, height) {
 
-     var self = this;
 
-     var colors = this.getColors();
 
-     if (!colors) {
 
-       throw new Error('Colors not specified, try `new tracking.ColorTracker("magenta")`.');
 
-     }
 
-     var results = [];
 
-     colors.forEach(function(color) {
 
-       results = results.concat(self.trackColor_(pixels, width, height, color));
 
-     });
 
-     this.emit('track', {
 
-       data: results
 
-     });
 
-   };
 
-   /**
 
-    * Find the given color in the given matrix of pixels using Flood fill
 
-    * algorithm to determines the area connected to a given node in a
 
-    * multi-dimensional array.
 
-    * @param {Uint8ClampedArray} pixels The pixels data to track.
 
-    * @param {number} width The pixels canvas width.
 
-    * @param {number} height The pixels canvas height.
 
-    * @param {string} color The color to be found
 
-    * @private
 
-    */
 
-   tracking.ColorTracker.prototype.trackColor_ = function(pixels, width, height, color) {
 
-     var colorFn = tracking.ColorTracker.knownColors_[color];
 
-     var currGroup = new Int32Array(pixels.length >> 2);
 
-     var currGroupSize;
 
-     var currI;
 
-     var currJ;
 
-     var currW;
 
-     var marked = new Int8Array(pixels.length);
 
-     var minGroupSize = this.getMinGroupSize();
 
-     var neighboursW = this.getNeighboursForWidth_(width);
 
-     var queue = new Int32Array(pixels.length);
 
-     var queuePosition;
 
-     var results = [];
 
-     var w = -4;
 
-     if (!colorFn) {
 
-       return results;
 
-     }
 
-     for (var i = 0; i < height; i++) {
 
-       for (var j = 0; j < width; j++) {
 
-         w += 4;
 
-         if (marked[w]) {
 
-           continue;
 
-         }
 
-         currGroupSize = 0;
 
-         queuePosition = -1;
 
-         queue[++queuePosition] = w;
 
-         queue[++queuePosition] = i;
 
-         queue[++queuePosition] = j;
 
-         marked[w] = 1;
 
-         while (queuePosition >= 0) {
 
-           currJ = queue[queuePosition--];
 
-           currI = queue[queuePosition--];
 
-           currW = queue[queuePosition--];
 
-           if (colorFn(pixels[currW], pixels[currW + 1], pixels[currW + 2], pixels[currW + 3], currW, currI, currJ)) {
 
-             currGroup[currGroupSize++] = currJ;
 
-             currGroup[currGroupSize++] = currI;
 
-             for (var k = 0; k < neighboursW.length; k++) {
 
-               var otherW = currW + neighboursW[k];
 
-               var otherI = currI + neighboursI[k];
 
-               var otherJ = currJ + neighboursJ[k];
 
-               if (!marked[otherW] && otherI >= 0 && otherI < height && otherJ >= 0 && otherJ < width) {
 
-                 queue[++queuePosition] = otherW;
 
-                 queue[++queuePosition] = otherI;
 
-                 queue[++queuePosition] = otherJ;
 
-                 marked[otherW] = 1;
 
-               }
 
-             }
 
-           }
 
-         }
 
-         if (currGroupSize >= minGroupSize) {
 
-           var data = this.calculateDimensions_(currGroup, currGroupSize);
 
-           if (data) {
 
-             data.color = color;
 
-             results.push(data);
 
-           }
 
-         }
 
-       }
 
-     }
 
-     return this.mergeRectangles_(results);
 
-   };
 
-   // Default colors
 
-   //===================
 
-   tracking.ColorTracker.registerColor('cyan', function(r, g, b) {
 
-     var thresholdGreen = 50,
 
-       thresholdBlue = 70,
 
-       dx = r - 0,
 
-       dy = g - 255,
 
-       dz = b - 255;
 
-     if ((g - r) >= thresholdGreen && (b - r) >= thresholdBlue) {
 
-       return true;
 
-     }
 
-     return dx * dx + dy * dy + dz * dz < 6400;
 
-   });
 
-   tracking.ColorTracker.registerColor('magenta', function(r, g, b) {
 
-     var threshold = 50,
 
-       dx = r - 255,
 
-       dy = g - 0,
 
-       dz = b - 255;
 
-     if ((r - g) >= threshold && (b - g) >= threshold) {
 
-       return true;
 
-     }
 
-     return dx * dx + dy * dy + dz * dz < 19600;
 
-   });
 
-   tracking.ColorTracker.registerColor('yellow', function(r, g, b) {
 
-     var threshold = 50,
 
-       dx = r - 255,
 
-       dy = g - 255,
 
-       dz = b - 0;
 
-     if ((r - b) >= threshold && (g - b) >= threshold) {
 
-       return true;
 
-     }
 
-     return dx * dx + dy * dy + dz * dz < 10000;
 
-   });
 
-   // Caching neighbour i/j offset values.
 
-   //=====================================
 
-   var neighboursI = new Int32Array([-1, -1, 0, 1, 1, 1, 0, -1]);
 
-   var neighboursJ = new Int32Array([0, 1, 1, 1, 0, -1, -1, -1]);
 
- }());
 
- (function() {
 
-   /**
 
-    * ObjectTracker utility.
 
-    * @constructor
 
-    * @param {string|Array.<string|Array.<number>>} opt_classifiers Optional
 
-    *     object classifiers to track.
 
-    * @extends {tracking.Tracker}
 
-    */
 
-   tracking.ObjectTracker = function(opt_classifiers) {
 
-     tracking.ObjectTracker.base(this, 'constructor');
 
-     if (opt_classifiers) {
 
-       if (!Array.isArray(opt_classifiers)) {
 
-         opt_classifiers = [opt_classifiers];
 
-       }
 
-       if (Array.isArray(opt_classifiers)) {
 
-         opt_classifiers.forEach(function(classifier, i) {
 
-           if (typeof classifier === 'string') {
 
-             opt_classifiers[i] = tracking.ViolaJones.classifiers[classifier];
 
-           }
 
-           if (!opt_classifiers[i]) {
 
-             throw new Error('Object classifier not valid, try `new tracking.ObjectTracker("face")`.');
 
-           }
 
-         });
 
-       }
 
-     }
 
-     this.setClassifiers(opt_classifiers);
 
-   };
 
-   tracking.inherits(tracking.ObjectTracker, tracking.Tracker);
 
-   /**
 
-    * Specifies the edges density of a block in order to decide whether to skip
 
-    * it or not.
 
-    * @default 0.2
 
-    * @type {number}
 
-    */
 
-   tracking.ObjectTracker.prototype.edgesDensity = 0.2;
 
-   /**
 
-    * Specifies the initial scale to start the feature block scaling.
 
-    * @default 1.0
 
-    * @type {number}
 
-    */
 
-   tracking.ObjectTracker.prototype.initialScale = 1.0;
 
-   /**
 
-    * Specifies the scale factor to scale the feature block.
 
-    * @default 1.25
 
-    * @type {number}
 
-    */
 
-   tracking.ObjectTracker.prototype.scaleFactor = 1.25;
 
-   /**
 
-    * Specifies the block step size.
 
-    * @default 1.5
 
-    * @type {number}
 
-    */
 
-   tracking.ObjectTracker.prototype.stepSize = 1.5;
 
-   /**
 
-    * Gets the tracker HAAR classifiers.
 
-    * @return {TypedArray.<number>}
 
-    */
 
-   tracking.ObjectTracker.prototype.getClassifiers = function() {
 
-     return this.classifiers;
 
-   };
 
-   /**
 
-    * Gets the edges density value.
 
-    * @return {number}
 
-    */
 
-   tracking.ObjectTracker.prototype.getEdgesDensity = function() {
 
-     return this.edgesDensity;
 
-   };
 
-   /**
 
-    * Gets the initial scale to start the feature block scaling.
 
-    * @return {number}
 
-    */
 
-   tracking.ObjectTracker.prototype.getInitialScale = function() {
 
-     return this.initialScale;
 
-   };
 
-   /**
 
-    * Gets the scale factor to scale the feature block.
 
-    * @return {number}
 
-    */
 
-   tracking.ObjectTracker.prototype.getScaleFactor = function() {
 
-     return this.scaleFactor;
 
-   };
 
-   /**
 
-    * Gets the block step size.
 
-    * @return {number}
 
-    */
 
-   tracking.ObjectTracker.prototype.getStepSize = function() {
 
-     return this.stepSize;
 
-   };
 
-   /**
 
-    * Tracks the `Video` frames. This method is called for each video frame in
 
-    * order to emit `track` event.
 
-    * @param {Uint8ClampedArray} pixels The pixels data to track.
 
-    * @param {number} width The pixels canvas width.
 
-    * @param {number} height The pixels canvas height.
 
-    */
 
-   tracking.ObjectTracker.prototype.track = function(pixels, width, height) {
 
-     var self = this;
 
-     var classifiers = this.getClassifiers();
 
-     if (!classifiers) {
 
-       throw new Error('Object classifier not specified, try `new tracking.ObjectTracker("face")`.');
 
-     }
 
-     var results = [];
 
-     classifiers.forEach(function(classifier) {
 
-       results = results.concat(tracking.ViolaJones.detect(pixels, width, height, self.getInitialScale(), self.getScaleFactor(), self.getStepSize(), self.getEdgesDensity(), classifier));
 
-     });
 
-     this.emit('track', {
 
-       data: results
 
-     });
 
-   };
 
-   /**
 
-    * Sets the tracker HAAR classifiers.
 
-    * @param {TypedArray.<number>} classifiers
 
-    */
 
-   tracking.ObjectTracker.prototype.setClassifiers = function(classifiers) {
 
-     this.classifiers = classifiers;
 
-   };
 
-   /**
 
-    * Sets the edges density.
 
-    * @param {number} edgesDensity
 
-    */
 
-   tracking.ObjectTracker.prototype.setEdgesDensity = function(edgesDensity) {
 
-     this.edgesDensity = edgesDensity;
 
-   };
 
-   /**
 
-    * Sets the initial scale to start the block scaling.
 
-    * @param {number} initialScale
 
-    */
 
-   tracking.ObjectTracker.prototype.setInitialScale = function(initialScale) {
 
-     this.initialScale = initialScale;
 
-   };
 
-   /**
 
-    * Sets the scale factor to scale the feature block.
 
-    * @param {number} scaleFactor
 
-    */
 
-   tracking.ObjectTracker.prototype.setScaleFactor = function(scaleFactor) {
 
-     this.scaleFactor = scaleFactor;
 
-   };
 
-   /**
 
-    * Sets the block step size.
 
-    * @param {number} stepSize
 
-    */
 
-   tracking.ObjectTracker.prototype.setStepSize = function(stepSize) {
 
-     this.stepSize = stepSize;
 
-   };
 
- }());
 
- (function() {
 
-   tracking.LandmarksTracker = function() {
 
-     tracking.LandmarksTracker.base(this, 'constructor');
 
-   }
 
-   tracking.inherits(tracking.LandmarksTracker, tracking.ObjectTracker);
 
-   tracking.LandmarksTracker.prototype.track = function(pixels, width, height) {
 
- 	 
 
-     var image = {
 
-       'data': pixels,
 
-       'width': width,
 
-       'height': height
 
-     };
 
-     var classifier = tracking.ViolaJones.classifiers['face'];
 
-     var faces = tracking.ViolaJones.detect(pixels, width, height, 
 
-       this.getInitialScale(), this.getScaleFactor(), this.getStepSize(), 
 
-       this.getEdgesDensity(), classifier);
 
-     var landmarks = tracking.LBF.align(pixels, width, height, faces);
 
-     this.emit('track', {
 
-       'data': {
 
-         'faces' : faces,
 
-         'landmarks' : landmarks
 
-       }
 
-     });
 
-   }
 
- }());
 
- (function() {
 
-   tracking.LBF = {};
 
-   /**
 
-    * LBF Regressor utility.
 
-    * @constructor
 
-    */
 
-   tracking.LBF.Regressor = function(maxNumStages){
 
-     this.maxNumStages = maxNumStages;
 
-     this.rfs = new Array(maxNumStages);
 
-     this.models = new Array(maxNumStages);
 
-     for(var i=0; i < maxNumStages; i++){
 
-       this.rfs[i] = new tracking.LBF.RandomForest(i);
 
-       this.models[i] = tracking.LBF.RegressorData[i].models;
 
-     }
 
-     this.meanShape = tracking.LBF.LandmarksData;
 
-   }
 
-   /**
 
-    * Predicts the position of the landmarks based on the bounding box of the face.
 
-    * @param {pixels} pixels The grayscale pixels in a linear array.
 
-    * @param {number} width Width of the image.
 
-    * @param {number} height Height of the image.
 
-    * @param {object} boudingBox Bounding box of the face to be aligned.
 
-    * @return {matrix} A matrix with each landmark position in a row [x,y].
 
-    */
 
-   tracking.LBF.Regressor.prototype.predict = function(pixels, width, height, boundingBox) {
 
-     var images = [];
 
-     var currentShapes = [];
 
-     var boundingBoxes = [];
 
-     var meanShapeClone = tracking.Matrix.clone(this.meanShape);
 
-     images.push({
 
-       'data': pixels,
 
-       'width': width,
 
-       'height': height
 
-     });
 
-     boundingBoxes.push(boundingBox);
 
-     currentShapes.push(tracking.LBF.projectShapeToBoundingBox_(meanShapeClone, boundingBox));
 
-     for(var stage = 0; stage < this.maxNumStages; stage++){
 
-       var binaryFeatures = tracking.LBF.Regressor.deriveBinaryFeat(this.rfs[stage], images, currentShapes, boundingBoxes, meanShapeClone);
 
-       this.applyGlobalPrediction(binaryFeatures, this.models[stage], currentShapes, boundingBoxes);
 
-     }
 
-     return currentShapes[0];
 
-   };
 
-   /**
 
-    * Multiplies the binary features of the landmarks with the regression matrix
 
-    * to obtain the displacement for each landmark. Then applies this displacement
 
-    * into the landmarks shape.
 
-    * @param {object} binaryFeatures The binary features for the landmarks.
 
-    * @param {object} models The regressor models.
 
-    * @param {matrix} currentShapes The landmarks shapes.
 
-    * @param {array} boudingBoxes The bounding boxes of the faces.
 
-    */
 
-   tracking.LBF.Regressor.prototype.applyGlobalPrediction = function(binaryFeatures, models, currentShapes, 
 
-     boundingBoxes){
 
-     var residual = currentShapes[0].length * 2;
 
-     var rotation = [];
 
-     var deltashape = new Array(residual/2);
 
-     for(var i=0; i < residual/2; i++){
 
-       deltashape[i] = [0.0, 0.0];
 
-     }
 
-     for(var i=0; i < currentShapes.length; i++){
 
-       for(var j=0; j < residual; j++){
 
-         var tmp = 0;
 
-         for(var lx=0, idx=0; (idx = binaryFeatures[i][lx].index) != -1; lx++){
 
-           if(idx <= models[j].nr_feature){
 
-             tmp += models[j].data[(idx - 1)] * binaryFeatures[i][lx].value;
 
-           }
 
-         }
 
-         if(j < residual/2){
 
-           deltashape[j][0] = tmp;
 
-         }else{
 
-           deltashape[j - residual/2][1] = tmp;
 
-         }
 
-       }
 
-       var res = tracking.LBF.similarityTransform_(tracking.LBF.unprojectShapeToBoundingBox_(currentShapes[i], boundingBoxes[i]), this.meanShape);
 
-       var rotation = tracking.Matrix.transpose(res[0]);
 
-       var s = tracking.LBF.unprojectShapeToBoundingBox_(currentShapes[i], boundingBoxes[i]);
 
-       s = tracking.Matrix.add(s, deltashape);
 
-       currentShapes[i] = tracking.LBF.projectShapeToBoundingBox_(s, boundingBoxes[i]);
 
-     }
 
-   };
 
-   /**
 
-    * Derives the binary features from the image for each landmark. 
 
-    * @param {object} forest The random forest to search for the best binary feature match.
 
-    * @param {array} images The images with pixels in a grayscale linear array.
 
-    * @param {array} currentShapes The current landmarks shape.
 
-    * @param {array} boudingBoxes The bounding boxes of the faces.
 
-    * @param {matrix} meanShape The mean shape of the current landmarks set.
 
-    * @return {array} The binary features extracted from the image and matched with the
 
-    *     training data.
 
-    * @static
 
-    */
 
-   tracking.LBF.Regressor.deriveBinaryFeat = function(forest, images, currentShapes, boundingBoxes, meanShape){
 
-     var binaryFeatures = new Array(images.length);
 
-     for(var i=0; i < images.length; i++){
 
-       var t = forest.maxNumTrees * forest.landmarkNum + 1;
 
-       binaryFeatures[i] = new Array(t);
 
-       for(var j=0; j < t; j++){
 
-         binaryFeatures[i][j] = {};
 
-       }
 
-     }
 
-     var leafnodesPerTree = 1 << (forest.maxDepth - 1);
 
-     for(var i=0; i < images.length; i++){
 
-       var projectedShape = tracking.LBF.unprojectShapeToBoundingBox_(currentShapes[i], boundingBoxes[i]);
 
-       var transform = tracking.LBF.similarityTransform_(projectedShape, meanShape);
 
-       
 
-       for(var j=0; j < forest.landmarkNum; j++){
 
-         for(var k=0; k < forest.maxNumTrees; k++){
 
-           var binaryCode = tracking.LBF.Regressor.getCodeFromTree(forest.rfs[j][k], images[i], 
 
-                               currentShapes[i], boundingBoxes[i], transform[0], transform[1]);
 
-           var index = j*forest.maxNumTrees + k;
 
-           binaryFeatures[i][index].index = leafnodesPerTree * index + binaryCode;
 
-           binaryFeatures[i][index].value = 1;
 
-         }
 
-       }
 
-       binaryFeatures[i][forest.landmarkNum * forest.maxNumTrees].index = -1;
 
-       binaryFeatures[i][forest.landmarkNum * forest.maxNumTrees].value = -1;
 
-     }
 
-     return binaryFeatures;
 
-   }
 
-   /**
 
-    * Gets the binary code for a specific tree in a random forest. For each landmark,
 
-    * the position from two pre-defined points are recovered from the training data
 
-    * and then the intensity of the pixels corresponding to these points is extracted 
 
-    * from the image and used to traverse the trees in the random forest. At the end,
 
-    * the ending nodes will be represented by 1, and the remaining nodes by 0.
 
-    * 
 
-    * +--------------------------- Random Forest -----------------------------+ 
 
-    * | Ø = Ending leaf                                                       |
 
-    * |                                                                       |
 
-    * |       O             O             O             O             O       |
 
-    * |     /   \         /   \         /   \         /   \         /   \     |
 
-    * |    O     O       O     O       O     O       O     O       O     O    |
 
-    * |   / \   / \     / \   / \     / \   / \     / \   / \     / \   / \   |
 
-    * |  Ø   O O   O   O   O Ø   O   O   Ø O   O   O   O Ø   O   O   O O   Ø  |
 
-    * |  1   0 0   0   0   0 1   0   0   1 0   0   0   0 1   0   0   0 0   1  |
 
-    * +-----------------------------------------------------------------------+
 
-    * Final binary code for this landmark: 10000010010000100001
 
-    *
 
-    * @param {object} forest The tree to be analyzed.
 
-    * @param {array} image The image with pixels in a grayscale linear array.
 
-    * @param {matrix} shape The current landmarks shape.
 
-    * @param {object} boudingBoxes The bounding box of the face.
 
-    * @param {matrix} rotation The rotation matrix used to transform the projected landmarks
 
-    *     into the mean shape.
 
-    * @param {number} scale The scale factor used to transform the projected landmarks
 
-    *     into the mean shape.
 
-    * @return {number} The binary code extracted from the tree.
 
-    * @static
 
-    */
 
-   tracking.LBF.Regressor.getCodeFromTree = function(tree, image, shape, boundingBox, rotation, scale){
 
-     var current = 0;
 
-     var bincode = 0;
 
-     while(true){
 
-       
 
-       var x1 = Math.cos(tree.nodes[current].feats[0]) * tree.nodes[current].feats[2] * tree.maxRadioRadius * boundingBox.width;
 
-       var y1 = Math.sin(tree.nodes[current].feats[0]) * tree.nodes[current].feats[2] * tree.maxRadioRadius * boundingBox.height;
 
-       var x2 = Math.cos(tree.nodes[current].feats[1]) * tree.nodes[current].feats[3] * tree.maxRadioRadius * boundingBox.width;
 
-       var y2 = Math.sin(tree.nodes[current].feats[1]) * tree.nodes[current].feats[3] * tree.maxRadioRadius * boundingBox.height;
 
-       var project_x1 = rotation[0][0] * x1 + rotation[0][1] * y1;
 
-       var project_y1 = rotation[1][0] * x1 + rotation[1][1] * y1;
 
-       var real_x1 = Math.floor(project_x1 + shape[tree.landmarkID][0]);
 
-       var real_y1 = Math.floor(project_y1 + shape[tree.landmarkID][1]);
 
-       real_x1 = Math.max(0.0, Math.min(real_x1, image.height - 1.0));
 
-       real_y1 = Math.max(0.0, Math.min(real_y1, image.width - 1.0));
 
-       var project_x2 = rotation[0][0] * x2 + rotation[0][1] * y2;
 
-       var project_y2 = rotation[1][0] * x2 + rotation[1][1] * y2;
 
-       var real_x2 = Math.floor(project_x2 + shape[tree.landmarkID][0]);
 
-       var real_y2 = Math.floor(project_y2 + shape[tree.landmarkID][1]);
 
-       real_x2 = Math.max(0.0, Math.min(real_x2, image.height - 1.0));
 
-       real_y2 = Math.max(0.0, Math.min(real_y2, image.width - 1.0));
 
-       var pdf = Math.floor(image.data[real_y1*image.width + real_x1]) - 
 
-           Math.floor(image.data[real_y2 * image.width +real_x2]);
 
-       if(pdf < tree.nodes[current].thresh){
 
-         current = tree.nodes[current].cnodes[0];
 
-       }else{
 
-         current = tree.nodes[current].cnodes[1];
 
-       }
 
-       if (tree.nodes[current].is_leafnode == 1) {
 
-         bincode = 1;
 
-         for (var i=0; i < tree.leafnodes.length; i++) {
 
-           if (tree.leafnodes[i] == current) {
 
-             return bincode;
 
-           }
 
-           bincode++;
 
-         }
 
-         return bincode;
 
-       }
 
-     }
 
-     return bincode;
 
-   }
 
- }());
 
- (function() {
 
-   /**
 
-    * Face Alignment via Regressing Local Binary Features (LBF)
 
-    * This approach has two components: a set of local binary features and
 
-    * a locality principle for learning those features.
 
-    * The locality principle is used to guide the learning of a set of highly
 
-    * discriminative local binary features for each landmark independently.
 
-    * The obtained local binary features are used to learn a linear regression
 
-    * that later will be used to guide the landmarks in the alignment phase.
 
-    * 
 
-    * @authors: VoxarLabs Team (http://cin.ufpe.br/~voxarlabs)
 
-    *           Lucas Figueiredo <lsf@cin.ufpe.br>, Thiago Menezes <tmc2@cin.ufpe.br>,
 
-    *           Thiago Domingues <tald@cin.ufpe.br>, Rafael Roberto <rar3@cin.ufpe.br>,
 
-    *           Thulio Araujo <tlsa@cin.ufpe.br>, Joao Victor <jvfl@cin.ufpe.br>,
 
-    *           Tomer Simis <tls@cin.ufpe.br>)
 
-    */
 
-   
 
-   /**
 
-    * Holds the maximum number of stages that will be used in the alignment algorithm.
 
-    * Each stage contains a different set of random forests and retrieves the binary
 
-    * code from a more "specialized" (i.e. smaller) region around the landmarks.
 
-    * @type {number}
 
-    * @static
 
-    */
 
-   tracking.LBF.maxNumStages = 4;
 
-   /**
 
-    * Holds the regressor that will be responsible for extracting the local features from 
 
-    * the image and guide the landmarks using the training data.
 
-    * @type {object}
 
-    * @protected
 
-    * @static
 
-    */
 
-   tracking.LBF.regressor_ = null; 
 
-   
 
-   /**
 
-    * Generates a set of landmarks for a set of faces
 
-    * @param {pixels} pixels The pixels in a linear [r,g,b,a,...] array.
 
-    * @param {number} width The image width.
 
-    * @param {number} height The image height.
 
-    * @param {array} faces The list of faces detected in the image
 
-    * @return {array} The aligned landmarks, each set of landmarks corresponding
 
-    *     to a specific face.
 
-    * @static
 
-    */
 
-   tracking.LBF.align = function(pixels, width, height, faces){
 
-     if(tracking.LBF.regressor_ == null){
 
-       tracking.LBF.regressor_ = new tracking.LBF.Regressor(
 
-         tracking.LBF.maxNumStages
 
-       );
 
-     }
 
-     pixels = tracking.Image.grayscale(pixels, width, height, false);
 
-     pixels = tracking.Image.equalizeHist(pixels, width, height);
 
-     var shapes = new Array(faces.length);
 
-     for(var i in faces){
 
-       faces[i].height = faces[i].width;
 
-       var boundingBox = {};
 
-       boundingBox.startX = faces[i].x;
 
-       boundingBox.startY = faces[i].y;
 
-       boundingBox.width = faces[i].width;
 
-       boundingBox.height = faces[i].height;
 
-       shapes[i] = tracking.LBF.regressor_.predict(pixels, width, height, boundingBox);
 
-     }
 
-     return shapes;
 
-   }
 
-   /**
 
-    * Unprojects the landmarks shape from the bounding box.
 
-    * @param {matrix} shape The landmarks shape.
 
-    * @param {matrix} boudingBox The bounding box.
 
-    * @return {matrix} The landmarks shape projected into the bounding box.
 
-    * @static
 
-    * @protected
 
-    */
 
-   tracking.LBF.unprojectShapeToBoundingBox_ = function(shape, boundingBox){
 
-     var temp = new Array(shape.length);
 
-     for(var i=0; i < shape.length; i++){
 
-       temp[i] = [
 
-         (shape[i][0] - boundingBox.startX) / boundingBox.width,
 
-         (shape[i][1] - boundingBox.startY) / boundingBox.height
 
-       ];
 
-     }
 
-     return temp;
 
-   }
 
-   /**
 
-    * Projects the landmarks shape into the bounding box. The landmarks shape has
 
-    * normalized coordinates, so it is necessary to map these coordinates into
 
-    * the bounding box coordinates.
 
-    * @param {matrix} shape The landmarks shape.
 
-    * @param {matrix} boudingBox The bounding box.
 
-    * @return {matrix} The landmarks shape.
 
-    * @static
 
-    * @protected
 
-    */
 
-   tracking.LBF.projectShapeToBoundingBox_ = function(shape, boundingBox){
 
-     var temp = new Array(shape.length);
 
-     for(var i=0; i < shape.length; i++){
 
-       temp[i] = [
 
-         shape[i][0] * boundingBox.width + boundingBox.startX,
 
-         shape[i][1] * boundingBox.height + boundingBox.startY
 
-       ];
 
-     }
 
-     return temp;
 
-   }
 
-   /**
 
-    * Calculates the rotation and scale necessary to transform shape1 into shape2.
 
-    * @param {matrix} shape1 The shape to be transformed.
 
-    * @param {matrix} shape2 The shape to be transformed in.
 
-    * @return {[matrix, scalar]} The rotation matrix and scale that applied to shape1
 
-    *     results in shape2.
 
-    * @static
 
-    * @protected
 
-    */
 
-   tracking.LBF.similarityTransform_ = function(shape1, shape2){
 
-     var center1 = [0,0];
 
-     var center2 = [0,0];
 
-     for (var i = 0; i < shape1.length; i++) {
 
-       center1[0] += shape1[i][0];
 
-       center1[1] += shape1[i][1];
 
-       center2[0] += shape2[i][0];
 
-       center2[1] += shape2[i][1];
 
-     }
 
-     center1[0] /= shape1.length;
 
-     center1[1] /= shape1.length;
 
-     center2[0] /= shape2.length;
 
-     center2[1] /= shape2.length;
 
-     var temp1 = tracking.Matrix.clone(shape1);
 
-     var temp2 = tracking.Matrix.clone(shape2);
 
-     for(var i=0; i < shape1.length; i++){
 
-       temp1[i][0] -= center1[0];
 
-       temp1[i][1] -= center1[1];
 
-       temp2[i][0] -= center2[0];
 
-       temp2[i][1] -= center2[1];
 
-     }
 
-     var covariance1, covariance2;
 
-     var mean1, mean2;
 
-     var t = tracking.Matrix.calcCovarMatrix(temp1);
 
-     covariance1 = t[0];
 
-     mean1 = t[1];
 
-     t = tracking.Matrix.calcCovarMatrix(temp2);
 
-     covariance2 = t[0];
 
-     mean2 = t[1];
 
-     var s1 = Math.sqrt(tracking.Matrix.norm(covariance1));
 
-     var s2 = Math.sqrt(tracking.Matrix.norm(covariance2));
 
-     var scale = s1/s2;
 
-     temp1 = tracking.Matrix.mulScalar(1.0/s1, temp1);
 
-     temp2 = tracking.Matrix.mulScalar(1.0/s2, temp2);
 
-     var num = 0, den = 0;
 
-     for (var i = 0; i < shape1.length; i++) {
 
-       num = num + temp1[i][1] * temp2[i][0] - temp1[i][0] * temp2[i][1];
 
-       den = den + temp1[i][0] * temp2[i][0] + temp1[i][1] * temp2[i][1];
 
-     }
 
-     var norm = Math.sqrt(num*num + den*den);
 
-     var sin_theta = num/norm;
 
-     var cos_theta = den/norm;
 
-     var rotation = [
 
-       [cos_theta, -sin_theta],
 
-       [sin_theta, cos_theta]
 
-     ];
 
-     return [rotation, scale];
 
-   }
 
-   /**
 
-    * LBF Random Forest data structure.
 
-    * @static
 
-    * @constructor
 
-    */
 
-   tracking.LBF.RandomForest = function(forestIndex){
 
-     this.maxNumTrees = tracking.LBF.RegressorData[forestIndex].max_numtrees;
 
-     this.landmarkNum = tracking.LBF.RegressorData[forestIndex].num_landmark;
 
-     this.maxDepth = tracking.LBF.RegressorData[forestIndex].max_depth;
 
-     this.stages = tracking.LBF.RegressorData[forestIndex].stages; 
 
-     this.rfs = new Array(this.landmarkNum);
 
-     for(var i=0; i < this.landmarkNum; i++){
 
-       this.rfs[i] = new Array(this.maxNumTrees);
 
-       for(var j=0; j < this.maxNumTrees; j++){
 
-         this.rfs[i][j] = new tracking.LBF.Tree(forestIndex, i, j);
 
-       }
 
-     }
 
-   }
 
-   /**
 
-    * LBF Tree data structure.
 
-    * @static
 
-    * @constructor
 
-    */
 
-   tracking.LBF.Tree = function(forestIndex, landmarkIndex, treeIndex){
 
-     var data = tracking.LBF.RegressorData[forestIndex].landmarks[landmarkIndex][treeIndex];
 
-     this.maxDepth = data.max_depth;
 
-     this.maxNumNodes = data.max_numnodes;
 
-     this.nodes = data.nodes;
 
-     this.landmarkID = data.landmark_id;
 
-     this.numLeafnodes = data.num_leafnodes;
 
-     this.numNodes = data.num_nodes;
 
-     this.maxNumFeats = data.max_numfeats;
 
-     this.maxRadioRadius = data.max_radio_radius;
 
-     this.leafnodes = data.id_leafnodes;
 
-   }
 
- }());
 
 
  |