Commit 2d0b3522 by Иван Кубота

lot of work

parent a86f011d
# Default ignored files
/workspace.xml
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/face-api.js.iml" filepath="$PROJECT_DIR$/.idea/face-api.js.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
var sqrt = Math.sqrt;
var abs = Math.abs || function(n){return n>0 ? n: -n}
var Point = function( x, y ){
if(arguments.length === 0){
x = 0;
y = 0;
}
if(x instanceof Point || x.hasOwnProperty('x')) {
y = x.y;
x = x.x;
}
this.x = x;
this.y = y;
};
Point.prototype = {
add: null, addClone: null,
sub: null, subClone: null,
mul: null, mulClone: null,
div: null, divClone: null,
mod: null, modClone: null,
passable: true,
borrow: function(from) {
this.x = from.x;
this.y = from.y;
return this;
},
join: function(symbol) {
return this.x+symbol+this.y;
},
set: function(x, y) {
this.x = x;
this.y = y;
return this;
},
middle: function(point) {
return new Point((this.x+point.x)/2, (this.y+point.y)/2)
},
clone: function(){
return new Point( this.x, this.y );
},
distance: function( obj ){
var tmp;
return sqrt( (tmp = this.x - obj.x) * tmp + (tmp = this.y - obj.y) * tmp );
},
distancePow2: function( obj ){
var tmp;
return (tmp = this.x - obj.x) * tmp + (tmp = this.y - obj.y) * tmp;
},
manhattan: function( obj ){
return abs(this.x - obj.x) + abs(this.y - obj.y);
},
magnitude: function() {
return sqrt(this.x*this.x+this.y*this.y);
},
rotate: function(angleRAD) {
var angle = Math.atan2(this.y, this.x) + angleRAD;
var length = this.magnitude();
return new Point(Math.cos(angle)*length,Math.sin(angle)*length)
},
getAngle: function(p) {
if(p)
return Math.atan2(p.y - this.y, p.x - this.x);
else
return Math.atan2(this.y, this.x);
},
toString: function(fixed) {
fixed === void 0 && (fixed = 3);
return 'x:'+this.x.toFixed(fixed)+' y:'+this.y.toFixed(fixed);
},
normalize: function() {
return this.div(this.magnitude())
},
projection: function(to) {
var angle = this.getAngle()-to.getAngle();
return to.clone().normalize().mul(this.magnitude()*Math.cos(angle));
},
lerp: function(to, amount) {
return new Point(this.x+(to.x-this.x)*amount,this.y+(to.y-this.y)*amount)
},
clamp: function(n) {
return new Point((n/2%1)+(this.x|0), (n/2%1)+(this.y|0));
}
};
Point.prototype.getter = Point.prototype.clone;
[
{
name: 'add',
sign: '+'
},
{
name: 'sub',
sign: '-'
},
{
name: 'mul',
sign: '*'
},
{
name: 'div',
sign: '/'
},
{
name: 'mod',
sign: '%'
}
].forEach(function( el ){
var sign = el.sign;
Point.prototype[ el.name ] = Function( 'objOrX, y', [
'if( y === void 0 ){',
' if( typeof objOrX === \'number\' ){',
' this.x '+ sign +'= objOrX;',
' this.y '+ sign +'= objOrX;',
' }else{',
' this.x '+ sign +'= objOrX.x;',
' this.y '+ sign +'= objOrX.y;',
' }',
'}else{',
' this.x '+ sign +'= objOrX;',
' this.y '+ sign +'= y;',
'}',
'return this;'
].join('\n') );
Point.prototype[ el.name +'Clone'] = Function( 'objOrX, y',
'return this.clone().'+el.name+'(objOrX, y);'
)
});
......@@ -22,7 +22,7 @@ async function requestExternalImage(imageUrl) {
}
}
function renderNavBar(navbarId, exampleUri) {
function renderNavBar(navbarId, exampleUri){
const examples = [
{
uri: 'face_detection',
......@@ -93,6 +93,8 @@ function renderNavBar(navbarId, exampleUri) {
name: 'Batch Face Recognition'
}
]
}
/*
const navbar = $(navbarId).get(0)
const pageContainer = $('.page-container').get(0)
......@@ -165,4 +167,4 @@ function renderOption(parent, text, value) {
option.innerHTML = text
option.value = value
parent.appendChild(option)
}
\ No newline at end of file
}*/
function rgbToHsv(r, g, b) {
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b), min = Math.min(r, g, b);
var h, s, v = max;
var d = max - min;
s = max == 0 ? 0 : d / max;
if (max == min) {
h = 0; // achromatic
} else {
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [ h, s, v ];
}
/**
* Converts an HSV color value to RGB. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSV_color_space.
* Assumes h, s, and v are contained in the set [0, 1] and
* returns r, g, and b in the set [0, 255].
*
* @param Number h The hue
* @param Number s The saturation
* @param Number v The value
* @return Array The RGB representation
*/
function hsvToRgb(h, s, v) {
var r, g, b;
var i = Math.floor(h * 6);
var f = h * 6 - i;
var p = v * (1 - s);
var q = v * (1 - f * s);
var t = v * (1 - (1 - f) * s);
switch (i % 6) {
case 0: r = v, g = t, b = p; break;
case 1: r = q, g = v, b = p; break;
case 2: r = p, g = v, b = t; break;
case 3: r = p, g = q, b = v; break;
case 4: r = t, g = p, b = v; break;
case 5: r = v, g = p, b = q; break;
}
return [ r * 255, g * 255, b * 255 ];
}
var extractColors = function( ctx, where, k, debug){
var points = [].concat.apply( [], where.map( function( polygon ){
return triangle.apply( null, polygon );
} ) );
var minX = Infinity, minY = Infinity,
maxX = -Infinity, maxY = -Infinity;
for( var i = 0, _i = points.length; i < _i; i++ ){
var point = points[ i ];
if( minX > point[ 0 ] ) minX = point[ 0 ];
if( minY > point[ 1 ] ) minY = point[ 1 ];
if( maxX < point[ 0 ] ) maxX = point[ 0 ];
if( maxY < point[ 1 ] ) maxY = point[ 1 ];
}
var w = maxX - minX + 1;
var imageData = ctx.getImageData( minX, minY, w, maxY - minY + 1 ),
data = imageData.data;
var r, g, b;
var colors = [];
for( var i = 0, _i = points.length; i < _i; i++ ){
var p = points[ i ], pointer = ( p[ 0 ] - minX + ( p[ 1 ] - minY ) * w ) * 4;
r = data[ pointer ];
g = data[ pointer + 1 ];
b = data[ pointer + 2 ];
//data[ pointer + 2 ] = 255
colors.push( rgbToHsv( r, g, b ) );
}
//ctx2.putImageData( imageData, minX, minY );
var means = new KMeans();
var result = { means: means, clusters: means.cluster( colors, k, hsvDistance ) };
var amount = 0;
for( var i = 0, _i = result.clusters.length; i < _i; i++ ){
var cluster = result.clusters[ i ] || [];
amount += cluster.length;
}
var filteredResult = result.clusters.map( function( c, i ){
return { color: c, normalized: c.length / amount };
} )
.filter( function( c ){
return c.normalized > 1 / k;
} )
.sort( function( a, b ){
return a.normalized - b.normalized;
} )
.map( function( c ){
return c.color[0];//result.means.centroids.slice().sort(distanceToHSV(c.color[0]))[0];
} );
var similars = filteredResult.map(function(c, i) {
return {color: c, i: i, similar: [i]}
});
var similarColor = 0.03;
// O^2 similarity search
for( var i = 0, _i = similars.length; i < _i; i++ ){
var c1 = similars[ i ];
for( var j = 0, _j = similars.length; j < _j; j++ ){
if(i === j)
continue;
var c2 = similars[ j ];
if(Math.abs(hsvDistance(c1.color, c2.color))<similarColor){
if(c1.similar.indexOf(j) === -1){
c1.similar.push( j );
}
}
}
}
var used = {};
var different = similars.reduce(function(store, c) {
if(!(c.i in used))
store.push(c);
for( var i = 0, _i = c.similar.length; i < _i; i++ ){
var similarElement = c.similar[ i ];
var item = similars[similarElement];
if(!(item.i in used)){
used[item.i] = true;
}
}
return store;
}, []);
if(debug){
similars, result
}
filteredResult = different.map(function(item) {
return item.color;
});
return filteredResult.map(function(color) {
return {color: color, distance: hsvDistance(color, filteredResult[0])};
}).filter(function(color) {
var delta = Math.abs(color.distance);
return delta <0.0000001 || delta > 0.03;
});
};
var abs = Math.abs, min = Math.min;
var hsvDistance = function( c1, c2 ){
var dh = min( abs( c2[ 0 ] - c1[ 0 ] ), 360 - abs( c2[ 0 ] - c1[ 0 ] ) ) / 180.0,
ds = abs( c2[ 1 ] - c1[ 1 ] ), dv = c2[ 2 ] - c1[ 2 ];
return dh*30 + ds / 12 + dv / 6;
};
var extractor = function(ctx, from, k, debug) {
return extractColors(ctx, from, k, debug)
.map(function(m) {
return {color: hsvToRgb.apply(null, m.color).map(function(a){return a|0}), distance: m.distance};
})
.map(function(m){
return {
html: '<span style="display: inline-block;width:32px;height:32px;background:rgb('+m.color.join(',')+');border-radius:3px;border:2px solid #000;margin:2px">'+m.distance.toFixed(2)+'</span>'
};
});
};
\ No newline at end of file
......@@ -78,21 +78,21 @@ function isFaceDetectionModelLoaded() {
}
async function changeFaceDetector(detector) {
['#ssd_mobilenetv1_controls', '#tiny_face_detector_controls']
.forEach(id => $(id).hide())
/*['#ssd_mobilenetv1_controls', '#tiny_face_detector_controls']
.forEach(id => $(id).hide())*/
selectedFaceDetector = detector
const faceDetectorSelect = $('#selectFaceDetector')
faceDetectorSelect.val(detector)
faceDetectorSelect.material_select()
//const faceDetectorSelect = $('#selectFaceDetector')
//faceDetectorSelect.val(detector)
//faceDetectorSelect.material_select()
$('#loader').show()
//$('#loader').show()
if (!isFaceDetectionModelLoaded()) {
await getCurrentFaceDetectionNet().load('/')
}
$(`#${detector}_controls`).show()
$('#loader').hide()
//$(`#${detector}_controls`).show()
//$('#loader').hide()
}
async function onSelectedFaceDetectorChanged(e) {
......
var toPoint = function(p) {
if(p instanceof Point)
return p.clone();
return new Point(p.x, p.y)
};
var FaceMarks = function(landmarks) {
var jaw = landmarks.getJawOutline(),
nose = landmarks.getNose(),
mouth = landmarks.getMouth(),
leftBrow = landmarks.getLeftEyeBrow(),
rightBrow = landmarks.getRightEyeBrow(),
leftEye = landmarks.getLeftEye(),
rightEye = landmarks.getRightEye();
var marks = this.marks = {
cheek: {
left: {
},
right: {
}
},
lips: {
top: {
},
bottom: {
}
},
brows: {
left: {}, right: {}
},
eyes: {
left: {}, right: {}
}
};
// CHEEKS
marks.cheek.left = this.cheek(nose[3], toPoint(jaw[0]).middle(toPoint(jaw[1])), mouth[0]);
marks.cheek.right = this.cheek(nose[3], toPoint(jaw[15]).middle(toPoint(jaw[16])), mouth[6]);
marks.lips.top = this.lip(mouth[2], mouth[4], mouth[13], mouth[15], true);
marks.lips.bottom = this.lip(mouth[19], mouth[17], mouth[10], mouth[8], false);
marks.eyes.left = this.eye(leftBrow[0], leftBrow[3], leftEye[0], leftEye[2], leftEye[3], leftEye[4]);
marks.eyes.right = this.eye(rightBrow[4], rightBrow[1], rightEye[3], rightEye[1], rightEye[0], rightEye[5]);
};
FaceMarks.prototype = {
eye: function(b1,b2, e1,e2,e3,e4) {
b1 = toPoint(b1),
b2 = toPoint(b2),
e1 = toPoint(e1),
e2 = toPoint(e2),
e3 = toPoint(e3),
e4 = toPoint(e4);
return {
t1: [
b2.lerp(e2, 2/3),
b1.lerp(e1, 2/3),
b1.lerp(e1, 1/3)
],
t2: [
b1.lerp(e1, 0.95/3),
b1.lerp(b2, 0.5).lerp(e1, 1/3),
b1.lerp(b2, 0.5).lerp(e1, 1.4/3)
],
t3: [
e2.lerp(e3, 2),
e2.lerp(e4, 1.65),
e2.lerp(e4, 2.35)
],
t4: [
e2.lerp(e4, 1.65),
e2.lerp(e4, 2.35),
b2.lerp(e1, 1.5)
]
}
},
cheek: function(nose, jaw, mouthSide) {
var p1 = toPoint(nose),
p2 = toPoint(jaw),
p3 = toPoint(mouthSide), originP3 = p3.clone();
p3.add(p2.subClone(p3).mul(1/2));
var v1 = p2.subClone(p1);
p1.add(v1.mulClone(1/2));
p2.sub(v1.mul(1/3));
var cheek = [p1,p2,p3];
var vx = cheek[0].subClone(cheek[1]),
vy = cheek[1].subClone(cheek[2]);
var bonusArea = [
cheek[1].subClone(vx.mulClone(1/2)),
cheek[1].subClone(vx.normalize().mul(3))
];
bonusArea.push(bonusArea[1].subClone(vy.mul(1.4)));
bonusArea[0].sub(vy.mulClone(1/2));
bonusArea[1].sub(vy.mulClone(1/5));
var bonusArea2 = [
bonusArea[2].clone(),
cheek[0].clone()
];
var middle = bonusArea2[0].middle(bonusArea2[1]),
toMouthVector = originP3.subClone(middle);
bonusArea2.push(middle.add(toMouthVector.mul(1/3)));
toMouthVector.normalize().mul(2);
bonusArea2[0].add(toMouthVector);
bonusArea2[1].add(toMouthVector);
return {base: cheek, bonus1: bonusArea, bonus2: bonusArea2};
},
lip: function(p1,p2,p3,p4, isTop) { // rectangular zone
p1 = toPoint(p1); p2 = toPoint(p2); p3 = toPoint(p3); p4 = toPoint(p4);
var lipVertical = p3.middle(p4).sub(p1.middle(p2)),
lipHorizontal = toPoint(p2).sub(toPoint(p1)),
lipDeltaX = lipHorizontal.clone().normalize().mul(3);
var lips = [];
lips.push([
toPoint(p1).add(lipVertical.mulClone(1/3)),
toPoint(p2).add(lipVertical.mulClone(1/3)),
toPoint(p3).sub(lipVertical.mulClone(1/3))
]);
lips.push([
toPoint(p2).add(lipVertical.mulClone(1/3)).add(lipDeltaX),
toPoint(p4).sub(lipVertical.mulClone(1/3)).add(lipDeltaX),
toPoint(p3).sub(lipVertical.mulClone(1/3)).add(lipDeltaX)
]);
lips.push( [
lips[ 0 ][ isTop?2:0 ].subClone( lipHorizontal.mulClone( 1 / 2 ) ),
lips[ 0 ][ 0 ].subClone( lipDeltaX ),
lips[ 0 ][ 2 ].subClone( lipDeltaX ),
] );
lips.push( [
lips[ 1 ][ isTop?1:0 ].addClone( lipHorizontal.mulClone( 1 / 2 ) ),
lips[ 1 ][ 1 ].addClone( lipDeltaX ),
lips[ 1 ][ 0 ].addClone( lipDeltaX ),
] );
return lips;
}
};
\ No newline at end of file
......@@ -51,13 +51,13 @@ function renderImageSelectList(selectListId, onChange, initialValue, withFaceExp
}
function initImageSelectionControls(initialValue = 'bbt1.jpg', withFaceExpressionImages = false) {
renderImageSelectList(
/*renderImageSelectList(
'#selectList',
async (uri) => {
await onSelectedImageChanged(uri)
},
initialValue,
withFaceExpressionImages
)
onSelectedImageChanged($('#selectList select').val())
)*/
//onSelectedImageChanged(document.querySelector('#selectList select').value)
}
\ No newline at end of file
function KMeans(points, k, distance) {
this.centroids = [];
Math.random.seeded.setSeed(66613);
};
function mulberry32(a) {
var out = function() {
var t = a += 0x6D2B79F5;
t = Math.imul(t ^ t >>> 15, t | 1);
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
return ((t ^ t >>> 14) >>> 0) / 4294967296;
}
out.getSeed = function() {
return a;
};
out.setSeed = function(A) {
a = A;
};
out.setStringSeed = function(str) {
str = str.replace(/[^0-9a-z]/g,'').substr(0,12);
if(str.length === 0)str = '1';
a = parseInt(str,36);
};
out.getStringSeed = function() {
return a.toString(36);
};
return out;
}
Math.random.seeded = mulberry32(Math.floor(Math.random()*4294967296));
KMeans.prototype = {
randomCentroids: function( points, k ){
var centroids = points.slice( 0 ); // copy
centroids.sort( function(){
return ( Math.round( Math.random.seeded() ) - 0.5 );
} );
return centroids.slice( 0, k );
},
classify: function( point, distance ){
var min = Infinity,
index = 0;
for( var i = 0; i < this.centroids.length; i++ ){
var dist = distance( point, this.centroids[ i ] );
if( dist < min ){
min = dist;
index = i;
}
}
return index;
},
cluster: function( points, k, distance ){
k = k || Math.max( 2, Math.ceil( Math.sqrt( points.length / 2 ) ) );
this.centroids = this.randomCentroids( points, k );
var assignment = new Array( points.length );
var clusters = new Array( k );
var iterations = 0;
var movement = true;
while( movement ){
iterations++;
if(iterations>300)
break;
// update point-to-centroid assignments
for( var i = 0; i < points.length; i++ ){
assignment[ i ] = this.classify( points[ i ], distance );
}
// update location of each centroid
movement = false;
for( var j = 0; j < k; j++ ){
var assigned = [];
for( var i = 0; i < assignment.length; i++ ){
if( assignment[ i ] == j ){
assigned.push( points[ i ] );
}
}
if( !assigned.length ){
continue;
}
var centroid = this.centroids[ j ];
var newCentroid = new Array( centroid.length );
for( var g = 0; g < centroid.length; g++ ){
var sum = 0;
for( var i = 0; i < assigned.length; i++ ){
sum += assigned[ i ][ g ];
}
newCentroid[ g ] = sum / assigned.length;
if( newCentroid[ g ] != centroid[ g ] ){
movement = true;
}
}
this.centroids[ j ] = newCentroid;
clusters[ j ] = assigned;
}
}
return clusters;
}
};
\ No newline at end of file
var toPoint = function(p) {
return new Point(p.x, p.y)
};
var axelStops = function(start, end) {
if(start)
var vector;
};
\ No newline at end of file
var triangle = (function(){
var tmp = new Point(),
swap = function(p1, p2){
tmp.borrow(p1);
p1.borrow(p2);
p2.borrow(tmp);
},
invslope1,
invslope2,
curx1,
curx2,
scanLineY,
scanLineTo,
p1 = new Point(), p2 = new Point(), p3 = new Point(),
fillLine, tmpNum;
var scanline = function (x1, x2, y, arr) {
if(x2<x1){
tmpNum = x1; x1 = x2; x2 = tmpNum;
}
for(;x1<=x2;x1++)
arr.push([x1|0, y]);
};
var flatBottom = function(p1, p2, p3, arr){
invslope1 = (p2.x - p1.x) / (p2.y - p1.y),
invslope2 = (p3.x - p1.x) / (p3.y - p1.y),
curx1 = p1.x,
curx2 = p1.x,
scanLineY = p1.y,
scanLineTo = p2.y;
for (; scanLineY <= scanLineTo; scanLineY++){
scanline(curx1|0,curx2|0, scanLineY|0, arr);
curx1 += invslope1;
curx2 += invslope2;
}
},
flatTop = function(p1, p2, p3, arr){
invslope1 = (p3.x - p1.x) / (p3.y - p1.y),
invslope2 = (p3.x - p2.x) / (p3.y - p2.y),
curx1 = p3.x,
curx2 = p3.x,
scanLineY = p3.y,
scanLineTo = p1.y;
for (; scanLineY > scanLineTo; scanLineY--){
scanline(curx1|0,curx2|0, scanLineY|0, arr);
curx1 -= invslope1;
curx2 -= invslope2;
}
};
var p4 = new Point();
var triangle = function triangle(_p1, _p2, _p3){
var arr = [];
p1.borrow(_p1); p2.borrow(_p2); p3.borrow(_p3);
if (p1.y > p2.y) swap(p1, p2);
if (p2.y > p3.y) swap(p2, p3);
if (p1.y > p2.y) swap(p1, p2);
if (p2.y === p3.y) {
flatBottom(p1, p2, p3, arr);
} else if (p1.y === p2.y) {
flatTop(p1, p2, p3, arr);
} else {
p4.x = p1.x + (p2.y - p1.y)/(p3.y - p1.y)*(p3.x - p1.x);
p4.y = p2.y;
flatBottom(p1, p2, p4, arr);
flatTop(p2, p4, p3, arr);
}
return arr;
};
return triangle;
})();
\ No newline at end of file
......@@ -33,6 +33,7 @@ app.get('/bbt_face_matching', (req, res) => res.sendFile(path.join(viewsDir, 'bb
app.get('/bbt_face_recognition', (req, res) => res.sendFile(path.join(viewsDir, 'bbtFaceRecognition.html')))
app.get('/batch_face_landmarks', (req, res) => res.sendFile(path.join(viewsDir, 'batchFaceLandmarks.html')))
app.get('/batch_face_recognition', (req, res) => res.sendFile(path.join(viewsDir, 'batchFaceRecognition.html')))
app.get('/demo', (req, res) => res.sendFile(path.join(viewsDir, 'demo.html')))
app.post('/fetch_external_image', async (req, res) => {
const { imageUrl } = req.body
......
<!DOCTYPE html>
<html>
<head>
<script src="face-api.js"></script>
<script src="face-api.min.js"></script>
<script src="js/commons.js"></script>
<script src="js/bbt.js"></script>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css">
<!--<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>-->
</head>
<body>
<div id="navbar"></div>
......@@ -34,10 +34,10 @@
let landmarks
let currentImg
function onChangeDrawLines(e) {
/*function onChangeDrawLines(e) {
drawLines = $(e.target).prop('checked')
redraw()
}
}*/
function redraw() {
const canvas = faceapi.createCanvasFromMedia(currentImg)
......@@ -58,7 +58,7 @@
await onSelectionChanged($('#selectList select').val())
}
$(document).ready(function() {
/* $(document).ready(function() {
renderNavBar('#navbar', 'bbt_face_landmark_detection')
renderFaceImageSelectList(
'#selectList',
......@@ -66,7 +66,7 @@
{ className: 'sheldon', imageIdx: 1 }
)
run()
})
})*/
</script>
......
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="face-api.js"></script>
<script src="js/Point.js"></script>
<script src="js/triangle.js"></script>
<script src="js/kmean.js"></script>
<script src="js/facemarks.js"></script>
<script src="js/extract-colors.js"></script>
</head>
<body>
<video onloadedmetadata="" id="inputVideo" style="opacity: 0" autoplay muted playsinline></video>
<canvas id="playback" style="position: absolute;left:0"></canvas>
<canvas id="overlay" style="position: absolute;left:0"></canvas>
<div id="colors"></div>
<div>
<label><input type="checkbox" id="cb"><span id="upload">Upload an image</span></label>
<input type="file" id="input"/>
</div>
<script>
var TINY_FACE_DETECTOR = 1;var SSD_MOBILENETV1 = 2
function getCurrentFaceDetectionNet() {
selectedFaceDetector = TINY_FACE_DETECTOR
if (selectedFaceDetector === SSD_MOBILENETV1) {
return faceapi.nets.ssdMobilenetv1
}
if (selectedFaceDetector === TINY_FACE_DETECTOR) {
return faceapi.nets.tinyFaceDetector
}
}
function isFaceDetectionModelLoaded() {
return !!getCurrentFaceDetectionNet().params
}
window.s0 = 224;
window.bonusAreaCalc = function(cheek) {
var vx = cheek[0][0].subClone(cheek[0][1]),
vy = cheek[0][1].subClone(cheek[0][2]);
var bonusArea = [
cheek[0][1].subClone(vx.mulClone(1/3)),
cheek[0][1].subClone(vx.normalize().mul(3))
];
bonusArea.push(bonusArea[1].subClone(vy.mul(1.5)));
bonusArea[0].add(vy.mulClone(1/4));
bonusArea[1].add(vy.mulClone(1/5));
return bonusArea;
};
var img = new Image();
function handleFiles(e) {
var url = URL.createObjectURL(e.target.files[0]);
img.onload = function() {
//ctx.drawImage(img, 0, 0);
};
img.src = url;
}
var input = document.getElementById('input');
var cb = document.getElementById('cb');
var upload = document.getElementById('upload');
cb.addEventListener('change', function() {
if(cb.checked){
upload.innerText = 'Upload an image'
}else{
upload.innerText = 'Use camera'
}
});
input.addEventListener('change', handleFiles, false);
var ctx = overlay.getContext('2d');
var ctx2 = playback.getContext('2d');
var canvas = overlay;
var dims = {width:640, height: 480};
canvas.width = playback.width = dims.width;
canvas.height = playback.height = dims.height;
var f = async function(){
let inputSize = s0;
let scoreThreshold = 0.5;
var videoEl = inputVideo;
if (!isFaceDetectionModelLoaded()){
await getCurrentFaceDetectionNet().load( '/' );
await faceapi.loadFaceLandmarkModel('/');
}
var options = new faceapi.TinyFaceDetectorOptions( { inputSize, scoreThreshold } );
//const result = await faceapi.detectAllFaces( videoEl, options).withFaceLandmarks()
//const dims = faceapi.matchDimensions( canvas, videoEl, true );
//faceapi.matchDimensions( playback, videoEl, true );
if(cb.checked){
ctx2.drawImage( videoEl, 0, 0, dims.width, dims.height );
}else{
ctx2.clearRect(0,0,dims.width, dims.height);
if(img.width/dims.width*dims.height>img.height){
var h = img.height/(img.width/dims.width);
ctx2.drawImage(img, 0, (dims.height-h)/2, dims.width, h);
}else{
var w = img.width/(img.height/dims.height);
ctx2.drawImage(img, (dims.width-w)/2, 0, w, dims.height);
}
}
const result = await faceapi.detectSingleFace( playback, options ).withFaceLandmarks();//.withFaceDescriptor();
if(result){
//const resizedResults = faceapi.resizeResults(result, videoEl)
ctx.clearRect(0,0,dims.width, dims.height)
faceapi.draw.drawFaceLandmarks( canvas, faceapi.resizeResults( result, dims ) );
var toPoint = function(p) {
return new Point(p.x, p.y)
};
var jaw = result.landmarks.getJawOutline(),
nose = result.landmarks.getNose(),
mouth = result.landmarks.getMouth(),
leftBrow = result.landmarks.getLeftEyeBrow(),
rightBrow = result.landmarks.getRightEyeBrow(),
leftEye = result.landmarks.getLeftEye(),
rightEye = result.landmarks.getRightEye();
ctx.fillStyle='blue'; mouth.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });
ctx.fillStyle='red'; jaw.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });
ctx.fillStyle='yellow'; leftEye.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });
ctx.fillStyle='yellow'; rightEye.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });
ctx.fillStyle='red'; leftBrow.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });
ctx.fillStyle='red'; rightBrow.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });
ctx.fillStyle='blue'; nose.forEach(function(p, i) { ctx.fillText(i+'', p.x, p.y) });
var faceMarks = new FaceMarks(result.landmarks);
var cheek = faceMarks.marks.cheek;
var ratio = (cheek.left.base[0].distance(cheek.left.base[1])/cheek.right.base[0].distance(cheek.right.base[1]));
var bad = 2;
var lips = [];
lips = lips.concat(faceMarks.marks.lips.top);
lips = lips.concat(faceMarks.marks.lips.bottom);
var browsSearchArea = [];
browsSearchArea.push([
toPoint(leftBrow[4]),
toPoint(leftEye[2]).middle(toPoint(leftBrow[4])),
toPoint(leftBrow[1])
]);
browsSearchArea.push([
toPoint(rightBrow[0]),
toPoint(rightEye[1]).middle(toPoint(rightBrow[0])),
toPoint(rightBrow[3])
]);
var eyes = [];
if(ratio > bad){
cheek = [cheek.left.base, cheek.left.bonus1, cheek.left.bonus2];
browsSearchArea.pop();
eyes = [
faceMarks.marks.eyes.left.t1,
faceMarks.marks.eyes.left.t2,
faceMarks.marks.eyes.left.t3,
faceMarks.marks.eyes.left.t4
];
}else if(ratio < 1/bad){
cheek = [cheek.right.base, cheek.right.bonus1, cheek.right.bonus2];
browsSearchArea.shift();
eyes = [
faceMarks.marks.eyes.right.t1,
faceMarks.marks.eyes.right.t2,
faceMarks.marks.eyes.right.t3,
faceMarks.marks.eyes.right.t4
];
}else{
cheek = [
cheek.left.base,
cheek.left.bonus1,
cheek.left.bonus2,
cheek.right.base,
cheek.right.bonus1,
cheek.right.bonus2
];
eyes = [
faceMarks.marks.eyes.left.t1,
faceMarks.marks.eyes.left.t2,
faceMarks.marks.eyes.left.t3,
faceMarks.marks.eyes.left.t4,
faceMarks.marks.eyes.right.t1,
faceMarks.marks.eyes.right.t2,
faceMarks.marks.eyes.right.t3,
faceMarks.marks.eyes.right.t4
];
}
var drawPoly = function(poly) {
ctx.beginPath();
for(var i = 0,_i = poly.length; i <= _i; i++ ){
if(i === 0){
ctx.moveTo( poly[ i ].x, poly[ i ].y );
}else{
ctx.lineTo( poly[ i % _i ].x, poly[ i % _i ].y );
}
}
ctx.stroke();
};
cheek.forEach(drawPoly);
lips.forEach(drawPoly);
browsSearchArea.forEach(drawPoly);
eyes.forEach(drawPoly);
document.getElementById('colors').innerHTML = [
block(
'Lips',
extractor(ctx2, lips, 5).map(a=>a.html).join('\n')
),
block(
'Blush',
extractor(ctx2, cheek, 5).map(a=>a.html).join('\n')
),
block(
'Brows',
extractor(ctx2, browsSearchArea, 5).map(a=>a.html).join('\n')
),
block(
'Eyes',
extractor(ctx2, eyes, 5, 1).map(a=>a.html).join('\n')
)
].join('\n');
//ctx2.putImageData(imageData, minX, minY);
// debugger;
//var means = new KMeans()
//colors.innerHTML = block('Mouth',colors());
}
requestAnimationFrame(f);
//setTimeout(f, 300)
};
var block = function(title, children) {
return '<div class="block"><h2>'+ title +'</h2><p>'+children+'</p></div>'
};
var f0 = async function() {
const stream = await navigator.mediaDevices.getUserMedia({ video: {} })
const videoEl = inputVideo
videoEl.srcObject = stream
f()
}
f0();
</script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<script src="face-api.js"></script>
<script src="js/commons.js"></script>
<script src="js/faceDetectionControls.js"></script>
<script src="js/imageSelectionControls.js"></script>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css">
<!--<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>-->
</head>
<body>
<div id="navbar"></div>
......@@ -118,7 +115,10 @@
</span>
<!-- tiny_face_detector_controls -->
</body>
<script src="face-api.js"></script>
<script src="js/commons.js"></script>
<script src="js/faceDetectionControls.js"></script>
<script src="js/imageSelectionControls.js"></script>
<script>
let withBoxes = true
......@@ -133,12 +133,12 @@
return
}
const inputImgEl = $('#inputImg').get(0)
const inputImgEl = document.querySelector('#inputImg')
const options = getFaceDetectorOptions()
const results = await faceapi.detectAllFaces(inputImgEl, options).withFaceLandmarks()
const canvas = $('#overlay').get(0)
const canvas = document.querySelector('#overlay')
faceapi.matchDimensions(canvas, inputImgEl)
const resizedResults = faceapi.resizeResults(results, inputImgEl)
......@@ -150,19 +150,19 @@
async function run() {
// load face detection and face landmark models
await changeFaceDetector(SSD_MOBILENETV1)
await changeFaceDetector(TINY_FACE_DETECTOR)
await faceapi.loadFaceLandmarkModel('/')
// start processing image
updateResults()
}
$(document).ready(function() {
renderNavBar('#navbar', 'face_landmark_detection')
initImageSelectionControls()
initFaceDetectionControls()
//initFaceDetectionControls()
run()
})
</script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<script src="face-api.js"></script>
<script src="js/commons.js"></script>
<script src="js/faceDetectionControls.js"></script>
<script src="js/imageSelectionControls.js"></script>
<link rel="stylesheet" href="styles.css">
<!--<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>-->
</head>
<body>
<div id="navbar"></div>
<div class="center-content page-container">
<div class="progress" id="loader">
<div class="indeterminate"></div>
</div>
<div style="position: relative" class="margin">
<img id="inputImg" src="" style="max-width: 800px;" />
<canvas id="overlay" />
</div>
<div class="row side-by-side">
<!-- image_selection_control -->
<div id="selectList"></div>
<div class="row">
<label for="imgUrlInput">Get image from URL:</label>
<input id="imgUrlInput" type="text" class="bold">
</div>
<button
class="waves-effect waves-light btn"
onclick="loadImageFromUrl()"
>
Ok
</button>
<input id="queryImgUploadInput" type="file" class="waves-effect btn bold" onchange="loadImageFromUpload()" accept=".jpg, .jpeg, .png">
<!-- image_selection_control -->
</div>
<div class="row side-by-side">
<!-- face_detector_selection_control -->
<div id="face_detector_selection_control" class="row input-field" style="margin-right: 20px;">
<select id="selectFaceDetector">
<option value="ssd_mobilenetv1">SSD Mobilenet V1</option>
<option value="tiny_face_detector">Tiny Face Detector</option>
</select>
<label>Select Face Detector</label>
</div>
<!-- face_detector_selection_control -->
<!-- check boxes -->
<div class="row" style="width: 220px;">
<input type="checkbox" id="hideBoundingBoxesCheckbox" onchange="onChangeHideBoundingBoxes(event)" />
<label for="hideBoundingBoxesCheckbox">Hide Bounding Boxes</label>
</div>
<!-- check boxes -->
</div>
<!-- ssd_mobilenetv1_controls -->
<span id="ssd_mobilenetv1_controls">
<div class="row side-by-side">
<div class="row">
<label for="minConfidence">Min Confidence:</label>
<input disabled value="0.5" id="minConfidence" type="text" class="bold">
</div>
<button
class="waves-effect waves-light btn"
onclick="onDecreaseMinConfidence()"
>
<i class="material-icons left">-</i>
</button>
<button
class="waves-effect waves-light btn"
onclick="onIncreaseMinConfidence()"
>
<i class="material-icons left">+</i>
</button>
</div>
</span>
<!-- ssd_mobilenetv1_controls -->
<!-- tiny_face_detector_controls -->
<span id="tiny_face_detector_controls">
<div class="row side-by-side">
<div class="row input-field" style="margin-right: 20px;">
<select id="inputSize">
<option value="" disabled selected>Input Size:</option>
<option value="160">160 x 160</option>
<option value="224">224 x 224</option>
<option value="320">320 x 320</option>
<option value="416">416 x 416</option>
<option value="512">512 x 512</option>
<option value="608">608 x 608</option>
</select>
<label>Input Size</label>
</div>
<div class="row">
<label for="scoreThreshold">Score Threshold:</label>
<input disabled value="0.5" id="scoreThreshold" type="text" class="bold">
</div>
<button
class="waves-effect waves-light btn"
onclick="onDecreaseScoreThreshold()"
>
<i class="material-icons left">-</i>
</button>
<button
class="waves-effect waves-light btn"
onclick="onIncreaseScoreThreshold()"
>
<i class="material-icons left">+</i>
</button>
</div>
</span>
<!-- tiny_face_detector_controls -->
</body>
<script>
let withBoxes = true
function onChangeHideBoundingBoxes(e) {
withBoxes = !$(e.target).prop('checked')
updateResults()
}
async function updateResults() {
if (!isFaceDetectionModelLoaded()) {
return
}
const inputImgEl = $('#inputImg').get(0)
const options = getFaceDetectorOptions()
const results = await faceapi.detectAllFaces(inputImgEl, options).withFaceLandmarks()
const canvas = $('#overlay').get(0)
faceapi.matchDimensions(canvas, inputImgEl)
const resizedResults = faceapi.resizeResults(results, inputImgEl)
if (withBoxes) {
faceapi.draw.drawDetections(canvas, resizedResults)
}
faceapi.draw.drawFaceLandmarks(canvas, resizedResults)
}
async function run() {
// load face detection and face landmark models
//await changeFaceDetector(SSD_MOBILENETV1)
await changeFaceDetector(TINY_FACE_DETECTOR)
await faceapi.loadFaceLandmarkModel('/')
// start processing image
updateResults()
}
$(document).ready(function() {
renderNavBar('#navbar', 'face_landmark_detection')
initImageSelectionControls()
initFaceDetectionControls()
run()
})
</script>
</body>
</html>
\ No newline at end of file
export * from './WithFaceDescriptor'
export * from './WithFaceDetection'
export * from './WithFaceExpressions'
//export * from './WithFaceExpressions'
export * from './WithFaceLandmarks'
export * from './WithAge'
export * from './WithGender'
\ No newline at end of file
//export * from './WithAge'
//export * from './WithGender'
\ No newline at end of file
......@@ -9,20 +9,20 @@ export {
tf
}
export * from './ageGenderNet/index';
//export * from './ageGenderNet/index';
export * from './classes/index';
export * from './dom/index'
export * from './env/index';
export * from './faceExpressionNet/index';
//export * from './faceExpressionNet/index';
export * from './faceLandmarkNet/index';
export * from './faceRecognitionNet/index';
//export * from './faceRecognitionNet/index';
export * from './factories/index';
export * from './globalApi/index';
export * from './mtcnn/index';
export * from './ops/index';
export * from './ssdMobilenetv1/index';
//export * from './mtcnn/index';
//export * from './ops/index';
//export * from './ssdMobilenetv1/index';
export * from './tinyFaceDetector/index';
export * from './tinyYolov2/index';
//export * from './tinyYolov2/index';
export * from './euclideanDistance';
export * from './NeuralNetwork';
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment