Riconoscimento facciale: rilevare la prossimità di un volto in javascript


 
 

No, non è una prerogativa di Facebook...La Face Detection è una tecnologia informatica che determina la posizione e le dimensioni di volti umani rappresentati in immagini digitali.

Sicuramente avrete già  visto al lavoro questo tipo di tecnologia in programmi come Picasa, iPhoto. per chi ha un Mac, o più banalmente su Facebook.

Uno degli algoritmi piú conosciuti, è stato sviluppato in JavaScript con l’aiuto dell’elemento canvas, da un programmatore cinese Liu Liu.

La demo, sembra essere abbastanza affidabile nel rilevare volti nelle fotografie: disegna un riquadro rosso intorno al viso che trova nella foto. Il codice è disponibile anche su GitHub.

 Grazie ai progressi delle tecniche di riconoscimento facciale, non c'è dispositivo che oggigiorno non riesca ad identificare un volto in tempo pressoché reale.

Ma gli attuali strumenti informatici hanno dei limiti : riescono a essere precisi solo quando lavorano su immagini che rispettano determinate condizioni, ovvero foto scattate in condizioni di piena luminosità e con volti ripresi frontalmente.

Dalla Stanford University, stanno studiando un nuovo algoritmo che lavora sul riconoscimento del viso da diverse angolazioni: Sachin Farfade, Mohammad Saberian e Li-Jia Li , hanno trovato un modo per superare i limiti delle attuali tecnologie basate su pattern, sfruttando reti neurali basate su decine di migliaia di modelli registrati, in questo caso immagini di volti riprese da più angolazioni.

La tecnica, utilizzata, chiamata Deep Dense Face Detector, ricorda per certi versi quella annunciata da Facebook all’interno del suo programma di deep learning

Ma voliamo bassi...vediamo come, grazie al Javascript, possiamo rilevare un volto prossimo.

Ora, supponiamo che si voglia che i visitatori del nostro sito web possano effettuare una registrazione video o possano scattare una foto del proprio viso.

Utilizziamo la API getUserMedia

Cominciamo con poche linee di codice:

navigator.mediaDevices     
.getUserMedia({audio: false, video: true})     
.then(function(stream) {         
// OK     
})    
 .catch(function(error) {         
// Error     
});

ora

navigator.mediaDevices = navigator.mediaDevices || ((navigator.mozGetUserMedia || navigator.webkitGetUserMedia) ? {     
getUserMedia: function(c) {       
return new Promise(function(y, n) {         
(navigator.mozGetUserMedia ||          
navigator.webkitGetUserMedia).call(navigator, c, y, n);      
 });     
}  
} : null);    
// this is not part of the polyfill  
if (!navigator.mediaDevices) {    throw new Error('getUserMedia() not supported.');  
}   
 navigator.mediaDevices     
.getUserMedia({audio: false, video: true})     
.then(function(stream) {         
    // OK     })    
 .catch(function(error) {         
   // Error    
 });

Una volta definito l'oggetto  MediaStream, useremo su "video", il metodo URL.createObjectURL().

function startCamera() {}    
return navigator.mediaDevices      
.getUserMedia({audio: false, video: true})      
.then(function(stream) {        
// assume you have a `` tag somewhere in the DOM        
var video = document.querySelector('video');        
video.src = URL.createObjectURL(stream);        
video.play();          
// return the stream so that chained promises can use it        
return stream;      
})  
}

Prima di far partire la nostra demo, focalizziamoci sui bottoni che possono far partire e far fermare la riproduzione video.

document.querySelector('button').onclick = function() {    
var button = this;    
button.textContent = 'Starting camera';      
// the function that wraps the getUserMedia call    
startCamera()    
.then(function() {     
 button.textContent = 'Stop camera';    
});  
}

Potete trovare un esempio più completo e funzionale su CodePen.

A questo punto avreste giá dovuto giocare un pó con la demo... cosa avete notato? È stato complicato centrare il volto e posizionarsi nel mezzo?

Si, vero? Questo perchè l'immagine nel mirino non rimanda la vostra immagine speculare ma è una visione reale del vostro volto, proprio come vi vedono i vostri amici.

Per risolvere questo problema (sempre se lo riteniate tale...), basta utilizzare la proprietà trasform dei CSS:

video {transform: rotateY(180deg);}

Qui trovate una DEMO

Migliorare il nostro script, aggiungendo l'elemento CANVAS.

// assuming you have a  tag somewhere in the DOM  
var canvas = document.querySelector('canvas');  
var context = canvas.getContext('2d');    
function startCamera() {}    
return navigator.mediaDevices.getUserMedia({audio: false, video: true})   
 .then(function(stream) {      
// same as before      
var video = document.querySelector('video');      
video.src = URL.createObjectURL(stream);      
video.play();        
// The critical point where we transfer some frames to      
// a canvas element.      
setInterval(function() {        
context.drawImage(video, 0, 0, canvas.width, canvas.height);      
}, 100);    
})  
}

Non abbiamo bisogno che l'elemento CANVAS sia visibile basta aggiungerlo al DOM, pertanto lo nasconderemo.

canvas {display: none;}

L'API context.drawImage è impressionante. Possiamo semplicemente passare un elemento video e successivamente le coordinate.

Dunque, ci siamo!

Abbiamo l'immagine restituita dalla nostra webcam completamente proiettata sull'elemento canvas.

Per completare il nostro lavorao ci affideremo all'algoritmo del sopracitato Liu Liu. I file che ci servono sono disponibili su GitHub.

Il funzionamento della API è molto semplice: si passano al canvas alcuni parametri, e come risultato otterremo un array di oggetti.

Dopo aver caricato i file face.js e ccv.js, è necessario richiamarli nel nostro codice:

// using global `ccv` from ccv.js and `cascade` from face.js  
var faces = ccv.detect_objects({    
canvas: ccv.pre(canvas),    
cascade: cascade,    
interval: 2,    
min_neighbors: 1  
});

Tali oggetti, sono in realtà facce e appariranno così:

{    
confidence: 0.33769726999999994,    
height: 60.97621039495391,    
width: 60.97621039495391,    
neighbors: 1,   
 x: 131.5317891890668,   
 y: 66.0158945945334  
}

Come utilizzeremo tutto ció?

Torniamo a lavorare sul nostro script.

Per capire cosa stiamo realizzando e cosa sono tutte le coordinate che abbiamo passato, il modo piú semplice è disegnare un rettangolo rosso dal contorno definito.

Quindi, rendiamo il canvas visibile e trasformiamolo in un rettangolo rosso.

Possiamo vedere il codice su CodePen.

La distanza del vostro naso dallo schermo è calcolata in base al valore dell' altezza del volto che è stato rilevato.

Una volta conosciuta l'altezza del volto e l'altezza della tela (canvas), si può calcolare una percentuale che rappresenterebbe "la giusta distanza dallo schermo".

Tenete presente che tale percentuale la potete scegliere voi. Il modo migliore per capirlo è testare lo script su se stessi.

Ecco uno script che vi sarà utile per stabilizzare le percentuali:

var percentages = [];  
function rollingAverage(size) {    
percentages.splice(0, percentages.length - size);    
var sum = percentages.reduce(function(total, num) {      
return total + num   
 }, 0);    
return sum / percentages.length;  
}

In conclusione, ne valeva la pena? Sicuramente questa tecnica per sapere se la persona di fronte alla telecamera si è seduta troppo vicino o troppo lontano dallo schermo è molto imprecisa. Siatene consapevoli, e prendetela con un pò senso dell'umorismo, in fondo non è molto diversa da quella implementata dalle cabine fotografiche tradizionali...

 

 

 

 
 

tags: javascript coding webdev webcam script face detection


Comments area, use one of your social accounts to log-in and post a comment.



Responses to the post

Questo sito fa uso di cookie, anche di terze parti, per migliorare la tua esperienza di navigazione. Accettando questa informativa dai il consenso al loro utilizzo. È possibile modificare le impostazioni dei cookie o ottenere ulteriori informazioni qui: Politica dei cookies.