diff --git a/public_html/index.php b/public_html/index.php index 45ee7ad..8e038d5 100644 --- a/public_html/index.php +++ b/public_html/index.php @@ -14,10 +14,11 @@ - - - - + + + + + diff --git a/public_html/js/action-script.js b/public_html/js/action-script.js index 9054b48..116da84 100644 --- a/public_html/js/action-script.js +++ b/public_html/js/action-script.js @@ -1,86 +1,61 @@ -/* [0] Initialisation -=========================================================*/ -/* (1) Elements du DOM */ -var DOM = { - body: $('body'), - canvas: $('canvas'), - imageLoader: $('#image-loader') -}; +{ /* [0] Initialisation + =========================================================*/ -/* (2) dat.GUI initialization */ -var Controller = new dat.GUI(); + /* (1) Elements du DOM */ + var DOM = { + body: $('body'), + canvas: $('canvas'), + imageLoader: $('#image-loader') + }; -/* (3) Canvas initialisation */ -var _CAN = DOM.canvas; - _CAN.width = _CAN.height = 1000; -var _CON = _CAN.getContext('2d'); + /* (2) dat.GUI initialization */ + var Controller = new dat.GUI(); -/* (4) Image Loader + Définitions */ -var iL; + /* (3) Canvas initialisation */ + var _CAN = DOM.canvas; + _CAN.width = _CAN.height = 1000; + var _CON = _CAN.getContext('2d'); -var process; -var exec = false; -var last; + /* (4) Image Loader + Définitions */ + var iL; + + var filterManager; + var process; + var exec = false; + var last; + +} - -/* [1] Initialisation -=========================================================*/ -var init = function(){ - /* (1) Image par défaut */ - this.src = 'front:male:1.jpg'; - - /* (2) Attachement de dat.GUI */ - Controller.addFolder('image source'); - Controller.add(this, 'src', this._images).listen(); - - last = this.src; -}; +{ /* [1] Initialisation du process + =========================================================*/ + var init = function(){ + /* (1) Image par défaut */ + this.src = 'front:male:1.jpg'; -/* (x) Variables globales ----------------------------------------------------------*/ -/* (1) Gestion du ration de l'image */ -var pixelRatio = { + /* (2) Attachement de dat.GUI */ + Controller.addFolder('image source'); + Controller.add(this, 'src', this._images).listen(); - initialized: false, + last = this.src; + }; - init: function(){ - if( this.initialized ) - return; + /* (2) Gestion de tracking.js */ + var zones; - this.initialized = true; + /* (3) Gestion du track de l'image */ + var track = {update: true}; + var tracker = new tracking.ObjectTracker(['face', 'eye', 'mouth']); + tracker.setStepSize(1.5); - this._w = this._h = 0.9; - this.width = this.height = null; + Controller.addFolder('Tracking.js'); + Controller.add(track, 'update'); - this.__defineGetter__('width', function(){ return this._w; }); - this.__defineGetter__('height', function(){ return this._h; }); +} - this.__defineSetter__('width', function(v){ this._w = v; process.bind(iL._wrapper)(); }); - this.__defineSetter__('height', function(v){ this._h = v; process.bind(iL._wrapper)(); }); - - - Controller.addFolder('Image Ratio'); - Controller.add(this, 'width', 0, 2).listen(); - Controller.add(this, 'height', 0, 2).listen(); - } - -}; - -/* (2) Gestion de tracking.js */ -var zones; - -/* (3) Gestion du track de l'image */ -var track = {update: true}; -var tracker = new tracking.ObjectTracker(['face', 'eye', 'mouth']); - -tracker.setStepSize(1.5); - -Controller.addFolder('Tracking.js'); -Controller.add(track, 'update'); /* [2] Routine principale =========================================================*/ @@ -110,8 +85,7 @@ process = function(){ this.defaultHeight = this.height; log('Image copied', '[Canvas]'); - - /* (2) Si `track.update` est TRUE, on lance `Tracking.js` + /* (3) Si `track.update` est TRUE, on lance `Tracking.js` ---------------------------------------------------------*/ if( track.update ){ @@ -147,19 +121,20 @@ process = function(){ { /* [2] Copie sur le `` =========================================================*/ - /* (1) Initialisation du gestionnaire de `ratio` */ - pixelRatio.init(); + /* (1) Ratio */ + filterManager.get('ratio').apply(); - /* (2) Calcul de la taille de l'image en fonction du `ratio` */ - this.width = this.defaultWidth * (pixelRatio.width * _CAN.width / this.defaultWidth); - this.height = this.defaultHeight * (pixelRatio.height * _CAN.height / this.defaultHeight); - - /* (3) Copie de l'image sur le `` */ - _CON.drawImage(this, 0, 0, this.width, this.height); } - { /* [3] Tracking.js + { /* [3] Filtrage pre-processing + =========================================================*/ + + + } + + + { /* [4] Tracking.js =========================================================*/ /* (1) On reporte chaque zone trackée sur le `` */ @@ -181,11 +156,33 @@ process = function(){ } + { /* [5] Filtrage post-processing + =========================================================*/ + + } + console.timeEnd('PROCESS'); }; +{ /* [3] Gestion des `ReactiveFilter` + =========================================================*/ + /* (1) Création du Manager */ + filterManager = new ReactiveFilterManager(DOM.imageLoader, _CAN, process); + + /* (2) Ajout des filtres */ + filterManager.add('ratio', reactiveRatio); + + /* (3) On attache tout à dat.GUI */ + Controller.addFolder('Image Ratio'); + Controller.add(filterManager.get('ratio'), 'width', 0, 2).listen(); + Controller.add(filterManager.get('ratio'), 'height', 0, 2).listen(); + +} + + + /* [x] Chargement image =========================================================*/ iL = new ImageLoader( DOM.imageLoader, init, process ); diff --git a/public_html/js/lib/min/reactive-filter.js b/public_html/js/lib/min/reactive-filter.js new file mode 100644 index 0000000..eda9cd0 --- /dev/null +++ b/public_html/js/lib/min/reactive-filter.js @@ -0,0 +1,5 @@ +var ReactiveFilter=function(a){this._manager={_process:function(){}};this._attr=a instanceof Object?a:{};for(var b in this._attr)this.__defineGetter__(b,function(a){return this._attr[a]}.bind(this,b)),this.__defineSetter__(b,function(a,b){return function(d){a._attr[b]=d;a._manager.process()}}(this,b));this.apply=function(){}},ReactiveFilterManager=function(a,b,c){this._target=a instanceof HTMLImageElement?a:null;if(!this._target)throw Error("Param 1 expected to be an HTMLImageElement (), but "+ +a.constructor.name+" received");this._canvas=b instanceof HTMLCanvasElement?b:null;if(!this._canvas)throw Error("Param 2 expected to be an HTMLCanvasElement (), but "+b.constructor.name+" received");this._context=this._canvas.getContext("2d");this._process=c instanceof Function?c:null;if(!this._process)throw Error("Param 3 expected to be a Function, but "+c.constructor.name+" received");this._filter={}}; +ReactiveFilterManager.prototype.add=function(a,b){a="string"===typeof a?a:null;if(!a)throw Error("Param 1 expected to be a `string`, but "+a.constructor.name+" received");b=b instanceof ReactiveFilter?b:null;if(!b)throw Error("Param 2 expected to be a `ReactiveFilter`, but "+b.constructor.name+" received");if(null!=this._filter[a])return!0;this._filter[a]=b;b._manager=this}; +ReactiveFilterManager.prototype.get=function(a){a="string"===typeof a?a:null;if(!a)throw Error("Param 1 expected to be a `string`, but "+a.constructor.name+" received");return null!=this._filter[a]?this._filter[a]:!1};ReactiveFilterManager.prototype.process=function(){this._process.bind(this._target)()};var reactiveRatio=new ReactiveFilter({width:.95,height:.95}); +reactiveRatio.apply=function(){if(this._manager instanceof ReactiveFilterManager){var a=this._manager._target,b=this._manager._canvas,c=this._manager._context;a.width=this.width*b.width/a.defaultWidth*a.defaultWidth;a.height=this.height*b.height/a.defaultHeight*a.defaultHeight;c.drawImage(a,0,0,a.width,a.height)}}; diff --git a/public_html/js/lib/reactive-filter.js b/public_html/js/lib/reactive-filter.js new file mode 100644 index 0000000..d4fe171 --- /dev/null +++ b/public_html/js/lib/reactive-filter.js @@ -0,0 +1,165 @@ +/* INTERFACE DE `ReactiveFilter` +* +*/ +var ReactiveFilter = function(attr){ + /* [1] Initialisation des arguments + =========================================================*/ + this._manager = {_process: function(){}}; + this._attr = attr instanceof Object ? attr : {}; + + /* [2] Gestion des getters/setters + =========================================================*/ + for( var key in this._attr ){ + + /* (1) Getter */ + this.__defineGetter__(key, function(k){ + return this._attr[k]; + }.bind(this, key) ); + + /* (2) Setter */ + this.__defineSetter__(key, (function(o, k){ return function(v){ + o._attr[k] = v; + o._manager.process(); + }; })(this, key) ); + + } + + + // ABSTRACT + this.apply = function(){}; +}; + + + +/* CONSTRUCTEUR -> Gestionnaire des ReactiveFilter +* +* @pImageTarget Image cible +* @pCanvas Canvas de rendu +* @pProcessFunction Fonction qui met à jour le rendu +* +*/ +var ReactiveFilterManager = function(pImageTarget, pCanvas, pProcessFunction){ + /* [0] Gestion des arguments + =========================================================*/ + /* (1) Image cible */ + this._target = pImageTarget instanceof HTMLImageElement ? pImageTarget : null; + if( !this._target ) throw new Error('Param 1 expected to be an HTMLImageElement (), but '+pImageTarget.constructor.name+' received'); + + /* (2) Canvas de rendu */ + this._canvas = pCanvas instanceof HTMLCanvasElement ? pCanvas : null; + if( !this._canvas ) throw new Error('Param 2 expected to be an HTMLCanvasElement (), but '+pCanvas.constructor.name+' received'); + + // On récupère aussi le contexte + this._context = this._canvas.getContext('2d'); + + /* (3) Routine de process */ + this._process = pProcessFunction instanceof Function ? pProcessFunction : null; + if( !this._process ) throw new Error('Param 3 expected to be a Function, but '+pProcessFunction.constructor.name+' received'); + + /* [1] Initialisation des filtres + =========================================================*/ + this._filter = {}; +}; + +/* AJOUT D'UN `ReactiveFilter` +* +* @pFilterKey Identifiant du filtre +* @pFilter Filtre en question +* +* @return added Etat de l'ajout (TRUE: ajouté) +* +*/ +ReactiveFilterManager.prototype.add = function(pFilterKey, pFilter){ + /* [0] Gestion des paramètres + =========================================================*/ + /* (1) Clé */ + pFilterKey = typeof pFilterKey === 'string' ? pFilterKey : null; + if( !pFilterKey ) throw new Error('Param 1 expected to be a `string`, but '+pFilterKey.constructor.name+' received'); + + /* (2) filtre */ + pFilter = pFilter instanceof ReactiveFilter ? pFilter : null; + if( !pFilter ) throw new Error('Param 2 expected to be a `ReactiveFilter`, but '+pFilter.constructor.name+' received'); + + + /* [1] Si le filtre est déja présent, on ne fait rien + =========================================================*/ + if( this._filter[pFilterKey] != null ) + return true; + + + /* [2] On ajoute le filtre + =========================================================*/ + /* (1) Ajout du filtre au manager */ + this._filter[pFilterKey] = pFilter; + + /* (2) Ajout du manager au filtre */ + pFilter._manager = this; + +}; + +/* GET D'UN `ReactiveFilter` +* +* @pFilterKey Identifiant du filtre +* +* @return filter Filtre ou FALSE +* +*/ +ReactiveFilterManager.prototype.get = function(pFilterKey){ + /* [0] Gestion des paramètres + =========================================================*/ + /* (1) Clé */ + pFilterKey = typeof pFilterKey === 'string' ? pFilterKey : null; + if( !pFilterKey ) throw new Error('Param 1 expected to be a `string`, but '+pFilterKey.constructor.name+' received'); + + + /* [1] Si le filtre est déja présent, on ne fait rien + =========================================================*/ + if( this._filter[pFilterKey] != null ) + return this._filter[pFilterKey]; + + + /* [2] Si on a rien, on retourne FALSE + =========================================================*/ + return false; + +}; + +/* LANCEMENT DE ROUTINE DE PROCESS +* +*/ +ReactiveFilterManager.prototype.process = function(){ + this._process.bind(this._target)(); +}; + + + + + + +/************************************************ +**** Gestion de la ratio de l'image **** +************************************************/ +var reactiveRatio = new ReactiveFilter({ width: .95, height: .95 }); + +reactiveRatio.apply = function(){ + /* [1] Si pas de manager, on exit + =========================================================*/ + if( !(this._manager instanceof ReactiveFilterManager) ) + return; + + /* [2] On effectue notre modification + =========================================================*/ + var o = { + image: this._manager._target, + canvas: this._manager._canvas, + context: this._manager._context + }; + + /* (2) Calcul de la taille de l'image en fonction du `ratio` */ + o.image.width = o.image.defaultWidth * (this.width * o.canvas.width / o.image.defaultWidth); + o.image.height = o.image.defaultHeight * (this.height * o.canvas.height / o.image.defaultHeight); + + /* (3) Copie de l'image sur le `` */ + o.context.drawImage(o.image, 0, 0, o.image.width, o.image.height); + +}; diff --git a/public_html/js/min/action-script.js b/public_html/js/min/action-script.js index e2ae2fc..1ef860f 100644 --- a/public_html/js/min/action-script.js +++ b/public_html/js/min/action-script.js @@ -1,6 +1,5 @@ -var DOM={body:$("body"),canvas:$("canvas"),imageLoader:$("#image-loader")},Controller=new dat.GUI,_CAN=DOM.canvas;_CAN.width=_CAN.height=1E3; -var _CON=_CAN.getContext("2d"),iL,process,exec=!1,last,init=function(){this.src="front:male:1.jpg";Controller.addFolder("image source");Controller.add(this,"src",this._images).listen();last=this.src},pixelRatio={initialized:!1,init:function(){this.initialized||(this.initialized=!0,this._w=this._h=.9,this.width=this.height=null,this.__defineGetter__("width",function(){return this._w}),this.__defineGetter__("height",function(){return this._h}),this.__defineSetter__("width",function(a){this._w=a;process.bind(iL._wrapper)()}), -this.__defineSetter__("height",function(a){this._h=a;process.bind(iL._wrapper)()}),Controller.addFolder("Image Ratio"),Controller.add(this,"width",0,2).listen(),Controller.add(this,"height",0,2).listen())}},zones,track={update:!0},tracker=new tracking.ObjectTracker(["face","eye","mouth"]);tracker.setStepSize(1.5);Controller.addFolder("Tracking.js");Controller.add(track,"update"); +var DOM={body:$("body"),canvas:$("canvas"),imageLoader:$("#image-loader")},Controller=new dat.GUI,_CAN=DOM.canvas;_CAN.width=_CAN.height=1E3;var _CON=_CAN.getContext("2d"),iL,filterManager,process,exec=!1,last,init=function(){this.src="front:male:1.jpg";Controller.addFolder("image source");Controller.add(this,"src",this._images).listen();last=this.src},zones,track={update:!0},tracker=new tracking.ObjectTracker(["face","eye","mouth"]);tracker.setStepSize(1.5);Controller.addFolder("Tracking.js"); +Controller.add(track,"update"); process=function(){if(this instanceof HTMLImageElement){console.time("PROCESS");this.src!=last&&(exec=!1,last=this.src);exec||(this.defaultWidth=this.width,this.defaultHeight=this.height,log("Image copied","[Canvas]"),track.update&&(zones=[],tracking.track(DOM.imageLoader,tracker),tracker.on("track",function(a){a.data.forEach(function(a){zones.push({x:a.x/DOM.imageLoader.defaultWidth,y:a.y/DOM.imageLoader.defaultHeight,w:a.width/DOM.imageLoader.defaultWidth,h:a.height/DOM.imageLoader.defaultHeight})}); -log("Recognition done","[Tracking.js]");process.bind(DOM.imageLoader)()})),exec=!0);_CON.clearRect(0,0,_CAN.width,_CAN.height);pixelRatio.init();this.width=pixelRatio.width*_CAN.width/this.defaultWidth*this.defaultWidth;this.height=pixelRatio.height*_CAN.height/this.defaultHeight*this.defaultHeight;_CON.drawImage(this,0,0,this.width,this.height);for(var a in zones){var b=zones[a].x*this.width,c=zones[a].y*this.height,d=zones[a].w*this.width,e=zones[a].h*this.height;_CON.beginPath();_CON.moveTo(b, -c);_CON.lineTo(b,c+e);_CON.lineTo(b+d,c+e);_CON.lineTo(b+d,c);_CON.lineTo(b,c);_CON.lineWidth=5;_CON.stroke()}console.timeEnd("PROCESS")}};iL=new ImageLoader(DOM.imageLoader,init,process); +log("Recognition done","[Tracking.js]");process.bind(DOM.imageLoader)()})),exec=!0);_CON.clearRect(0,0,_CAN.width,_CAN.height);filterManager.get("ratio").apply();for(var c in zones){var a=zones[c].x*this.width,b=zones[c].y*this.height,d=zones[c].w*this.width,e=zones[c].h*this.height;_CON.beginPath();_CON.moveTo(a,b);_CON.lineTo(a,b+e);_CON.lineTo(a+d,b+e);_CON.lineTo(a+d,b);_CON.lineTo(a,b);_CON.lineWidth=5;_CON.stroke()}console.timeEnd("PROCESS")}}; +filterManager=new ReactiveFilterManager(DOM.imageLoader,_CAN,process);filterManager.add("ratio",reactiveRatio);Controller.addFolder("Image Ratio");Controller.add(filterManager.get("ratio"),"width",0,2).listen();Controller.add(filterManager.get("ratio"),"height",0,2).listen();iL=new ImageLoader(DOM.imageLoader,init,process);