Correction [SobelFilter] + [CannyFilter] inspired by examples on `jsfeat` demo website

This commit is contained in:
xdrm-brackets 2016-11-03 15:01:51 +01:00
parent 8909d5f86d
commit 73f86e838a
6 changed files with 245 additions and 164 deletions

View File

@ -40,8 +40,7 @@
var Controller, var Controller,
init, init,
featureZones, zones = {feature: [], face: []},
faceZones,
track, track,
featureTracker, featureTracker,
faceTracker, faceTracker,
@ -75,18 +74,18 @@ ControllerRememberer.fetch(function(loaded_data){
}; };
/* (2) Gestion de tracking.js */ /* (2) Gestion de tracking.js */
featureZones = []; zones.feature = [];
faceZones = []; zones.face = [];
/* (3) Gestion du track de l'image */ /* (3) Gestion du track de l'image */
track = { track = {
trackFeatures: function(){ trackFeatures: function(){
featureZones = []; zones.feature = [];
featureTrackerTask = tracking.track(_CAN, featureTracker); featureTrackerTask = tracking.track(_CAN, featureTracker);
}, },
trackFace: function(){ trackFace: function(){
faceZones = []; zones.face = [];
faceTrackerTask = tracking.track(_CAN, faceTracker); faceTrackerTask = tracking.track(_CAN, faceTracker);
} }
}; };
@ -95,15 +94,19 @@ ControllerRememberer.fetch(function(loaded_data){
faceTracker = new tracking.ObjectTracker(['face']); faceTracker = new tracking.ObjectTracker(['face']);
featureTracker = new tracking.ObjectTracker(['eye', 'mouth']); featureTracker = new tracking.ObjectTracker(['eye', 'mouth']);
faceTracker.setStepSize(1.5); faceTracker.setInitialScale(1.0);
featureTracker.setStepSize(1.5); featureTracker.setInitialScale(1.0);
faceTracker.setStepSize(1.2);
featureTracker.setStepSize(1.2);
faceTracker.setEdgesDensity(0.1);
featureTracker.setEdgesDensity(0.1);
trackerCallback = function(zones, e){ trackerCallback = function(z, e){
zones.length = 0; zones[z].length = 0;
e.data.forEach(function(rect){ e.data.forEach(function(rect){
zones.push({ zones[z].push({
x: rect.x / _CAN.width, x: rect.x / _CAN.width,
y: rect.y / _CAN.height, y: rect.y / _CAN.height,
w: rect.width / _CAN.width, w: rect.width / _CAN.width,
@ -111,15 +114,18 @@ ControllerRememberer.fetch(function(loaded_data){
}); });
}); });
// On enregistre dans `featureZones` les featureZones trackées // On enregistre dans `zones.feature` les zones.feature trackées
log('Recognition done', '[Tracking.js]'); if( zones[z].length > 0 )
log(z+' recognition done', '[Tracking.js]');
else
log(z+' recognition failed', '[Tracking.js]');
// On met à jour le rendu (affichage des featureZones) // On met à jour le rendu (affichage des zones.feature)
process.apply(DOM.imageLoader); process.apply(DOM.imageLoader);
} }
faceTracker.on('track', function(e){ return trackerCallback.apply(this, [faceZones, e]); }); faceTracker.on('track', function(e){ return trackerCallback.apply(this, ['face', e]); });
featureTracker.on('track', function(e){ return trackerCallback.apply(this, [featureZones, e]); }); featureTracker.on('track', function(e){ return trackerCallback.apply(this, ['feature', e]); });
} }
@ -136,8 +142,8 @@ ControllerRememberer.fetch(function(loaded_data){
/* [0.0] Gestion du changement d'image /* [0.0] Gestion du changement d'image
=========================================================*/ =========================================================*/
if( this.src != last ){ if( this.src != last ){
faceZones = []; zones.face = [];
featureZones = []; zones.feature = [];
exec = false; exec = false;
last = this.src; last = this.src;
} }
@ -176,13 +182,16 @@ ControllerRememberer.fetch(function(loaded_data){
/* (1) Contraste */ /* (1) Contraste */
filterManager.get('contrast').apply(); filterManager.get('contrast').apply();
/* (2) Sobel */ /* (2) Contraste */
filterManager.get('grayscale').apply();
/* (3) Sobel */
filterManager.get('sobel').apply(); filterManager.get('sobel').apply();
/* (3) Gaussian Filter */ /* (4) Gaussian Filter */
filterManager.get('gaussian').apply(); filterManager.get('gaussian').apply();
/* (4) Canny Filter */ /* (5) Canny Filter */
filterManager.get('canny').apply(); filterManager.get('canny').apply();
} }
@ -192,36 +201,28 @@ ControllerRememberer.fetch(function(loaded_data){
/* (1) On reporte chaque zone trackée sur le `<canvas>` */ /* (1) On reporte chaque zone trackée sur le `<canvas>` */
var i, x, y, w, h; var i, x, y, w, h;
for( i in featureZones ){ for( i in zones.feature ){
x = featureZones[i].x * _CAN.width; x = zones.feature[i].x * _CAN.width;
y = featureZones[i].y * _CAN.height; y = zones.feature[i].y * _CAN.height;
w = featureZones[i].w * _CAN.width; w = zones.feature[i].w * _CAN.width;
h = featureZones[i].h * _CAN.height; h = zones.feature[i].h * _CAN.height;
_CON.beginPath();
_CON.moveTo( x, y );
_CON.lineTo( x, y+h );
_CON.lineTo( x+w, y+h );
_CON.lineTo( x+w, y );
_CON.lineTo( x, y );
_CON.lineWidth = 5; _CON.lineWidth = 5;
_CON.strokeStyle = '#f00'; _CON.strokeStyle = '#f00';
_CON.stroke();
_CON.strokeRect(x, y, w, h);
} }
for( i in faceZones ){ for( i in zones.face ){
x = faceZones[i].x * _CAN.width; x = zones.face[i].x * _CAN.width;
y = faceZones[i].y * _CAN.height; y = zones.face[i].y * _CAN.height;
w = faceZones[i].w * _CAN.width; w = zones.face[i].w * _CAN.width;
h = faceZones[i].h * _CAN.height; h = zones.face[i].h * _CAN.height;
_CON.beginPath();
_CON.moveTo( x, y );
_CON.lineTo( x, y+h );
_CON.lineTo( x+w, y+h );
_CON.lineTo( x+w, y );
_CON.lineTo( x, y );
_CON.lineWidth = 5; _CON.lineWidth = 5;
_CON.strokeStyle = '#ff0'; _CON.strokeStyle = '#ff0';
_CON.stroke();
_CON.strokeRect(x, y, w, h);
} }
} }
@ -245,6 +246,7 @@ ControllerRememberer.fetch(function(loaded_data){
/* (2) Ajout des filtres */ /* (2) Ajout des filtres */
filterManager.add('resolution', reactiveResolution); filterManager.add('resolution', reactiveResolution);
filterManager.add('contrast', reactiveContrast); filterManager.add('contrast', reactiveContrast);
filterManager.add('grayscale', reactiveGrayscale);
filterManager.add('sobel', reactiveSobel); filterManager.add('sobel', reactiveSobel);
filterManager.add('gaussian', reactiveGaussianBlur); filterManager.add('gaussian', reactiveGaussianBlur);
filterManager.add('canny', reactiveCanny); filterManager.add('canny', reactiveCanny);
@ -252,6 +254,7 @@ ControllerRememberer.fetch(function(loaded_data){
/* (3) Gestion des backups */ /* (3) Gestion des backups */
Controller.remember(filterManager.get('resolution')); Controller.remember(filterManager.get('resolution'));
Controller.remember(filterManager.get('contrast')); Controller.remember(filterManager.get('contrast'));
Controller.remember(filterManager.get('grayscale'));
Controller.remember(filterManager.get('sobel')); Controller.remember(filterManager.get('sobel'));
Controller.remember(filterManager.get('canny')); Controller.remember(filterManager.get('canny'));
Controller.remember(filterManager.get('gaussian')); Controller.remember(filterManager.get('gaussian'));
@ -261,16 +264,23 @@ ControllerRememberer.fetch(function(loaded_data){
Controller.add(track, 'trackFace'); Controller.add(track, 'trackFace');
Controller.add(track, 'trackFeatures'); Controller.add(track, 'trackFeatures');
Controller.addFolder('Image Resolution'); Controller.addFolder('Image Resolution');
Controller.add(filterManager.get('resolution'), 'width', 0, 2).step(0.1);//listen(); Controller.add(filterManager.get('resolution'), 'width', 0, 2).step(0.1);
Controller.add(filterManager.get('resolution'), 'height', 0, 2).step(0.1);//listen(); Controller.add(filterManager.get('resolution'), 'height', 0, 2).step(0.1);
Controller.addFolder('Basic Image Processing'); Controller.addFolder('Basic Image Processing');
Controller.add(filterManager.get('contrast'), 'contrast', 0, 100);//listen(); Controller.add(filterManager.get('contrast'), 'contrast', 0, 100);
Controller.add(filterManager.get('grayscale'), 'grayscale');
Controller.addFolder('Gaussian Blur'); Controller.addFolder('Gaussian Blur');
Controller.add(filterManager.get('gaussian'), 'sigma', 0, 10).step(0.5);//listen(); Controller.add(filterManager.get('gaussian'), 'sigma', 0, 10).step(0.5);
Controller.add(filterManager.get('gaussian'), 'radius', 1, 11).step(1);//listen(); Controller.add(filterManager.get('gaussian'), 'radius', 1, 11).step(1);
Controller.addFolder('Convolution Filters'); Controller.addFolder('Sobel Filter');
Controller.add(filterManager.get('sobel'), 'sobelActive');//listen(); Controller.add(filterManager.get('sobel'), 'sobelActive');
Controller.add(filterManager.get('canny'), 'canny_radius');//listen(); Controller.addFolder('Canny Filter');
Controller.add(filterManager.get('canny'), 'active');
Controller.add(filterManager.get('canny'), 'radius', 0, 4).step(1);
Controller.add(filterManager.get('canny'), 'low_threshold', 1, 127).step(1);
Controller.add(filterManager.get('canny'), 'high_threshold', 1, 127).step(1);
Controller.addFolder('Process');
Controller.add({render: process}, 'render');
/* (5) Gestion du @PermanentStorage */ /* (5) Gestion du @PermanentStorage */

View File

@ -1,13 +1,16 @@
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(c){a._attr[b]=c;a._manager.process()}}(this,b));this.apply=function(){}},ReactiveFilterManager=function(a,b,d){this._target=a instanceof HTMLImageElement?a:null;if(!this._target)throw Error("Param 1 expected to be an HTMLImageElement (<img>), but "+ var ReactiveFilter=function(a){this._manager={_process:function(){}};this._attr=a instanceof Object?a:{};for(var c in this._attr)this.__defineGetter__(c,function(a){return this._attr[a]}.bind(this,c)),this.__defineSetter__(c,function(a,b){return function(c){a._attr[b]=c;a._manager.process()}}(this,c));this.apply=function(){}},ReactiveFilterManager=function(a,c,d){this._target=a instanceof HTMLImageElement?a:null;if(!this._target)throw Error("Param 1 expected to be an HTMLImageElement (<img>), but "+
a.constructor.name+" received");this._canvas=b instanceof HTMLCanvasElement?b:null;if(!this._canvas)throw Error("Param 2 expected to be an HTMLCanvasElement (<canvas>), but "+b.constructor.name+" received");this._context=this._canvas.getContext("2d");this._process=d instanceof Function?d:null;if(!this._process)throw Error("Param 3 expected to be a Function, but "+d.constructor.name+" received");this._filter={}}; a.constructor.name+" received");this._canvas=c instanceof HTMLCanvasElement?c:null;if(!this._canvas)throw Error("Param 2 expected to be an HTMLCanvasElement (<canvas>), but "+c.constructor.name+" received");this._context=this._canvas.getContext("2d");this._process=d instanceof Function?d:null;if(!this._process)throw Error("Param 3 expected to be a Function, but "+d.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.add=function(a,c){a="string"===typeof a?a:null;if(!a)throw Error("Param 1 expected to be a `string`, but "+a.constructor.name+" received");c=c instanceof ReactiveFilter?c:null;if(!c)throw Error("Param 2 expected to be a `ReactiveFilter`, but "+c.constructor.name+" received");if(null!=this._filter[a])return!0;this._filter[a]=c;c._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)()}; 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)()};
ConvolutionFilter=function(a,b,d,e){var c,f,h,g,p=parseInt(e.length/2),q=parseInt(e[0].length/2),l=d.slice(0),n,k,m,r,t,u;for(k=p;k<b;k++)for(n=q;n<a;n++){g=h=f=c=0;for(r=-p;r<=p;r++)for(m=-q;m<=q;m++)t=e[p+r][q+m],u=4*((k+r)*a+(n+m)),c+=l[u+0]*t,f+=l[u+1]*t,h+=l[u+2]*t,g+=l[u+3]*t;m=4*(k*a+n);d[m+0]=c;d[m+1]=f;d[m+2]=h;d[m+3]=g}}; ConvolutionFilter=function(a,c,d,b){var e,g,f,h,q=parseInt(b.length/2),p=parseInt(b[0].length/2),l=d.slice(0),k,n,m,r,t,u;for(n=q;n<c;n++)for(k=p;k<a;k++){h=f=g=e=0;for(r=-q;r<=q;r++)for(m=-p;m<=p;m++)t=b[q+r][p+m],u=4*((n+r)*a+(k+m)),e+=l[u+0]*t,g+=l[u+1]*t,f+=l[u+2]*t,h+=l[u+3]*t;m=4*(n*a+k);d[m+0]=e;d[m+1]=g;d[m+2]=f;d[m+3]=h}};
SobelFilter=function(a,b,d){var e=[[-1,0,1],[-2,0,2],[-1,0,1]],c=[[1,2,1],[0,0,0],[-1,-2,-1]],f=parseInt(e.length/2),h=parseInt(e[0].length/2),g=d.slice(0),p,q,l,n,k,m;for(q=f;q<b;q++)for(p=h;p<a;p++){k=0;for(n=-f;n<=f;n++)for(l=-h;l<=h;l++)m=4*((q+n)*a+(p+l)),k+=g[m+0]*(e[f+n][h+l]+c[f+n][h+l])/2;l=q*a+p;k=Math.abs(k);d[l]=k<<32|k<<16|k<<8|255}};var reactiveResolution=new ReactiveFilter({width:1,height:1}); SobelFilter=function(a,c,d){var b=[[-1,0,1],[-2,0,2],[-1,0,1]],e=[[1,2,1],[0,0,0],[-1,-2,-1]],g=parseInt(b.length/2),f=parseInt(b[0].length/2),h=d.slice(0),q,p,l,k,n,m;for(p=g;p<c;p++)for(q=f;q<a;q++){n=0;for(k=-g;k<=g;k++)for(l=-f;l<=f;l++)m=4*((p+k)*a+(q+l)),n+=h[m+0]*(b[g+k][f+l]+e[g+k][f+l])/2;l=p*a+q;n=Math.abs(n);d[l]=(n<<32)+(n<<16)+(n<<8)|4278190080}};var reactiveResolution=new ReactiveFilter({width:1,height:1});
reactiveResolution.apply=function(){if(this._manager instanceof ReactiveFilterManager){var a=this._manager._target,b=this._manager._canvas,d=this._manager._context;b.width=a.width*this.width;b.height=a.height*this.height;d.drawImage(a,0,0,b.width,b.height)}};var reactiveContrast=new ReactiveFilter({contrast:0}); reactiveResolution.apply=function(){if(this._manager instanceof ReactiveFilterManager){var a=this._manager._target,c=this._manager._canvas,d=this._manager._context;c.width=a.width*this.width;c.height=a.height*this.height;d.drawImage(a,0,0,c.width,c.height)}};var reactiveContrast=new ReactiveFilter({contrast:0});
reactiveContrast.apply=function(){if(this._manager instanceof ReactiveFilterManager){for(var a=this._manager._canvas,b=this._manager._context,a=b.getImageData(0,0,a.width,a.height),d=a.data,e=this.contrast;1<e;)e/=100;for(var e=127*(1-e),c=0,f=d.length;c<f;c++)0!=c%3&&(d[c]>=127+e&&(d[c]=255),d[c]<=127-e&&(d[c]=0));b.putImageData(a,0,0)}};var reactiveSobel=new ReactiveFilter({sobelActive:!1}); reactiveContrast.apply=function(){if(this._manager instanceof ReactiveFilterManager){for(var a=this._manager._canvas,c=this._manager._context,a=c.getImageData(0,0,a.width,a.height),d=a.data,b=this.contrast;1<b;)b/=100;for(var b=127*(1-b),e=0,g=d.length;e<g;e++)0!=e%3&&(d[e]>=127+b&&(d[e]=255),d[e]<=127-b&&(d[e]=0));c.putImageData(a,0,0)}};var reactiveGrayscale=new ReactiveFilter({grayscale:!1});
reactiveSobel.apply=function(){if(this._manager instanceof ReactiveFilterManager&&this.sobelActive){var a=this._manager._canvas,b=this._manager._context,d=b.getImageData(0,0,a.width,a.height),e=new Uint32Array(d.buffer);SobelFilter(a.width,a.height,e);b.putImageData(d,0,0)}};var reactiveGaussianBlur=new ReactiveFilter({sigma:0,radius:3}); reactiveGrayscale.apply=function(){if(this._manager instanceof ReactiveFilterManager&&this.grayscale){for(var a=this._manager._canvas,c=this._manager._context,a=c.getImageData(0,0,a.width,a.height),d=a.data,b=this.contrast;1<b;)b/=100;for(var e=0,g=d.length;e<g;e++)0<e%4||(b=Math.round(.298*d[e]+.586*d[e+1]+.114*d[e+2]),d[e]=d[e+1]=d[e+2]=b);c.putImageData(a,0,0)}};var reactiveSobel=new ReactiveFilter({sobelActive:!1});
reactiveGaussianBlur.apply=function(){if(this._manager instanceof ReactiveFilterManager){var a=this._manager._target,b=this._manager._canvas,d=this._manager._context,e=d.getImageData(0,0,b.width,b.height),c=new Uint32Array(e.buffer),b=document.createElement("canvas").getContext("2d").createImageData(b.width,b.height);b.data.set(e.data.slice(0));tBuf=new Uint32Array(b.buffer);for(var f=new jsfeat.matrix_t(a.width,a.height,jsfeat.U8C1_t),h=new jsfeat.matrix_t(a.width,a.height,jsfeat.U8C1_t),a=a.width* reactiveSobel.apply=function(){if(this._manager instanceof ReactiveFilterManager&&this.sobelActive){var a=this._manager._canvas,c=this._manager._context,d=c.getImageData(0,0,a.width,a.height);new Uint32Array(d.buffer);var b=new jsfeat.matrix_t(a.width,a.height,jsfeat.U8C1_t),e=new jsfeat.matrix_t(a.width,a.height,jsfeat.S32C2_t),g=new jsfeat.matrix_t(a.width,a.height,jsfeat.S32C1_t),f,h,q,p,l,k,n,m,r;jsfeat.imgproc.grayscale(d.data,a.width,a.height,b);jsfeat.imgproc.gaussian_blur(b,b,3);jsfeat.imgproc.sobel_derivatives(b,
a.height,g;0<=--a;)g=c[a],f.data[a]=g<<24|g<<16|g<<8|g;jsfeat.imgproc.gaussian_blur(f,h,this.radius+1<<1,this.sigma);for(a=h.cols*h.rows;0<=--a;)g=h.data[a],tBuf[a]=g<<24|g<<16|g<<8|g;e.data.set(b.data);d.putImageData(b,0,0)}};var reactiveCanny=new ReactiveFilter({canny_radius:3}); e);a=b.cols*b.rows;p=l=agx=agy=0;e=e.data;k=g.data;for(n=b.data;0<=--a;)f=e[a<<1],h=e[(a<<1)+1],k[a]=f*f+h*h;for(q=1;q<b.rows-1;++q)for(a=q*b.cols+1|0,g=1;g<b.cols-1;++g,++a)f=e[a<<1],h=e[(a<<1)+1],agx=(f^f>>31)-(f>>31)|0,agy=(h^h>>31)-(h>>31)|0,0<f&&(p=1)||(p=-1),0<h&&(l=b.cols)||(l=-b.cols),agx>agy?(m=k[a+p],r=k[a+p+-l],f=k[a-p],h=k[a-p+l],m=(agx-agy)*m+agy*r,f=(agx-agy)*f+agy*h,h=k[a]*agx,n[a]=h>=m&&h>f?agx&255:0):(m=k[a+-l],r=k[a+p+-l],f=k[a+l],h=k[a-p+l],m=(agy-agx)*m+agx*r,f=(agy-agx)*f+agx*
reactiveCanny.apply=function(){if(this._manager instanceof ReactiveFilterManager){var a=this._manager._target,b=this._manager._canvas,d=this._manager._context,b=d.getImageData(0,0,b.width,b.height),e=new Uint32Array(b.buffer),a=new jsfeat.matrix_t(a.width,a.height,jsfeat.U8C1_t),c,f=e.length;c={};jsfeat.imgproc.canny(a,a,40,40);for(i=0;i<f;i++)c=a.data[i],c|=c<<16|c<<8,c={a:-16777216,b:(c&16711680)>>16,g:(c&65280)>>8,r:c&255},255===c.r&&255===c.g&&255===c.b?c={r:c.r,g:0,b:0,a:-16777216}:c.a=0,e[i]= h,h=k[a]*agy,n[a]=h>=m&&h>f?agy&255:0);data_u32=new Uint32Array(d.data.buffer);for(a=b.cols*b.rows;0<=--a;)data_u32[a]=-16777216|n[a]<<16|n[a]<<8|n[a];c.putImageData(d,0,0)}};var reactiveGaussianBlur=new ReactiveFilter({sigma:0,radius:3});
c.a|c.b<<16|c.g<<8|c.r;d.putImageData(b,0,0)}}; reactiveGaussianBlur.apply=function(){if(this._manager instanceof ReactiveFilterManager){for(var a=this._manager._target,c=this._manager._canvas,d=this._manager._context,c=d.getImageData(0,0,c.width,c.height),b=new Uint32Array(c.buffer),e=new jsfeat.matrix_t(a.width,a.height,jsfeat.U8C1_t),g=new jsfeat.matrix_t(a.width,a.height,jsfeat.U8C1_t),a=a.width*a.height,f;0<=--a;)f=b[a],e.data[a]=f<<24|f<<16|f<<8|f;jsfeat.imgproc.gaussian_blur(e,g,this.radius+1<<1,this.sigma);for(a=g.cols*g.rows;0<=--a;)f=
g.data[a],b[a]=f<<24|f<<16|f<<8|f;d.putImageData(c,0,0)}};var reactiveCanny=new ReactiveFilter({active:!1,low_threshold:1,high_threshold:1,radius:3});
reactiveCanny.apply=function(){if(this._manager instanceof ReactiveFilterManager&&this.active){var a=this._manager._canvas,c=this._manager._context,d=c.getImageData(0,0,a.width,a.height),b=new jsfeat.matrix_t(a.width,a.height,jsfeat.U8C1_t),e,g;jsfeat.imgproc.grayscale(d.data,a.width,a.height,b);jsfeat.imgproc.gaussian_blur(b,b,(this.radius|0)+1<<1,0);jsfeat.imgproc.canny(b,b,this.low_threshold|0,this.high_threshold|0);a=new Uint32Array(d.data.buffer);e=b.cols*b.rows;for(pix=0;0<=--e;)g=b.data[e],
a[e]=-16777216|g<<16|g<<8|g;c.putImageData(d,0,0)}};

View File

@ -256,7 +256,7 @@ SobelFilter = function(width, height, buff32){
dIndex = (y*width + x); // indice destination dIndex = (y*width + x); // indice destination
convolved = Math.abs(convolved); convolved = Math.abs(convolved);
buff32[dIndex] = convolved << 32 | convolved << 16 | convolved << 8 | 0xff; buff32[dIndex] = (convolved << 32) + (convolved << 16) + (convolved << 8) | 0xff000000;
// buff32[dIndex+1] = Math.abs(convolved); // buff32[dIndex+1] = Math.abs(convolved);
// buff32[dIndex+2] = Math.abs(convolved); // buff32[dIndex+2] = Math.abs(convolved);
// buff32[dIndex+3] = 0xff; // buff32[dIndex+3] = 0xff;
@ -344,6 +344,56 @@ reactiveContrast.apply = function(){
}; };
/************************************************
**** Gestion du grayscale ****
************************************************/
var reactiveGrayscale = new ReactiveFilter({ grayscale: false });
reactiveGrayscale.apply = function(){
/* [1] Si pas de manager, on exit
=========================================================*/
if( !(this._manager instanceof ReactiveFilterManager) )
return;
if( !this.grayscale )
return;
/* [2] On recupère notre back-buffer (8Uint)
=========================================================*/
var o = {
image: this._manager._target,
canvas: this._manager._canvas,
context: this._manager._context
};
var imageData = o.context.getImageData(0, 0, o.canvas.width, o.canvas.height);
var buffer = imageData.data;
// var buffer32 = new Uint32Array( imageData.imageData );
/* [3] On effectue notre modification
=========================================================*/
/* (1) On récupère la valeur du contraste */
var thresold = this.contrast;
while( thresold > 1 ) thresold /= 100;
thresold = (1-thresold) * 127;
/* (1) Gestion du contraste */
var g;
for( var i = 0, len = buffer.length ; i < len ; i++ ){
// si pas pixel rouge, on ne fait rien
if( i%4 > 0 ) continue;
// Grayscale
g = Math.round(0.298 * buffer[i] + 0.586 * buffer[i+1] + 0.114 * buffer[i+2]);
buffer[i] = buffer[i+1] = buffer[i+2] = g;
}
/* (2) Copie le résultat sur le `<canvas>` */
o.context.putImageData(imageData, 0, 0);
};
/************************************************ /************************************************
**** Gestion du Sobel **** **** Gestion du Sobel ****
@ -368,41 +418,78 @@ reactiveSobel.apply = function(){
}; };
var imageData = o.context.getImageData(0, 0, o.canvas.width, o.canvas.height); var imageData = o.context.getImageData(0, 0, o.canvas.width, o.canvas.height);
// var buffer = imageData.data;
var buffer32 = new Uint32Array( imageData.buffer ); var buffer32 = new Uint32Array( imageData.buffer );
var img_u8 = new jsfeat.matrix_t(o.canvas.width, o.canvas.height, jsfeat.U8C1_t),
img_gxgy = new jsfeat.matrix_t(o.canvas.width, o.canvas.height, jsfeat.S32C2_t),
img_mag = new jsfeat.matrix_t(o.canvas.width, o.canvas.height, jsfeat.S32C1_t);
var i, gx, gy, x, y, dx, dy, gd, mag, id, a1, a2, b1, b2, A, B, point, data_32, a, p;
/* [3] On effectue notre modification /* [3] On effectue notre modification
=========================================================*/ =========================================================*/
SobelFilter(o.canvas.width, o.canvas.height, buffer32); jsfeat.imgproc.grayscale(imageData.data, o.canvas.width, o.canvas.height, img_u8);
/* (1) On calcule la convolution horizontale */ jsfeat.imgproc.gaussian_blur(img_u8, img_u8, 3);
// var Gx = buffer.slice(0); jsfeat.imgproc.sobel_derivatives(img_u8, img_gxgy);
// ConvolutionFilter(o.canvas.width, o.canvas.height, Gx, [
// [-1, 0, 1], i = img_u8.cols*img_u8.rows;
// [-2, 0, 2], gx = gy = x = y = dx = dy = agx = agy = 0;
// [-1, 0, 1] gd = img_gxgy.data;
// ]); mag = img_mag.data;
// id = img_u8.data;
// /* (2) On calcule la convolution verticale */
// var Gy = buffer.slice(0); while( --i >= 0 ){
// ConvolutionFilter(o.canvas.width, o.canvas.height, Gy, [ gx = gd[ i<<1 ];
// [1, 2, 1], gy = gd[ (i<<1) + 1 ];
// [0, 0, 0], mag[i] = gx*gx + gy*gy;
// [-1, -2, -1] }
// ]);
// for( y = 1 ; y < img_u8.rows - 1 ; ++y ){
// /* (3) On mixe les 2 */ i = (y * img_u8.cols + 1) | 0;
// for( var i = 0, len = buffer.length ; i < len ; i += 4 ){
// for( x = 1 ; x < img_u8.cols - 1 ; ++x, ++i){
// /* (4.1) On ajoute la convolution horizontale en rouge */
// buffer[i] = Math.abs(Gy[i]); gx = gd[ i<<1 ];
// gy = gd[ (i<<1) + 1 ];
// /* (4.2) On ajoute la convolution verticale en vert */ agx = ((gx ^ (gx >> 31)) - (gx >> 31))|0;
// buffer[i+1] = Math.abs(Gx[i+1]); agy = ((gy ^ (gy >> 31)) - (gy >> 31))|0;
//
// buffer[i+2] = 0x00; (gx > 0) && (dx = 1) || (dx = -1);
// buffer[i+3] = 0xff;
// } (gy > 0) && (dy = img_u8.cols) || (dy = -img_u8.cols);
if( agx > agy ){
a1 = mag[i+dx];
a2 = mag[i+dx+(-dy)];
b1 = mag[i-dx];
b2 = mag[i-dx+dy];
A = (agx - agy)*a1 + agy*a2;
B = (agx - agy)*b1 + agy*b2;
point = mag[i] * agx;
id[i] = (point >= A && point > B) ? agx&0xff : 0x0;
} else {
a1 = mag[i+(-dy)];
a2 = mag[i+dx+(-dy)];
b1 = mag[i+dy];
b2 = mag[i-dx+dy];
A = (agy - agx)*a1 + agx*a2;
B = (agy - agx)*b1 + agx*b2;
point = mag[i] * agy;
id[i] = (point >= A && point > B) ? agy&0xff : 0x0;
}
}
}
// render result back to canvas
data_u32 = new Uint32Array(imageData.data.buffer);
a = (0xff << 24);
p = 0;
i = img_u8.cols*img_u8.rows;
while( --i >= 0 )
data_u32[i] = a | (id[i] << 16) | (id[i] << 8) | id[i];
/* (2) Copie le résultat sur le `<canvas>` */ /* (2) Copie le résultat sur le `<canvas>` */
@ -434,12 +521,6 @@ reactiveGaussianBlur.apply = function(){
// var buffer = imageData.data; // var buffer = imageData.data;
var buffer32 = new Uint32Array( imageData.buffer ); var buffer32 = new Uint32Array( imageData.buffer );
/* (2) Create target */
var tCan = document.createElement('canvas');
var tmp = tCan.getContext('2d').createImageData(o.canvas.width, o.canvas.height);
tmp.data.set( imageData.data.slice(0) );
tBuf = new Uint32Array( tmp.buffer );
/* [3] On effectue notre modification /* [3] On effectue notre modification
=========================================================*/ =========================================================*/
@ -460,25 +541,26 @@ reactiveGaussianBlur.apply = function(){
p_num = target.cols * target.rows; p_num = target.cols * target.rows;
while( --p_num >= 0 ){ while( --p_num >= 0 ){
pixel = target.data[p_num]; pixel = target.data[p_num];
tBuf[p_num] = (pixel << 24) | (pixel << 16) | (pixel << 8) | pixel; buffer32[p_num] = (pixel << 24) | (pixel << 16) | (pixel << 8) | pixel;
} }
/* (2) Copie le résultat sur le `<canvas>` */ /* (2) Copie le résultat sur le `<canvas>` */
imageData.data.set( tmp.data ); o.context.putImageData(imageData, 0, 0);
o.context.putImageData(tmp, 0, 0);
}; };
/************************************************ /************************************************
**** Gestion du Canny Filter **** **** Gestion du Canny Filter ****
************************************************/ ************************************************/
var reactiveCanny = new ReactiveFilter({ canny_radius: 3 }); var reactiveCanny = new ReactiveFilter({ active: false, low_threshold: 1, high_threshold: 1, radius: 3 });
reactiveCanny.apply = function(){ reactiveCanny.apply = function(){
/* [1] Si pas de manager, on exit /* [1] Si pas de manager, on exit
=========================================================*/ =========================================================*/
if( !(this._manager instanceof ReactiveFilterManager) ) if( !(this._manager instanceof ReactiveFilterManager) )
return; return;
if( !this.active )
return;
/* [2] On recupère notre back-buffer (8Uint) /* [2] On recupère notre back-buffer (8Uint)
=========================================================*/ =========================================================*/
@ -490,43 +572,28 @@ reactiveCanny.apply = function(){
/* (1) Get source */ /* (1) Get source */
var imageData = o.context.getImageData(0, 0, o.canvas.width, o.canvas.height); var imageData = o.context.getImageData(0, 0, o.canvas.width, o.canvas.height);
// var buffer = imageData.data; var img_u8 = new jsfeat.matrix_t(o.canvas.width, o.canvas.height, jsfeat.U8C1_t);
var buffer32 = new Uint32Array( imageData.buffer );
var r, kernel_size, buffer32, a, i, p;
/* [3] On effectue notre modification /* [3] On effectue notre modification
=========================================================*/ =========================================================*/
var matrix = new jsfeat.matrix_t(o.image.width, o.image.height, jsfeat.U8C1_t); jsfeat.imgproc.grayscale(imageData.data, o.canvas.width, o.canvas.height, img_u8);
var pixel,
kernel_size = (this.canny_radius + 1) << 1,
alpha = (0x000000FF << 24),
p_num = buffer32.length,
low_threshold = 40,
high_threshold = 40,
x = {},
cur;
// jsfeat.imgproc.gaussian_blur(matrix, matrix, kernel_size, 0); r = this.radius|0;
kernel_size = (r+1) << 1;
jsfeat.imgproc.gaussian_blur(img_u8, img_u8, kernel_size, 0);
jsfeat.imgproc.canny(img_u8, img_u8, this.low_threshold|0, this.high_threshold|0);
jsfeat.imgproc.canny(matrix, matrix, low_threshold | 0, high_threshold | 0); // render result back to canvas
buffer32 = new Uint32Array( imageData.data.buffer );
for( i = 0 ; i < p_num ; i++ ){ a = (0xff << 24);
pixel = matrix.data[i]; i = img_u8.cols*img_u8.rows, pix = 0;
cur = (pixel << 16) | (pixel << 8) | pixel; while( --i >= 0 ){
x = { p = img_u8.data[i];
a: alpha, buffer32[i] = a | (p << 16) | (p << 8) | p;
b: (cur & 0x00FF0000) >> 16,
g: (cur & 0x0000FF00) >> 8,
r: cur & 0x000000FF
};
if( x.r === 255 && x.g === 255 && x.b === 255 ) // white
x = { r: x.r, g: 0, b: 0, a: (0x000000FF << 24) };
else
x.a = (0x00000000 << 24); // 'alpha' is set to min., i.e., '0'
buffer32[i] = x.a | (x.b << 16) | (x.g << 8) | x.r;
} }
/* (2) Copie le résultat sur le `<canvas>` */ /* (2) Copie le résultat sur le `<canvas>` */
o.context.putImageData(imageData, 0, 0); o.context.putImageData(imageData, 0, 0);

View File

@ -1,9 +1,10 @@
var DOM={body:$("body"),canvas:$("canvas"),imageLoader:$("#image-loader")},_CAN=DOM.canvas;_CAN.width=_CAN.height=1E3;var _CON=_CAN.getContext("2d"),iL,filterManager,process=function(){},exec=!1,last,featureTrackerTask,faceTrackerTask,trackerCallback,Controller,init,featureZones,faceZones,track,featureTracker,faceTracker,initialized=!1,ControllerRememberer=new PermanentStorage; var DOM={body:$("body"),canvas:$("canvas"),imageLoader:$("#image-loader")},_CAN=DOM.canvas;_CAN.width=_CAN.height=1E3;var _CON=_CAN.getContext("2d"),iL,filterManager,process=function(){},exec=!1,last,featureTrackerTask,faceTrackerTask,trackerCallback,Controller,init,zones={feature:[],face:[]},track,featureTracker,faceTracker,initialized=!1,ControllerRememberer=new PermanentStorage;
ControllerRememberer.fetch(function(f){log("Preset loaded.","[PermanentStorage]");Controller=new dat.GUI({load:JSON.parse(f),preset:"default"});init=function(){last=this.src="front/male/1.jpg";initialized=!0;Controller.addFolder("Source Picture");Controller.remember(this);Controller.add(this,"src",this._images).listen()};featureZones=[];faceZones=[];track={trackFeatures:function(){featureZones=[];featureTrackerTask=tracking.track(_CAN,featureTracker)},trackFace:function(){faceZones=[];faceTrackerTask= ControllerRememberer.fetch(function(f){log("Preset loaded.","[PermanentStorage]");Controller=new dat.GUI({load:JSON.parse(f),preset:"default"});init=function(){last=this.src="front/male/1.jpg";initialized=!0;Controller.addFolder("Source Picture");Controller.remember(this);Controller.add(this,"src",this._images).listen()};zones.feature=[];zones.face=[];track={trackFeatures:function(){zones.feature=[];featureTrackerTask=tracking.track(_CAN,featureTracker)},trackFace:function(){zones.face=[];faceTrackerTask=
tracking.track(_CAN,faceTracker)}};faceTracker=new tracking.ObjectTracker(["face"]);featureTracker=new tracking.ObjectTracker(["eye","mouth"]);faceTracker.setStepSize(1.5);featureTracker.setStepSize(1.5);trackerCallback=function(a,c){a.length=0;c.data.forEach(function(b){a.push({x:b.x/_CAN.width,y:b.y/_CAN.height,w:b.width/_CAN.width,h:b.height/_CAN.height})});log("Recognition done","[Tracking.js]");process.apply(DOM.imageLoader)};faceTracker.on("track",function(a){return trackerCallback.apply(this, tracking.track(_CAN,faceTracker)}};faceTracker=new tracking.ObjectTracker(["face"]);featureTracker=new tracking.ObjectTracker(["eye","mouth"]);faceTracker.setInitialScale(1);featureTracker.setInitialScale(1);faceTracker.setStepSize(1.2);featureTracker.setStepSize(1.2);faceTracker.setEdgesDensity(.1);featureTracker.setEdgesDensity(.1);trackerCallback=function(a,c){zones[a].length=0;c.data.forEach(function(b){zones[a].push({x:b.x/_CAN.width,y:b.y/_CAN.height,w:b.width/_CAN.width,h:b.height/_CAN.height})});
[faceZones,a])});featureTracker.on("track",function(a){return trackerCallback.apply(this,[featureZones,a])});process=function(){if(initialized&&this instanceof HTMLImageElement){console.time("PROCESS");this.src!=last&&(faceZones=[],featureZones=[],exec=!1,last=this.src);exec||(this.defaultWidth=this.width,this.defaultHeight=this.height,log("Image copied","[Canvas]"),exec=!0);_CON.clearRect(0,0,_CAN.width,_CAN.height);filterManager.get("resolution").apply();filterManager.get("contrast").apply();filterManager.get("sobel").apply(); 0<zones[a].length?log(a+" recognition done","[Tracking.js]"):log(a+" recognition failed","[Tracking.js]");process.apply(DOM.imageLoader)};faceTracker.on("track",function(a){return trackerCallback.apply(this,["face",a])});featureTracker.on("track",function(a){return trackerCallback.apply(this,["feature",a])});process=function(){if(initialized&&this instanceof HTMLImageElement){console.time("PROCESS");this.src!=last&&(zones.face=[],zones.feature=[],exec=!1,last=this.src);exec||(this.defaultWidth=this.width,
filterManager.get("gaussian").apply();filterManager.get("canny").apply();var a,c,b,d,e;for(a in featureZones)c=featureZones[a].x*_CAN.width,b=featureZones[a].y*_CAN.height,d=featureZones[a].w*_CAN.width,e=featureZones[a].h*_CAN.height,_CON.beginPath(),_CON.moveTo(c,b),_CON.lineTo(c,b+e),_CON.lineTo(c+d,b+e),_CON.lineTo(c+d,b),_CON.lineTo(c,b),_CON.lineWidth=5,_CON.strokeStyle="#f00",_CON.stroke();for(a in faceZones)c=faceZones[a].x*_CAN.width,b=faceZones[a].y*_CAN.height,d=faceZones[a].w*_CAN.width, this.defaultHeight=this.height,log("Image copied","[Canvas]"),exec=!0);_CON.clearRect(0,0,_CAN.width,_CAN.height);filterManager.get("resolution").apply();filterManager.get("contrast").apply();filterManager.get("grayscale").apply();filterManager.get("sobel").apply();filterManager.get("gaussian").apply();filterManager.get("canny").apply();var a,c,b,d,e;for(a in zones.feature)c=zones.feature[a].x*_CAN.width,b=zones.feature[a].y*_CAN.height,d=zones.feature[a].w*_CAN.width,e=zones.feature[a].h*_CAN.height,
e=faceZones[a].h*_CAN.height,_CON.beginPath(),_CON.moveTo(c,b),_CON.lineTo(c,b+e),_CON.lineTo(c+d,b+e),_CON.lineTo(c+d,b),_CON.lineTo(c,b),_CON.lineWidth=5,_CON.strokeStyle="#ff0",_CON.stroke();console.timeEnd("PROCESS")}};filterManager=new ReactiveFilterManager(DOM.imageLoader,_CAN,process);filterManager.add("resolution",reactiveResolution);filterManager.add("contrast",reactiveContrast);filterManager.add("sobel",reactiveSobel);filterManager.add("gaussian",reactiveGaussianBlur);filterManager.add("canny", _CON.lineWidth=5,_CON.strokeStyle="#f00",_CON.strokeRect(c,b,d,e);for(a in zones.face)c=zones.face[a].x*_CAN.width,b=zones.face[a].y*_CAN.height,d=zones.face[a].w*_CAN.width,e=zones.face[a].h*_CAN.height,_CON.lineWidth=5,_CON.strokeStyle="#ff0",_CON.strokeRect(c,b,d,e);console.timeEnd("PROCESS")}};filterManager=new ReactiveFilterManager(DOM.imageLoader,_CAN,process);filterManager.add("resolution",reactiveResolution);filterManager.add("contrast",reactiveContrast);filterManager.add("grayscale",reactiveGrayscale);
reactiveCanny);Controller.remember(filterManager.get("resolution"));Controller.remember(filterManager.get("contrast"));Controller.remember(filterManager.get("sobel"));Controller.remember(filterManager.get("canny"));Controller.remember(filterManager.get("gaussian"));Controller.addFolder("Tracking.js");Controller.add(track,"trackFace");Controller.add(track,"trackFeatures");Controller.addFolder("Image Resolution");Controller.add(filterManager.get("resolution"),"width",0,2).step(.1);Controller.add(filterManager.get("resolution"), filterManager.add("sobel",reactiveSobel);filterManager.add("gaussian",reactiveGaussianBlur);filterManager.add("canny",reactiveCanny);Controller.remember(filterManager.get("resolution"));Controller.remember(filterManager.get("contrast"));Controller.remember(filterManager.get("grayscale"));Controller.remember(filterManager.get("sobel"));Controller.remember(filterManager.get("canny"));Controller.remember(filterManager.get("gaussian"));Controller.addFolder("Tracking.js");Controller.add(track,"trackFace");
"height",0,2).step(.1);Controller.addFolder("Basic Image Processing");Controller.add(filterManager.get("contrast"),"contrast",0,100);Controller.addFolder("Gaussian Blur");Controller.add(filterManager.get("gaussian"),"sigma",0,10).step(.5);Controller.add(filterManager.get("gaussian"),"radius",1,11).step(1);Controller.addFolder("Convolution Filters");Controller.add(filterManager.get("sobel"),"sobelActive");Controller.add(filterManager.get("canny"),"canny_radius");Controller.__save_row.children[2].addEventListener("click", Controller.add(track,"trackFeatures");Controller.addFolder("Image Resolution");Controller.add(filterManager.get("resolution"),"width",0,2).step(.1);Controller.add(filterManager.get("resolution"),"height",0,2).step(.1);Controller.addFolder("Basic Image Processing");Controller.add(filterManager.get("contrast"),"contrast",0,100);Controller.add(filterManager.get("grayscale"),"grayscale");Controller.addFolder("Gaussian Blur");Controller.add(filterManager.get("gaussian"),"sigma",0,10).step(.5);Controller.add(filterManager.get("gaussian"),
"radius",1,11).step(1);Controller.addFolder("Sobel Filter");Controller.add(filterManager.get("sobel"),"sobelActive");Controller.addFolder("Canny Filter");Controller.add(filterManager.get("canny"),"active");Controller.add(filterManager.get("canny"),"radius",0,4).step(1);Controller.add(filterManager.get("canny"),"low_threshold",1,127).step(1);Controller.add(filterManager.get("canny"),"high_threshold",1,127).step(1);Controller.addFolder("Process");Controller.add({render:process},"render");Controller.__save_row.children[2].addEventListener("click",
function(){Controller.save();try{var a=JSON.stringify(Controller.getSaveObject());ControllerRememberer.store(a,function(){log("dat.GUI preset stored.","[PermanentStorage]");return!0})}catch(c){log("Corrupted data.","[PermanentStorage]")}},!1);iL=new ImageLoader(DOM.imageLoader,init,process);return!0}); function(){Controller.save();try{var a=JSON.stringify(Controller.getSaveObject());ControllerRememberer.store(a,function(){log("dat.GUI preset stored.","[PermanentStorage]");return!0})}catch(c){log("Corrupted data.","[PermanentStorage]")}},!1);iL=new ImageLoader(DOM.imageLoader,init,process);return!0});

View File

@ -1 +1 @@
{"preset":"default","remembered":{"default":{"0":{"width":1,"height":1},"1":{"contrast":0},"2":{"sobelActive":false},"3":{"canny_radius":3},"4":{"sigma":6,"radius":3},"5":{"src":"front/male/1.jpg"}},"test1":{"0":{"width":1.8,"height":0.5},"1":{"contrast":55.27520549370516},"2":{"sobelActive":false},"3":{"canny_radius":3},"4":{"sigma":0,"radius":3},"5":{"src":"front/male/1.jpg"}}},"closed":false,"folders":{"Tracking.js":{"preset":"Default","closed":true,"folders":{}},"Image Resolution":{"preset":"Default","closed":true,"folders":{}},"Basic Image Processing":{"preset":"Default","closed":true,"folders":{}},"Gaussian Blur":{"preset":"Default","closed":true,"folders":{}},"Convolution Filters":{"preset":"Default","closed":true,"folders":{}},"Source Picture":{"preset":"Default","closed":true,"folders":{}}}} {"preset":"default","remembered":{"default":{"0":{"width":0.7000000000000001,"height":0.7000000000000001},"1":{"contrast":0},"2":{"grayscale":false},"3":{"sobelActive":false},"4":{"canny_radius":3},"5":{"sigma":9,"radius":3},"6":{"src":"front/male/1.jpg"}},"test1":{"0":{"width":1.8,"height":0.5},"1":{"contrast":55.27520549370516},"2":{"sobelActive":false},"3":{"canny_radius":3},"4":{"sigma":0,"radius":3},"5":{"src":"front/male/1.jpg"}}},"closed":false,"folders":{"Tracking.js":{"preset":"Default","closed":true,"folders":{}},"Image Resolution":{"preset":"Default","closed":true,"folders":{}},"Basic Image Processing":{"preset":"Default","closed":true,"folders":{}},"Gaussian Blur":{"preset":"Default","closed":true,"folders":{}},"Convolution Filters":{"preset":"Default","closed":true,"folders":{}},"Process":{"preset":"Default","closed":true,"folders":{}},"Source Picture":{"preset":"Default","closed":true,"folders":{}}}}