Skip to content

Commit a644af1

Browse files
getters for coordinates the contours for landmarks and draw contours
1 parent 0c75bc3 commit a644af1

File tree

3 files changed

+94
-8
lines changed

3 files changed

+94
-8
lines changed

examples/views/faceLandmarks.html

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,36 @@
2323
<div id="selectList"></div>
2424
</div>
2525
</div>
26+
<p>
27+
<input type="checkbox" id="drawLinesCheckbox" checked="checked" onchange="onChangeDrawLines(event)" />
28+
<label for="drawLinesCheckbox">Draw Lines</label>
29+
</p>
2630
</div>
2731
</div>
2832

2933
<script>
3034
let net
35+
let drawLines = true
36+
let landmarks
37+
let currentImg
3138

32-
async function onSelectionChanged(uri) {
33-
const imgBuf = await fetchImage(uri)
34-
const img = await faceapi.bufferToImage(imgBuf)
35-
const canvas = faceapi.createCanvasFromMedia(img)
39+
function onChangeDrawLines(e) {
40+
drawLines = $(e.target).prop('checked')
41+
redraw()
42+
}
43+
44+
function redraw() {
45+
const canvas = faceapi.createCanvasFromMedia(currentImg)
3646
$('#faceContainer').empty()
3747
$('#faceContainer').append(canvas)
48+
faceapi.drawLandmarks(canvas, landmarks, { lineWidth: drawLines ? 2 : 4, drawLines })
49+
}
3850

39-
const landmarks = await net.detectLandmarks(canvas)
40-
faceapi.drawLandmarks(canvas, landmarks, { lineWidth: 4 })
51+
async function onSelectionChanged(uri) {
52+
const imgBuf = await fetchImage(uri)
53+
currentImg = await faceapi.bufferToImage(imgBuf)
54+
landmarks = await net.detectLandmarks(currentImg)
55+
redraw()
4156
}
4257

4358
async function run() {

src/faceLandmarkNet/FaceLandmarks.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,34 @@ export class FaceLandmarks {
2828
)
2929
}
3030

31+
public getJawOutline() {
32+
return this._faceLandmarks.slice(0, 17)
33+
}
34+
35+
public getLeftEyeBrow() {
36+
return this._faceLandmarks.slice(17, 22)
37+
}
38+
39+
public getRightEyeBrow() {
40+
return this._faceLandmarks.slice(22, 27)
41+
}
42+
43+
public getNose() {
44+
return this._faceLandmarks.slice(27, 36)
45+
}
46+
47+
public getLeftEye() {
48+
return this._faceLandmarks.slice(36, 42)
49+
}
50+
51+
public getRightEye() {
52+
return this._faceLandmarks.slice(42, 48)
53+
}
54+
55+
public getMouth() {
56+
return this._faceLandmarks.slice(48, 68)
57+
}
58+
3159
public forSize(width: number, height: number): FaceLandmarks {
3260
return new FaceLandmarks(this.getRelativePositions(), { width, height })
3361
}

src/utils.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { FaceDetection } from './faceDetectionNet/FaceDetection';
22
import { FaceLandmarks } from './faceLandmarkNet/FaceLandmarks';
33
import { Dimensions, DrawBoxOptions, DrawLandmarksOptions, DrawOptions, DrawTextOptions } from './types';
4+
import { Point } from './Point';
45

56
export function isFloat(num: number) {
67
return num % 1 !== 0
@@ -163,6 +164,33 @@ export function drawDetection(
163164
})
164165
}
165166

167+
function drawContour(
168+
ctx: CanvasRenderingContext2D,
169+
points: Point[],
170+
isClosed: boolean = false
171+
) {
172+
ctx.beginPath()
173+
174+
points.slice(1).forEach(({ x, y }, prevIdx) => {
175+
const from = points[prevIdx]
176+
ctx.moveTo(from.x, from.y)
177+
ctx.lineTo(x, y)
178+
})
179+
180+
if (isClosed) {
181+
const from = points[points.length - 1]
182+
const to = points[0]
183+
if (!from || !to) {
184+
return
185+
}
186+
187+
ctx.moveTo(from.x, from.y)
188+
ctx.lineTo(to.x, to.y)
189+
}
190+
191+
ctx.stroke()
192+
}
193+
166194
export function drawLandmarks(
167195
canvasArg: string | HTMLCanvasElement,
168196
faceLandmarks: FaceLandmarks,
@@ -181,8 +209,23 @@ export function drawLandmarks(
181209
const { drawLines } = Object.assign({ drawLines: false }, (options || {}))
182210

183211
const ctx = getContext2dOrThrow(canvas)
184-
const { lineWidth,color } = drawOptions
185-
ctx.fillStyle = color
212+
const { lineWidth, color } = drawOptions
213+
214+
if (drawLines) {
215+
ctx.strokeStyle = color
216+
ctx.lineWidth = lineWidth
217+
drawContour(ctx, faceLandmarks.getJawOutline())
218+
drawContour(ctx, faceLandmarks.getLeftEyeBrow())
219+
drawContour(ctx, faceLandmarks.getRightEyeBrow())
220+
drawContour(ctx, faceLandmarks.getNose())
221+
drawContour(ctx, faceLandmarks.getLeftEye(), true)
222+
drawContour(ctx, faceLandmarks.getRightEye(), true)
223+
drawContour(ctx, faceLandmarks.getMouth(), true)
224+
return
225+
}
226+
227+
// else draw points
186228
const ptOffset = lineWidth / 2
229+
ctx.fillStyle = color
187230
faceLandmarks.getPositions().forEach(pt => ctx.fillRect(pt.x - ptOffset, pt.y - ptOffset, lineWidth, lineWidth))
188231
}

0 commit comments

Comments
 (0)