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 ## Changelog
### **HEAD -> master** 2022/04/01 mandic00@live.com
### **1.6.7** 2022/04/01 mandic00@live.com ### **1.6.7** 2022/04/01 mandic00@live.com
- fixed typo error (#97)
### **origin/master** 2022/03/10 45914394+abdemirza@users.noreply.github.com
### **1.6.6** 2022/03/04 mandic00@live.com ### **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", "@tensorflow/tfjs-node-gpu": "^3.15.0",
"@types/node": "^17.0.23", "@types/node": "^17.0.23",
"@types/offscreencanvas": "^2019.6.4", "@types/offscreencanvas": "^2019.6.4",
"@typescript-eslint/eslint-plugin": "^5.17.0", "@typescript-eslint/eslint-plugin": "^5.18.0",
"@typescript-eslint/parser": "^5.17.0", "@typescript-eslint/parser": "^5.18.0",
"@vladmandic/build": "^0.7.2", "@vladmandic/build": "^0.7.2",
"@vladmandic/pilogger": "^0.4.4", "@vladmandic/pilogger": "^0.4.4",
"@vladmandic/tfjs": "github:vladmandic/tfjs", "@vladmandic/tfjs": "github:vladmandic/tfjs",
"canvas": "^2.9.1", "canvas": "^2.9.1",
"chokidar": "^3.5.3", "chokidar": "^3.5.3",
"dayjs": "^1.11.0", "dayjs": "^1.11.0",
"esbuild": "^0.14.29", "esbuild": "^0.14.31",
"eslint": "^8.12.0", "eslint": "^8.12.0",
"eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-import": "^2.25.4", "eslint-plugin-import": "^2.25.4",

View File

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

View File

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

View File

@ -57,12 +57,9 @@ function calculateFaceAngle(mesh) {
return angle; return angle;
} }
export function extendWithFaceLandmarks< export function extendWithFaceLandmarks<TSource extends WithFaceDetection<{}>, TFaceLandmarks extends FaceLandmarks = FaceLandmarks68 >(sourceObj: TSource, unshiftedLandmarks: TFaceLandmarks): WithFaceLandmarks<TSource, TFaceLandmarks> {
TSource extends WithFaceDetection<{}>,
TFaceLandmarks extends FaceLandmarks = FaceLandmarks68 >(sourceObj: TSource, unshiftedLandmarks: TFaceLandmarks): WithFaceLandmarks<TSource, TFaceLandmarks> {
const { box: shift } = sourceObj.detection; const { box: shift } = sourceObj.detection;
const landmarks = unshiftedLandmarks.shiftBy<TFaceLandmarks>(shift.x, shift.y); const landmarks = unshiftedLandmarks.shiftBy<TFaceLandmarks>(shift.x, shift.y);
const rect = landmarks.align(); const rect = landmarks.align();
const { imageDims } = sourceObj.detection; const { imageDims } = sourceObj.detection;
const alignedRect = new FaceDetection(sourceObj.detection.score, rect.rescale(imageDims.reverse()), imageDims); 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 const faces: Array<HTMLCanvasElement | tf.Tensor3D> = this.input instanceof tf.Tensor
? await extractFaceTensors(this.input, detections) ? await extractFaceTensors(this.input, detections)
: await extractFaces(this.input, detections); : await extractFaces(this.input, detections);
const faceLandmarksByFace = await Promise.all( const faceLandmarksByFace = await Promise.all(faces.map((face) => this.landmarkNet.detectLandmarks(face))) as FaceLandmarks68[];
faces.map((face) => this.landmarkNet.detectLandmarks(face)),
) as FaceLandmarks68[];
faces.forEach((f) => f instanceof tf.Tensor && f.dispose()); 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() { 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