Commit 391caaba by vincent

unit tests for toNetInput

parent f05a5f23
import { FaceDetection } from '../faceDetectionNet/FaceDetection';
import { FaceLandmarks } from '../faceLandmarkNet/FaceLandmarks';
import { DrawBoxOptions, DrawLandmarksOptions, DrawOptions, DrawTextOptions } from './types';
export declare function getDefaultDrawOptions(): DrawOptions;
export declare function drawBox(ctx: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, options: DrawBoxOptions): void;
export declare function drawText(ctx: CanvasRenderingContext2D, x: number, y: number, text: string, options: DrawTextOptions): void;
export declare function drawDetection(canvasArg: string | HTMLCanvasElement, detection: FaceDetection | FaceDetection[], options?: DrawBoxOptions & DrawTextOptions & {
withScore: boolean;
}): void;
export declare function drawLandmarks(canvasArg: string | HTMLCanvasElement, faceLandmarks: FaceLandmarks | FaceLandmarks[], options?: DrawLandmarksOptions & {
drawLines: boolean;
}): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var utils_1 = require("../utils");
function getDefaultDrawOptions() {
return {
color: 'blue',
lineWidth: 2,
fontSize: 20,
fontStyle: 'Georgia'
};
}
exports.getDefaultDrawOptions = getDefaultDrawOptions;
function drawBox(ctx, x, y, w, h, options) {
var drawOptions = Object.assign(getDefaultDrawOptions(), (options || {}));
ctx.strokeStyle = drawOptions.color;
ctx.lineWidth = drawOptions.lineWidth;
ctx.strokeRect(x, y, w, h);
}
exports.drawBox = drawBox;
function drawText(ctx, x, y, text, options) {
var drawOptions = Object.assign(getDefaultDrawOptions(), (options || {}));
var padText = 2 + drawOptions.lineWidth;
ctx.fillStyle = drawOptions.color;
ctx.font = drawOptions.fontSize + "px " + drawOptions.fontStyle;
ctx.fillText(text, x + padText, y + padText + (drawOptions.fontSize * 0.6));
}
exports.drawText = drawText;
function drawDetection(canvasArg, detection, options) {
var canvas = utils_1.getElement(canvasArg);
if (!(canvas instanceof HTMLCanvasElement)) {
throw new Error('drawBox - expected canvas to be of type: HTMLCanvasElement');
}
var detectionArray = Array.isArray(detection)
? detection
: [detection];
detectionArray.forEach(function (det) {
var _a = det.getBox(), x = _a.x, y = _a.y, width = _a.width, height = _a.height;
var drawOptions = Object.assign(getDefaultDrawOptions(), (options || {}));
var withScore = Object.assign({ withScore: true }, (options || {})).withScore;
var ctx = utils_1.getContext2dOrThrow(canvas);
drawBox(ctx, x, y, width, height, drawOptions);
if (withScore) {
drawText(ctx, x, y, "" + utils_1.round(det.getScore()), drawOptions);
}
});
}
exports.drawDetection = drawDetection;
function drawContour(ctx, points, isClosed) {
if (isClosed === void 0) { isClosed = false; }
ctx.beginPath();
points.slice(1).forEach(function (_a, prevIdx) {
var x = _a.x, y = _a.y;
var from = points[prevIdx];
ctx.moveTo(from.x, from.y);
ctx.lineTo(x, y);
});
if (isClosed) {
var from = points[points.length - 1];
var to = points[0];
if (!from || !to) {
return;
}
ctx.moveTo(from.x, from.y);
ctx.lineTo(to.x, to.y);
}
ctx.stroke();
}
function drawLandmarks(canvasArg, faceLandmarks, options) {
var canvas = utils_1.getElement(canvasArg);
if (!(canvas instanceof HTMLCanvasElement)) {
throw new Error('drawLandmarks - expected canvas to be of type: HTMLCanvasElement');
}
var drawOptions = Object.assign(getDefaultDrawOptions(), (options || {}));
var drawLines = Object.assign({ drawLines: false }, (options || {})).drawLines;
var ctx = utils_1.getContext2dOrThrow(canvas);
var lineWidth = drawOptions.lineWidth, color = drawOptions.color;
var faceLandmarksArray = Array.isArray(faceLandmarks) ? faceLandmarks : [faceLandmarks];
faceLandmarksArray.forEach(function (landmarks) {
if (drawLines) {
ctx.strokeStyle = color;
ctx.lineWidth = lineWidth;
drawContour(ctx, landmarks.getJawOutline());
drawContour(ctx, landmarks.getLeftEyeBrow());
drawContour(ctx, landmarks.getRightEyeBrow());
drawContour(ctx, landmarks.getNose());
drawContour(ctx, landmarks.getLeftEye(), true);
drawContour(ctx, landmarks.getRightEye(), true);
drawContour(ctx, landmarks.getMouth(), true);
return;
}
// else draw points
var ptOffset = lineWidth / 2;
ctx.fillStyle = color;
landmarks.getPositions().forEach(function (pt) { return ctx.fillRect(pt.x - ptOffset, pt.y - ptOffset, lineWidth, lineWidth); });
});
}
exports.drawLandmarks = drawLandmarks;
//# sourceMappingURL=index.js.map
\ No newline at end of file
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/drawing/index.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
export declare type DrawBoxOptions = {
lineWidth?: number;
color?: string;
};
export declare type DrawTextOptions = {
lineWidth?: number;
fontSize?: number;
fontStyle?: string;
color?: string;
};
export declare type DrawLandmarksOptions = {
lineWidth?: number;
color?: string;
};
export declare type DrawOptions = {
lineWidth: number;
fontSize: number;
fontStyle: string;
color: string;
};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=types.js.map
\ No newline at end of file
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/drawing/types.ts"],"names":[],"mappings":""}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
export { tf };
export * from './FullFaceDescription';
export * from './NetInput';
export * from './Point';
export * from './Rect';
export * from './drawing';
export * from './euclideanDistance';
export * from './extractFaces';
export * from './extractFaceTensors';
......
......@@ -4,8 +4,10 @@ var tslib_1 = require("tslib");
var tf = require("@tensorflow/tfjs-core");
exports.tf = tf;
tslib_1.__exportStar(require("./FullFaceDescription"), exports);
tslib_1.__exportStar(require("./NetInput"), exports);
tslib_1.__exportStar(require("./Point"), exports);
tslib_1.__exportStar(require("./Rect"), exports);
tslib_1.__exportStar(require("./drawing"), exports);
tslib_1.__exportStar(require("./euclideanDistance"), exports);
tslib_1.__exportStar(require("./extractFaces"), exports);
tslib_1.__exportStar(require("./extractFaceTensors"), exports);
......
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,0CAA4C;AAG1C,gBAAE;AAGJ,gEAAsC;AACtC,kDAAwB;AACxB,iDAAuB;AAEvB,8DAAoC;AACpC,yDAA8B;AAC9B,+DAAoC;AACpC,6DAAmC;AACnC,4DAAkC;AAClC,+DAAqC;AACrC,sDAA4B;AAC5B,wDAA8B;AAC9B,uDAA6B;AAC7B,kDAAuB"}
\ No newline at end of file
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,0CAA4C;AAG1C,gBAAE;AAGJ,gEAAsC;AACtC,qDAA2B;AAC3B,kDAAwB;AACxB,iDAAuB;AAEvB,oDAA0B;AAC1B,8DAAoC;AACpC,yDAA8B;AAC9B,+DAAoC;AACpC,6DAAmC;AACnC,4DAAkC;AAClC,+DAAqC;AACrC,sDAA4B;AAC5B,wDAA8B;AAC9B,uDAA6B;AAC7B,kDAAuB"}
\ No newline at end of file
......@@ -5,23 +5,3 @@ export declare type Dimensions = {
width: number;
height: number;
};
export declare type DrawBoxOptions = {
lineWidth?: number;
color?: string;
};
export declare type DrawTextOptions = {
lineWidth?: number;
fontSize?: number;
fontStyle?: string;
color?: string;
};
export declare type DrawLandmarksOptions = {
lineWidth?: number;
color?: string;
};
export declare type DrawOptions = {
lineWidth: number;
fontSize: number;
fontStyle: string;
color: string;
};
import * as tf from '@tensorflow/tfjs-core';
import { FaceDetection } from './faceDetectionNet/FaceDetection';
import { FaceLandmarks } from './faceLandmarkNet/FaceLandmarks';
import { Dimensions, DrawBoxOptions, DrawLandmarksOptions, DrawOptions, DrawTextOptions } from './types';
import { Dimensions } from './types';
export declare function isFloat(num: number): boolean;
export declare function isEven(num: number): boolean;
export declare function round(num: number): number;
......@@ -17,12 +15,3 @@ export declare function getMediaDimensions(media: HTMLImageElement | HTMLVideoEl
};
export declare function bufferToImage(buf: Blob): Promise<HTMLImageElement>;
export declare function imageTensorToCanvas(imgTensor: tf.Tensor4D, canvas?: HTMLCanvasElement): Promise<HTMLCanvasElement>;
export declare function getDefaultDrawOptions(): DrawOptions;
export declare function drawBox(ctx: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, options: DrawBoxOptions): void;
export declare function drawText(ctx: CanvasRenderingContext2D, x: number, y: number, text: string, options: DrawTextOptions): void;
export declare function drawDetection(canvasArg: string | HTMLCanvasElement, detection: FaceDetection | FaceDetection[], options?: DrawBoxOptions & DrawTextOptions & {
withScore: boolean;
}): void;
export declare function drawLandmarks(canvasArg: string | HTMLCanvasElement, faceLandmarks: FaceLandmarks | FaceLandmarks[], options?: DrawLandmarksOptions & {
drawLines: boolean;
}): void;
......@@ -22,8 +22,8 @@ function getElement(arg) {
}
exports.getElement = getElement;
function isLoaded(media) {
return media instanceof HTMLImageElement && media.complete
|| media instanceof HTMLVideoElement && media.readyState >= 3;
return (media instanceof HTMLImageElement && media.complete)
|| (media instanceof HTMLVideoElement && media.readyState >= 3);
}
exports.isLoaded = isLoaded;
function awaitMediaLoaded(media) {
......@@ -120,98 +120,4 @@ function imageTensorToCanvas(imgTensor, canvas) {
});
}
exports.imageTensorToCanvas = imageTensorToCanvas;
function getDefaultDrawOptions() {
return {
color: 'blue',
lineWidth: 2,
fontSize: 20,
fontStyle: 'Georgia'
};
}
exports.getDefaultDrawOptions = getDefaultDrawOptions;
function drawBox(ctx, x, y, w, h, options) {
var drawOptions = Object.assign(getDefaultDrawOptions(), (options || {}));
ctx.strokeStyle = drawOptions.color;
ctx.lineWidth = drawOptions.lineWidth;
ctx.strokeRect(x, y, w, h);
}
exports.drawBox = drawBox;
function drawText(ctx, x, y, text, options) {
var drawOptions = Object.assign(getDefaultDrawOptions(), (options || {}));
var padText = 2 + drawOptions.lineWidth;
ctx.fillStyle = drawOptions.color;
ctx.font = drawOptions.fontSize + "px " + drawOptions.fontStyle;
ctx.fillText(text, x + padText, y + padText + (drawOptions.fontSize * 0.6));
}
exports.drawText = drawText;
function drawDetection(canvasArg, detection, options) {
var canvas = getElement(canvasArg);
if (!(canvas instanceof HTMLCanvasElement)) {
throw new Error('drawBox - expected canvas to be of type: HTMLCanvasElement');
}
var detectionArray = Array.isArray(detection)
? detection
: [detection];
detectionArray.forEach(function (det) {
var _a = det.getBox(), x = _a.x, y = _a.y, width = _a.width, height = _a.height;
var drawOptions = Object.assign(getDefaultDrawOptions(), (options || {}));
var withScore = Object.assign({ withScore: true }, (options || {})).withScore;
var ctx = getContext2dOrThrow(canvas);
drawBox(ctx, x, y, width, height, drawOptions);
if (withScore) {
drawText(ctx, x, y, "" + round(det.getScore()), drawOptions);
}
});
}
exports.drawDetection = drawDetection;
function drawContour(ctx, points, isClosed) {
if (isClosed === void 0) { isClosed = false; }
ctx.beginPath();
points.slice(1).forEach(function (_a, prevIdx) {
var x = _a.x, y = _a.y;
var from = points[prevIdx];
ctx.moveTo(from.x, from.y);
ctx.lineTo(x, y);
});
if (isClosed) {
var from = points[points.length - 1];
var to = points[0];
if (!from || !to) {
return;
}
ctx.moveTo(from.x, from.y);
ctx.lineTo(to.x, to.y);
}
ctx.stroke();
}
function drawLandmarks(canvasArg, faceLandmarks, options) {
var canvas = getElement(canvasArg);
if (!(canvas instanceof HTMLCanvasElement)) {
throw new Error('drawLandmarks - expected canvas to be of type: HTMLCanvasElement');
}
var drawOptions = Object.assign(getDefaultDrawOptions(), (options || {}));
var drawLines = Object.assign({ drawLines: false }, (options || {})).drawLines;
var ctx = getContext2dOrThrow(canvas);
var lineWidth = drawOptions.lineWidth, color = drawOptions.color;
var faceLandmarksArray = Array.isArray(faceLandmarks) ? faceLandmarks : [faceLandmarks];
faceLandmarksArray.forEach(function (landmarks) {
if (drawLines) {
ctx.strokeStyle = color;
ctx.lineWidth = lineWidth;
drawContour(ctx, landmarks.getJawOutline());
drawContour(ctx, landmarks.getLeftEyeBrow());
drawContour(ctx, landmarks.getRightEyeBrow());
drawContour(ctx, landmarks.getNose());
drawContour(ctx, landmarks.getLeftEye(), true);
drawContour(ctx, landmarks.getRightEye(), true);
drawContour(ctx, landmarks.getMouth(), true);
return;
}
// else draw points
var ptOffset = lineWidth / 2;
ctx.fillStyle = color;
landmarks.getPositions().forEach(function (pt) { return ctx.fillRect(pt.x - ptOffset, pt.y - ptOffset, lineWidth, lineWidth); });
});
}
exports.drawLandmarks = drawLandmarks;
//# sourceMappingURL=utils.js.map
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
import { FaceDetection } from '../faceDetectionNet/FaceDetection';
import { FaceLandmarks } from '../faceLandmarkNet/FaceLandmarks';
import { Point } from '../Point';
import { getContext2dOrThrow, getElement, round } from '../utils';
import { DrawBoxOptions, DrawLandmarksOptions, DrawOptions, DrawTextOptions } from './types';
export function getDefaultDrawOptions(): DrawOptions {
return {
color: 'blue',
lineWidth: 2,
fontSize: 20,
fontStyle: 'Georgia'
}
}
export function drawBox(
ctx: CanvasRenderingContext2D,
x: number,
y: number,
w: number,
h: number,
options: DrawBoxOptions
) {
const drawOptions = Object.assign(
getDefaultDrawOptions(),
(options || {})
)
ctx.strokeStyle = drawOptions.color
ctx.lineWidth = drawOptions.lineWidth
ctx.strokeRect(x, y, w, h)
}
export function drawText(
ctx: CanvasRenderingContext2D,
x: number,
y: number,
text: string,
options: DrawTextOptions
) {
const drawOptions = Object.assign(
getDefaultDrawOptions(),
(options || {})
)
const padText = 2 + drawOptions.lineWidth
ctx.fillStyle = drawOptions.color
ctx.font = `${drawOptions.fontSize}px ${drawOptions.fontStyle}`
ctx.fillText(text, x + padText, y + padText + (drawOptions.fontSize * 0.6))
}
export function drawDetection(
canvasArg: string | HTMLCanvasElement,
detection: FaceDetection | FaceDetection[],
options?: DrawBoxOptions & DrawTextOptions & { withScore: boolean }
) {
const canvas = getElement(canvasArg)
if (!(canvas instanceof HTMLCanvasElement)) {
throw new Error('drawBox - expected canvas to be of type: HTMLCanvasElement')
}
const detectionArray = Array.isArray(detection)
? detection
: [detection]
detectionArray.forEach((det) => {
const {
x,
y,
width,
height
} = det.getBox()
const drawOptions = Object.assign(
getDefaultDrawOptions(),
(options || {})
)
const { withScore } = Object.assign({ withScore: true }, (options || {}))
const ctx = getContext2dOrThrow(canvas)
drawBox(
ctx,
x,
y,
width,
height,
drawOptions
)
if (withScore) {
drawText(
ctx,
x,
y,
`${round(det.getScore())}`,
drawOptions
)
}
})
}
function drawContour(
ctx: CanvasRenderingContext2D,
points: Point[],
isClosed: boolean = false
) {
ctx.beginPath()
points.slice(1).forEach(({ x, y }, prevIdx) => {
const from = points[prevIdx]
ctx.moveTo(from.x, from.y)
ctx.lineTo(x, y)
})
if (isClosed) {
const from = points[points.length - 1]
const to = points[0]
if (!from || !to) {
return
}
ctx.moveTo(from.x, from.y)
ctx.lineTo(to.x, to.y)
}
ctx.stroke()
}
export function drawLandmarks(
canvasArg: string | HTMLCanvasElement,
faceLandmarks: FaceLandmarks | FaceLandmarks[],
options?: DrawLandmarksOptions & { drawLines: boolean }
) {
const canvas = getElement(canvasArg)
if (!(canvas instanceof HTMLCanvasElement)) {
throw new Error('drawLandmarks - expected canvas to be of type: HTMLCanvasElement')
}
const drawOptions = Object.assign(
getDefaultDrawOptions(),
(options || {})
)
const { drawLines } = Object.assign({ drawLines: false }, (options || {}))
const ctx = getContext2dOrThrow(canvas)
const { lineWidth, color } = drawOptions
const faceLandmarksArray = Array.isArray(faceLandmarks) ? faceLandmarks : [faceLandmarks]
faceLandmarksArray.forEach(landmarks => {
if (drawLines) {
ctx.strokeStyle = color
ctx.lineWidth = lineWidth
drawContour(ctx, landmarks.getJawOutline())
drawContour(ctx, landmarks.getLeftEyeBrow())
drawContour(ctx, landmarks.getRightEyeBrow())
drawContour(ctx, landmarks.getNose())
drawContour(ctx, landmarks.getLeftEye(), true)
drawContour(ctx, landmarks.getRightEye(), true)
drawContour(ctx, landmarks.getMouth(), true)
return
}
// else draw points
const ptOffset = lineWidth / 2
ctx.fillStyle = color
landmarks.getPositions().forEach(pt => ctx.fillRect(pt.x - ptOffset, pt.y - ptOffset, lineWidth, lineWidth))
})
}
\ No newline at end of file
export type DrawBoxOptions = {
lineWidth?: number
color?: string
}
export type DrawTextOptions = {
lineWidth?: number
fontSize?: number
fontStyle?: string
color?: string
}
export type DrawLandmarksOptions = {
lineWidth?: number
color?: string
}
export type DrawOptions = {
lineWidth: number
fontSize: number
fontStyle: string
color: string
}
\ No newline at end of file
......@@ -5,9 +5,11 @@ export {
}
export * from './FullFaceDescription';
export * from './NetInput';
export * from './Point';
export * from './Rect';
export * from './drawing';
export * from './euclideanDistance';
export * from './extractFaces'
export * from './extractFaceTensors'
......
......@@ -7,28 +7,4 @@ export type TNetInput = TNetInputArg | Array<TNetInputArg>
export type Dimensions = {
width: number
height: number
}
export type DrawBoxOptions = {
lineWidth?: number
color?: string
}
export type DrawTextOptions = {
lineWidth?: number
fontSize?: number
fontStyle?: string
color?: string
}
export type DrawLandmarksOptions = {
lineWidth?: number
color?: string
}
export type DrawOptions = {
lineWidth: number
fontSize: number
fontStyle: string
color: string
}
\ No newline at end of file
import * as tf from '@tensorflow/tfjs-core';
import { FaceDetection } from './faceDetectionNet/FaceDetection';
import { FaceLandmarks } from './faceLandmarkNet/FaceLandmarks';
import { Point } from './Point';
import { Dimensions, DrawBoxOptions, DrawLandmarksOptions, DrawOptions, DrawTextOptions } from './types';
import { Dimensions } from './types';
export function isFloat(num: number) {
return num % 1 !== 0
......@@ -25,8 +22,8 @@ export function getElement(arg: string | any) {
}
export function isLoaded(media: HTMLImageElement | HTMLVideoElement) : boolean {
return media instanceof HTMLImageElement && media.complete
|| media instanceof HTMLVideoElement && media.readyState >= 3
return (media instanceof HTMLImageElement && media.complete)
|| (media instanceof HTMLVideoElement && media.readyState >= 3)
}
export function awaitMediaLoaded(media: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement) {
......@@ -118,170 +115,4 @@ export async function imageTensorToCanvas(
await tf.toPixels(imgTensor.as3D(height, width, numChannels).toInt(), targetCanvas)
return targetCanvas
}
export function getDefaultDrawOptions(): DrawOptions {
return {
color: 'blue',
lineWidth: 2,
fontSize: 20,
fontStyle: 'Georgia'
}
}
export function drawBox(
ctx: CanvasRenderingContext2D,
x: number,
y: number,
w: number,
h: number,
options: DrawBoxOptions
) {
const drawOptions = Object.assign(
getDefaultDrawOptions(),
(options || {})
)
ctx.strokeStyle = drawOptions.color
ctx.lineWidth = drawOptions.lineWidth
ctx.strokeRect(x, y, w, h)
}
export function drawText(
ctx: CanvasRenderingContext2D,
x: number,
y: number,
text: string,
options: DrawTextOptions
) {
const drawOptions = Object.assign(
getDefaultDrawOptions(),
(options || {})
)
const padText = 2 + drawOptions.lineWidth
ctx.fillStyle = drawOptions.color
ctx.font = `${drawOptions.fontSize}px ${drawOptions.fontStyle}`
ctx.fillText(text, x + padText, y + padText + (drawOptions.fontSize * 0.6))
}
export function drawDetection(
canvasArg: string | HTMLCanvasElement,
detection: FaceDetection | FaceDetection[],
options?: DrawBoxOptions & DrawTextOptions & { withScore: boolean }
) {
const canvas = getElement(canvasArg)
if (!(canvas instanceof HTMLCanvasElement)) {
throw new Error('drawBox - expected canvas to be of type: HTMLCanvasElement')
}
const detectionArray = Array.isArray(detection)
? detection
: [detection]
detectionArray.forEach((det) => {
const {
x,
y,
width,
height
} = det.getBox()
const drawOptions = Object.assign(
getDefaultDrawOptions(),
(options || {})
)
const { withScore } = Object.assign({ withScore: true }, (options || {}))
const ctx = getContext2dOrThrow(canvas)
drawBox(
ctx,
x,
y,
width,
height,
drawOptions
)
if (withScore) {
drawText(
ctx,
x,
y,
`${round(det.getScore())}`,
drawOptions
)
}
})
}
function drawContour(
ctx: CanvasRenderingContext2D,
points: Point[],
isClosed: boolean = false
) {
ctx.beginPath()
points.slice(1).forEach(({ x, y }, prevIdx) => {
const from = points[prevIdx]
ctx.moveTo(from.x, from.y)
ctx.lineTo(x, y)
})
if (isClosed) {
const from = points[points.length - 1]
const to = points[0]
if (!from || !to) {
return
}
ctx.moveTo(from.x, from.y)
ctx.lineTo(to.x, to.y)
}
ctx.stroke()
}
export function drawLandmarks(
canvasArg: string | HTMLCanvasElement,
faceLandmarks: FaceLandmarks | FaceLandmarks[],
options?: DrawLandmarksOptions & { drawLines: boolean }
) {
const canvas = getElement(canvasArg)
if (!(canvas instanceof HTMLCanvasElement)) {
throw new Error('drawLandmarks - expected canvas to be of type: HTMLCanvasElement')
}
const drawOptions = Object.assign(
getDefaultDrawOptions(),
(options || {})
)
const { drawLines } = Object.assign({ drawLines: false }, (options || {}))
const ctx = getContext2dOrThrow(canvas)
const { lineWidth, color } = drawOptions
const faceLandmarksArray = Array.isArray(faceLandmarks) ? faceLandmarks : [faceLandmarks]
faceLandmarksArray.forEach(landmarks => {
if (drawLines) {
ctx.strokeStyle = color
ctx.lineWidth = lineWidth
drawContour(ctx, landmarks.getJawOutline())
drawContour(ctx, landmarks.getLeftEyeBrow())
drawContour(ctx, landmarks.getRightEyeBrow())
drawContour(ctx, landmarks.getNose())
drawContour(ctx, landmarks.getLeftEye(), true)
drawContour(ctx, landmarks.getRightEye(), true)
drawContour(ctx, landmarks.getMouth(), true)
return
}
// else draw points
const ptOffset = lineWidth / 2
ctx.fillStyle = color
landmarks.getPositions().forEach(pt => ctx.fillRect(pt.x - ptOffset, pt.y - ptOffset, lineWidth, lineWidth))
})
}
\ No newline at end of file
import { getModelUris } from '../src/commons/loadWeightMap';
import { getModelUris } from '../../../src/commons/loadWeightMap';
const FAKE_DEFAULT_MODEL_NAME = 'default_model_name'
......
import * as faceapi from '../../src';
import { FaceDetection } from '../../src/faceDetectionNet/FaceDetection';
import { IRect } from '../../src/Rect';
import { expectMaxDelta } from '../utils';
import * as faceapi from '../../../src';
import { FaceDetection } from '../../../src/faceDetectionNet/FaceDetection';
import { IRect } from '../../../src/Rect';
import { expectMaxDelta } from '../../utils';
function expectRectClose(
result: IRect,
......
import * as faceapi from '../../src';
import { FaceLandmarks } from '../../src/faceLandmarkNet/FaceLandmarks';
import { Point } from '../../src/Point';
import { expectMaxDelta } from '../utils';
import * as faceapi from '../../../src';
import { FaceLandmarks } from '../../../src/faceLandmarkNet/FaceLandmarks';
import { Point } from '../../../src/Point';
import { expectMaxDelta } from '../../utils';
describe('faceLandmarkNet', () => {
......
import * as faceapi from '../../src';
import * as faceapi from '../../../src';
describe('faceRecognitionNet', () => {
......
import * as tf from '@tensorflow/tfjs-core';
import { padToSquare } from '../src/padToSquare';
import { ones, zeros } from './utils';
import { padToSquare } from '../../src/padToSquare';
import { ones, zeros } from '../utils';
describe('padToSquare', () => {
......
import { NetInput } from '../../src/NetInput';
import { toNetInput } from '../../src/toNetInput';
describe('toNetInput', () => {
describe('valid args', () => {
it('from HTMLImageElement', async () => {
const netInput = await toNetInput(document.createElement('img'))
expect(netInput instanceof NetInput).toBe(true)
expect(netInput.canvases.length).toEqual(1)
})
it('from HTMLVideoElement', async () => {
const videoEl = document.createElement('video')
spyOnProperty(videoEl, 'readyState', 'get').and.returnValue(4)
const netInput = await toNetInput(videoEl)
expect(netInput instanceof NetInput).toBe(true)
expect(netInput.canvases.length).toEqual(1)
})
it('from HTMLCanvasElement', async () => {
const netInput = await toNetInput(document.createElement('canvas'))
expect(netInput instanceof NetInput).toBe(true)
expect(netInput.canvases.length).toEqual(1)
})
it('from HTMLImageElement array', async () => {
const netInput = await toNetInput([
document.createElement('img'),
document.createElement('img')
])
expect(netInput instanceof NetInput).toBe(true)
expect(netInput.canvases.length).toEqual(2)
})
it('from HTMLVideoElement array', async () => {
const videoElements = [
document.createElement('video'),
document.createElement('video')
]
videoElements.forEach(videoEl =>
spyOnProperty(videoEl, 'readyState', 'get').and.returnValue(4)
)
const netInput = await toNetInput(videoElements)
expect(netInput instanceof NetInput).toBe(true)
expect(netInput.canvases.length).toEqual(2)
})
it('from HTMLCanvasElement array', async () => {
const netInput = await toNetInput([
document.createElement('canvas'),
document.createElement('canvas')
])
expect(netInput instanceof NetInput).toBe(true)
expect(netInput.canvases.length).toEqual(2)
})
it('from mixed media array', async () => {
const videoEl = document.createElement('video')
spyOnProperty(videoEl, 'readyState', 'get').and.returnValue(4)
const netInput = await toNetInput([
document.createElement('img'),
document.createElement('canvas'),
videoEl
])
expect(netInput instanceof NetInput).toBe(true)
expect(netInput.canvases.length).toEqual(3)
})
})
describe('invalid args', () => {
it('undefined', async () => {
let errorMessage
try {
await toNetInput(undefined as any)
} catch (error) {
errorMessage = error.message;
}
expect(errorMessage).toBe('toNetInput - expected media to be of type HTMLImageElement | HTMLVideoElement | HTMLCanvasElement, or to be an element id')
})
it('empty array', async () => {
let errorMessage
try {
await toNetInput([])
} catch (error) {
errorMessage = error.message;
}
expect(errorMessage).toBe('toNetInput - empty array passed as input')
})
it('undefined at input index 1', async () => {
let errorMessage
try {
await toNetInput([document.createElement('img'), undefined] as any)
} catch (error) {
errorMessage = error.message;
}
expect(errorMessage).toBe('toNetInput - at input index 1: expected media to be of type HTMLImageElement | HTMLVideoElement | HTMLCanvasElement, or to be an element id')
})
})
})
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