本文可视为《[用HTML5实现人脸识别](http://blog.csdn.net/hfahe/article/details/7485452)》的进阶,在人脸识别的基础上,我们将使用纯Javascript来实现如下的功能:
- 识别和标注人脸以及五官
![](https://box.kancloud.cn/2016-08-09_57a9a2e5d9849.jpg)
- 对人脸进行美容
![](https://box.kancloud.cn/2016-08-09_57a9a2e5ee4ee.jpg)
从本文的内容中,你将意识到,Javascript能做的,能实现的,远远比你想象的多。
[![](https://box.kancloud.cn/2016-08-09_57a9a2e5bfb2a.jpg)](http://namepk.sinaapp.com/demo/face/index.html)
演示
**一、实现**
**1、人脸识别**
Face.com有包括检测、识别在内的多个API接口,根据《[用HTML5实现人脸识别](http://blog.csdn.net/hfahe/article/details/7485452)》一文,我们已经可以实现图片上传,并得到检测的结果,结果如下:
![](https://box.kancloud.cn/2016-08-09_57a9a2e618ce0.jpg)
返回的参数
返回参数的详细解释参见[http://developers.face.com/docs/api/return-values/](http://developers.face.com/docs/api/return-values/),其中tags为多张照片的识别结果,每一个结果包括了耳朵、眼睛、嘴、鼻的中心位置,以及年龄、性别、是否佩戴眼镜、情绪、是否在笑等多种信息。
上传图片并请求接口的代码如下。
~~~
function buildRequest(imgSrc) {
document.getElementById("detect").disabled = true;
document.getElementById("beauty").disabled = true;
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var imgObj = new Image();
imgObj.src = imgSrc;
canvas.width = imgObj.width;
canvas.height = imgObj.height;
ctx.drawImage(imgObj, 0, 0);
var imgPixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
document.getElementById("bigImg").style.width = imgObj.width;
var data = canvas.toDataURL('image/jpeg', 1.0);
newblob = dataURItoBlob(data);
var formdata = new FormData();
formdata.append("api_key", "your key");
formdata.append("api_secret", "your secret");
formdata.append("filename","avatar.jpg");
formdata.append("file",newblob);
$.ajax({
url: 'http://api.face.com/faces/detect.json?attributes=age_est,gender,mood,smiling,glasses',
data: formdata,
cache: false,
contentType: false,
processData: false,
dataType:"json",
type: 'POST',
success: function (data) {
handleResult(data.photos[0]);
}
});
}
~~~
**人脸标注**
我们将根据人脸识别的结果对五官和面部进行标注。标注的方式有两种,一种是基于Canvas的绘图,一种是传统DIV方式标注。下面我们采用第二种方式,原理是在各个点上画一个3*3的DIV,DIV的背景色为红色,采用绝对定位。接口返回的五官数值为宽高所在点的百分比值,所以需要先进行换算。
标注五官的方法如下:
~~~
function drawFacial(data) {
var width = data.width;
var height = data.height;
var points = ["eye_left", "eye_right", "mouth_left", "mouth_center", "mouth_right", "nose", "ear_left", "ear_right"];
for(var i = 0; i < points.length; i++) {
var div = document.createElement('div');
div.style.width = "3px";
div.style.height = "3px";
div.style.backgroundColor = "red";
div.style.position = "absolute";
div.className = "facePoint";
var values = data.tags[0][points[i]];
if(values != null) {
var left_x = values.x;
div.style.left = left_x * width / 100 - 1 + "px";
var left_y = values.y;
div.style.top = left_y * height / 100 - 1 + "px";
document.body.appendChild(div);
}
}
}
~~~
标注人脸区域的方法如下:
~~~
function drawFace(data) {
var width = data.width;
var height = data.height;
var faceWidth = data.tags[0].width * width / 100;
var faceHeight = data.tags[0].height * height / 100;
var faceCenter = data.tags[0].center;
var div = document.createElement('div');
div.style.width = faceWidth + "px";
div.style.height = faceHeight + "px";
div.style.borderColor = "red";
div.style.borderWidth = "1px";
div.style.borderStyle = "dotted";
div.style.position = "absolute";
div.className = "faceBox";
div.style.left = faceCenter.x * width / 100 - faceWidth / 2 - 1 + "px";
div.style.top = faceCenter.y * height / 100 - faceHeight / 2 - 1 + "px";
document.body.appendChild(div);
}
~~~
从结果来看,Face.com的检测结果非常精准。
**人脸美容**
对人脸我们采用两种效果叠加进行美容,分别是增加亮度和模糊度,这样可以让人脸看起来更白,皮肤更好。
1、 增加亮度
增加亮度其实非常简单,只需要在像素点的RGB通道上增加一个固定的值。代码如下:
~~~
var imgPixels = ctx.getImageData(faceLeft, faceTop, faceWidth, faceHeight);
var data = imgPixels.data;
adjustment = 5;
for (var i = 0; i < data.length; i += 4) {
data[i] += adjustment;
data[i+1] += adjustment;
data[i+2] += adjustment;
}
~~~
2、 添加模糊效果
模糊效果较为复杂,平常我们常用到的包括均值模糊和高斯模糊。在HTML5Rocks上有一篇很棒的文章《[IMAGE FILTERSWITH CANVAS](http://www.html5rocks.com/en/tutorials/canvas/imagefilters/)》,里面有各种图像处理效果,我们可以直接应用里面的模糊效果(也即3*3的均值模糊)。
![](https://box.kancloud.cn/2016-08-09_57a9a2e6304f6.jpg)
原图
![](https://box.kancloud.cn/2016-08-09_57a9a2e645193.jpg)
锐化
![](https://box.kancloud.cn/2016-08-09_57a9a2e65878c.jpg)
索贝尔滤镜
代码如下:
~~~
var Filters = {};
Filters.convolute = function(pixels, weights, opaque) {
var side = Math.round(Math.sqrt(weights.length));
var halfSide = Math.floor(side/2);
var src = pixels.data;
var sw = pixels.width;
var sh = pixels.height;
// pad output by the convolution matrix
var w = sw;
var h = sh;
var output = Filters.createImageData(w, h);
var dst = output.data;
// go through the destination image pixels
var alphaFac = opaque ? 1 : 0;
for (var y=0; y<h; y++) {
for (var x=0; x<w; x++) {
var sy = y;
var sx = x;
var dstOff = (y*w+x)*4;
// calculate the weighed sum of the source image pixels that
// fall under the convolution matrix
var r=0, g=0, b=0, a=0;
for (var cy=0; cy<side; cy++) {
for (var cx=0; cx<side; cx++) {
var scy = sy + cy - halfSide;
var scx = sx + cx - halfSide;
if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) {
var srcOff = (scy*sw+scx)*4;
var wt = weights[cy*side+cx];
r += src[srcOff] * wt;
g += src[srcOff+1] * wt;
b += src[srcOff+2] * wt;
a += src[srcOff+3] * wt;
}
}
}
dst[dstOff] = r;
dst[dstOff+1] = g;
dst[dstOff+2] = b;
dst[dstOff+3] = a + alphaFac*(255-a);
}
}
return output;
};
Filters.tmpCanvas = document.createElement('canvas');
Filters.tmpCtx = Filters.tmpCanvas.getContext('2d');
Filters.createImageData = function(w,h) {
return this.tmpCtx.createImageData(w,h);
};
~~~
最后对Canvas里的图像叠加两种效果的代码如下:
~~~
var width = data.width;
var height = data.height;
var faceWidth = data.tags[0].width * width / 100;
var faceHeight = data.tags[0].height * height / 100;
var faceCenter = data.tags[0].center;
var faceLeft = faceCenter.x * width / 100 - faceWidth / 2;
var faceTop = faceCenter.y * height / 100 - faceHeight / 2;
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var imgPixels = ctx.getImageData(faceLeft, faceTop, faceWidth, faceHeight);
var data = imgPixels.data;
adjustment = 5;
for (var i = 0; i < data.length; i += 4) {
data[i] += adjustment;
data[i+1] += adjustment;
data[i+2] += adjustment;
}
imgPixels = Filters.convolute(imgPixels, [ 1/9, 1/9, 1/9,
1/9, 1/9, 1/9,
1/9, 1/9, 1/9 ], 1);
ctx.putImageData(imgPixels, faceLeft, faceTop, 1, 1, faceWidth - 3, faceHeight - 3);
~~~
这样,我们完成了所有的代码。是不是相当的有成就感?看起来我们完成了相当新颖而酷炫的工作。
**二、思考**
1、 美容滤镜是否有其他实现的方式?
之前我介绍过CSS3滤镜,它有虚化和亮度调节两个方法可以方便直接的为图片添加滤镜效果,可以在《[遇见CSS3滤镜](http://blog.csdn.net/hfahe/article/details/7104496)》这篇文章里了解到。
2、我们还可以实现哪些美容效果?
1)去红眼
检测到眼睛位置后,我们可以采用一定范围内的滤镜,把这个范围内的红色转换为黑色,从而实现去红眼效果。
2)眼睛放大
检测到眼睛位置后,我们还可以采用一定的算法,实现眼睛放大的效果。要体验这个效果,可以下载[百度魔图](http://motu.baidu.com/)客户端体验。
![](https://box.kancloud.cn/2016-08-09_57a9a2e66c89d.jpg)
百度魔图-强大的图片处理客户端
3)背景虚化
背景虚化效果基本和我们文中提到的效果是相反的方式。
3、 文中的效果是否还可以优化?
例如是否可以把文中美容的区域将正方形变为椭圆形,更为贴近人脸的形状?其实并不难,读者有兴趣可深入思考和实现。
4、 除了美容,我们还能完成什么样的功能?
Face.com提供了三个功能演示:人脸Tag、情景照片、人脸查找。对于应用开发者来说,从来不缺乏创意,例如Face.com图片检测返回的参数里包括图片旋转角度,我们可以利用这个参数实现图片批量自动旋转的功能(我最近在整理旅游的照片时就深深的理解了这个功能的便利性和必要性)。或者基于微博的图片爱情速配App?我期待更有创意和使用价值idea的出现。
**扩展阅读**
- 《[遇见CSS3滤镜](http://blog.csdn.net/hfahe/article/details/7104496)》
- 《[如何使用HTML5实现拍照上传应用](http://blog.csdn.net/hfahe/article/details/7354912)》
- 《[用HTML5创建超酷图像灰度渐变效果](http://blog.csdn.net/hfahe/article/details/6208765)》
本文来自[蒋宇捷的博客](http://blog.csdn.net/hfahe),转载请注明。
- 前言
- AutoPager的简单实现
- 利用CSS3特性巧妙实现漂亮的DIV箭头
- IE9在Win7下任务栏新特性简介
- 浏览器九宫格的简单实现
- Raphael js库简介
- 使用CSS3构建Ajax加载动画
- 用CSS3创建动画价格表
- 用CSS3实现浏览器的缩放功能
- 用纯CSS3实现QQ LOGO
- 用CSS3创建旋转载入器
- 使用Javascript开发移动应用程序
- 用HTML5创建超酷图像灰度渐变效果
- 使用CSS3创建文字颜色渐变(CSS3 Text Gradient)
- 仅用CSS创建立体旋转幻灯片
- 如何创建跨浏览器的HTML5表单
- 用CSS3实现动画进度条
- HTML5 Guitar Tab Player
- 奇妙的HTML5 Canvas动画实例
- 谈HTML5和CSS3的国际化支持
- 实现跨浏览器的HTML5占位符
- 前端开发必备工具:WhatFont Bookmarklet-方便的查询网页上的字体
- 使用HTML5和CSS3来创建幻灯片
- HTML5之美
- 如何使用HTML5创建在线精美简历
- 以小见大、由浅入深-谈如何面试Javascript工程师
- 快速入门:HTML5强大的Details元素
- 用CSS3实现图像风格
- HTML5视频字幕与WebVTT
- 用纯CSS3实现Path华丽动画
- 用3个步骤实现响应式网页设计
- 遇见CSS3滤镜
- 关于CSS3滤镜的碎念
- 用纯CSS3绘制萌系漫画人物动态头像
- CSS3新的鼠标样式介绍
- 用HTML5献上爱的3D玫瑰
- 对HTML5 Device API相关规范的解惑
- 如何使用HTML5实现拍照上传应用
- 2012第一季度国外HTML5移动开发趋势
- HTML5新特性:范围样式
- 百度开发者大会-《用HTML5新特性开发移动App》PPT分享
- Chrome 19对于HTML5最新支持的动态:电池状态API,全屏API,震动API,语音API
- 遇见Javascript类型数组(Typed Array)
- 用HTML5 Audio API开发游戏音乐
- 用HTML5实现人脸识别
- 用Javascript实现人脸美容
- Chrome 20对于HTML5最新支持的动态:颜色输入,网络信息API,CSS着色器
- 用HTML5实现手机摇一摇的功能
- 用HTML5实现iPad应用无限平滑滚动
- 用非响应式设计构建跨端Web App
- 了解SVG
- HTML5图像适配介绍
- HTML5安全:内容安全策略(CSP)简介
- HTML5安全:CORS(跨域资源共享)简介
- 用CSS3 Region和3D变换实现书籍翻页效果
- 谈谈移动App的思维误区
- Chrome新特性:文件夹拖拽支持
- 《关注HTML5安全》
- HTML5安全风险详析之一:CORS攻击
- HTML5安全风险详析之二:Web Storage攻击
- HTML5图像适配最新进展:响应式图片规范草案
- HTML5移动Web App相关标准状态及路线图
- HTML5安全风险详析之三:WebSQL攻击
- Chrome引入WebRTC支持视频聊天App
- HTML5安全风险详析之四:Web Worker攻击
- HTML5安全风险详析之五:劫持攻击
- HTML5安全风险详析之六:API攻击
- HTML5安全攻防详析之七:新标签攻击
- 在iOS Safari中播放离线音频
- 使用WebRTC实现远程屏幕共享
- Firefox、Android、iOS遇见WebRTC
- HTML5光线传感器简介
- HTML5安全攻防详析之八:Web Socket攻击
- HTML5安全攻防详析之完结篇:HTML5对安全的改进
- 激动人心!在网页上通过语音输入文字 - HTML5 Web Speech API介绍
- Web滚动性能优化实战
- 用CSS3设计响应式导航菜单
- 用HTML5构建高性能视差网站
- 漫谈@supports与CSS3条件规则
- HTML5下载属性简介
- 如何开发优秀的HTML5游戏?-迪斯尼《寻找奥兹之路》游戏技术详解(一)
- 如何开发优秀的HTML5游戏?-迪斯尼《寻找奥兹之路》游戏技术详解(二)
- 趋势:Chrome为打包应用提供强大新特性
- 从HTML5移动应用现状谈发展趋势
- 基于HTML5的Web跨设备超声波通信方案