face-api/src/draw/DrawFaceLandmarks.ts

97 lines
3.3 KiB
TypeScript
Raw Normal View History

2020-12-19 17:46:41 +01:00
import { IPoint } from '../classes/index';
2020-08-18 13:54:53 +02:00
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 => {
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)
})
}