? ? ? 本文可視為《[用HTML5實現人臉識別](http://blog.csdn.net/hfahe/article/details/7485452)》的進階,在人臉識別的基礎上,我們將使用純Javascript來實現如下的功能:
- 識別和標注人臉以及五官

- 對人臉進行美容

? ? ??從本文的內容中,你將意識到,Javascript能做的,能實現的,遠遠比你想象的多。
[](http://namepk.sinaapp.com/demo/face/index.html)
演示
**一、實現**
**1、人臉識別**
? ? ??Face.com有包括檢測、識別在內的多個API接口,根據《[用HTML5實現人臉識別](http://blog.csdn.net/hfahe/article/details/7485452)》一文,我們已經可以實現圖片上傳,并得到檢測的結果,結果如下:

返回的參數
? ? ??返回參數的詳細解釋參見[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的均值模糊)。

原圖

銳化

索貝爾濾鏡
? ? ??代碼如下:
~~~
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/)客戶端體驗。

百度魔圖-強大的圖片處理客戶端
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跨設備超聲波通信方案