Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added files

  • Loading branch information...
commit b66c840ef06fec751046b9a8d14fe1b6f8daeaa9 1 parent ef38d1b
@neave authored
Showing with 1,034 additions and 3 deletions.
  1. +2 −3 README.md
  2. +460 −0 ccv.js
  3. +172 −0 face.html
  4. +400 −0 face.js
  5. BIN  glasses.png
View
5 README.md
@@ -1,4 +1,3 @@
-face-detection
-==============
+# Face Detection in JavaScript with getUserMedia
-Face Detection in JavaScript with getUserMedia
+Adapted to work with the getUserMedia API using code from [github.com/wesbos/HTML5-Face-Detection]()
View
460 ccv.js
@@ -0,0 +1,460 @@
+if (parallable === undefined) {
+ var parallable = function (file, funct) {
+ parallable.core[funct.toString()] = funct().core;
+ return function () {
+ var i;
+ var async, worker_num, params;
+ if (arguments.length > 1) {
+ async = arguments[arguments.length - 2];
+ worker_num = arguments[arguments.length - 1];
+ params = new Array(arguments.length - 2);
+ for (i = 0; i < arguments.length - 2; i++)
+ params[i] = arguments[i];
+ } else {
+ async = arguments[0].async;
+ worker_num = arguments[0].worker;
+ params = arguments[0];
+ delete params["async"];
+ delete params["worker"];
+ params = [params];
+ }
+ var scope = { "shared" : {} };
+ var ctrl = funct.apply(scope, params);
+ if (async) {
+ return function (complete, error) {
+ var executed = 0;
+ var outputs = new Array(worker_num);
+ var inputs = ctrl.pre.apply(scope, [worker_num]);
+ /* sanitize scope shared because for Chrome/WebKit, worker only support JSONable data */
+ for (i in scope.shared)
+ /* delete function, if any */
+ if (typeof scope.shared[i] == "function")
+ delete scope.shared[i];
+ /* delete DOM object, if any */
+ else if (scope.shared[i].tagName !== undefined)
+ delete scope.shared[i];
+ for (i = 0; i < worker_num; i++) {
+ var worker = new Worker(file);
+ worker.onmessage = (function (i) {
+ return function (event) {
+ outputs[i] = (typeof event.data == "string") ? JSON.parse(event.data) : event.data;
+ executed++;
+ if (executed == worker_num)
+ complete(ctrl.post.apply(scope, [outputs]));
+ }
+ })(i);
+ var msg = { "input" : inputs[i],
+ "name" : funct.toString(),
+ "shared" : scope.shared,
+ "id" : i,
+ "worker" : params.worker_num };
+ try {
+ worker.postMessage(msg);
+ } catch (e) {
+ worker.postMessage(JSON.stringify(msg));
+ }
+ }
+ }
+ } else {
+ return ctrl.post.apply(scope, [[ctrl.core.apply(scope, [ctrl.pre.apply(scope, [1])[0], 0, 1])]]);
+ }
+ }
+ };
+ parallable.core = {};
+}
+
+function get_named_arguments(params, names) {
+ if (params.length > 1) {
+ var new_params = {};
+ for (var i = 0; i < names.length; i++)
+ new_params[names[i]] = params[i];
+ return new_params;
+ } else if (params.length == 1) {
+ return params[0];
+ } else {
+ return {};
+ }
+}
+
+var ccv = {
+ pre : function (image) {
+ if (image.tagName.toLowerCase() == "img") {
+ var canvas = document.createElement("canvas");
+ document.body.appendChild(image);
+ canvas.width = image.offsetWidth;
+ canvas.style.width = image.offsetWidth.toString() + "px";
+ canvas.height = image.offsetHeight;
+ canvas.style.height = image.offsetHeight.toString() + "px";
+ document.body.removeChild(image);
+ var ctx = canvas.getContext("2d");
+ ctx.drawImage(image, 0, 0);
+ return canvas;
+ }
+ return image;
+ },
+
+ grayscale : function (canvas) {
+ var ctx = canvas.getContext("2d");
+ var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
+ var data = imageData.data;
+ var pix1, pix2, pix = canvas.width * canvas.height * 4;
+ while (pix > 0)
+ data[pix -= 4] = data[pix1 = pix + 1] = data[pix2 = pix + 2] = (data[pix] * 0.3 + data[pix1] * 0.59 + data[pix2] * 0.11);
+ ctx.putImageData(imageData, 0, 0);
+ return canvas;
+ },
+
+ array_group : function (seq, gfunc) {
+ var i, j;
+ var node = new Array(seq.length);
+ for (i = 0; i < seq.length; i++)
+ node[i] = {"parent" : -1,
+ "element" : seq[i],
+ "rank" : 0};
+ for (i = 0; i < seq.length; i++) {
+ if (!node[i].element)
+ continue;
+ var root = i;
+ while (node[root].parent != -1)
+ root = node[root].parent;
+ for (j = 0; j < seq.length; j++) {
+ if( i != j && node[j].element && gfunc(node[i].element, node[j].element)) {
+ var root2 = j;
+
+ while (node[root2].parent != -1)
+ root2 = node[root2].parent;
+
+ if(root2 != root) {
+ if(node[root].rank > node[root2].rank)
+ node[root2].parent = root;
+ else {
+ node[root].parent = root2;
+ if (node[root].rank == node[root2].rank)
+ node[root2].rank++;
+ root = root2;
+ }
+
+ /* compress path from node2 to the root: */
+ var temp, node2 = j;
+ while (node[node2].parent != -1) {
+ temp = node2;
+ node2 = node[node2].parent;
+ node[temp].parent = root;
+ }
+
+ /* compress path from node to the root: */
+ node2 = i;
+ while (node[node2].parent != -1) {
+ temp = node2;
+ node2 = node[node2].parent;
+ node[temp].parent = root;
+ }
+ }
+ }
+ }
+ }
+ var idx = new Array(seq.length);
+ var class_idx = 0;
+ for(i = 0; i < seq.length; i++) {
+ j = -1;
+ var node1 = i;
+ if(node[node1].element) {
+ while (node[node1].parent != -1)
+ node1 = node[node1].parent;
+ if(node[node1].rank >= 0)
+ node[node1].rank = ~class_idx++;
+ j = ~node[node1].rank;
+ }
+ idx[i] = j;
+ }
+ return {"index" : idx, "cat" : class_idx};
+ },
+
+ detect_objects : parallable("ccv.js", function (canvas, cascade, interval, min_neighbors) {
+ if (this.shared !== undefined) {
+ var params = get_named_arguments(arguments, ["canvas", "cascade", "interval", "min_neighbors"]);
+ this.shared.canvas = params.canvas;
+ this.shared.interval = params.interval;
+ this.shared.min_neighbors = params.min_neighbors;
+ this.shared.cascade = params.cascade;
+ this.shared.scale = Math.pow(2, 1 / (params.interval + 1));
+ this.shared.next = params.interval + 1;
+ this.shared.scale_upto = Math.floor(Math.log(Math.min(params.canvas.width / params.cascade.width, params.canvas.height / params.cascade.height)) / Math.log(this.shared.scale));
+ var i;
+ for (i = 0; i < this.shared.cascade.stage_classifier.length; i++)
+ this.shared.cascade.stage_classifier[i].orig_feature = this.shared.cascade.stage_classifier[i].feature;
+ }
+ function pre(worker_num) {
+ var canvas = this.shared.canvas;
+ var interval = this.shared.interval;
+ var scale = this.shared.scale;
+ var next = this.shared.next;
+ var scale_upto = this.shared.scale_upto;
+ var pyr = new Array((scale_upto + next * 2) * 4);
+ var ret = new Array((scale_upto + next * 2) * 4);
+ pyr[0] = canvas;
+ ret[0] = { "width" : pyr[0].width,
+ "height" : pyr[0].height,
+ "data" : pyr[0].getContext("2d").getImageData(0, 0, pyr[0].width, pyr[0].height).data };
+ var i;
+ for (i = 1; i <= interval; i++) {
+ pyr[i * 4] = document.createElement("canvas");
+ pyr[i * 4].width = Math.floor(pyr[0].width / Math.pow(scale, i));
+ pyr[i * 4].height = Math.floor(pyr[0].height / Math.pow(scale, i));
+ pyr[i * 4].getContext("2d").drawImage(pyr[0], 0, 0, pyr[0].width, pyr[0].height, 0, 0, pyr[i * 4].width, pyr[i * 4].height);
+ ret[i * 4] = { "width" : pyr[i * 4].width,
+ "height" : pyr[i * 4].height,
+ "data" : pyr[i * 4].getContext("2d").getImageData(0, 0, pyr[i * 4].width, pyr[i * 4].height).data };
+ }
+ for (i = next; i < scale_upto + next * 2; i++) {
+ pyr[i * 4] = document.createElement("canvas");
+ pyr[i * 4].width = Math.floor(pyr[i * 4 - next * 4].width / 2);
+ pyr[i * 4].height = Math.floor(pyr[i * 4 - next * 4].height / 2);
+ pyr[i * 4].getContext("2d").drawImage(pyr[i * 4 - next * 4], 0, 0, pyr[i * 4 - next * 4].width, pyr[i * 4 - next * 4].height, 0, 0, pyr[i * 4].width, pyr[i * 4].height);
+ ret[i * 4] = { "width" : pyr[i * 4].width,
+ "height" : pyr[i * 4].height,
+ "data" : pyr[i * 4].getContext("2d").getImageData(0, 0, pyr[i * 4].width, pyr[i * 4].height).data };
+ }
+ for (i = next * 2; i < scale_upto + next * 2; i++) {
+ pyr[i * 4 + 1] = document.createElement("canvas");
+ pyr[i * 4 + 1].width = Math.floor(pyr[i * 4 - next * 4].width / 2);
+ pyr[i * 4 + 1].height = Math.floor(pyr[i * 4 - next * 4].height / 2);
+ pyr[i * 4 + 1].getContext("2d").drawImage(pyr[i * 4 - next * 4], 1, 0, pyr[i * 4 - next * 4].width - 1, pyr[i * 4 - next * 4].height, 0, 0, pyr[i * 4 + 1].width - 2, pyr[i * 4 + 1].height);
+ ret[i * 4 + 1] = { "width" : pyr[i * 4 + 1].width,
+ "height" : pyr[i * 4 + 1].height,
+ "data" : pyr[i * 4 + 1].getContext("2d").getImageData(0, 0, pyr[i * 4 + 1].width, pyr[i * 4 + 1].height).data };
+ pyr[i * 4 + 2] = document.createElement("canvas");
+ pyr[i * 4 + 2].width = Math.floor(pyr[i * 4 - next * 4].width / 2);
+ pyr[i * 4 + 2].height = Math.floor(pyr[i * 4 - next * 4].height / 2);
+ pyr[i * 4 + 2].getContext("2d").drawImage(pyr[i * 4 - next * 4], 0, 1, pyr[i * 4 - next * 4].width, pyr[i * 4 - next * 4].height - 1, 0, 0, pyr[i * 4 + 2].width, pyr[i * 4 + 2].height - 2);
+ ret[i * 4 + 2] = { "width" : pyr[i * 4 + 2].width,
+ "height" : pyr[i * 4 + 2].height,
+ "data" : pyr[i * 4 + 2].getContext("2d").getImageData(0, 0, pyr[i * 4 + 2].width, pyr[i * 4 + 2].height).data };
+ pyr[i * 4 + 3] = document.createElement("canvas");
+ pyr[i * 4 + 3].width = Math.floor(pyr[i * 4 - next * 4].width / 2);
+ pyr[i * 4 + 3].height = Math.floor(pyr[i * 4 - next * 4].height / 2);
+ pyr[i * 4 + 3].getContext("2d").drawImage(pyr[i * 4 - next * 4], 1, 1, pyr[i * 4 - next * 4].width - 1, pyr[i * 4 - next * 4].height - 1, 0, 0, pyr[i * 4 + 3].width - 2, pyr[i * 4 + 3].height - 2);
+ ret[i * 4 + 3] = { "width" : pyr[i * 4 + 3].width,
+ "height" : pyr[i * 4 + 3].height,
+ "data" : pyr[i * 4 + 3].getContext("2d").getImageData(0, 0, pyr[i * 4 + 3].width, pyr[i * 4 + 3].height).data };
+ }
+ return [ret];
+ };
+
+ function core(pyr, id, worker_num) {
+ var cascade = this.shared.cascade;
+ var interval = this.shared.interval;
+ var scale = this.shared.scale;
+ var next = this.shared.next;
+ var scale_upto = this.shared.scale_upto;
+ var i, j, k, x, y, q;
+ var scale_x = 1, scale_y = 1;
+ var dx = [0, 1, 0, 1];
+ var dy = [0, 0, 1, 1];
+ var seq = [];
+ for (i = 0; i < scale_upto; i++) {
+ var qw = pyr[i * 4 + next * 8].width - Math.floor(cascade.width / 4);
+ var qh = pyr[i * 4 + next * 8].height - Math.floor(cascade.height / 4);
+ var step = [pyr[i * 4].width * 4, pyr[i * 4 + next * 4].width * 4, pyr[i * 4 + next * 8].width * 4];
+ var paddings = [pyr[i * 4].width * 16 - qw * 16,
+ pyr[i * 4 + next * 4].width * 8 - qw * 8,
+ pyr[i * 4 + next * 8].width * 4 - qw * 4];
+ for (j = 0; j < cascade.stage_classifier.length; j++) {
+ var orig_feature = cascade.stage_classifier[j].orig_feature;
+ var feature = cascade.stage_classifier[j].feature = new Array(cascade.stage_classifier[j].count);
+ for (k = 0; k < cascade.stage_classifier[j].count; k++) {
+ feature[k] = {"size" : orig_feature[k].size,
+ "px" : new Array(orig_feature[k].size),
+ "pz" : new Array(orig_feature[k].size),
+ "nx" : new Array(orig_feature[k].size),
+ "nz" : new Array(orig_feature[k].size)};
+ for (q = 0; q < orig_feature[k].size; q++) {
+ feature[k].px[q] = orig_feature[k].px[q] * 4 + orig_feature[k].py[q] * step[orig_feature[k].pz[q]];
+ feature[k].pz[q] = orig_feature[k].pz[q];
+ feature[k].nx[q] = orig_feature[k].nx[q] * 4 + orig_feature[k].ny[q] * step[orig_feature[k].nz[q]];
+ feature[k].nz[q] = orig_feature[k].nz[q];
+ }
+ }
+ }
+ for (q = 0; q < 4; q++) {
+ var u8 = [pyr[i * 4].data, pyr[i * 4 + next * 4].data, pyr[i * 4 + next * 8 + q].data];
+ var u8o = [dx[q] * 8 + dy[q] * pyr[i * 4].width * 8, dx[q] * 4 + dy[q] * pyr[i * 4 + next * 4].width * 4, 0];
+ for (y = 0; y < qh; y++) {
+ for (x = 0; x < qw; x++) {
+ var sum = 0;
+ var flag = true;
+ for (j = 0; j < cascade.stage_classifier.length; j++) {
+ sum = 0;
+ var alpha = cascade.stage_classifier[j].alpha;
+ var feature = cascade.stage_classifier[j].feature;
+ for (k = 0; k < cascade.stage_classifier[j].count; k++) {
+ var feature_k = feature[k];
+ var p, pmin = u8[feature_k.pz[0]][u8o[feature_k.pz[0]] + feature_k.px[0]];
+ var n, nmax = u8[feature_k.nz[0]][u8o[feature_k.nz[0]] + feature_k.nx[0]];
+ if (pmin <= nmax) {
+ sum += alpha[k * 2];
+ } else {
+ var f, shortcut = true;
+ for (f = 0; f < feature_k.size; f++) {
+ if (feature_k.pz[f] >= 0) {
+ p = u8[feature_k.pz[f]][u8o[feature_k.pz[f]] + feature_k.px[f]];
+ if (p < pmin) {
+ if (p <= nmax) {
+ shortcut = false;
+ break;
+ }
+ pmin = p;
+ }
+ }
+ if (feature_k.nz[f] >= 0) {
+ n = u8[feature_k.nz[f]][u8o[feature_k.nz[f]] + feature_k.nx[f]];
+ if (n > nmax) {
+ if (pmin <= n) {
+ shortcut = false;
+ break;
+ }
+ nmax = n;
+ }
+ }
+ }
+ sum += (shortcut) ? alpha[k * 2 + 1] : alpha[k * 2];
+ }
+ }
+ if (sum < cascade.stage_classifier[j].threshold) {
+ flag = false;
+ break;
+ }
+ }
+ if (flag) {
+ seq.push({"x" : (x * 4 + dx[q] * 2) * scale_x,
+ "y" : (y * 4 + dy[q] * 2) * scale_y,
+ "width" : cascade.width * scale_x,
+ "height" : cascade.height * scale_y,
+ "neighbor" : 1,
+ "confidence" : sum});
+ }
+ u8o[0] += 16;
+ u8o[1] += 8;
+ u8o[2] += 4;
+ }
+ u8o[0] += paddings[0];
+ u8o[1] += paddings[1];
+ u8o[2] += paddings[2];
+ }
+ }
+ scale_x *= scale;
+ scale_y *= scale;
+ }
+ return seq;
+ };
+
+ function post(seq) {
+ var min_neighbors = this.shared.min_neighbors;
+ var cascade = this.shared.cascade;
+ var interval = this.shared.interval;
+ var scale = this.shared.scale;
+ var next = this.shared.next;
+ var scale_upto = this.shared.scale_upto;
+ var i, j;
+ for (i = 0; i < cascade.stage_classifier.length; i++)
+ cascade.stage_classifier[i].feature = cascade.stage_classifier[i].orig_feature;
+ seq = seq[0];
+ if (!(min_neighbors > 0))
+ return seq;
+ else {
+ var result = ccv.array_group(seq, function (r1, r2) {
+ var distance = Math.floor(r1.width * 0.25 + 0.5);
+
+ return r2.x <= r1.x + distance &&
+ r2.x >= r1.x - distance &&
+ r2.y <= r1.y + distance &&
+ r2.y >= r1.y - distance &&
+ r2.width <= Math.floor(r1.width * 1.5 + 0.5) &&
+ Math.floor(r2.width * 1.5 + 0.5) >= r1.width;
+ });
+ var ncomp = result.cat;
+ var idx_seq = result.index;
+ var comps = new Array(ncomp + 1);
+ for (i = 0; i < comps.length; i++)
+ comps[i] = {"neighbors" : 0,
+ "x" : 0,
+ "y" : 0,
+ "width" : 0,
+ "height" : 0,
+ "confidence" : 0};
+
+ // count number of neighbors
+ for(i = 0; i < seq.length; i++)
+ {
+ var r1 = seq[i];
+ var idx = idx_seq[i];
+
+ if (comps[idx].neighbors == 0)
+ comps[idx].confidence = r1.confidence;
+
+ ++comps[idx].neighbors;
+
+ comps[idx].x += r1.x;
+ comps[idx].y += r1.y;
+ comps[idx].width += r1.width;
+ comps[idx].height += r1.height;
+ comps[idx].confidence = Math.max(comps[idx].confidence, r1.confidence);
+ }
+
+ var seq2 = [];
+ // calculate average bounding box
+ for(i = 0; i < ncomp; i++)
+ {
+ var n = comps[i].neighbors;
+ if (n >= min_neighbors)
+ seq2.push({"x" : (comps[i].x * 2 + n) / (2 * n),
+ "y" : (comps[i].y * 2 + n) / (2 * n),
+ "width" : (comps[i].width * 2 + n) / (2 * n),
+ "height" : (comps[i].height * 2 + n) / (2 * n),
+ "neighbors" : comps[i].neighbors,
+ "confidence" : comps[i].confidence});
+ }
+
+ var result_seq = [];
+ // filter out small face rectangles inside large face rectangles
+ for(i = 0; i < seq2.length; i++)
+ {
+ var r1 = seq2[i];
+ var flag = true;
+ for(j = 0; j < seq2.length; j++)
+ {
+ var r2 = seq2[j];
+ var distance = Math.floor(r2.width * 0.25 + 0.5);
+
+ if(i != j &&
+ r1.x >= r2.x - distance &&
+ r1.y >= r2.y - distance &&
+ r1.x + r1.width <= r2.x + r2.width + distance &&
+ r1.y + r1.height <= r2.y + r2.height + distance &&
+ (r2.neighbors > Math.max(3, r1.neighbors) || r1.neighbors < 3))
+ {
+ flag = false;
+ break;
+ }
+ }
+
+ if(flag)
+ result_seq.push(r1);
+ }
+ return result_seq;
+ }
+ };
+ return { "pre" : pre, "core" : core, "post" : post };
+ })
+}
+
+onmessage = function (event) {
+ var data = (typeof event.data == "string") ? JSON.parse(event.data) : event.data;
+ var scope = { "shared" : data.shared };
+ var result = parallable.core[data.name].apply(scope, [data.input, data.id, data.worker]);
+ try {
+ postMessage(result);
+ } catch (e) {
+ postMessage(JSON.stringify(result));
+ }
+}
View
172 face.html
@@ -0,0 +1,172 @@
+<!DOCTYPE html>
+<html lang="en">
+<!-- Adapted to work with the getUserMedia API using code from http://wesbos.com/html5-video-face-detection-canvas-javascript/ -->
+ <head>
+ <meta charset="utf-8">
+ <title>HTML5 Face Detection - JavaScript getUserMedia API and Groucho Marx glasses!</title>
+ <style>
+body {
+ font-family: sans-serif;
+ font-size: 17px;
+ line-height: 24px;
+ color: #fff;
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ text-align: center;
+ background-color: #111;
+}
+
+#info {
+ position: absolute;
+ width: 100%;
+ height: 30px;
+ top: 50%;
+ margin-top: -15px;
+}
+
+#output {
+ width: auto;
+ height: 100%;
+ background: black;
+ -webkit-transform: scale(-1, 1);
+}
+ </style>
+ </head>
+ <body>
+ <p id="info">Please allow access to your camera!</p>
+ <canvas id="output"></canvas>
+ <script src="ccv.js"></script>
+ <script src="face.js"></script>
+ <script>
+
+// requestAnimationFrame shim
+(function() {
+ var i = 0,
+ lastTime = 0,
+ vendors = ['ms', 'moz', 'webkit', 'o'];
+
+ while (i < vendors.length && !window.requestAnimationFrame) {
+ window.requestAnimationFrame = window[vendors[i] + 'RequestAnimationFrame'];
+ i++;
+ }
+
+ if (!window.requestAnimationFrame) {
+ window.requestAnimationFrame = function(callback, element) {
+ var currTime = new Date().getTime(),
+ timeToCall = Math.max(0, 1000 / 60 - currTime + lastTime),
+ id = setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
+
+ lastTime = currTime + timeToCall;
+ return id;
+ };
+ }
+}());
+
+var App = {
+ start: function(stream) {
+ App.video.addEventListener('canplay', function() {
+ App.video.removeEventListener('canplay');
+ setTimeout(function() {
+ App.video.play();
+ App.canvas.style.display = 'inline';
+ App.info.style.display = 'none';
+ App.canvas.width = App.video.videoWidth;
+ App.canvas.height = App.video.videoHeight;
+ App.backCanvas.width = App.video.videoWidth / 4;
+ App.backCanvas.height = App.video.videoHeight / 4;
+ App.backContext = App.backCanvas.getContext('2d');
+
+ var w = 300 / 4 * 0.8,
+ h = 270 / 4 * 0.8;
+
+ App.comp = [{
+ x: (App.video.videoWidth / 4 - w) / 2,
+ y: (App.video.videoHeight / 4 - h) / 2,
+ width: w,
+ height: h,
+ }];
+
+ App.drawToCanvas();
+ }, 500);
+ }, true);
+
+ var domURL = window.URL || window.webkitURL;
+ App.video.src = domURL ? domURL.createObjectURL(stream) : stream;
+ },
+ denied: function() {
+ App.info.innerHTML = 'Camera access denied!<br>Please reload and try again.';
+ },
+ error: function(e) {
+ if (e) {
+ console.error(e);
+ }
+ App.info.innerHTML = 'Please go to about:flags in Google Chrome and enable the &quot;MediaStream&quot; flag.';
+ },
+ drawToCanvas: function() {
+ requestAnimationFrame(App.drawToCanvas);
+
+ var video = App.video,
+ ctx = App.context,
+ backCtx = App.backContext,
+ m = 4,
+ w = 4,
+ i,
+ comp;
+
+ ctx.drawImage(video, 0, 0, App.canvas.width, App.canvas.height);
+
+ backCtx.drawImage(video, 0, 0, App.backCanvas.width, App.backCanvas.height);
+
+ comp = ccv.detect_objects(App.ccv = App.ccv || {
+ canvas: App.backCanvas,
+ cascade: cascade,
+ interval: 4,
+ min_neighbors: 1
+ });
+
+ if (comp.length) {
+ App.comp = comp;
+ }
+
+ for (i = App.comp.length; i--; ) {
+ ctx.drawImage(App.glasses, (App.comp[i].x - w / 2) * m, (App.comp[i].y - w / 2) * m, (App.comp[i].width + w) * m, (App.comp[i].height + w) * m);
+ }
+ }
+};
+
+App.glasses = new Image();
+App.glasses.src = 'glasses.png';
+
+App.init = function() {
+ App.video = document.createElement('video');
+ App.backCanvas = document.createElement('canvas');
+ App.canvas = document.querySelector('#output');
+ App.canvas.style.display = 'none';
+ App.context = App.canvas.getContext('2d');
+ App.info = document.querySelector('#info');
+
+ navigator.getUserMedia_ = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
+
+ try {
+ navigator.getUserMedia_({
+ video: true,
+ audio: false
+ }, App.start, App.denied);
+ } catch (e) {
+ try {
+ navigator.getUserMedia_('video', App.start, App.denied);
+ } catch (e) {
+ App.error(e);
+ }
+ }
+
+ App.video.loop = App.video.muted = true;
+ App.video.load();
+};
+
+App.init();
+
+ </script>
+ </body>
+</html>
View
400 face.js
400 additions, 0 deletions not shown
View
BIN  glasses.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Please sign in to comment.
Something went wrong with that request. Please try again.