2016-11-02 18:15:20 +00:00
|
|
|
/**************************
|
|
|
|
* PermanentStorage *
|
|
|
|
* 08-09-16 *
|
|
|
|
***************************
|
|
|
|
* Designed & Developed by *
|
|
|
|
* xdrm-brackets *
|
|
|
|
* & *
|
|
|
|
* SeekDaSky *
|
|
|
|
***************************
|
|
|
|
* https://xdrm.io/ *
|
|
|
|
* http://seekdasky.ovh/ *
|
|
|
|
**************************/
|
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
|
2016-10-07 08:50:06 +00:00
|
|
|
{ /* [0] Initialisation
|
|
|
|
=========================================================*/
|
2016-10-05 10:13:48 +00:00
|
|
|
|
2016-10-07 08:50:06 +00:00
|
|
|
/* (1) Elements du DOM */
|
|
|
|
var DOM = {
|
2016-11-04 17:44:29 +00:00
|
|
|
body: $('body'),
|
|
|
|
canvas: $('canvas'),
|
|
|
|
imageLoader: $('#image-loader')
|
2016-10-07 08:50:06 +00:00
|
|
|
};
|
2016-10-05 13:04:48 +00:00
|
|
|
|
2016-10-07 08:50:06 +00:00
|
|
|
/* (3) Canvas initialisation */
|
|
|
|
var _CAN = DOM.canvas;
|
|
|
|
_CAN.width = _CAN.height = 1000;
|
|
|
|
var _CON = _CAN.getContext('2d');
|
2016-10-05 13:04:48 +00:00
|
|
|
|
2016-10-07 08:50:06 +00:00
|
|
|
/* (4) Image Loader + Définitions */
|
|
|
|
var iL;
|
2016-10-05 13:04:48 +00:00
|
|
|
|
2016-10-07 08:50:06 +00:00
|
|
|
var filterManager;
|
2016-11-02 18:15:20 +00:00
|
|
|
var process = function(){};
|
2016-10-07 08:50:06 +00:00
|
|
|
var exec = false;
|
|
|
|
var last;
|
2016-11-03 12:25:56 +00:00
|
|
|
var featureTrackerTask;
|
|
|
|
var trackerCallback;
|
2016-10-05 13:04:48 +00:00
|
|
|
|
2016-11-04 17:44:29 +00:00
|
|
|
var Controller, CFolder = {},
|
2016-11-03 09:36:23 +00:00
|
|
|
init,
|
2016-11-04 17:44:29 +00:00
|
|
|
zones = {feature: []},
|
2016-11-03 09:36:23 +00:00
|
|
|
track,
|
2016-11-03 12:25:56 +00:00
|
|
|
featureTracker,
|
2016-11-03 09:36:23 +00:00
|
|
|
initialized = false;
|
|
|
|
|
2016-10-07 08:50:06 +00:00
|
|
|
}
|
2016-10-05 13:04:48 +00:00
|
|
|
|
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
var ControllerRememberer = new PermanentStorage();
|
|
|
|
ControllerRememberer.fetch(function(loaded_data){
|
2016-10-05 13:04:48 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
log('Preset loaded.', '[PermanentStorage]')
|
2016-10-05 13:04:48 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
{ /* [1] Initialisation du process
|
|
|
|
=========================================================*/
|
|
|
|
/* (1) dat.GUI initialization */
|
|
|
|
Controller = new dat.GUI({ load: JSON.parse(loaded_data), preset: 'default' });
|
2016-10-05 13:04:48 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
init = function(){
|
|
|
|
/* (1) Image par défaut */
|
|
|
|
this.src = 'front/male/1.jpg';
|
2016-10-05 13:04:48 +00:00
|
|
|
|
2016-11-03 12:25:56 +00:00
|
|
|
/* (2) Initialization */
|
2016-11-03 09:36:23 +00:00
|
|
|
last = this.src;
|
|
|
|
initialized = true;
|
2016-11-03 12:25:56 +00:00
|
|
|
|
|
|
|
/* (3) Attachment to dat.GUI */
|
2016-11-04 17:44:29 +00:00
|
|
|
CFolder.src = Controller.addFolder('Source Picture');
|
2016-11-03 12:25:56 +00:00
|
|
|
Controller.remember(this);
|
2016-11-04 17:44:29 +00:00
|
|
|
CFolder.src.add(this, 'src', this._images).listen();
|
2016-11-03 09:36:23 +00:00
|
|
|
};
|
2016-10-07 15:48:53 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
/* (2) Gestion de tracking.js */
|
2016-11-03 14:01:51 +00:00
|
|
|
zones.feature = [];
|
2016-10-05 10:13:48 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
/* (3) Gestion du track de l'image */
|
|
|
|
track = {
|
2016-11-03 12:25:56 +00:00
|
|
|
trackFeatures: function(){
|
2016-11-04 17:44:29 +00:00
|
|
|
LOADER.start();
|
2016-11-03 14:01:51 +00:00
|
|
|
zones.feature = [];
|
2016-11-03 12:25:56 +00:00
|
|
|
featureTrackerTask = tracking.track(_CAN, featureTracker);
|
2016-11-04 17:44:29 +00:00
|
|
|
LOADER.stop();
|
2016-11-03 09:36:23 +00:00
|
|
|
}
|
2016-11-04 17:44:29 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
};
|
2016-10-06 17:15:29 +00:00
|
|
|
|
2016-11-03 12:25:56 +00:00
|
|
|
/* (4) Initializing `Tracking.js` */
|
|
|
|
featureTracker = new tracking.ObjectTracker(['eye', 'mouth']);
|
2016-11-02 18:15:20 +00:00
|
|
|
|
2016-11-03 14:01:51 +00:00
|
|
|
featureTracker.setInitialScale(1.0);
|
|
|
|
featureTracker.setStepSize(1.2);
|
|
|
|
featureTracker.setEdgesDensity(0.1);
|
2016-11-02 18:15:20 +00:00
|
|
|
|
2016-11-03 14:01:51 +00:00
|
|
|
trackerCallback = function(z, e){
|
2016-11-02 18:15:20 +00:00
|
|
|
|
2016-11-03 14:01:51 +00:00
|
|
|
zones[z].length = 0;
|
2016-11-02 18:15:20 +00:00
|
|
|
|
2016-11-03 12:25:56 +00:00
|
|
|
e.data.forEach(function(rect){
|
2016-11-03 14:01:51 +00:00
|
|
|
zones[z].push({
|
2016-11-03 09:36:23 +00:00
|
|
|
x: rect.x / _CAN.width,
|
|
|
|
y: rect.y / _CAN.height,
|
|
|
|
w: rect.width / _CAN.width,
|
|
|
|
h: rect.height / _CAN.height
|
|
|
|
});
|
|
|
|
});
|
2016-11-02 18:15:20 +00:00
|
|
|
|
2016-11-03 14:01:51 +00:00
|
|
|
// On enregistre dans `zones.feature` les zones.feature trackées
|
|
|
|
if( zones[z].length > 0 )
|
|
|
|
log(z+' recognition done', '[Tracking.js]');
|
|
|
|
else
|
|
|
|
log(z+' recognition failed', '[Tracking.js]');
|
2016-10-06 17:15:29 +00:00
|
|
|
|
2016-11-03 14:01:51 +00:00
|
|
|
// On met à jour le rendu (affichage des zones.feature)
|
2016-11-03 12:25:56 +00:00
|
|
|
process.apply(DOM.imageLoader);
|
|
|
|
}
|
2016-10-06 17:15:29 +00:00
|
|
|
|
2016-11-03 14:01:51 +00:00
|
|
|
featureTracker.on('track', function(e){ return trackerCallback.apply(this, ['feature', e]); });
|
2016-10-05 10:13:48 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
}
|
2016-10-06 17:15:29 +00:00
|
|
|
|
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
/* [2] Routine principale
|
2016-10-06 17:15:29 +00:00
|
|
|
=========================================================*/
|
2016-11-04 17:44:29 +00:00
|
|
|
LOADER.init();
|
2016-11-03 09:36:23 +00:00
|
|
|
process = function(){
|
2016-11-04 17:44:29 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
// Si erreur de `bind()`, on quitte
|
|
|
|
if( !initialized || !(this instanceof HTMLImageElement) )
|
|
|
|
return;
|
2016-10-05 10:13:48 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
console.time('PROCESS');
|
2016-11-04 17:44:29 +00:00
|
|
|
LOADER.start();
|
|
|
|
|
2016-10-06 17:15:29 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
/* [0.0] Gestion du changement d'image
|
|
|
|
=========================================================*/
|
|
|
|
if( this.src != last ){
|
2016-11-04 17:44:29 +00:00
|
|
|
reactiveFaceTracking.zones = [];
|
|
|
|
zones.feature = [];
|
2016-11-03 12:25:56 +00:00
|
|
|
exec = false;
|
|
|
|
last = this.src;
|
2016-11-03 09:36:23 +00:00
|
|
|
}
|
2016-10-06 17:15:29 +00:00
|
|
|
|
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
/* [0.1] Gestion de la première exécution (par image)
|
|
|
|
=========================================================*/
|
|
|
|
if( !exec ){
|
2016-10-06 17:15:29 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
/* (1) On enregistre les dimensions par défaut
|
|
|
|
---------------------------------------------------------*/
|
|
|
|
this.defaultWidth = this.width;
|
|
|
|
this.defaultHeight = this.height;
|
|
|
|
log('Image copied', '[Canvas]');
|
2016-10-06 17:15:29 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
// On change la valeur de `exec` pour qu'il n'entre plus dans ce `if`
|
|
|
|
exec = true;
|
|
|
|
}
|
2016-10-05 13:04:48 +00:00
|
|
|
|
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
/* [1] On initialise/efface le `<canvas>`
|
|
|
|
=========================================================*/
|
|
|
|
_CON.clearRect(0, 0, _CAN.width, _CAN.height);
|
2016-10-07 15:48:53 +00:00
|
|
|
|
2016-10-07 08:50:06 +00:00
|
|
|
|
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
{ /* [2] Copie sur le `<canvas>`
|
|
|
|
=========================================================*/
|
|
|
|
/* (1) Resolution */
|
|
|
|
filterManager.get('resolution').apply();
|
|
|
|
}
|
2016-10-07 15:48:53 +00:00
|
|
|
|
2016-11-02 18:15:20 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
{ /* [3] Filtrage pre-processing
|
|
|
|
=========================================================*/
|
|
|
|
/* (1) Contraste */
|
|
|
|
filterManager.get('contrast').apply();
|
2016-11-02 18:15:20 +00:00
|
|
|
|
2016-11-03 14:01:51 +00:00
|
|
|
/* (2) Contraste */
|
|
|
|
filterManager.get('grayscale').apply();
|
|
|
|
|
|
|
|
/* (3) Sobel */
|
2016-11-03 09:36:23 +00:00
|
|
|
filterManager.get('sobel').apply();
|
2016-10-06 17:15:29 +00:00
|
|
|
|
2016-11-03 14:01:51 +00:00
|
|
|
/* (4) Gaussian Filter */
|
2016-11-03 09:36:23 +00:00
|
|
|
filterManager.get('gaussian').apply();
|
2016-10-06 17:15:29 +00:00
|
|
|
|
2016-11-03 14:01:51 +00:00
|
|
|
/* (5) Canny Filter */
|
2016-11-03 09:36:23 +00:00
|
|
|
filterManager.get('canny').apply();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
{ /* [4] Tracking.js
|
|
|
|
=========================================================*/
|
|
|
|
|
|
|
|
/* (1) On reporte chaque zone trackée sur le `<canvas>` */
|
2016-11-03 12:25:56 +00:00
|
|
|
var i, x, y, w, h;
|
2016-11-03 14:01:51 +00:00
|
|
|
for( i in zones.feature ){
|
|
|
|
x = zones.feature[i].x * _CAN.width;
|
|
|
|
y = zones.feature[i].y * _CAN.height;
|
|
|
|
w = zones.feature[i].w * _CAN.width;
|
|
|
|
h = zones.feature[i].h * _CAN.height;
|
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
_CON.lineWidth = 5;
|
|
|
|
_CON.strokeStyle = '#f00';
|
2016-11-03 14:01:51 +00:00
|
|
|
|
|
|
|
_CON.strokeRect(x, y, w, h);
|
2016-11-03 09:36:23 +00:00
|
|
|
}
|
2016-10-06 17:15:29 +00:00
|
|
|
|
2016-11-04 17:44:29 +00:00
|
|
|
for( i in reactiveFaceTracking.zones ){
|
|
|
|
x = reactiveFaceTracking.zones[i].x * _CAN.width;
|
|
|
|
y = reactiveFaceTracking.zones[i].y * _CAN.height;
|
|
|
|
w = reactiveFaceTracking.zones[i].w * _CAN.width;
|
|
|
|
h = reactiveFaceTracking.zones[i].h * _CAN.height;
|
2016-11-03 14:01:51 +00:00
|
|
|
|
2016-11-03 12:25:56 +00:00
|
|
|
_CON.lineWidth = 5;
|
|
|
|
_CON.strokeStyle = '#ff0';
|
2016-11-03 14:01:51 +00:00
|
|
|
|
|
|
|
_CON.strokeRect(x, y, w, h);
|
2016-11-03 12:25:56 +00:00
|
|
|
}
|
2016-10-06 17:15:29 +00:00
|
|
|
}
|
|
|
|
|
2016-10-05 13:04:48 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
{ /* [5] Filtrage post-processing
|
|
|
|
=========================================================*/
|
2016-10-05 10:13:48 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
}
|
2016-10-07 08:50:06 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
console.timeEnd('PROCESS');
|
2016-11-04 17:44:29 +00:00
|
|
|
LOADER.stop();
|
2016-11-03 09:36:23 +00:00
|
|
|
};
|
2016-10-07 08:50:06 +00:00
|
|
|
|
2016-10-05 08:49:25 +00:00
|
|
|
|
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
{ /* [3] Gestion des `ReactiveFilter`
|
|
|
|
=========================================================*/
|
|
|
|
/* (1) Création du Manager */
|
|
|
|
filterManager = new ReactiveFilterManager(DOM.imageLoader, _CAN, process);
|
|
|
|
|
|
|
|
/* (2) Ajout des filtres */
|
2016-11-04 17:44:29 +00:00
|
|
|
filterManager.add('face_tracking', reactiveFaceTracking);
|
|
|
|
filterManager.add('resolution', reactiveResolution);
|
|
|
|
filterManager.add('contrast', reactiveContrast);
|
|
|
|
filterManager.add('grayscale', reactiveGrayscale);
|
|
|
|
filterManager.add('sobel', reactiveSobel);
|
|
|
|
filterManager.add('gaussian', reactiveGaussianBlur);
|
|
|
|
filterManager.add('canny', reactiveCanny);
|
|
|
|
filterManager.add('haar_face', reactiveHaarFace);
|
2016-11-03 09:36:23 +00:00
|
|
|
|
|
|
|
/* (3) Gestion des backups */
|
2016-11-04 17:44:29 +00:00
|
|
|
Controller.remember(filterManager.get('face_tracking'));
|
2016-11-03 09:36:23 +00:00
|
|
|
Controller.remember(filterManager.get('resolution'));
|
|
|
|
Controller.remember(filterManager.get('contrast'));
|
2016-11-03 14:01:51 +00:00
|
|
|
Controller.remember(filterManager.get('grayscale'));
|
2016-11-03 09:36:23 +00:00
|
|
|
Controller.remember(filterManager.get('sobel'));
|
|
|
|
Controller.remember(filterManager.get('canny'));
|
|
|
|
Controller.remember(filterManager.get('gaussian'));
|
2016-11-04 10:25:07 +00:00
|
|
|
Controller.remember(filterManager.get('haar_face'));
|
2016-11-03 09:36:23 +00:00
|
|
|
|
|
|
|
/* (4) On attache tout à dat.GUI */
|
2016-11-04 17:44:29 +00:00
|
|
|
CFolder.custom = Controller.addFolder('custom');
|
|
|
|
CFolder.resolution = CFolder.custom.addFolder('Image Resolution');
|
|
|
|
CFolder.resolution.add(filterManager.get('resolution'), 'width', 0, 2).step(0.1);
|
|
|
|
CFolder.resolution.add(filterManager.get('resolution'), 'height', 0, 2).step(0.1);
|
|
|
|
CFolder.basic = CFolder.custom.addFolder('Basic Image Processing');
|
|
|
|
CFolder.basic.add(filterManager.get('contrast'), 'contrast', 0, 100);
|
|
|
|
CFolder.basic.add(filterManager.get('grayscale'), 'grayscale');
|
|
|
|
|
|
|
|
CFolder.tracking = Controller.addFolder('Tracking.js');
|
|
|
|
CFolder.face_tracking = CFolder.tracking.addFolder('Face tracking');
|
|
|
|
CFolder.face_tracking.add(filterManager.get('face_tracking'), 'apply');
|
|
|
|
CFolder.face_tracking.add(filterManager.get('face_tracking'), 'initial_scale', 1, 10).step(0.5);
|
|
|
|
CFolder.face_tracking.add(filterManager.get('face_tracking'), 'step_size', 1, 5).step(0.5);
|
|
|
|
CFolder.face_tracking.add(filterManager.get('face_tracking'), 'edges_density', 0.1, 0.5).step(0.01);
|
|
|
|
|
|
|
|
CFolder.jsfeat = Controller.addFolder('jsfeat');
|
|
|
|
CFolder.haar_face = CFolder.jsfeat.addFolder('Haar Face Detection');
|
|
|
|
CFolder.haar_face.add(filterManager.get('haar_face'), 'apply');
|
|
|
|
CFolder.haar_face.add(filterManager.get('haar_face'), 'min_scale', 1, 4).step(0.1);
|
|
|
|
CFolder.haar_face.add(filterManager.get('haar_face'), 'scale_factor', 1.1, 2).step(0.025);
|
|
|
|
CFolder.haar_face.add(filterManager.get('haar_face'), 'equalize_histogram');
|
|
|
|
CFolder.haar_face.add(filterManager.get('haar_face'), 'use_canny');
|
|
|
|
CFolder.haar_face.add(filterManager.get('haar_face'), 'edges_density', 0.01, 1.0).step(0.005);
|
|
|
|
CFolder.gaussian = CFolder.jsfeat.addFolder('Gaussian Blur');
|
|
|
|
CFolder.gaussian.add(filterManager.get('gaussian'), 'active');
|
|
|
|
CFolder.gaussian.add(filterManager.get('gaussian'), 'sigma', 0, 10).step(0.5);
|
|
|
|
CFolder.gaussian.add(filterManager.get('gaussian'), 'radius', 1, 11).step(1);
|
|
|
|
CFolder.sobel = CFolder.jsfeat.addFolder('Sobel Filter');
|
|
|
|
CFolder.sobel.add(filterManager.get('sobel'), 'sobelActive');
|
|
|
|
CFolder.canny = CFolder.jsfeat.addFolder('Canny Filter');
|
|
|
|
CFolder.canny.add(filterManager.get('canny'), 'active');
|
|
|
|
CFolder.canny.add(filterManager.get('canny'), 'radius', 0, 4).step(1);
|
|
|
|
CFolder.canny.add(filterManager.get('canny'), 'low_threshold', 1, 127).step(1);
|
|
|
|
CFolder.canny.add(filterManager.get('canny'), 'high_threshold', 1, 127).step(1);
|
|
|
|
|
|
|
|
CFolder.process = Controller.addFolder('Process');
|
|
|
|
CFolder.process.add({render: process}, 'render');
|
2016-11-03 09:36:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* (5) Gestion du @PermanentStorage */
|
|
|
|
Controller.__save_row.children[2].addEventListener('click', function(){
|
|
|
|
/* (1) Update properties */
|
|
|
|
Controller.save();
|
|
|
|
|
|
|
|
/* (2) Get stored data */
|
|
|
|
try{
|
|
|
|
var stored = JSON.stringify( Controller.getSaveObject() );
|
|
|
|
ControllerRememberer.store(stored, function(){ log('dat.GUI preset stored.', '[PermanentStorage]'); return true; });
|
|
|
|
|
|
|
|
}catch(e){ log('Corrupted data.', '[PermanentStorage]'); }
|
|
|
|
|
|
|
|
}, false);
|
2016-11-02 18:15:20 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
}
|
2016-10-07 08:50:06 +00:00
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
/* [x] Chargement image
|
|
|
|
=========================================================*/
|
|
|
|
iL = new ImageLoader( DOM.imageLoader, init, process );
|
2016-10-07 08:50:06 +00:00
|
|
|
|
|
|
|
|
2016-11-03 09:36:23 +00:00
|
|
|
return true;
|
|
|
|
});
|