exclude impossible detected face boxes

pull/115/head
Vladimir Mandic 2022-04-05 07:38:11 -04:00
parent 6cafeafba1
commit 2fce7338dc
21 changed files with 823 additions and 838 deletions

View File

@ -9,11 +9,12 @@
## Changelog
### **HEAD -> master** 2022/04/01 mandic00@live.com
### **1.6.7** 2022/04/01 mandic00@live.com
### **origin/master** 2022/03/10 45914394+abdemirza@users.noreply.github.com
- fixed typo error (#97)
### **1.6.6** 2022/03/04 mandic00@live.com

File diff suppressed because one or more lines are too long

548
dist/face-api.esm.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

490
dist/face-api.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

540
dist/tfjs.esm.js vendored

File diff suppressed because one or more lines are too long

View File

@ -57,15 +57,15 @@
"@tensorflow/tfjs-node-gpu": "^3.15.0",
"@types/node": "^17.0.23",
"@types/offscreencanvas": "^2019.6.4",
"@typescript-eslint/eslint-plugin": "^5.17.0",
"@typescript-eslint/parser": "^5.17.0",
"@typescript-eslint/eslint-plugin": "^5.18.0",
"@typescript-eslint/parser": "^5.18.0",
"@vladmandic/build": "^0.7.2",
"@vladmandic/pilogger": "^0.4.4",
"@vladmandic/tfjs": "github:vladmandic/tfjs",
"canvas": "^2.9.1",
"chokidar": "^3.5.3",
"dayjs": "^1.11.0",
"esbuild": "^0.14.29",
"esbuild": "^0.14.31",
"eslint": "^8.12.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.25.4",

View File

@ -128,9 +128,7 @@ export class Box<BoxType = any> implements IBoundingBox, IRect {
this.width + padX,
this.height + padY,
];
return new Box({
x, y, width, height,
});
return new Box({ x, y, width, height });
}
public clipAtImageBorders(imgWidth: number, imgHeight: number): Box<BoxType> {
@ -143,9 +141,7 @@ export class Box<BoxType = any> implements IBoundingBox, IRect {
const clippedWidth = Math.min(newWidth, imgWidth - clippedX);
const clippedHeight = Math.min(newHeight, imgHeight - clippedY);
return (new Box({
x: clippedX, y: clippedY, width: clippedWidth, height: clippedHeight,
})).floor();
return (new Box({ x: clippedX, y: clippedY, width: clippedWidth, height: clippedHeight })).floor();
}
public shift(sx: number, sy: number): Box<BoxType> {
@ -153,9 +149,7 @@ export class Box<BoxType = any> implements IBoundingBox, IRect {
const x = this.x + sx;
const y = this.y + sy;
return new Box({
x, y, width, height,
});
return new Box({ x, y, width, height });
}
public padAtBorders(imageHeight: number, imageWidth: number) {
@ -189,9 +183,7 @@ export class Box<BoxType = any> implements IBoundingBox, IRect {
y = 1;
}
return {
dy, edy, dx, edx, y, ey, x, ex, w, h,
};
return { dy, edy, dx, edx, y, ey, x, ex, w, h };
}
public calibrate(region: Box) {

View File

@ -25,17 +25,11 @@ export async function extractFaceTensors(imageTensor: tf.Tensor3D | tf.Tensor4D,
return tf.tidy(() => {
const [imgHeight, imgWidth, numChannels] = imageTensor.shape.slice(isTensor4D(imageTensor) ? 1 : 0);
const boxes = detections
.map((det) => (det instanceof FaceDetection
? det.forSize(imgWidth, imgHeight).box
: det))
const boxes = detections.map((det) => (det instanceof FaceDetection ? det.forSize(imgWidth, imgHeight).box : det))
.map((box) => box.clipAtImageBorders(imgWidth, imgHeight));
const faceTensors = boxes.map(({
x, y, width, height,
}) => tf.slice3d(imageTensor.as3D(imgHeight, imgWidth, numChannels), [y, x, 0], [height, width, numChannels]));
const faceTensors = boxes
.filter((box) => box.width > 0 && box.height > 0)
.map(({ x, y, width, height }) => tf.slice3d(imageTensor.as3D(imgHeight, imgWidth, numChannels), [y, x, 0], [height, width, numChannels]));
return faceTensors;
});
}

View File

@ -57,12 +57,9 @@ function calculateFaceAngle(mesh) {
return angle;
}
export function extendWithFaceLandmarks<
TSource extends WithFaceDetection<{}>,
TFaceLandmarks extends FaceLandmarks = FaceLandmarks68 >(sourceObj: TSource, unshiftedLandmarks: TFaceLandmarks): WithFaceLandmarks<TSource, TFaceLandmarks> {
export function extendWithFaceLandmarks<TSource extends WithFaceDetection<{}>, TFaceLandmarks extends FaceLandmarks = FaceLandmarks68 >(sourceObj: TSource, unshiftedLandmarks: TFaceLandmarks): WithFaceLandmarks<TSource, TFaceLandmarks> {
const { box: shift } = sourceObj.detection;
const landmarks = unshiftedLandmarks.shiftBy<TFaceLandmarks>(shift.x, shift.y);
const rect = landmarks.align();
const { imageDims } = sourceObj.detection;
const alignedRect = new FaceDetection(sourceObj.detection.score, rect.rescale(imageDims.reverse()), imageDims);

View File

@ -39,11 +39,12 @@ export class DetectAllFaceLandmarksTask<TSource extends WithFaceDetection<{}>> e
const faces: Array<HTMLCanvasElement | tf.Tensor3D> = this.input instanceof tf.Tensor
? await extractFaceTensors(this.input, detections)
: await extractFaces(this.input, detections);
const faceLandmarksByFace = await Promise.all(
faces.map((face) => this.landmarkNet.detectLandmarks(face)),
) as FaceLandmarks68[];
const faceLandmarksByFace = await Promise.all(faces.map((face) => this.landmarkNet.detectLandmarks(face))) as FaceLandmarks68[];
faces.forEach((f) => f instanceof tf.Tensor && f.dispose());
return parentResults.map((parentResult, i) => extendWithFaceLandmarks<TSource>(parentResult, faceLandmarksByFace[i]));
const result = parentResults
.filter((_parentResult, i) => faceLandmarksByFace[i])
.map((parentResult, i) => extendWithFaceLandmarks<TSource>(parentResult, faceLandmarksByFace[i]));
return result;
}
withFaceExpressions() {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long