基于浏览器的人脸识别标记
Posted x_x
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于浏览器的人脸识别标记相关的知识,希望对你有一定的参考价值。
最近,Chrome在Chrome中集成了一套与图形识别相关的 API——Shape Detector API,只需要少量代码就能够实现人脸识别、二维码/条形码识别和文本识别。虽然这些 API 还处于实验阶段,只要条件允许,还是可以一下的。在 Windows 10 Chrome Canary 和 安卓 Chrome 等应用中,开启 chrome://flags/#enable-experimental-web-platform-features 功能,在控制台下输入
window.FaceDetector
window.BarcodeDetector
window.TextDetector
若得到“[native code]”,那么就可以使用这些 API 了。亲测 Windows7 Chrome 61 开启了 enable-experimental-web-platform-features 之后,虽然 window 包含以上三个 API,但调用 new FaceDetector.detector 时会报错:Face detection service unavailable.
本来只是想简单的体验一下这个 API,没想到一不小心就写了这么多。。。
Demo1
在这个 demo 中,一共有三个类:
(1)FaceTag:所有的逻辑操作(人脸识别、搜索面部、面部标记)都在该类中实现。
(2)ShowImg:实现图片按原比例绘制、缩放图片、获取 base64、清除功能。
(3)SignTool:实现绘制方框、绘制文字、清除功能。
实际上,ShowImg 完全可以用 <img> 代替的,我只是为了能够缩小图片,缩短人脸检测的时间。由于图片一旦确定后,在检测和标记阶段是不变的,为了方便操作,ShowImg 和 SignTool 各包含一个 canvas。为了减少代码的重复,将创建 canvas 和获取 ctx 的任务交给了 FaceTag 。
面部检测
FaceDetector 真的很简单。
创建实例的时候,可以给它传递FaceDetectorOptions,这个对象只含两个有效参数:
maxDetectedFaces:检测人脸的最大数目。
fastMode:是否优先考虑速度。
而它只提供了 detect(img) 一个方法,传入待检测的图像,结果以 Promise 的形式返回,是包含一组 DetectedFace 元素的数组,若检测不到则返回一个空数组。DetectedFace 的相关信息:x,y,left,top,right,bottom 等都包含在 boundingBox 中。
至于检测结果的话,正脸的精确度挺高的,但是侧脸基本检测不到。
class FaceTag {
constructor(opt={}){
...
this.detector = new FaceDetector(orignOpt.detectorOpt);
...
}
...
faceDetector(aspect = 1) { return new Promise((resolve, reject) => { let img = this.img.getImage(); this.detector.detect(img) .then(faces => { if(faces.length === 0) { reject(\'检测不到面部哦\'); }else { this.faces = faces; resolve(this.faces); } }) .catch(err => { reject(err); }) }) }
...
}
根据检测到的结果信息在 signTool 的 canvas 中绘制出来。
class SignTool { ... /* * 标识面部 * param {Array} faces 需要标识的部分 */ drawFaces(faces=[], aspect = 1) { faces.length > 0 && faces.forEach(face => { this.drawRect(face.boundingBox, aspect); }) } /* * 绘制 rect * param {object} rect 需要绘制的 rect */ drawRect(rect={}, aspect = 1) { this.ctx.save() this.ctx.beginPath(); this.ctx.lineWidth = rect.lineWidth || 2; this.ctx.strokeStyle = rect.color || \'red\'; this.ctx.rect(Math.floor(rect.x * aspect), Math.floor(rect.y * aspect), Math.floor(rect.width * aspect), Math.floor(rect.height * aspect) ); this.ctx.stroke(); this.ctx.restore(); } ... }
选择面部
本 demo 中为 signTool 的 canvas添加点击事件,通过鼠标坐标与检测到的所有面部信息进行比较,判断是否选中面部。选中之后,重新绘制一遍所有的面部,在将选中面部高亮。
class FaceTag { ... /* * signTool 的 canvas 添加点击事件 */ addEvent() { if(!this.signTool.canvas) { return; } let canvas = this.signTool.canvas; let canvasBox = canvas.getBoundingClientRect(); canvas.addEventListener(\'click\', e => { // 计算鼠标在canvas中的位置 let eX = e.clientX - canvasBox.left; let eY = e.clientY - canvasBox.top; this.findFace(this.img.getImage(), eX, eY) .then(face => { this.signTool.drawFaces(this.faces); this.heightLighRect(face); // 保存选中的面部 this.beTagFace = face; }) }) }
... }
最后,beTagFace 的信息,将文字标注在方框附近 ,对面部的标记就完成啦。
Demo2
本 demo 结合了 WebRTC,并将 面部检测部分移到了 Web Worker 中计算。
/* * 获取视频流 * @param {Object} opt video 的参数 */ getUserMedia(opt) { navigator.mediaDevices.getUserMedia({ video: opt }).then(stream => { this.createVideo(stream); resizeCanvas(); }).catch(err => { alert(err); }) } /* * 创建 video 标签 * @param {Object} stream 视频流 */ createVideo(stream) { this.video = document.createElement(\'video\'); this.video.autoplay = \'autoplay\'; this.video.src = window.URL.createObjectURL(stream); this.container.appendChild(this.video); }
通过 navigator.mediaDevices.getUserMedia 获取权限打开摄像头,获取视频流。
由于 detect()需要传入 ImageBitmapSource 对象,因此将视频流绘制到 canvas 中,通过 canvas 获取图像信息,将图像信息传递给 Web Worker,进行面部检测。之后的就和 demo1 大致相同。
以上是关于基于浏览器的人脸识别标记的主要内容,如果未能解决你的问题,请参考以下文章