mirror of https://github.com/vladmandic/human
add similarity score range normalization
parent
e85b359095
commit
31b24d7692
|
@ -9,8 +9,9 @@
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
### **HEAD -> main** 2021/11/10 mandic00@live.com
|
### **HEAD -> main** 2021/11/11 mandic00@live.com
|
||||||
|
|
||||||
|
- documentation overhaul
|
||||||
- auto tensor shape and channels handling
|
- auto tensor shape and channels handling
|
||||||
- disable use of path2d in node
|
- disable use of path2d in node
|
||||||
- add liveness module and facerecognition demo
|
- add liveness module and facerecognition demo
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
html { font-family: 'Lato', 'Segoe UI'; font-size: 16px; font-variant: small-caps; }
|
html { font-family: 'Lato', 'Segoe UI'; font-size: 16px; font-variant: small-caps; }
|
||||||
body { margin: 0; padding: 16px; background: black; color: white; overflow-x: hidden; width: 100vw; height: 100vh; }
|
body { margin: 0; padding: 16px; background: black; color: white; overflow-x: hidden; width: 100vw; height: 100vh; }
|
||||||
body::-webkit-scrollbar { display: none; }
|
body::-webkit-scrollbar { display: none; }
|
||||||
.button { padding: 2px; cursor: pointer; box-shadow: 2px 2px black; width: 64px; text-align: center; margin-left: 16px; height: 16px }
|
.button { padding: 2px; cursor: pointer; box-shadow: 2px 2px black; width: 64px; text-align: center; margin-left: 16px; height: 16px; display: none }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -225,19 +225,13 @@ async function deleteRecord() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function detectFace() {
|
async function detectFace() {
|
||||||
var _a;
|
var _a, _b;
|
||||||
|
(_a = dom.canvas.getContext("2d")) == null ? void 0 : _a.clearRect(0, 0, options.minSize, options.minSize);
|
||||||
if (!face || !face.tensor || !face.embedding)
|
if (!face || !face.tensor || !face.embedding)
|
||||||
return 0;
|
return 0;
|
||||||
dom.canvas.width = face.tensor.shape[1] || 0;
|
|
||||||
dom.canvas.height = face.tensor.shape[0] || 0;
|
|
||||||
dom.source.width = dom.canvas.width;
|
|
||||||
dom.source.height = dom.canvas.height;
|
|
||||||
dom.canvas.style.width = "";
|
|
||||||
human.tf.browser.toPixels(face.tensor, dom.canvas);
|
human.tf.browser.toPixels(face.tensor, dom.canvas);
|
||||||
const descriptors = db2.map((rec) => rec.descriptor);
|
const descriptors = db2.map((rec) => rec.descriptor);
|
||||||
const res = await human.match(face.embedding, descriptors);
|
const res = await human.match(face.embedding, descriptors);
|
||||||
dom.match.style.display = "flex";
|
|
||||||
dom.retry.style.display = "block";
|
|
||||||
if (res.index === -1) {
|
if (res.index === -1) {
|
||||||
log2("no matches");
|
log2("no matches");
|
||||||
dom.delete.style.display = "none";
|
dom.delete.style.display = "none";
|
||||||
|
@ -248,11 +242,12 @@ async function detectFace() {
|
||||||
dom.delete.style.display = "";
|
dom.delete.style.display = "";
|
||||||
dom.name.value = current.name;
|
dom.name.value = current.name;
|
||||||
dom.source.style.display = "";
|
dom.source.style.display = "";
|
||||||
(_a = dom.source.getContext("2d")) == null ? void 0 : _a.putImageData(current.image, 0, 0);
|
(_b = dom.source.getContext("2d")) == null ? void 0 : _b.putImageData(current.image, 0, 0);
|
||||||
}
|
}
|
||||||
return res.similarity > options.threshold;
|
return res.similarity > options.threshold;
|
||||||
}
|
}
|
||||||
async function main() {
|
async function main() {
|
||||||
|
var _a, _b;
|
||||||
ok.faceCount = false;
|
ok.faceCount = false;
|
||||||
ok.faceConfidence = false;
|
ok.faceConfidence = false;
|
||||||
ok.facingCenter = false;
|
ok.facingCenter = false;
|
||||||
|
@ -269,9 +264,16 @@ async function main() {
|
||||||
startTime = human.now();
|
startTime = human.now();
|
||||||
face = await validationLoop();
|
face = await validationLoop();
|
||||||
dom.fps.style.display = "none";
|
dom.fps.style.display = "none";
|
||||||
|
dom.canvas.width = ((_a = face == null ? void 0 : face.tensor) == null ? void 0 : _a.shape[1]) || options.minSize;
|
||||||
|
dom.canvas.height = ((_b = face == null ? void 0 : face.tensor) == null ? void 0 : _b.shape[0]) || options.minSize;
|
||||||
|
dom.source.width = dom.canvas.width;
|
||||||
|
dom.source.height = dom.canvas.height;
|
||||||
|
dom.canvas.style.width = "";
|
||||||
|
dom.match.style.display = "flex";
|
||||||
|
dom.retry.style.display = "block";
|
||||||
if (!allOk()) {
|
if (!allOk()) {
|
||||||
log2("did not find valid input", face);
|
log2("did not find valid face");
|
||||||
return 0;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
const res = await detectFace();
|
const res = await detectFace();
|
||||||
document.body.style.background = res ? "darkgreen" : "maroon";
|
document.body.style.background = res ? "darkgreen" : "maroon";
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -179,18 +179,11 @@ async function deleteRecord() {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function detectFace() {
|
async function detectFace() {
|
||||||
// draw face and dispose face tensor immediatey afterwards
|
dom.canvas.getContext('2d')?.clearRect(0, 0, options.minSize, options.minSize);
|
||||||
if (!face || !face.tensor || !face.embedding) return 0;
|
if (!face || !face.tensor || !face.embedding) return 0;
|
||||||
dom.canvas.width = face.tensor.shape[1] || 0;
|
|
||||||
dom.canvas.height = face.tensor.shape[0] || 0;
|
|
||||||
dom.source.width = dom.canvas.width;
|
|
||||||
dom.source.height = dom.canvas.height;
|
|
||||||
dom.canvas.style.width = '';
|
|
||||||
human.tf.browser.toPixels(face.tensor as unknown as TensorLike, dom.canvas);
|
human.tf.browser.toPixels(face.tensor as unknown as TensorLike, dom.canvas);
|
||||||
const descriptors = db.map((rec) => rec.descriptor);
|
const descriptors = db.map((rec) => rec.descriptor);
|
||||||
const res = await human.match(face.embedding, descriptors);
|
const res = await human.match(face.embedding, descriptors);
|
||||||
dom.match.style.display = 'flex';
|
|
||||||
dom.retry.style.display = 'block';
|
|
||||||
if (res.index === -1) {
|
if (res.index === -1) {
|
||||||
log('no matches');
|
log('no matches');
|
||||||
dom.delete.style.display = 'none';
|
dom.delete.style.display = 'none';
|
||||||
|
@ -223,9 +216,16 @@ async function main() { // main entry point
|
||||||
startTime = human.now();
|
startTime = human.now();
|
||||||
face = await validationLoop(); // start validation loop
|
face = await validationLoop(); // start validation loop
|
||||||
dom.fps.style.display = 'none';
|
dom.fps.style.display = 'none';
|
||||||
|
dom.canvas.width = face?.tensor?.shape[1] || options.minSize;
|
||||||
|
dom.canvas.height = face?.tensor?.shape[0] || options.minSize;
|
||||||
|
dom.source.width = dom.canvas.width;
|
||||||
|
dom.source.height = dom.canvas.height;
|
||||||
|
dom.canvas.style.width = '';
|
||||||
|
dom.match.style.display = 'flex';
|
||||||
|
dom.retry.style.display = 'block';
|
||||||
if (!allOk()) {
|
if (!allOk()) {
|
||||||
log('did not find valid input', face);
|
log('did not find valid face');
|
||||||
return 0;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// log('found valid face');
|
// log('found valid face');
|
||||||
const res = await detectFace();
|
const res = await detectFace();
|
||||||
|
|
|
@ -184,9 +184,8 @@ async function AddImageElement(index, image, length) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
const img = new Image(128, 128);
|
const img = new Image(128, 128);
|
||||||
img.onload = () => { // must wait until image is loaded
|
img.onload = () => { // must wait until image is loaded
|
||||||
human.detect(img, userConfig).then(async (res) => {
|
human.detect(img, userConfig).then((res) => {
|
||||||
const ok = AddFaceCanvas(index, res, image); // then wait until image is analyzed
|
const ok = AddFaceCanvas(index, res, image); // then wait until image is analyzed
|
||||||
// log('Add image:', index + 1, image, 'faces:', res.face.length);
|
|
||||||
if (ok) document.getElementById('images').appendChild(img); // and finally we can add it
|
if (ok) document.getElementById('images').appendChild(img); // and finally we can add it
|
||||||
resolve(true);
|
resolve(true);
|
||||||
});
|
});
|
||||||
|
@ -250,11 +249,13 @@ async function main() {
|
||||||
// const promises = [];
|
// const promises = [];
|
||||||
// for (let i = 0; i < images.length; i++) promises.push(AddImageElement(i, images[i], images.length));
|
// for (let i = 0; i < images.length; i++) promises.push(AddImageElement(i, images[i], images.length));
|
||||||
// await Promise.all(promises);
|
// await Promise.all(promises);
|
||||||
|
const t0 = human.now();
|
||||||
for (let i = 0; i < images.length; i++) await AddImageElement(i, images[i], images.length);
|
for (let i = 0; i < images.length; i++) await AddImageElement(i, images[i], images.length);
|
||||||
|
const t1 = human.now();
|
||||||
|
|
||||||
// print stats
|
// print stats
|
||||||
const num = all.reduce((prev, cur) => prev += cur.length, 0);
|
const num = all.reduce((prev, cur) => prev += cur.length, 0);
|
||||||
log('Extracted faces:', num, 'from images:', all.length);
|
log('Extracted faces:', num, 'from images:', all.length, 'time:', Math.round(t1 - t0));
|
||||||
log(human.tf.engine().memory());
|
log(human.tf.engine().memory());
|
||||||
|
|
||||||
// if we didn't download db, generate it from current faces
|
// if we didn't download db, generate it from current faces
|
||||||
|
|
|
@ -11973,7 +11973,7 @@ function calc2(newResult, config3) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/face/match.ts
|
// src/face/match.ts
|
||||||
function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 20 }) {
|
function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 25 }) {
|
||||||
let sum2 = 0;
|
let sum2 = 0;
|
||||||
for (let i = 0; i < descriptor1.length; i++) {
|
for (let i = 0; i < descriptor1.length; i++) {
|
||||||
const diff = !options3.order || options3.order === 2 ? descriptor1[i] - descriptor2[i] : Math.abs(descriptor1[i] - descriptor2[i]);
|
const diff = !options3.order || options3.order === 2 ? descriptor1[i] - descriptor2[i] : Math.abs(descriptor1[i] - descriptor2[i]);
|
||||||
|
@ -11981,29 +11981,35 @@ function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 2
|
||||||
}
|
}
|
||||||
return (options3.multiplier || 20) * sum2;
|
return (options3.multiplier || 20) * sum2;
|
||||||
}
|
}
|
||||||
function similarity(descriptor1, descriptor2, options3 = { order: 2, multiplier: 20 }) {
|
var normalizeDistance = (dist, order, min2, max4) => {
|
||||||
|
if (dist === 0)
|
||||||
|
return 1;
|
||||||
|
const root = order === 2 ? Math.sqrt(dist) : dist ** (1 / order);
|
||||||
|
const norm = (1 - root / 100 - min2) / (max4 - min2);
|
||||||
|
const clamp2 = Math.max(Math.min(norm, 1), 0);
|
||||||
|
return clamp2;
|
||||||
|
};
|
||||||
|
function similarity(descriptor1, descriptor2, options3 = { order: 2, multiplier: 25, min: 0.2, max: 0.8 }) {
|
||||||
const dist = distance(descriptor1, descriptor2, options3);
|
const dist = distance(descriptor1, descriptor2, options3);
|
||||||
const root = !options3.order || options3.order === 2 ? Math.sqrt(dist) : dist ** (1 / options3.order);
|
return normalizeDistance(dist, options3.order || 2, options3.min || 0, options3.max || 1);
|
||||||
const invert = Math.max(0, 100 - root) / 100;
|
|
||||||
return invert;
|
|
||||||
}
|
}
|
||||||
function match2(descriptor, descriptors, options3 = { order: 2, multiplier: 20, threshold: 0 }) {
|
function match2(descriptor, descriptors, options3 = { order: 2, multiplier: 25, threshold: 0, min: 0.2, max: 0.8 }) {
|
||||||
if (!Array.isArray(descriptor) || !Array.isArray(descriptors) || descriptor.length < 64 || descriptors.length === 0 || descriptor.length !== descriptors[0].length) {
|
if (!Array.isArray(descriptor) || !Array.isArray(descriptors) || descriptor.length < 64 || descriptors.length === 0 || descriptor.length !== descriptors[0].length) {
|
||||||
return { index: -1, distance: Number.POSITIVE_INFINITY, similarity: 0 };
|
return { index: -1, distance: Number.POSITIVE_INFINITY, similarity: 0 };
|
||||||
}
|
}
|
||||||
let best = Number.MAX_SAFE_INTEGER;
|
let lowestDistance = Number.MAX_SAFE_INTEGER;
|
||||||
let index2 = -1;
|
let index2 = -1;
|
||||||
for (let i = 0; i < descriptors.length; i++) {
|
for (let i = 0; i < descriptors.length; i++) {
|
||||||
const res = distance(descriptor, descriptors[i], options3);
|
const res = distance(descriptor, descriptors[i], options3);
|
||||||
if (res < best) {
|
if (res < lowestDistance) {
|
||||||
best = res;
|
lowestDistance = res;
|
||||||
index2 = i;
|
index2 = i;
|
||||||
}
|
}
|
||||||
if (best < (options3.threshold || 0))
|
if (lowestDistance < (options3.threshold || 0))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
best = !options3.order || options3.order === 2 ? Math.sqrt(best) : best ** (1 / options3.order);
|
const normalizedSimilarity = normalizeDistance(lowestDistance, options3.order || 2, options3.min || 0, options3.max || 1);
|
||||||
return { index: index2, distance: best, similarity: Math.max(0, 100 - best) / 100 };
|
return { index: index2, distance: lowestDistance, similarity: normalizedSimilarity };
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/util/persons.ts
|
// src/util/persons.ts
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -82298,7 +82298,7 @@ function calc2(newResult, config3) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/face/match.ts
|
// src/face/match.ts
|
||||||
function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 20 }) {
|
function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 25 }) {
|
||||||
let sum7 = 0;
|
let sum7 = 0;
|
||||||
for (let i = 0; i < descriptor1.length; i++) {
|
for (let i = 0; i < descriptor1.length; i++) {
|
||||||
const diff = !options3.order || options3.order === 2 ? descriptor1[i] - descriptor2[i] : Math.abs(descriptor1[i] - descriptor2[i]);
|
const diff = !options3.order || options3.order === 2 ? descriptor1[i] - descriptor2[i] : Math.abs(descriptor1[i] - descriptor2[i]);
|
||||||
|
@ -82306,29 +82306,35 @@ function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 2
|
||||||
}
|
}
|
||||||
return (options3.multiplier || 20) * sum7;
|
return (options3.multiplier || 20) * sum7;
|
||||||
}
|
}
|
||||||
function similarity(descriptor1, descriptor2, options3 = { order: 2, multiplier: 20 }) {
|
var normalizeDistance = (dist, order, min7, max7) => {
|
||||||
|
if (dist === 0)
|
||||||
|
return 1;
|
||||||
|
const root = order === 2 ? Math.sqrt(dist) : dist ** (1 / order);
|
||||||
|
const norm2 = (1 - root / 100 - min7) / (max7 - min7);
|
||||||
|
const clamp3 = Math.max(Math.min(norm2, 1), 0);
|
||||||
|
return clamp3;
|
||||||
|
};
|
||||||
|
function similarity(descriptor1, descriptor2, options3 = { order: 2, multiplier: 25, min: 0.2, max: 0.8 }) {
|
||||||
const dist = distance(descriptor1, descriptor2, options3);
|
const dist = distance(descriptor1, descriptor2, options3);
|
||||||
const root = !options3.order || options3.order === 2 ? Math.sqrt(dist) : dist ** (1 / options3.order);
|
return normalizeDistance(dist, options3.order || 2, options3.min || 0, options3.max || 1);
|
||||||
const invert = Math.max(0, 100 - root) / 100;
|
|
||||||
return invert;
|
|
||||||
}
|
}
|
||||||
function match2(descriptor, descriptors, options3 = { order: 2, multiplier: 20, threshold: 0 }) {
|
function match2(descriptor, descriptors, options3 = { order: 2, multiplier: 25, threshold: 0, min: 0.2, max: 0.8 }) {
|
||||||
if (!Array.isArray(descriptor) || !Array.isArray(descriptors) || descriptor.length < 64 || descriptors.length === 0 || descriptor.length !== descriptors[0].length) {
|
if (!Array.isArray(descriptor) || !Array.isArray(descriptors) || descriptor.length < 64 || descriptors.length === 0 || descriptor.length !== descriptors[0].length) {
|
||||||
return { index: -1, distance: Number.POSITIVE_INFINITY, similarity: 0 };
|
return { index: -1, distance: Number.POSITIVE_INFINITY, similarity: 0 };
|
||||||
}
|
}
|
||||||
let best = Number.MAX_SAFE_INTEGER;
|
let lowestDistance = Number.MAX_SAFE_INTEGER;
|
||||||
let index2 = -1;
|
let index2 = -1;
|
||||||
for (let i = 0; i < descriptors.length; i++) {
|
for (let i = 0; i < descriptors.length; i++) {
|
||||||
const res = distance(descriptor, descriptors[i], options3);
|
const res = distance(descriptor, descriptors[i], options3);
|
||||||
if (res < best) {
|
if (res < lowestDistance) {
|
||||||
best = res;
|
lowestDistance = res;
|
||||||
index2 = i;
|
index2 = i;
|
||||||
}
|
}
|
||||||
if (best < (options3.threshold || 0))
|
if (lowestDistance < (options3.threshold || 0))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
best = !options3.order || options3.order === 2 ? Math.sqrt(best) : best ** (1 / options3.order);
|
const normalizedSimilarity = normalizeDistance(lowestDistance, options3.order || 2, options3.min || 0, options3.max || 1);
|
||||||
return { index: index2, distance: best, similarity: Math.max(0, 100 - best) / 100 };
|
return { index: index2, distance: lowestDistance, similarity: normalizedSimilarity };
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/util/persons.ts
|
// src/util/persons.ts
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -12035,7 +12035,7 @@ function calc2(newResult, config3) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/face/match.ts
|
// src/face/match.ts
|
||||||
function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 20 }) {
|
function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 25 }) {
|
||||||
let sum2 = 0;
|
let sum2 = 0;
|
||||||
for (let i = 0; i < descriptor1.length; i++) {
|
for (let i = 0; i < descriptor1.length; i++) {
|
||||||
const diff = !options3.order || options3.order === 2 ? descriptor1[i] - descriptor2[i] : Math.abs(descriptor1[i] - descriptor2[i]);
|
const diff = !options3.order || options3.order === 2 ? descriptor1[i] - descriptor2[i] : Math.abs(descriptor1[i] - descriptor2[i]);
|
||||||
|
@ -12043,29 +12043,35 @@ function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 2
|
||||||
}
|
}
|
||||||
return (options3.multiplier || 20) * sum2;
|
return (options3.multiplier || 20) * sum2;
|
||||||
}
|
}
|
||||||
function similarity(descriptor1, descriptor2, options3 = { order: 2, multiplier: 20 }) {
|
var normalizeDistance = (dist, order, min2, max4) => {
|
||||||
|
if (dist === 0)
|
||||||
|
return 1;
|
||||||
|
const root = order === 2 ? Math.sqrt(dist) : dist ** (1 / order);
|
||||||
|
const norm = (1 - root / 100 - min2) / (max4 - min2);
|
||||||
|
const clamp2 = Math.max(Math.min(norm, 1), 0);
|
||||||
|
return clamp2;
|
||||||
|
};
|
||||||
|
function similarity(descriptor1, descriptor2, options3 = { order: 2, multiplier: 25, min: 0.2, max: 0.8 }) {
|
||||||
const dist = distance(descriptor1, descriptor2, options3);
|
const dist = distance(descriptor1, descriptor2, options3);
|
||||||
const root = !options3.order || options3.order === 2 ? Math.sqrt(dist) : dist ** (1 / options3.order);
|
return normalizeDistance(dist, options3.order || 2, options3.min || 0, options3.max || 1);
|
||||||
const invert = Math.max(0, 100 - root) / 100;
|
|
||||||
return invert;
|
|
||||||
}
|
}
|
||||||
function match2(descriptor, descriptors, options3 = { order: 2, multiplier: 20, threshold: 0 }) {
|
function match2(descriptor, descriptors, options3 = { order: 2, multiplier: 25, threshold: 0, min: 0.2, max: 0.8 }) {
|
||||||
if (!Array.isArray(descriptor) || !Array.isArray(descriptors) || descriptor.length < 64 || descriptors.length === 0 || descriptor.length !== descriptors[0].length) {
|
if (!Array.isArray(descriptor) || !Array.isArray(descriptors) || descriptor.length < 64 || descriptors.length === 0 || descriptor.length !== descriptors[0].length) {
|
||||||
return { index: -1, distance: Number.POSITIVE_INFINITY, similarity: 0 };
|
return { index: -1, distance: Number.POSITIVE_INFINITY, similarity: 0 };
|
||||||
}
|
}
|
||||||
let best = Number.MAX_SAFE_INTEGER;
|
let lowestDistance = Number.MAX_SAFE_INTEGER;
|
||||||
let index2 = -1;
|
let index2 = -1;
|
||||||
for (let i = 0; i < descriptors.length; i++) {
|
for (let i = 0; i < descriptors.length; i++) {
|
||||||
const res = distance(descriptor, descriptors[i], options3);
|
const res = distance(descriptor, descriptors[i], options3);
|
||||||
if (res < best) {
|
if (res < lowestDistance) {
|
||||||
best = res;
|
lowestDistance = res;
|
||||||
index2 = i;
|
index2 = i;
|
||||||
}
|
}
|
||||||
if (best < (options3.threshold || 0))
|
if (lowestDistance < (options3.threshold || 0))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
best = !options3.order || options3.order === 2 ? Math.sqrt(best) : best ** (1 / options3.order);
|
const normalizedSimilarity = normalizeDistance(lowestDistance, options3.order || 2, options3.min || 0, options3.max || 1);
|
||||||
return { index: index2, distance: best, similarity: Math.max(0, 100 - best) / 100 };
|
return { index: index2, distance: lowestDistance, similarity: normalizedSimilarity };
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/util/persons.ts
|
// src/util/persons.ts
|
||||||
|
|
|
@ -12036,7 +12036,7 @@ function calc2(newResult, config3) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/face/match.ts
|
// src/face/match.ts
|
||||||
function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 20 }) {
|
function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 25 }) {
|
||||||
let sum2 = 0;
|
let sum2 = 0;
|
||||||
for (let i = 0; i < descriptor1.length; i++) {
|
for (let i = 0; i < descriptor1.length; i++) {
|
||||||
const diff = !options3.order || options3.order === 2 ? descriptor1[i] - descriptor2[i] : Math.abs(descriptor1[i] - descriptor2[i]);
|
const diff = !options3.order || options3.order === 2 ? descriptor1[i] - descriptor2[i] : Math.abs(descriptor1[i] - descriptor2[i]);
|
||||||
|
@ -12044,29 +12044,35 @@ function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 2
|
||||||
}
|
}
|
||||||
return (options3.multiplier || 20) * sum2;
|
return (options3.multiplier || 20) * sum2;
|
||||||
}
|
}
|
||||||
function similarity(descriptor1, descriptor2, options3 = { order: 2, multiplier: 20 }) {
|
var normalizeDistance = (dist, order, min2, max4) => {
|
||||||
|
if (dist === 0)
|
||||||
|
return 1;
|
||||||
|
const root = order === 2 ? Math.sqrt(dist) : dist ** (1 / order);
|
||||||
|
const norm = (1 - root / 100 - min2) / (max4 - min2);
|
||||||
|
const clamp2 = Math.max(Math.min(norm, 1), 0);
|
||||||
|
return clamp2;
|
||||||
|
};
|
||||||
|
function similarity(descriptor1, descriptor2, options3 = { order: 2, multiplier: 25, min: 0.2, max: 0.8 }) {
|
||||||
const dist = distance(descriptor1, descriptor2, options3);
|
const dist = distance(descriptor1, descriptor2, options3);
|
||||||
const root = !options3.order || options3.order === 2 ? Math.sqrt(dist) : dist ** (1 / options3.order);
|
return normalizeDistance(dist, options3.order || 2, options3.min || 0, options3.max || 1);
|
||||||
const invert = Math.max(0, 100 - root) / 100;
|
|
||||||
return invert;
|
|
||||||
}
|
}
|
||||||
function match2(descriptor, descriptors, options3 = { order: 2, multiplier: 20, threshold: 0 }) {
|
function match2(descriptor, descriptors, options3 = { order: 2, multiplier: 25, threshold: 0, min: 0.2, max: 0.8 }) {
|
||||||
if (!Array.isArray(descriptor) || !Array.isArray(descriptors) || descriptor.length < 64 || descriptors.length === 0 || descriptor.length !== descriptors[0].length) {
|
if (!Array.isArray(descriptor) || !Array.isArray(descriptors) || descriptor.length < 64 || descriptors.length === 0 || descriptor.length !== descriptors[0].length) {
|
||||||
return { index: -1, distance: Number.POSITIVE_INFINITY, similarity: 0 };
|
return { index: -1, distance: Number.POSITIVE_INFINITY, similarity: 0 };
|
||||||
}
|
}
|
||||||
let best = Number.MAX_SAFE_INTEGER;
|
let lowestDistance = Number.MAX_SAFE_INTEGER;
|
||||||
let index2 = -1;
|
let index2 = -1;
|
||||||
for (let i = 0; i < descriptors.length; i++) {
|
for (let i = 0; i < descriptors.length; i++) {
|
||||||
const res = distance(descriptor, descriptors[i], options3);
|
const res = distance(descriptor, descriptors[i], options3);
|
||||||
if (res < best) {
|
if (res < lowestDistance) {
|
||||||
best = res;
|
lowestDistance = res;
|
||||||
index2 = i;
|
index2 = i;
|
||||||
}
|
}
|
||||||
if (best < (options3.threshold || 0))
|
if (lowestDistance < (options3.threshold || 0))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
best = !options3.order || options3.order === 2 ? Math.sqrt(best) : best ** (1 / options3.order);
|
const normalizedSimilarity = normalizeDistance(lowestDistance, options3.order || 2, options3.min || 0, options3.max || 1);
|
||||||
return { index: index2, distance: best, similarity: Math.max(0, 100 - best) / 100 };
|
return { index: index2, distance: lowestDistance, similarity: normalizedSimilarity };
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/util/persons.ts
|
// src/util/persons.ts
|
||||||
|
|
|
@ -12035,7 +12035,7 @@ function calc2(newResult, config3) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/face/match.ts
|
// src/face/match.ts
|
||||||
function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 20 }) {
|
function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 25 }) {
|
||||||
let sum2 = 0;
|
let sum2 = 0;
|
||||||
for (let i = 0; i < descriptor1.length; i++) {
|
for (let i = 0; i < descriptor1.length; i++) {
|
||||||
const diff = !options3.order || options3.order === 2 ? descriptor1[i] - descriptor2[i] : Math.abs(descriptor1[i] - descriptor2[i]);
|
const diff = !options3.order || options3.order === 2 ? descriptor1[i] - descriptor2[i] : Math.abs(descriptor1[i] - descriptor2[i]);
|
||||||
|
@ -12043,29 +12043,35 @@ function distance(descriptor1, descriptor2, options3 = { order: 2, multiplier: 2
|
||||||
}
|
}
|
||||||
return (options3.multiplier || 20) * sum2;
|
return (options3.multiplier || 20) * sum2;
|
||||||
}
|
}
|
||||||
function similarity(descriptor1, descriptor2, options3 = { order: 2, multiplier: 20 }) {
|
var normalizeDistance = (dist, order, min2, max4) => {
|
||||||
|
if (dist === 0)
|
||||||
|
return 1;
|
||||||
|
const root = order === 2 ? Math.sqrt(dist) : dist ** (1 / order);
|
||||||
|
const norm = (1 - root / 100 - min2) / (max4 - min2);
|
||||||
|
const clamp2 = Math.max(Math.min(norm, 1), 0);
|
||||||
|
return clamp2;
|
||||||
|
};
|
||||||
|
function similarity(descriptor1, descriptor2, options3 = { order: 2, multiplier: 25, min: 0.2, max: 0.8 }) {
|
||||||
const dist = distance(descriptor1, descriptor2, options3);
|
const dist = distance(descriptor1, descriptor2, options3);
|
||||||
const root = !options3.order || options3.order === 2 ? Math.sqrt(dist) : dist ** (1 / options3.order);
|
return normalizeDistance(dist, options3.order || 2, options3.min || 0, options3.max || 1);
|
||||||
const invert = Math.max(0, 100 - root) / 100;
|
|
||||||
return invert;
|
|
||||||
}
|
}
|
||||||
function match2(descriptor, descriptors, options3 = { order: 2, multiplier: 20, threshold: 0 }) {
|
function match2(descriptor, descriptors, options3 = { order: 2, multiplier: 25, threshold: 0, min: 0.2, max: 0.8 }) {
|
||||||
if (!Array.isArray(descriptor) || !Array.isArray(descriptors) || descriptor.length < 64 || descriptors.length === 0 || descriptor.length !== descriptors[0].length) {
|
if (!Array.isArray(descriptor) || !Array.isArray(descriptors) || descriptor.length < 64 || descriptors.length === 0 || descriptor.length !== descriptors[0].length) {
|
||||||
return { index: -1, distance: Number.POSITIVE_INFINITY, similarity: 0 };
|
return { index: -1, distance: Number.POSITIVE_INFINITY, similarity: 0 };
|
||||||
}
|
}
|
||||||
let best = Number.MAX_SAFE_INTEGER;
|
let lowestDistance = Number.MAX_SAFE_INTEGER;
|
||||||
let index2 = -1;
|
let index2 = -1;
|
||||||
for (let i = 0; i < descriptors.length; i++) {
|
for (let i = 0; i < descriptors.length; i++) {
|
||||||
const res = distance(descriptor, descriptors[i], options3);
|
const res = distance(descriptor, descriptors[i], options3);
|
||||||
if (res < best) {
|
if (res < lowestDistance) {
|
||||||
best = res;
|
lowestDistance = res;
|
||||||
index2 = i;
|
index2 = i;
|
||||||
}
|
}
|
||||||
if (best < (options3.threshold || 0))
|
if (lowestDistance < (options3.threshold || 0))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
best = !options3.order || options3.order === 2 ? Math.sqrt(best) : best ** (1 / options3.order);
|
const normalizedSimilarity = normalizeDistance(lowestDistance, options3.order || 2, options3.min || 0, options3.max || 1);
|
||||||
return { index: index2, distance: best, similarity: Math.max(0, 100 - best) / 100 };
|
return { index: index2, distance: lowestDistance, similarity: normalizedSimilarity };
|
||||||
}
|
}
|
||||||
|
|
||||||
// src/util/persons.ts
|
// src/util/persons.ts
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/** Face descriptor type as number array */
|
/** Face descriptor type as number array */
|
||||||
export type Descriptor = Array<number>
|
export type Descriptor = Array<number>
|
||||||
export type Options = { order?: number, threshold?: number, multiplier?: number } | undefined;
|
export type MatchOptions = { order?: number, threshold?: number, multiplier?: number, min?: number, max?: number } | undefined;
|
||||||
|
|
||||||
/** Calculates distance between two descriptors
|
/** Calculates distance between two descriptors
|
||||||
* @param {object} options
|
* @param {object} options
|
||||||
|
@ -10,7 +10,7 @@ export type Options = { order?: number, threshold?: number, multiplier?: number
|
||||||
* - default is 20 which normalizes results to similarity above 0.5 can be considered a match
|
* - default is 20 which normalizes results to similarity above 0.5 can be considered a match
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
export function distance(descriptor1: Descriptor, descriptor2: Descriptor, options: Options = { order: 2, multiplier: 20 }) {
|
export function distance(descriptor1: Descriptor, descriptor2: Descriptor, options: MatchOptions = { order: 2, multiplier: 25 }) {
|
||||||
// general minkowski distance, euclidean distance is limited case where order is 2
|
// general minkowski distance, euclidean distance is limited case where order is 2
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
for (let i = 0; i < descriptor1.length; i++) {
|
for (let i = 0; i < descriptor1.length; i++) {
|
||||||
|
@ -20,19 +20,29 @@ export function distance(descriptor1: Descriptor, descriptor2: Descriptor, optio
|
||||||
return (options.multiplier || 20) * sum;
|
return (options.multiplier || 20) * sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// invert distance to similarity, normalize to given range and clamp
|
||||||
|
const normalizeDistance = (dist, order, min, max) => {
|
||||||
|
if (dist === 0) return 1; // short circuit for identical inputs
|
||||||
|
const root = order === 2 ? Math.sqrt(dist) : dist ** (1 / order); // take root of distance
|
||||||
|
const norm = (1 - (root / 100) - min) / (max - min); // normalize to range
|
||||||
|
const clamp = Math.max(Math.min(norm, 1), 0); // clamp to 0..1
|
||||||
|
return clamp;
|
||||||
|
};
|
||||||
|
|
||||||
/** Calculates normalized similarity between two face descriptors based on their `distance`
|
/** Calculates normalized similarity between two face descriptors based on their `distance`
|
||||||
* @param {object} options
|
* @param {object} options
|
||||||
* @param {number} options.order algorithm to use
|
* @param {number} options.order algorithm to use
|
||||||
* - Euclidean distance if `order` is 2 (default), Minkowski distance algorithm of nth order if `order` is higher than 2
|
* - Euclidean distance if `order` is 2 (default), Minkowski distance algorithm of nth order if `order` is higher than 2
|
||||||
* @param {number} options.multiplier by how much to enhance difference analysis in range of 1..100
|
* @param {number} options.multiplier by how much to enhance difference analysis in range of 1..100
|
||||||
* - default is 20 which normalizes results to similarity above 0.5 can be considered a match
|
* - default is 20 which normalizes results to similarity above 0.5 can be considered a match
|
||||||
|
* @param {number} options.min normalize similarity result to a given range
|
||||||
|
* @param {number} options.max normalzie similarity resutl to a given range
|
||||||
|
* - default is 0.2...0.8
|
||||||
* @returns {number} similarity between two face descriptors normalized to 0..1 range where 0 is no similarity and 1 is perfect similarity
|
* @returns {number} similarity between two face descriptors normalized to 0..1 range where 0 is no similarity and 1 is perfect similarity
|
||||||
*/
|
*/
|
||||||
export function similarity(descriptor1: Descriptor, descriptor2: Descriptor, options: Options = { order: 2, multiplier: 20 }) {
|
export function similarity(descriptor1: Descriptor, descriptor2: Descriptor, options: MatchOptions = { order: 2, multiplier: 25, min: 0.2, max: 0.8 }) {
|
||||||
const dist = distance(descriptor1, descriptor2, options);
|
const dist = distance(descriptor1, descriptor2, options);
|
||||||
const root = (!options.order || options.order === 2) ? Math.sqrt(dist) : dist ** (1 / options.order);
|
return normalizeDistance(dist, options.order || 2, options.min || 0, options.max || 1);
|
||||||
const invert = Math.max(0, 100 - root) / 100.0;
|
|
||||||
return invert;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Matches given descriptor to a closest entry in array of descriptors
|
/** Matches given descriptor to a closest entry in array of descriptors
|
||||||
|
@ -46,20 +56,20 @@ export function similarity(descriptor1: Descriptor, descriptor2: Descriptor, opt
|
||||||
* - {@link distance} calculated `distance` of given descriptor to the best match
|
* - {@link distance} calculated `distance` of given descriptor to the best match
|
||||||
* - {@link similarity} calculated normalized `similarity` of given descriptor to the best match
|
* - {@link similarity} calculated normalized `similarity` of given descriptor to the best match
|
||||||
*/
|
*/
|
||||||
export function match(descriptor: Descriptor, descriptors: Array<Descriptor>, options: Options = { order: 2, multiplier: 20, threshold: 0 }) {
|
export function match(descriptor: Descriptor, descriptors: Array<Descriptor>, options: MatchOptions = { order: 2, multiplier: 25, threshold: 0, min: 0.2, max: 0.8 }) {
|
||||||
if (!Array.isArray(descriptor) || !Array.isArray(descriptors) || descriptor.length < 64 || descriptors.length === 0 || descriptor.length !== descriptors[0].length) { // validate input
|
if (!Array.isArray(descriptor) || !Array.isArray(descriptors) || descriptor.length < 64 || descriptors.length === 0 || descriptor.length !== descriptors[0].length) { // validate input
|
||||||
return { index: -1, distance: Number.POSITIVE_INFINITY, similarity: 0 };
|
return { index: -1, distance: Number.POSITIVE_INFINITY, similarity: 0 };
|
||||||
}
|
}
|
||||||
let best = Number.MAX_SAFE_INTEGER;
|
let lowestDistance = Number.MAX_SAFE_INTEGER;
|
||||||
let index = -1;
|
let index = -1;
|
||||||
for (let i = 0; i < descriptors.length; i++) {
|
for (let i = 0; i < descriptors.length; i++) {
|
||||||
const res = distance(descriptor, descriptors[i], options);
|
const res = distance(descriptor, descriptors[i], options);
|
||||||
if (res < best) {
|
if (res < lowestDistance) {
|
||||||
best = res;
|
lowestDistance = res;
|
||||||
index = i;
|
index = i;
|
||||||
}
|
}
|
||||||
if (best < (options.threshold || 0)) break;
|
if (lowestDistance < (options.threshold || 0)) break;
|
||||||
}
|
}
|
||||||
best = (!options.order || options.order === 2) ? Math.sqrt(best) : best ** (1 / options.order);
|
const normalizedSimilarity = normalizeDistance(lowestDistance, options.order || 2, options.min || 0, options.max || 1);
|
||||||
return { index, distance: best, similarity: Math.max(0, 100 - best) / 100.0 };
|
return { index, distance: lowestDistance, similarity: normalizedSimilarity };
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
2021-11-11 11:24:03 [36mINFO: [39m @vladmandic/human version 2.5.1
|
2021-11-11 16:47:37 [36mINFO: [39m @vladmandic/human version 2.5.1
|
||||||
2021-11-11 11:24:03 [36mINFO: [39m User: vlado Platform: linux Arch: x64 Node: v17.0.1
|
2021-11-11 16:47:37 [36mINFO: [39m User: vlado Platform: linux Arch: x64 Node: v17.0.1
|
||||||
2021-11-11 11:24:03 [36mINFO: [39m Application: {"name":"@vladmandic/human","version":"2.5.1"}
|
2021-11-11 16:47:37 [36mINFO: [39m Application: {"name":"@vladmandic/human","version":"2.5.1"}
|
||||||
2021-11-11 11:24:03 [36mINFO: [39m Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true}
|
2021-11-11 16:47:37 [36mINFO: [39m Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true}
|
||||||
2021-11-11 11:24:03 [36mINFO: [39m Toolchain: {"build":"0.6.3","esbuild":"0.13.13","typescript":"4.4.4","typedoc":"0.22.8","eslint":"8.2.0"}
|
2021-11-11 16:47:37 [36mINFO: [39m Toolchain: {"build":"0.6.3","esbuild":"0.13.13","typescript":"4.4.4","typedoc":"0.22.8","eslint":"8.2.0"}
|
||||||
2021-11-11 11:24:03 [36mINFO: [39m Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]}
|
2021-11-11 16:47:37 [36mINFO: [39m Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]}
|
||||||
2021-11-11 11:24:03 [35mSTATE:[39m Clean: {"locations":["dist/*","types/*","typedoc/*"]}
|
2021-11-11 16:47:37 [35mSTATE:[39m Clean: {"locations":["dist/*","types/*","typedoc/*"]}
|
||||||
2021-11-11 11:24:03 [35mSTATE:[39m Compile: {"name":"tfjs/nodejs/cpu","format":"cjs","platform":"node","input":"tfjs/tf-node.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":102,"outputBytes":1275}
|
2021-11-11 16:47:37 [35mSTATE:[39m Compile: {"name":"tfjs/nodejs/cpu","format":"cjs","platform":"node","input":"tfjs/tf-node.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":102,"outputBytes":1275}
|
||||||
2021-11-11 11:24:03 [35mSTATE:[39m Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":57,"inputBytes":527509,"outputBytes":445576}
|
2021-11-11 16:47:37 [35mSTATE:[39m Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":57,"inputBytes":528202,"outputBytes":445886}
|
||||||
2021-11-11 11:24:03 [35mSTATE:[39m Compile: {"name":"tfjs/nodejs/gpu","format":"cjs","platform":"node","input":"tfjs/tf-node-gpu.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":110,"outputBytes":1283}
|
2021-11-11 16:47:37 [35mSTATE:[39m Compile: {"name":"tfjs/nodejs/gpu","format":"cjs","platform":"node","input":"tfjs/tf-node-gpu.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":110,"outputBytes":1283}
|
||||||
2021-11-11 11:24:03 [35mSTATE:[39m Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":57,"inputBytes":527517,"outputBytes":445580}
|
2021-11-11 16:47:38 [35mSTATE:[39m Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":57,"inputBytes":528210,"outputBytes":445890}
|
||||||
2021-11-11 11:24:03 [35mSTATE:[39m Compile: {"name":"tfjs/nodejs/wasm","format":"cjs","platform":"node","input":"tfjs/tf-node-wasm.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":149,"outputBytes":1350}
|
2021-11-11 16:47:38 [35mSTATE:[39m Compile: {"name":"tfjs/nodejs/wasm","format":"cjs","platform":"node","input":"tfjs/tf-node-wasm.ts","output":"dist/tfjs.esm.js","files":1,"inputBytes":149,"outputBytes":1350}
|
||||||
2021-11-11 11:24:04 [35mSTATE:[39m Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":57,"inputBytes":527584,"outputBytes":445652}
|
2021-11-11 16:47:38 [35mSTATE:[39m Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":57,"inputBytes":528277,"outputBytes":445962}
|
||||||
2021-11-11 11:24:04 [35mSTATE:[39m Compile: {"name":"tfjs/browser/version","format":"esm","platform":"browser","input":"tfjs/tf-version.ts","output":"dist/tfjs.version.js","files":1,"inputBytes":1063,"outputBytes":1652}
|
2021-11-11 16:47:38 [35mSTATE:[39m Compile: {"name":"tfjs/browser/version","format":"esm","platform":"browser","input":"tfjs/tf-version.ts","output":"dist/tfjs.version.js","files":1,"inputBytes":1063,"outputBytes":1652}
|
||||||
2021-11-11 11:24:04 [35mSTATE:[39m Compile: {"name":"tfjs/browser/esm/nobundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":2326,"outputBytes":912}
|
2021-11-11 16:47:38 [35mSTATE:[39m Compile: {"name":"tfjs/browser/esm/nobundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":2326,"outputBytes":912}
|
||||||
2021-11-11 11:24:04 [35mSTATE:[39m Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":57,"inputBytes":527146,"outputBytes":447674}
|
2021-11-11 16:47:38 [35mSTATE:[39m Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":57,"inputBytes":527839,"outputBytes":447984}
|
||||||
2021-11-11 11:24:04 [35mSTATE:[39m Compile: {"name":"tfjs/browser/esm/custom","format":"esm","platform":"browser","input":"tfjs/tf-custom.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":2562703,"outputBytes":2497652}
|
2021-11-11 16:47:38 [35mSTATE:[39m Compile: {"name":"tfjs/browser/esm/custom","format":"esm","platform":"browser","input":"tfjs/tf-custom.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":2562703,"outputBytes":2497652}
|
||||||
2021-11-11 11:24:04 [35mSTATE:[39m Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":57,"inputBytes":3023886,"outputBytes":1614842}
|
2021-11-11 16:47:39 [35mSTATE:[39m Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":57,"inputBytes":3024579,"outputBytes":1614926}
|
||||||
2021-11-11 11:24:05 [35mSTATE:[39m Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":57,"inputBytes":3023886,"outputBytes":2950895}
|
2021-11-11 16:47:39 [35mSTATE:[39m Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":57,"inputBytes":3024579,"outputBytes":2951207}
|
||||||
2021-11-11 11:24:30 [35mSTATE:[39m Typings: {"input":"src/human.ts","output":"types","files":50}
|
2021-11-11 16:48:01 [35mSTATE:[39m Typings: {"input":"src/human.ts","output":"types","files":50}
|
||||||
2021-11-11 11:24:38 [35mSTATE:[39m TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":50,"generated":true}
|
2021-11-11 16:48:08 [35mSTATE:[39m TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":50,"generated":true}
|
||||||
2021-11-11 11:24:38 [35mSTATE:[39m Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":5801,"outputBytes":3822}
|
2021-11-11 16:48:08 [35mSTATE:[39m Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":5801,"outputBytes":3822}
|
||||||
2021-11-11 11:24:38 [35mSTATE:[39m Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":13534,"outputBytes":10091}
|
2021-11-11 16:48:08 [35mSTATE:[39m Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":13584,"outputBytes":10354}
|
||||||
2021-11-11 11:25:16 [35mSTATE:[39m Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":90,"errors":0,"warnings":0}
|
2021-11-11 16:48:46 [35mSTATE:[39m Lint: {"locations":["*.json","src/**/*.ts","test/**/*.js","demo/**/*.js"],"files":90,"errors":0,"warnings":0}
|
||||||
2021-11-11 11:25:17 [35mSTATE:[39m ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"}
|
2021-11-11 16:48:47 [35mSTATE:[39m ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"}
|
||||||
2021-11-11 11:25:17 [36mINFO: [39m Done...
|
2021-11-11 16:48:47 [36mINFO: [39m Done...
|
||||||
|
|
1348
test/test.log
1348
test/test.log
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -1,9 +1,11 @@
|
||||||
/** Face descriptor type as number array */
|
/** Face descriptor type as number array */
|
||||||
export declare type Descriptor = Array<number>;
|
export declare type Descriptor = Array<number>;
|
||||||
export declare type Options = {
|
export declare type MatchOptions = {
|
||||||
order?: number;
|
order?: number;
|
||||||
threshold?: number;
|
threshold?: number;
|
||||||
multiplier?: number;
|
multiplier?: number;
|
||||||
|
min?: number;
|
||||||
|
max?: number;
|
||||||
} | undefined;
|
} | undefined;
|
||||||
/** Calculates distance between two descriptors
|
/** Calculates distance between two descriptors
|
||||||
* @param {object} options
|
* @param {object} options
|
||||||
|
@ -13,16 +15,19 @@ export declare type Options = {
|
||||||
* - default is 20 which normalizes results to similarity above 0.5 can be considered a match
|
* - default is 20 which normalizes results to similarity above 0.5 can be considered a match
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
export declare function distance(descriptor1: Descriptor, descriptor2: Descriptor, options?: Options): number;
|
export declare function distance(descriptor1: Descriptor, descriptor2: Descriptor, options?: MatchOptions): number;
|
||||||
/** Calculates normalized similarity between two face descriptors based on their `distance`
|
/** Calculates normalized similarity between two face descriptors based on their `distance`
|
||||||
* @param {object} options
|
* @param {object} options
|
||||||
* @param {number} options.order algorithm to use
|
* @param {number} options.order algorithm to use
|
||||||
* - Euclidean distance if `order` is 2 (default), Minkowski distance algorithm of nth order if `order` is higher than 2
|
* - Euclidean distance if `order` is 2 (default), Minkowski distance algorithm of nth order if `order` is higher than 2
|
||||||
* @param {number} options.multiplier by how much to enhance difference analysis in range of 1..100
|
* @param {number} options.multiplier by how much to enhance difference analysis in range of 1..100
|
||||||
* - default is 20 which normalizes results to similarity above 0.5 can be considered a match
|
* - default is 20 which normalizes results to similarity above 0.5 can be considered a match
|
||||||
|
* @param {number} options.min normalize similarity result to a given range
|
||||||
|
* @param {number} options.max normalzie similarity resutl to a given range
|
||||||
|
* - default is 0.2...0.8
|
||||||
* @returns {number} similarity between two face descriptors normalized to 0..1 range where 0 is no similarity and 1 is perfect similarity
|
* @returns {number} similarity between two face descriptors normalized to 0..1 range where 0 is no similarity and 1 is perfect similarity
|
||||||
*/
|
*/
|
||||||
export declare function similarity(descriptor1: Descriptor, descriptor2: Descriptor, options?: Options): number;
|
export declare function similarity(descriptor1: Descriptor, descriptor2: Descriptor, options?: MatchOptions): number;
|
||||||
/** Matches given descriptor to a closest entry in array of descriptors
|
/** Matches given descriptor to a closest entry in array of descriptors
|
||||||
* @param descriptor face descriptor
|
* @param descriptor face descriptor
|
||||||
* @param descriptors array of face descriptors to commpare given descriptor to
|
* @param descriptors array of face descriptors to commpare given descriptor to
|
||||||
|
@ -34,7 +39,7 @@ export declare function similarity(descriptor1: Descriptor, descriptor2: Descrip
|
||||||
* - {@link distance} calculated `distance` of given descriptor to the best match
|
* - {@link distance} calculated `distance` of given descriptor to the best match
|
||||||
* - {@link similarity} calculated normalized `similarity` of given descriptor to the best match
|
* - {@link similarity} calculated normalized `similarity` of given descriptor to the best match
|
||||||
*/
|
*/
|
||||||
export declare function match(descriptor: Descriptor, descriptors: Array<Descriptor>, options?: Options): {
|
export declare function match(descriptor: Descriptor, descriptors: Array<Descriptor>, options?: MatchOptions): {
|
||||||
index: number;
|
index: number;
|
||||||
distance: number;
|
distance: number;
|
||||||
similarity: number;
|
similarity: number;
|
||||||
|
|
Loading…
Reference in New Issue