├── .gitignore ├── images ├── ming.png ├── pizza.png ├── good_job.png ├── mingface.png ├── Om_nom_nom.png ├── explosion.png ├── olivepizza.png ├── pizzasmile.png ├── realpizza.png ├── thumbs_up.png ├── examplePink.jpeg ├── cookie_monster.png └── many_pizza_slices.jpeg ├── src ├── server.js ├── video.js ├── start.js ├── main.js └── tracking-min.js ├── package.json ├── index.html ├── README.md └── style └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | -------------------------------------------------------------------------------- /images/ming.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbwheeler/pizzaCatcherJS/HEAD/images/ming.png -------------------------------------------------------------------------------- /images/pizza.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbwheeler/pizzaCatcherJS/HEAD/images/pizza.png -------------------------------------------------------------------------------- /images/good_job.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbwheeler/pizzaCatcherJS/HEAD/images/good_job.png -------------------------------------------------------------------------------- /images/mingface.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbwheeler/pizzaCatcherJS/HEAD/images/mingface.png -------------------------------------------------------------------------------- /images/Om_nom_nom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbwheeler/pizzaCatcherJS/HEAD/images/Om_nom_nom.png -------------------------------------------------------------------------------- /images/explosion.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbwheeler/pizzaCatcherJS/HEAD/images/explosion.png -------------------------------------------------------------------------------- /images/olivepizza.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbwheeler/pizzaCatcherJS/HEAD/images/olivepizza.png -------------------------------------------------------------------------------- /images/pizzasmile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbwheeler/pizzaCatcherJS/HEAD/images/pizzasmile.png -------------------------------------------------------------------------------- /images/realpizza.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbwheeler/pizzaCatcherJS/HEAD/images/realpizza.png -------------------------------------------------------------------------------- /images/thumbs_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbwheeler/pizzaCatcherJS/HEAD/images/thumbs_up.png -------------------------------------------------------------------------------- /images/examplePink.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbwheeler/pizzaCatcherJS/HEAD/images/examplePink.jpeg -------------------------------------------------------------------------------- /images/cookie_monster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbwheeler/pizzaCatcherJS/HEAD/images/cookie_monster.png -------------------------------------------------------------------------------- /images/many_pizza_slices.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbwheeler/pizzaCatcherJS/HEAD/images/many_pizza_slices.jpeg -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | var connect = require('connect'); 2 | var serveStatic = require('serve-static'); 3 | 4 | connect().use(serveStatic(__dirname + '/../')).listen(process.env.PORT || 8080, function(){ 5 | console.log('Server running on 8080...'); 6 | }); 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "nodemon src/server.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "connect": "^3.5.0", 14 | "jquery": "^3.1.1", 15 | "nodemon": "^1.11.0", 16 | "serve-static": "^1.11.1", 17 | "tracking": "^1.1.3" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/video.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var video = document.querySelector("#webcam"); 3 | 4 | navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia; 5 | if (navigator.getUserMedia) { 6 | navigator.getUserMedia({ 7 | video: true 8 | }, handleVideo, videoError); 9 | } 10 | 11 | function handleVideo(stream) { 12 | video.src = window.URL.createObjectURL(stream); 13 | } 14 | 15 | function videoError(error) { 16 | console.log(error) 17 | } 18 | })() 19 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | pizzaCatcherJS - Catch the pizza! 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 |
18 | 19 |
20 | 21 |
22 | 23 | 24 |
25 | 26 | 27 |
28 |
29 | 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/start.js: -------------------------------------------------------------------------------- 1 | let time = 20; 2 | 3 | $('#site').addClass("hiddenClass"); 4 | 5 | let intervalId; 6 | let level = 1; 7 | function onTimer() { 8 | 9 | if($('#endgame')) $('#endgame').remove() 10 | 11 | if (time === 20) { 12 | if (level > 5) level = 1; 13 | intervalId = setInterval(() => fallingPizza(level), ((3500 - (150*level)))) 14 | level += 1 15 | } 16 | $('#site').removeClass("hiddenClass"); 17 | $('#site').addClass("showClass"); 18 | $('#mycounter').show() 19 | $('#start').hide() 20 | document.getElementById('mycounter').innerHTML = time; 21 | time--; 22 | 23 | if (time < 0) { 24 | $('#site').removeClass("showClass"); 25 | $('#site').addClass("hiddenClass"); 26 | document.getElementById('start').innerHTML = 'Start Game: Level ' + level; 27 | $('#start').show() 28 | $('#mycounter').hide() 29 | $('#score').hide() 30 | time = 20 31 | clearInterval(intervalId) 32 | endCheck(level) 33 | } 34 | 35 | else { 36 | setTimeout(onTimer, 1000); 37 | } 38 | } 39 | 40 | function endCheck(level) { 41 | if (level > 5) { 42 | $("#startbuttondiv").after(`
Game Over! Your score is ${score}!
`) 43 | $('#site').removeClass("showClass"); 44 | $('#site').addClass("hiddenClass"); 45 | document.getElementById('start').innerHTML = 'Start New Game'; 46 | $('#start').show() 47 | $('#mycounter').hide() 48 | $('#score').hide() 49 | score = 0 50 | time = 45 51 | clearInterval(intervalId) 52 | } 53 | } 54 | 55 | function addScore() { 56 | $('#score').show(); 57 | document.getElementById('score').innerHTML = `Score: ${score}`; 58 | } 59 | 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pizzaCatcherJS 2 | 3 | pizzaCatcherJS is a color detecting webcam game that allows people to interact with their computers and catch pizza thrown to them by our good friend Ming (it's an inside joke). It was built using Node, jQuery and a motion/color detecting library called tracking.js. It was made as a project for a hacakthon at Fullstack Acadmey. The game is deployed and viewable at http://pizzacatcherjs.herokuapp.com. 4 | 5 | ## Getting Started 6 | 7 | Follow these steps to get the game running on your machine 8 | 9 | ### Prerequisites 10 | 11 | This guide assumes that you have Node (and npm) installed. If you don't, you can get it here: https://nodejs.org. 12 | 13 | ### Installing 14 | 15 | Setup is easy, in the project directory run 16 | 17 | ``` 18 | npm install 19 | ``` 20 | 21 | then, to start the server run 22 | 23 | ``` 24 | npm start 25 | ``` 26 | 27 | and connect to localhost:8080 28 | 29 | You will need a pink sticker like the one located below (or a pink post-it note). This is what you will be catching the pizza with! 30 | 31 | ![alt text](https://github.com/sbwheeler/pizzaCatcherJS/blob/master/images/examplePink.jpeg) 32 | 33 | ## Running the tests 34 | 35 | Our test suite features testing for the routing and frontend. On the frontend, we test our jQuery for expected behavior, and also test specific actions of out libraries and modules. All tests are run via 36 | 37 | ``` 38 | npm test 39 | ``` 40 | 41 | ## Deployment 42 | 43 | pizzaCatcherJS is deployed on Heroku with minimal additional configuration. The .profile file and install scripts are written to handle deployment. 44 | 45 | ## Authors 46 | 47 | * **Anuj Shah** - [GitHub](https://github.com/anujshah108) 48 | * **Sam Wheeler** - [GitHub](https://github.com/sbwheeler) 49 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | tracking.ColorTracker.registerColor('pink', function(r, g, b) { 2 | if ((r > 180) && (g < 130 && g > 40) && (b < 160 && b > 80)) return true; 3 | return false; 4 | }) 5 | const tracker = new tracking.ColorTracker(['pink']); 6 | 7 | let trackerX; 8 | let trackerY; 9 | 10 | //for determining offset with different screen size 11 | let xOffset = document.getElementById('fullcontainer').offsetWidth; 12 | 13 | tracking.track('#webcam', tracker); 14 | tracker.on('track', function(event) { 15 | event.data.forEach(function(rect) { 16 | trackerX = (900 - rect.x) + ((xOffset - 900) / 2) 17 | trackerY = rect.y + 200; 18 | }); 19 | }); 20 | 21 | let score = 0; 22 | 23 | const pizzaImages = ['../images/pizza.png', '../images/pizzasmile.png', '../images/realpizza.png', '../images/olivepizza.png'] 24 | 25 | function fallingPizza(level) { 26 | let $pizzaSlice = $(``); 27 | $pizzaSlice.css({ 28 | 'left': (($('#webcam').offset().left + 25) + Math.random() * $('#webcam').width() - 50) + 'px', 29 | 'top': '200px' 30 | }); 31 | 32 | 33 | $('#pizzaZone').prepend($pizzaSlice); 34 | 35 | $pizzaSlice.animate({ 36 | top: '1000px' 37 | }, { 38 | duration: ((1 /level) * (Math.random() * (6000 - 4000) + 4000)), 39 | step: function(now, fx) { 40 | let pizzaX = $('.pizzaSlices').offset().left 41 | let pizzaY = $('.pizzaSlices').offset().top 42 | 43 | // console.log('pizza X: ', pizzaX, 'tracker X: ', trackerX) 44 | // console.log('pizza Y: ', pizzaY, 'tracker Y: ', trackerY) 45 | 46 | if ((pizzaX < trackerX + 75 && pizzaX > trackerX - 75) && (pizzaY < trackerY + 75 && pizzaY > trackerY - 75)) { 47 | score++; 48 | $('#score').html('Score: ' + score.toString()); 49 | let left; 50 | let top; 51 | if (this) { 52 | left = $(this).offset().left; 53 | top = $(this).offset().top; 54 | } 55 | const images = ['../images/mingface.png', '../images/explosion.png', '../images/Om_nom_nom.png', '../images/cookie_monster.png', '../images/good_job.png', '../images/thumbs_up.png'] 56 | $(this).replaceWith((``)) 57 | setTimeout(function() { 58 | $('#nomNom').remove() 59 | }, 1000) 60 | $(this).finish() 61 | } 62 | }, 63 | complete: function() { 64 | $(this).remove() 65 | } 66 | }); 67 | } 68 | -------------------------------------------------------------------------------- /style/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-image: url('../images/many_pizza_slices.jpeg'); 3 | font-family: "Arial", Helvetica, sans-serif; 4 | } 5 | 6 | .pizzaSlices { 7 | top: 0px; 8 | left: 0px; 9 | position: absolute; 10 | z-index: 200; 11 | width: 50px; 12 | } 13 | 14 | #webcam { 15 | transform: rotateY(180deg); 16 | -webkit-transform: rotateY(180deg); 17 | /* Safari and Chrome */ 18 | -moz-transform: rotateY(180deg); 19 | /* Firefox */ 20 | } 21 | 22 | #site { 23 | width: 900px; 24 | margin: 0 auto; 25 | } 26 | 27 | .hiddenClass { 28 | visibility: hidden 29 | } 30 | 31 | .showClass { 32 | visibility: visible; 33 | } 34 | 35 | #startbuttondiv { 36 | width: 200px; 37 | margin: 0 auto; 38 | } 39 | 40 | #start { 41 | background: #e61010; 42 | background-image: -webkit-linear-gradient(top, #e61010, #bf0404); 43 | background-image: -moz-linear-gradient(top, #e61010, #bf0404); 44 | background-image: -ms-linear-gradient(top, #e61010, #bf0404); 45 | background-image: -o-linear-gradient(top, #e61010, #bf0404); 46 | background-image: linear-gradient(to bottom, #e61010, #bf0404); 47 | -webkit-border-radius: 23; 48 | -moz-border-radius: 23; 49 | border-radius: 23px; 50 | text-shadow: 1px 1px 3px #cc262f; 51 | -webkit-box-shadow: 10px 4px 3px #a8a8a8; 52 | -moz-box-shadow: 10px 4px 3px #a8a8a8; 53 | box-shadow: 10px 4px 3px #a8a8a8; 54 | font-family: Georgia; 55 | color: #f5f5f5; 56 | font-size: 20px; 57 | padding: 28px; 58 | border: dotted #ff0000 5px; 59 | text-decoration: none; 60 | margin-left: 14%; 61 | } 62 | 63 | #start:hover { 64 | background: #e83131; 65 | background-image: -webkit-linear-gradient(top, #e83131, #f22424); 66 | background-image: -moz-linear-gradient(top, #e83131, #f22424); 67 | background-image: -ms-linear-gradient(top, #e83131, #f22424); 68 | background-image: -o-linear-gradient(top, #e83131, #f22424); 69 | background-image: linear-gradient(to bottom, #e83131, #f22424); 70 | text-decoration: none; 71 | } 72 | 73 | #ming { 74 | float: left; 75 | margin-left: 30%; 76 | } 77 | 78 | #score { 79 | float: right; 80 | margin-right: 0%; 81 | margin-top: -45%; 82 | font-size: 250%; 83 | padding:left 20px; 84 | } 85 | 86 | #mycounter { 87 | z-index: 2; 88 | position: absolute; 89 | margin-top: 24.2%; 90 | margin-left: -71%; 91 | font-size: 500%; 92 | border-radius: 90px; 93 | border: solid black 2px; 94 | width: 120px; 95 | text-align: center 96 | 97 | } 98 | 99 | #footer { 100 | text-align: center; 101 | } 102 | 103 | #endgame { 104 | border: solid black 3px; 105 | text-align: center; 106 | font-size: 200%; 107 | font-weight: bold; 108 | width:50%; 109 | margin: 0 auto; 110 | background-color: #DF0E0E; 111 | } 112 | -------------------------------------------------------------------------------- /src/tracking-min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * tracking - A modern approach for Computer Vision on the web. 3 | * @author Eduardo Lundgren 4 | * @version v1.1.2 5 | * @link http://trackingjs.com 6 | * @license BSD 7 | */ 8 | !function(t,r){t.tracking=t.tracking||{},tracking.inherits=function(t,r){function n(){}n.prototype=r.prototype,t.superClass_=r.prototype,t.prototype=new n,t.prototype.constructor=t,t.base=function(t,n){var e=Array.prototype.slice.call(arguments,2);return r.prototype[n].apply(t,e)}},tracking.initUserMedia_=function(r,n){t.navigator.getUserMedia({video:!0,audio:!(!n||!n.audio)},function(n){try{r.src=t.URL.createObjectURL(n)}catch(e){r.src=n}},function(){throw Error("Cannot capture user camera.")})},tracking.isNode=function(t){return t.nodeType||this.isWindow(t)},tracking.isWindow=function(t){return!!(t&&t.alert&&t.document)},tracking.one=function(t,r){return this.isNode(t)?t:(r||document).querySelector(t)},tracking.track=function(t,r,n){if(t=tracking.one(t),!t)throw new Error("Element not found, try a different element or selector.");if(!r)throw new Error("Tracker not specified, try `tracking.track(element, new tracking.FaceTracker())`.");switch(t.nodeName.toLowerCase()){case"canvas":return this.trackCanvas_(t,r,n);case"img":return this.trackImg_(t,r,n);case"video":return n&&n.camera&&this.initUserMedia_(t,n),this.trackVideo_(t,r,n);default:throw new Error("Element not supported, try in a canvas, img, or video.")}},tracking.trackCanvas_=function(t,r){var n=this,e=new tracking.TrackerTask(r);return e.on("run",function(){n.trackCanvasInternal_(t,r)}),e.run()},tracking.trackCanvasInternal_=function(t,r){var n=t.width,e=t.height,i=t.getContext("2d"),a=i.getImageData(0,0,n,e);r.track(a.data,n,e)},tracking.trackImg_=function(t,r){var n=t.width,e=t.height,i=document.createElement("canvas");i.width=n,i.height=e;var a=new tracking.TrackerTask(r);return a.on("run",function(){tracking.Canvas.loadImage(i,t.src,0,0,n,e,function(){tracking.trackCanvasInternal_(i,r)})}),a.run()},tracking.trackVideo_=function(r,n){var e,i,a=document.createElement("canvas"),o=a.getContext("2d"),c=function(){e=r.offsetWidth,i=r.offsetHeight,a.width=e,a.height=i};c(),r.addEventListener("resize",c);var s,g=function(){s=t.requestAnimationFrame(function(){if(r.readyState===r.HAVE_ENOUGH_DATA){try{o.drawImage(r,0,0,e,i)}catch(t){}tracking.trackCanvasInternal_(a,n)}g()})},h=new tracking.TrackerTask(n);return h.on("stop",function(){t.cancelAnimationFrame(s)}),h.on("run",function(){g()}),h.run()},t.URL||(t.URL=t.URL||t.webkitURL||t.msURL||t.oURL),navigator.getUserMedia||(navigator.getUserMedia=navigator.getUserMedia||navigator.webkitGetUserMedia||navigator.mozGetUserMedia||navigator.msGetUserMedia)}(window),function(){tracking.EventEmitter=function(){},tracking.EventEmitter.prototype.events_=null,tracking.EventEmitter.prototype.addListener=function(t,r){if("function"!=typeof r)throw new TypeError("Listener must be a function");return this.events_||(this.events_={}),this.emit("newListener",t,r),this.events_[t]||(this.events_[t]=[]),this.events_[t].push(r),this},tracking.EventEmitter.prototype.listeners=function(t){return this.events_&&this.events_[t]},tracking.EventEmitter.prototype.emit=function(t){var r=this.listeners(t);if(r){for(var n=Array.prototype.slice.call(arguments,1),e=0;ee)return this;n.splice(e,1)}return this},tracking.EventEmitter.prototype.setMaxListeners=function(){throw new Error("Not implemented")}}(),function(){tracking.Canvas={},tracking.Canvas.loadImage=function(t,r,n,e,i,a,o){var c=this,s=new window.Image;s.crossOrigin="*",s.onload=function(){var r=t.getContext("2d");t.width=i,t.height=a,r.drawImage(s,n,e,i,a),o&&o.call(c),s=null},s.src=r}}(),function(){tracking.DisjointSet=function(t){if(void 0===t)throw new Error("DisjointSet length not specified.");this.length=t,this.parent=new Uint32Array(t);for(var r=0;t>r;r++)this.parent[r]=r},tracking.DisjointSet.prototype.length=null,tracking.DisjointSet.prototype.parent=null,tracking.DisjointSet.prototype.find=function(t){return this.parent[t]===t?t:this.parent[t]=this.find(this.parent[t])},tracking.DisjointSet.prototype.union=function(t,r){var n=this.find(t),e=this.find(r);this.parent[n]=e}}(),function(){tracking.Image={},tracking.Image.blur=function(t,r,n,e){if(e=Math.abs(e),1>=e)throw new Error("Diameter should be greater than 1.");for(var i=e/2,a=Math.ceil(e)+(1-Math.ceil(e)%2),o=new Float32Array(a),c=(i+.5)/3,s=c*c,g=1/Math.sqrt(2*Math.PI*s),h=-1/(2*c*c),k=0,u=Math.floor(a/2),f=0;a>f;f++){var l=f-u,p=g*Math.exp(l*l*h);o[f]=p,k+=p}for(var v=0;vs;s++)for(var g=0;r>g;g++){var h=s*r*4+4*g,k=~~(.299*t[h]+.587*t[h+1]+.114*t[h+2]);if(e&&this.computePixelValueSAT_(e,r,s,g,k),i&&this.computePixelValueSAT_(i,r,s,g,k*k),a){var u=h-4*r,f=~~(.299*t[u]+.587*t[u+1]+.114*t[u+2]);this.computePixelValueRSAT_(a,r,s,g,k,f||0)}o&&this.computePixelValueSAT_(o,r,s,g,c[h])}},tracking.Image.computePixelValueRSAT_=function(t,r,n,e,i,a){var o=n*r+e;t[o]=(t[o-r-1]||0)+(t[o-r+1]||0)-(t[o-r-r]||0)+i+a},tracking.Image.computePixelValueSAT_=function(t,r,n,e,i){var a=n*r+e;t[a]=(t[a-r]||0)+(t[a-1]||0)+i-(t[a-r-1]||0)},tracking.Image.grayscale=function(t,r,n,e){for(var i=new Uint8ClampedArray(e?t.length:t.length>>2),a=0,o=0,c=0;n>c;c++)for(var s=0;r>s;s++){var g=.299*t[o]+.587*t[o+1]+.114*t[o+2];i[a++]=g,e&&(i[a++]=g,i[a++]=g,i[a++]=t[o+3]),o+=4}return i},tracking.Image.horizontalConvolve=function(t,r,n,e,i){for(var a=e.length,o=Math.floor(a/2),c=new Float32Array(r*n*4),s=i?1:0,g=0;n>g;g++)for(var h=0;r>h;h++){for(var k=g,u=h,f=4*(g*r+h),l=0,p=0,v=0,m=0,y=0;a>y;y++){var d=k,w=Math.min(r-1,Math.max(0,u+y-o)),T=4*(d*r+w),C=e[y];l+=t[T]*C,p+=t[T+1]*C,v+=t[T+2]*C,m+=t[T+3]*C}c[f]=l,c[f+1]=p,c[f+2]=v,c[f+3]=m+s*(255-m)}return c},tracking.Image.verticalConvolve=function(t,r,n,e,i){for(var a=e.length,o=Math.floor(a/2),c=new Float32Array(r*n*4),s=i?1:0,g=0;n>g;g++)for(var h=0;r>h;h++){for(var k=g,u=h,f=4*(g*r+h),l=0,p=0,v=0,m=0,y=0;a>y;y++){var d=Math.min(n-1,Math.max(0,k+y-o)),w=u,T=4*(d*r+w),C=e[y];l+=t[T]*C,p+=t[T+1]*C,v+=t[T+2]*C,m+=t[T+3]*C}c[f]=l,c[f+1]=p,c[f+2]=v,c[f+3]=m+s*(255-m)}return c},tracking.Image.separableConvolve=function(t,r,n,e,i,a){var o=this.verticalConvolve(t,r,n,i,a);return this.horizontalConvolve(o,r,n,e,a)},tracking.Image.sobel=function(t,r,n){t=this.grayscale(t,r,n,!0);for(var e=new Float32Array(r*n*4),i=new Float32Array([-1,0,1]),a=new Float32Array([1,2,1]),o=this.separableConvolve(t,r,n,i,a),c=this.separableConvolve(t,r,n,a,i),s=0;s0&&(s=new Int32Array(r*n)),tracking.Image.computeIntegralImage(t,r,n,k,u,f,s);for(var l=c[0],p=c[1],v=e*i,m=v*l|0,y=v*p|0;r>m&&n>y;){for(var d=v*a+.5|0,w=0;n-y>w;w+=d)for(var T=0;r-m>T;T+=d)o>0&&this.isTriviallyExcluded(o,s,w,T,r,m,y)||this.evalStages_(c,k,u,f,w,T,r,m,y,v)&&(h[g++]={width:m,height:y,x:T,y:w});v*=i,m=v*l|0,y=v*p|0}return this.mergeRectangles_(h)},tracking.ViolaJones.isTriviallyExcluded=function(t,r,n,e,i,a,o){var c=n*i+e,s=c+a,g=c+o*i,h=g+a,k=(r[c]-r[s]-r[g]+r[h])/(a*o*255);return t>k?!0:!1},tracking.ViolaJones.evalStages_=function(t,r,n,e,i,a,o,c,s,g){var h=1/(c*s),k=i*o+a,u=k+c,f=k+s*o,l=f+c,p=(r[k]-r[u]-r[f]+r[l])*h,v=(n[k]-n[u]-n[f]+n[l])*h-p*p,m=1;v>0&&(m=Math.sqrt(v));for(var y=t.length,d=2;y>d;){for(var w=0,T=t[d++],C=t[d++];C--;){for(var _=0,E=t[d++],M=t[d++],x=0;M>x;x++){var I,b,O,A,S=a+t[d++]*g+.5|0,D=i+t[d++]*g+.5|0,R=t[d++]*g+.5|0,j=t[d++]*g+.5|0,F=t[d++];E?(I=S-j+R+(D+R+j-1)*o,b=S+(D-1)*o,O=S-j+(D+j-1)*o,A=S+R+(D+R-1)*o,_+=(e[I]+e[b]-e[O]-e[A])*F):(I=D*o+S,b=I+R,O=I+j*o,A=O+R,_+=(r[I]-r[b]-r[O]+r[A])*F)}var L=t[d++],V=t[d++],U=t[d++];w+=L*m>_*h?V:U}if(T>w)return!1}return!0},tracking.ViolaJones.mergeRectangles_=function(t){for(var r=new tracking.DisjointSet(t.length),n=0;n=this.REGIONS_OVERLAP&&h/(u*(k/u))>=this.REGIONS_OVERLAP&&r.union(n,i)}}for(var f={},l=0;l>1)*(this.N>>5)),i=0,a=this.getRandomOffsets_(r),o=0,c=0;ch;h++)t[a[g++]+s]>1,a=n.length>>1,o=new Array(i),c=0;i>c;c++){for(var s=1/0,g=0,h=0;a>h;h++){for(var k=0,u=0,f=this.N>>5;f>u;u++)k+=tracking.Math.hammingWeight(r[c*f+u]^e[h*f+u]);s>k&&(s=k,g=h)}o[c]={index1:c,index2:g,keypoint1:[t[2*c],t[2*c+1]],keypoint2:[n[2*g],n[2*g+1]],confidence:1-s/this.N}}return o},tracking.Brief.reciprocalMatch=function(t,r,n,e){var i=[];if(0===t.length||0===n.length)return i;for(var a=tracking.Brief.match(t,r,n,e),o=tracking.Brief.match(n,e,t,r),c=0;cc;c++)for(var s=3;r-3>s;s++){for(var g=c*r+s,h=t[g],k=0;16>k;k++)a[k]=t[g+i[k]];this.isCorner(h,a,e)&&(o.push(s,c),s+=3)}return o},tracking.Fast.isBrighter=function(t,r,n){return t-r>n},tracking.Fast.isCorner=function(t,r,n){if(this.isTriviallyExcluded(r,t,n))return!1;for(var e=0;16>e;e++){for(var i=!0,a=!0,o=0;9>o;o++){var c=r[e+o&15];if(!this.isBrighter(t,c,n)&&(a=!1,i===!1))break;if(!this.isDarker(t,c,n)&&(i=!1,a===!1))break}if(a||i)return!0}return!1},tracking.Fast.isDarker=function(t,r,n){return r-t>n},tracking.Fast.isTriviallyExcluded=function(t,r,n){var e=0,i=t[8],a=t[12],o=t[4],c=t[0];return this.isBrighter(c,r,n)&&e++,this.isBrighter(o,r,n)&&e++,this.isBrighter(i,r,n)&&e++,this.isBrighter(a,r,n)&&e++,3>e&&(e=0,this.isDarker(c,r,n)&&e++,this.isDarker(o,r,n)&&e++,this.isDarker(i,r,n)&&e++,this.isDarker(a,r,n)&&e++,3>e)?!0:!1},tracking.Fast.getCircleOffsets_=function(t){if(this.circles_[t])return this.circles_[t];var r=new Int32Array(16);return r[0]=-t-t-t,r[1]=r[0]+1,r[2]=r[1]+t+1,r[3]=r[2]+t+1,r[4]=r[3]+t,r[5]=r[4]+t,r[6]=r[5]+t-1,r[7]=r[6]+t-1,r[8]=r[7]-1,r[9]=r[8]-1,r[10]=r[9]-t-1,r[11]=r[10]-t-1,r[12]=r[11]-t,r[13]=r[12]-t,r[14]=r[13]-t+1,r[15]=r[14]-t+1,this.circles_[t]=r,r}}(),function(){tracking.Math={},tracking.Math.distance=function(t,r,n,e){var i=n-t,a=e-r;return Math.sqrt(i*i+a*a)},tracking.Math.hammingWeight=function(t){return t-=t>>1&1431655765,t=(858993459&t)+(t>>2&858993459),16843009*(t+(t>>4)&252645135)>>24},tracking.Math.uniformRandom=function(t,r){return t+Math.random()*(r-t)},tracking.Math.intersectRect=function(t,r,n,e,i,a,o,c){return!(i>n||t>o||a>e||r>c)}}(),function(){tracking.Matrix={},tracking.Matrix.forEach=function(t,r,n,e,i){i=i||1;for(var a=0;n>a;a+=i)for(var o=0;r>o;o+=i){var c=a*r*4+4*o;e.call(this,t[c],t[c+1],t[c+2],t[c+3],c,a,o)}}}(),function(){tracking.EPnP={},tracking.EPnP.solve=function(t,r,n){}}(),function(){tracking.Tracker=function(){tracking.Tracker.base(this,"constructor")},tracking.inherits(tracking.Tracker,tracking.EventEmitter),tracking.Tracker.prototype.track=function(){}}(),function(){tracking.TrackerTask=function(t){if(tracking.TrackerTask.base(this,"constructor"),!t)throw new Error("Tracker instance not specified.");this.setTracker(t)},tracking.inherits(tracking.TrackerTask,tracking.EventEmitter),tracking.TrackerTask.prototype.tracker_=null,tracking.TrackerTask.prototype.running_=!1,tracking.TrackerTask.prototype.getTracker=function(){return this.tracker_},tracking.TrackerTask.prototype.inRunning=function(){return this.running_},tracking.TrackerTask.prototype.setRunning=function(t){this.running_=t},tracking.TrackerTask.prototype.setTracker=function(t){this.tracker_=t},tracking.TrackerTask.prototype.run=function(){var t=this;if(!this.inRunning())return this.setRunning(!0),this.reemitTrackEvent_=function(r){t.emit("track",r)},this.tracker_.on("track",this.reemitTrackEvent_),this.emit("run"),this},tracking.TrackerTask.prototype.stop=function(){return this.inRunning()?(this.setRunning(!1),this.emit("stop"),this.tracker_.removeListener("track",this.reemitTrackEvent_),this):void 0}}(),function(){tracking.ColorTracker=function(t){tracking.ColorTracker.base(this,"constructor"),"string"==typeof t&&(t=[t]),t&&(t.forEach(function(t){if(!tracking.ColorTracker.getColor(t))throw new Error('Color not valid, try `new tracking.ColorTracker("magenta")`.')}),this.setColors(t))},tracking.inherits(tracking.ColorTracker,tracking.Tracker),tracking.ColorTracker.knownColors_={},tracking.ColorTracker.neighbours_={},tracking.ColorTracker.registerColor=function(t,r){tracking.ColorTracker.knownColors_[t]=r},tracking.ColorTracker.getColor=function(t){return tracking.ColorTracker.knownColors_[t]},tracking.ColorTracker.prototype.colors=["magenta"],tracking.ColorTracker.prototype.minDimension=20,tracking.ColorTracker.prototype.maxDimension=1/0,tracking.ColorTracker.prototype.minGroupSize=30,tracking.ColorTracker.prototype.calculateDimensions_=function(t,r){for(var n=-1,e=-1,i=1/0,a=1/0,o=0;r>o;o+=2){var c=t[o],s=t[o+1];i>c&&(i=c),c>n&&(n=c),a>s&&(a=s),s>e&&(e=s)}return{width:n-i,height:e-a,x:i,y:a}},tracking.ColorTracker.prototype.getColors=function(){return this.colors},tracking.ColorTracker.prototype.getMinDimension=function(){return this.minDimension},tracking.ColorTracker.prototype.getMaxDimension=function(){return this.maxDimension},tracking.ColorTracker.prototype.getMinGroupSize=function(){return this.minGroupSize},tracking.ColorTracker.prototype.getNeighboursForWidth_=function(t){if(tracking.ColorTracker.neighbours_[t])return tracking.ColorTracker.neighbours_[t];var r=new Int32Array(8);return r[0]=4*-t,r[1]=4*-t+4,r[2]=4,r[3]=4*t+4,r[4]=4*t,r[5]=4*t-4,r[6]=-4,r[7]=4*-t-4,tracking.ColorTracker.neighbours_[t]=r,r},tracking.ColorTracker.prototype.mergeRectangles_=function(t){for(var r,n=[],e=this.getMinDimension(),i=this.getMaxDimension(),a=0;a=e&&o.height>=e&&o.width<=i&&o.height<=i&&n.push(o)}return n},tracking.ColorTracker.prototype.setColors=function(t){this.colors=t},tracking.ColorTracker.prototype.setMinDimension=function(t){this.minDimension=t},tracking.ColorTracker.prototype.setMaxDimension=function(t){this.maxDimension=t},tracking.ColorTracker.prototype.setMinGroupSize=function(t){this.minGroupSize=t},tracking.ColorTracker.prototype.track=function(t,r,n){var e=this,i=this.getColors();if(!i)throw new Error('Colors not specified, try `new tracking.ColorTracker("magenta")`.');var a=[];i.forEach(function(i){a=a.concat(e.trackColor_(t,r,n,i))}),this.emit("track",{data:a})},tracking.ColorTracker.prototype.trackColor_=function(n,e,i,a){var o,c,s,g,h,k=tracking.ColorTracker.knownColors_[a],u=new Int32Array(n.length>>2),f=new Int8Array(n.length),l=this.getMinGroupSize(),p=this.getNeighboursForWidth_(e),v=new Int32Array(n.length),m=[],y=-4;if(!k)return m;for(var d=0;i>d;d++)for(var w=0;e>w;w++)if(y+=4,!f[y]){for(o=0,h=-1,v[++h]=y,v[++h]=d,v[++h]=w,f[y]=1;h>=0;)if(s=v[h--],c=v[h--],g=v[h--],k(n[g],n[g+1],n[g+2],n[g+3],g,c,s)){u[o++]=s,u[o++]=c;for(var T=0;T=0&&i>_&&E>=0&&e>E&&(v[++h]=C,v[++h]=_,v[++h]=E,f[C]=1)}}if(o>=l){var M=this.calculateDimensions_(u,o);M&&(M.color=a,m.push(M))}}return this.mergeRectangles_(m)},tracking.ColorTracker.registerColor("cyan",function(t,r,n){var e=50,i=70,a=t-0,o=r-255,c=n-255;return r-t>=e&&n-t>=i?!0:6400>a*a+o*o+c*c}),tracking.ColorTracker.registerColor("magenta",function(t,r,n){var e=50,i=t-255,a=r-0,o=n-255;return t-r>=e&&n-r>=e?!0:19600>i*i+a*a+o*o}),tracking.ColorTracker.registerColor("yellow",function(t,r,n){var e=50,i=t-255,a=r-255,o=n-0;return t-n>=e&&r-n>=e?!0:1e4>i*i+a*a+o*o});var t=new Int32Array([-1,-1,0,1,1,1,0,-1]),r=new Int32Array([0,1,1,1,0,-1,-1,-1])}(),function(){tracking.ObjectTracker=function(t){tracking.ObjectTracker.base(this,"constructor"),t&&(Array.isArray(t)||(t=[t]),Array.isArray(t)&&t.forEach(function(r,n){if("string"==typeof r&&(t[n]=tracking.ViolaJones.classifiers[r]),!t[n])throw new Error('Object classifier not valid, try `new tracking.ObjectTracker("face")`.')})),this.setClassifiers(t)},tracking.inherits(tracking.ObjectTracker,tracking.Tracker),tracking.ObjectTracker.prototype.edgesDensity=.2,tracking.ObjectTracker.prototype.initialScale=1,tracking.ObjectTracker.prototype.scaleFactor=1.25,tracking.ObjectTracker.prototype.stepSize=1.5,tracking.ObjectTracker.prototype.getClassifiers=function(){return this.classifiers},tracking.ObjectTracker.prototype.getEdgesDensity=function(){return this.edgesDensity},tracking.ObjectTracker.prototype.getInitialScale=function(){return this.initialScale},tracking.ObjectTracker.prototype.getScaleFactor=function(){return this.scaleFactor},tracking.ObjectTracker.prototype.getStepSize=function(){return this.stepSize},tracking.ObjectTracker.prototype.track=function(t,r,n){var e=this,i=this.getClassifiers();if(!i)throw new Error('Object classifier not specified, try `new tracking.ObjectTracker("face")`.');var a=[];i.forEach(function(i){a=a.concat(tracking.ViolaJones.detect(t,r,n,e.getInitialScale(),e.getScaleFactor(),e.getStepSize(),e.getEdgesDensity(),i))}),this.emit("track",{data:a})},tracking.ObjectTracker.prototype.setClassifiers=function(t){this.classifiers=t},tracking.ObjectTracker.prototype.setEdgesDensity=function(t){this.edgesDensity=t},tracking.ObjectTracker.prototype.setInitialScale=function(t){this.initialScale=t},tracking.ObjectTracker.prototype.setScaleFactor=function(t){this.scaleFactor=t},tracking.ObjectTracker.prototype.setStepSize=function(t){this.stepSize=t}}(); --------------------------------------------------------------------------------