|
| 1 | +import { FaceDetector, createImage } from '@paddlejs-models/facedetect'; |
| 2 | + |
| 3 | +const resCanvas = document.getElementById('resCanvas') as HTMLCanvasElement; |
| 4 | +const resCtx = resCanvas.getContext('2d') as CanvasRenderingContext2D; |
| 5 | +const defaultImgPath = './img/multi_small_face.jpeg'; |
| 6 | +const fileReader = new FileReader(); |
| 7 | +const loading = document.getElementById('loading'); |
| 8 | +const faceDetector = new FaceDetector(); |
| 9 | +let faceDecoration = null as HTMLImageElement; |
| 10 | + |
| 11 | +load(); |
| 12 | +document.getElementById('uploadImg')!.onchange = function () { |
| 13 | + loadFile(this); |
| 14 | +}; |
| 15 | + |
| 16 | +async function load() { |
| 17 | + await faceDetector.init(); |
| 18 | + faceDecoration = await createImage('./img/facedecoration.png'); |
| 19 | + run(defaultImgPath); |
| 20 | +} |
| 21 | + |
| 22 | +async function run(imgPath: string) { |
| 23 | + loading.style.display = 'block'; |
| 24 | + const imgEle = await createImage(imgPath); |
| 25 | + drawImage(imgEle); |
| 26 | + // 预测 |
| 27 | + const res = await faceDetector.detect(imgEle, { shrink: 0.4 }); |
| 28 | + drawDecoration(res); |
| 29 | + loading.style.display = 'none'; |
| 30 | +} |
| 31 | + |
| 32 | +// 绘图 |
| 33 | +function drawImage(img: HTMLImageElement) { |
| 34 | + const { naturalWidth, naturalHeight } = img; |
| 35 | + resCanvas.width = naturalWidth; |
| 36 | + resCanvas.height = naturalHeight; |
| 37 | + resCtx.drawImage(img, 0, 0, naturalWidth, naturalHeight); |
| 38 | +} |
| 39 | + |
| 40 | +// 绘制头像框 |
| 41 | +function drawDecoration(data) { |
| 42 | + // 按照人脸框面积排序 近大远小 |
| 43 | + data.sort((item1, item2) => { |
| 44 | + return item1.width * item1.height - item2.width * item2.height; |
| 45 | + }); |
| 46 | + |
| 47 | + data.forEach(item => { |
| 48 | + resCtx.lineWidth = 4; |
| 49 | + // 人脸框位置 |
| 50 | + const x = item.left * resCanvas.width; |
| 51 | + const y = item.top * resCanvas.height; |
| 52 | + const w = item.width * resCanvas.width; |
| 53 | + const h = item.height * resCanvas.height; |
| 54 | + |
| 55 | + // 人脸装饰位置 |
| 56 | + const ratio = 1.7; |
| 57 | + const decW = ratio * w; |
| 58 | + const decH = ratio * h; |
| 59 | + const decY = y - (decH - h) / 2; |
| 60 | + const decX = x - (decW - w) / 2; |
| 61 | + resCtx.drawImage(faceDecoration, decX, decY, decW, decH); |
| 62 | + }); |
| 63 | +} |
| 64 | + |
| 65 | +function loadFile(ipt) { |
| 66 | + if (!ipt.files || !ipt.files[0]) { |
| 67 | + return; |
| 68 | + } |
| 69 | + fileReader.onload = function (evt) { |
| 70 | + if (evt.target && typeof evt.target.result === 'string') { |
| 71 | + run(evt.target.result); |
| 72 | + } |
| 73 | + }; |
| 74 | + fileReader.readAsDataURL(ipt.files[0]); |
| 75 | +} |
0 commit comments