Skip to content

Commit 16b7dc6

Browse files
implement drawFaceExpressions helper and use them in examples + nodejs face expression recognition example
1 parent c77c4d0 commit 16b7dc6

File tree

9 files changed

+103
-24
lines changed

9 files changed

+103
-24
lines changed

examples/examples-browser/public/js/drawing.js

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,25 +38,5 @@ function drawExpressions(dimensions, canvas, results, thresh, withBoxes = true)
3838
faceapi.drawDetection(canvas, resizedResults.map(det => det.detection), { withScore: false })
3939
}
4040

41-
resizedResults.forEach(res => {
42-
const { box, imageDims } = res.detection
43-
const { expressions } = res
44-
45-
const sorted = expressions.sort((a, b) => b.probability - a.probability)
46-
const resultsToDisplay = sorted.filter(expr => expr.probability > thresh)
47-
48-
let offset = (box.y + box.height + resultsToDisplay.length * 22) > imageDims.height
49-
? - (resultsToDisplay.length * 22)
50-
: 0
51-
resultsToDisplay.forEach((expr, i) => {
52-
const text = `${expr.expression} (${faceapi.round(expr.probability)})`
53-
faceapi.drawText(
54-
faceapi.getContext2dOrThrow($('#overlay').get(0)),
55-
box.x,
56-
box.y + box.height + i * 22 + offset,
57-
text,
58-
{ textColor: i === 0 ? 'red' : 'blue', fontSize: i === 0 ? 22 : 16 }
59-
)
60-
})
61-
})
41+
faceapi.drawFaceExpressions(canvas, resizedResults.map(({ detection, expressions }) => ({ position: detection.box, expressions })))
6242
}

examples/examples-browser/public/styles.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
right: 0;
44
margin: auto;
55
margin-top: 20px;
6-
padding-left: 260px;
6+
padding-left: 280px;
77
display: inline-flex !important;
88
}
99

examples/examples-nodejs/faceDetection.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ async function run() {
1111
faceapi.drawDetection(out, detections)
1212

1313
saveFile('faceDetection.jpg', out.toBuffer('image/jpeg'))
14+
console.log('done, saved results to out/faceDetection.jpg')
1415
}
1516

1617
run()
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { canvas, faceapi, faceDetectionNet, faceDetectionOptions, saveFile } from './commons';
2+
3+
async function run() {
4+
5+
await faceDetectionNet.loadFromDisk('../../weights')
6+
await faceapi.nets.faceExpressionNet.loadFromDisk('../../weights')
7+
8+
const img = await canvas.loadImage('../images/surprised.jpg')
9+
const results = await faceapi.detectAllFaces(img, faceDetectionOptions)
10+
.withFaceExpressions()
11+
12+
const out = faceapi.createCanvasFromMedia(img) as any
13+
faceapi.drawDetection(out, results.map(res => res.detection), { withScore: false })
14+
faceapi.drawFaceExpressions(out, results.map(({ detection, expressions }) => ({ position: detection.box, expressions })))
15+
16+
saveFile('faceExpressionRecognition.jpg', out.toBuffer('image/jpeg'))
17+
console.log('done, saved results to out/faceExpressionRecognition.jpg')
18+
}
19+
20+
run()

examples/examples-nodejs/faceLandmarkDetection.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ async function run() {
1414
faceapi.drawLandmarks(out, results.map(res => res.landmarks), { drawLines: true, color: 'red' })
1515

1616
saveFile('faceLandmarkDetection.jpg', out.toBuffer('image/jpeg'))
17+
console.log('done, saved results to out/faceLandmarkDetection.jpg')
1718
}
1819

1920
run()

examples/examples-nodejs/faceRecognition.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ async function run() {
3838
const outQuery = faceapi.createCanvasFromMedia(queryImage) as any
3939
faceapi.drawDetection(outQuery, queryBoxesWithText)
4040
saveFile('queryImage.jpg', outQuery.toBuffer('image/jpeg'))
41+
console.log('done, saved results to out/queryImage.jpg')
4142
}
4243

4344
run()

src/dom/drawFaceExpressions.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { drawText, env, getContext2dOrThrow, getDefaultDrawOptions, resolveInput, round } from 'tfjs-image-recognition-base';
2+
import { IRect } from 'tfjs-tiny-yolov2';
3+
4+
import { DrawFaceExpressionsInput, DrawFaceExpressionsOptions } from './types';
5+
6+
export function drawFaceExpressions(
7+
canvasArg: string | HTMLCanvasElement,
8+
faceExpressions: DrawFaceExpressionsInput | DrawFaceExpressionsInput[],
9+
options?: DrawFaceExpressionsOptions
10+
) {
11+
const canvas = resolveInput(canvasArg)
12+
if (!(canvas instanceof env.getEnv().Canvas)) {
13+
throw new Error('drawFaceExpressions - expected canvas to be of type: HTMLCanvasElement')
14+
}
15+
16+
const drawOptions = Object.assign(
17+
getDefaultDrawOptions(options),
18+
(options || {})
19+
)
20+
21+
const ctx = getContext2dOrThrow(canvas)
22+
const {
23+
primaryColor = 'red',
24+
secondaryColor = 'blue',
25+
primaryFontSize = 22,
26+
secondaryFontSize = 16,
27+
minConfidence = 0.2
28+
} = drawOptions
29+
30+
const faceExpressionsArray = Array.isArray(faceExpressions)
31+
? faceExpressions
32+
: [faceExpressions]
33+
34+
faceExpressionsArray.forEach(({ position, expressions }) => {
35+
const { x, y } = position
36+
const height = (position as IRect).height || 0
37+
const sorted = expressions.sort((a, b) => b.probability - a.probability)
38+
const resultsToDisplay = sorted.filter(expr => expr.probability > minConfidence)
39+
40+
let offset = (y + height + resultsToDisplay.length * primaryFontSize) > canvas.height
41+
? -(resultsToDisplay.length * primaryFontSize)
42+
: 0
43+
resultsToDisplay.forEach((expr, i) => {
44+
const text = `${expr.expression} (${round(expr.probability)})`
45+
drawText(
46+
ctx,
47+
x,
48+
y + height + (i * primaryFontSize) + offset,
49+
text,
50+
{
51+
textColor: i === 0 ? primaryColor : secondaryColor,
52+
fontSize: i === 0 ? primaryFontSize : secondaryFontSize
53+
}
54+
)
55+
})
56+
})
57+
58+
59+
}

src/dom/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export * from './drawContour'
22
export * from './drawLandmarks'
3+
export * from './drawFaceExpressions'
34
export * from './extractFaces'
45
export * from './extractFaceTensors'
56
export * from './types'

src/dom/types.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
1+
import { IPoint, IRect } from 'tfjs-tiny-yolov2';
2+
3+
import { WithFaceExpressions } from '../factories/WithFaceExpressions';
4+
15
export type DrawLandmarksOptions = {
26
lineWidth?: number
3-
color?: string,
7+
color?: string
48
drawLines?: boolean
5-
}
9+
}
10+
11+
export type DrawFaceExpressionsOptions = {
12+
primaryColor?: string
13+
secondaryColor?: string
14+
primaryFontSize?: number
15+
secondaryFontSize?: number
16+
minConfidence?: number
17+
}
18+
19+
export type DrawFaceExpressionsInput = WithFaceExpressions<{
20+
position: IPoint | IRect
21+
}>

0 commit comments

Comments
 (0)