UNPKG

@vladmandic/face-api

Version:

FaceAPI: AI-powered Face Detection & Rotation Tracking, Face Description & Recognition, Age & Gender & Emotion Prediction for Browser and NodeJS using TensorFlow/JS

110 lines (90 loc) 3.53 kB
/* eslint-disable max-classes-per-file */ import { IPoint } from '../classes/index'; import { FaceLandmarks } from '../classes/FaceLandmarks'; import { FaceLandmarks68 } from '../classes/FaceLandmarks68'; import { getContext2dOrThrow } from '../dom/getContext2dOrThrow'; import { WithFaceDetection } from '../factories/WithFaceDetection'; import { isWithFaceLandmarks, WithFaceLandmarks } from '../factories/WithFaceLandmarks'; import { drawContour } from './drawContour'; export interface IDrawFaceLandmarksOptions { drawLines?: boolean drawPoints?: boolean lineWidth?: number pointSize?: number lineColor?: string pointColor?: string } export class DrawFaceLandmarksOptions { public drawLines: boolean public drawPoints: boolean public lineWidth: number public pointSize: number public lineColor: string public pointColor: string constructor(options: IDrawFaceLandmarksOptions = {}) { const { drawLines = true, drawPoints = true, lineWidth, lineColor, pointSize, pointColor, } = options; this.drawLines = drawLines; this.drawPoints = drawPoints; this.lineWidth = lineWidth || 1; this.pointSize = pointSize || 2; this.lineColor = lineColor || 'rgba(0, 255, 255, 1)'; this.pointColor = pointColor || 'rgba(255, 0, 255, 1)'; } } export class DrawFaceLandmarks { public faceLandmarks: FaceLandmarks public options: DrawFaceLandmarksOptions constructor( faceLandmarks: FaceLandmarks, options: IDrawFaceLandmarksOptions = {}, ) { this.faceLandmarks = faceLandmarks; this.options = new DrawFaceLandmarksOptions(options); } draw(canvasArg: string | HTMLCanvasElement | CanvasRenderingContext2D) { const ctx = getContext2dOrThrow(canvasArg); const { drawLines, drawPoints, lineWidth, lineColor, pointSize, pointColor, } = this.options; if (drawLines && this.faceLandmarks instanceof FaceLandmarks68) { ctx.strokeStyle = lineColor; ctx.lineWidth = lineWidth; drawContour(ctx, this.faceLandmarks.getJawOutline()); drawContour(ctx, this.faceLandmarks.getLeftEyeBrow()); drawContour(ctx, this.faceLandmarks.getRightEyeBrow()); drawContour(ctx, this.faceLandmarks.getNose()); drawContour(ctx, this.faceLandmarks.getLeftEye(), true); drawContour(ctx, this.faceLandmarks.getRightEye(), true); drawContour(ctx, this.faceLandmarks.getMouth(), true); } if (drawPoints) { ctx.strokeStyle = pointColor; ctx.fillStyle = pointColor; const drawPoint = (pt: IPoint) => { ctx.beginPath(); ctx.arc(pt.x, pt.y, pointSize, 0, 2 * Math.PI); ctx.fill(); }; this.faceLandmarks.positions.forEach(drawPoint); } } } export type DrawFaceLandmarksInput = FaceLandmarks | WithFaceLandmarks<WithFaceDetection<{}>> export function drawFaceLandmarks( canvasArg: string | HTMLCanvasElement, faceLandmarks: DrawFaceLandmarksInput | Array<DrawFaceLandmarksInput>, ) { const faceLandmarksArray = Array.isArray(faceLandmarks) ? faceLandmarks : [faceLandmarks]; faceLandmarksArray.forEach((f) => { // eslint-disable-next-line no-nested-ternary const landmarks = f instanceof FaceLandmarks ? f : (isWithFaceLandmarks(f) ? f.landmarks : undefined); if (!landmarks) { throw new Error('drawFaceLandmarks - expected faceExpressions to be FaceLandmarks | WithFaceLandmarks<WithFaceDetection<{}>> or array thereof'); } new DrawFaceLandmarks(landmarks).draw(canvasArg); }); }