Face++人脸检测与识别初试
项目背景:
最近被人民日报换军装的H5刷爆朋友圈,于是有汽车厂商想做类似的项目。用于旅游照片换脸分享朋友圈,植入汽车公众号进行宣传。
可是之前没有类似的项目经验,于是搜集相关代码和当前人脸识别市场进行调研。主要有以下几大阵营:
- Face++https://www.faceplusplus.com.cn/
- 腾讯优图和天天P图。天天P图和腾讯优图是不同部门负责http://open.youtu.qq.com/welcome/experience
- 百度AI开发平台http://ai.baidu.com/tech/face
- 其他阵营,如美图秀秀等
人民日报换军装的H5,就是由天天P图公司制作的。
对比API和技术支持
Face++、腾迅优图API以及百度AI平台图像处理方面产品线都比较全,都在进行产品线更新。
- 首先联系的Face++, Face++不支持换军装定制开发。
- 然后联系腾讯优图,说会转个天天P图的同事,然后一直没有回音。
- 最后在腾讯优图找到了换军装的Demo,里面找到了作者联系方式,报价10+万。
- 没有联系百度公司。
估计成本太高,客户后面就没有了反馈。
等待总是漫长的,作为技术总是爱折腾和尝试。以下是进行的折腾之旅:
思路一 Face++背景融合:
用户上传个人全身照,选择场景进行图片叠加处理。
1. 注册开发者获取api_key和api_secret
进行接口权限认证和数据请求需要用到。
2. 上传原始图片
3. 获取灰度图
发送原始图片,获取返回的灰度图。
var params = $('form').serializeArray();
$.ajax({
url: 'https://api-cn.faceplusplus.com/humanbodypp/beta/segment',
type: 'POST',
data: params,
dataType: 'json',
success: function(data){
console.log(data);
var grayImg = 'data:image/jpeg;base64,'+data.result;
$('#resultImg').attr('src', grayImg);
$('#addedImg').attr('src', clipImgWithGrayImg( grayImg));
},
error: function (msg) {
console.log(msg);
}
});
调用接口返回二进制数据流,增加data:image/jpeg;base64,
前缀,即可使用img
读取图片。
4. 裁剪原始图片与背景图片融合
根据获取的灰度图,使用canvas对原图进行像素级操作,裁剪原图。针对非人像部分,进行像素透明操作。可以进行对边界部分进行参数调节操作,如下:
<!-- 已知灰度图裁切原始图片 -->
function clipImgWithGrayImg(grayImg) {
var canvas = document.getElementById("myCanvas");
var image = document.getElementById("resultImg");
image.crossOrigin="Anonymous";
<!-- 将得到的图像绘制在Canvas对象中的代码如下:-->
canvas.width=image.width;
canvas.height=image.height;
var ctx=canvas.getContext("2d");
ctx.drawImage(image, 0, 0);
<!-- 从Canvas对象中获取图像像素数据的代码如下:-->
var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);
<!-- 读取像素值与实现灰度计算的代码如下:-->
for ( var x = 0; x < canvasData.width; x++) {
for ( var y = 0; y < canvasData.height; y++) {
// Index of the pixel in the array
var idx = (x + y * canvasData.width) * 4;
var r = canvasData.data[idx + 0];
var g = canvasData.data[idx + 1];
var b = canvasData.data[idx + 2];
if (r < 128 || g < 128 || b < 128) {
canvasData.data[idx + 3] = 0; // Alpha channel
}
}
}
var data = canvasData.data;
ctx.clearRect(0,0, canvas.width, canvas.height);
var srcImage = document.getElementById("srcImg");
ctx.drawImage(srcImage, 0, 0);
srcImage.crossOrigin="Anonymous";
<!-- 从Canvas对象中获取图像像素数据的代码如下:-->
var canvasData2 = ctx.getImageData(0, 0, canvas.width, canvas.height);
for ( var j = 0; j < canvasData2.width; j++) {
for ( var k = 0; k < canvasData2.height; k++) {
// Index of the pixel in the array
var idx = (j + k * canvasData2.width) * 4;
canvasData2.data[idx + 3] = data[idx + 3];
}
}
ctx.putImageData(canvasData2,0,0);
return canvas.toDataURL();
}
与背景图合成结果:
总结:边界判断还需要优化,不能够满足商用的完美融合需求。
思路二 人脸检测与人脸替换:
使用换脸的正常流程: 人脸检测–>人脸特征提取–>模型脸型匹配–>替换人脸–>肤色更换
1. 获取人脸检测数据
上传图片,调用人脸检测的接口,获取人脸特征数。
var params = $('form').serializeArray();
$.ajax({
url: 'https://api-cn.faceplusplus.com/facepp/v3/detect', // 人脸检测API
type: 'POST',
data: params,
dataType: 'json',
crossDomain: true,
success: function(data){
console.log(data);
if (data.faces.length > 0) {
drawFace(data.faces[0].face_rectangle, data.faces[0].landmark);
}
},
error: function (msg) {
console.log(msg);
}
});
2. 识别人脸
调用Face++人脸识别接口,返回的特征可以正常匹配,但是人脸的位置异常。
代码如下:
<!-- 显示面部区域draw face -->
function drawFace(rect, landmark) {
var canvas = document.getElementById("myCanvas");
var image = document.getElementById("srcImg");
image.crossOrigin="Anonymous";
var points = [
{'x': landmark.contour_left1.x, 'y':landmark.contour_left1.y},
{'x': landmark.contour_left2.x, 'y':landmark.contour_left2.y},
{'x': landmark.contour_left3.x, 'y':landmark.contour_left3.y},
{'x': landmark.contour_left4.x, 'y':landmark.contour_left4.y},
{'x': landmark.contour_left5.x, 'y':landmark.contour_left5.y},
{'x': landmark.contour_left6.x, 'y':landmark.contour_left6.y},
{'x': landmark.contour_left7.x, 'y':landmark.contour_left7.y},
{'x': landmark.contour_left8.x, 'y':landmark.contour_left8.y},
{'x': landmark.contour_left9.x, 'y':landmark.contour_left9.y},
{'x': landmark.contour_chin.x, 'y':landmark.contour_chin.y},
{'x': landmark.contour_right9.x, 'y':landmark.contour_right9.y},
{'x': landmark.contour_right8.x, 'y':landmark.contour_right8.y},
{'x': landmark.contour_right7.x, 'y':landmark.contour_right7.y},
{'x': landmark.contour_right6.x, 'y':landmark.contour_right6.y},
{'x': landmark.contour_right5.x, 'y':landmark.contour_right5.y},
{'x': landmark.contour_right4.x, 'y':landmark.contour_right4.y},
{'x': landmark.contour_right3.x, 'y':landmark.contour_right3.y},
{'x': landmark.contour_right2.x, 'y':landmark.contour_right2.y},
{'x': landmark.contour_right1.x, 'y':landmark.contour_right1.y},
{'x': landmark.right_eyebrow_right_corner.x, 'y':landmark.right_eyebrow_right_corner.y},
{'x': landmark.right_eyebrow_upper_middle.x, 'y':landmark.right_eyebrow_upper_middle.y},
{'x': landmark.left_eyebrow_upper_middle.x, 'y':landmark.left_eyebrow_upper_middle.y},
{'x': landmark.left_eyebrow_left_corner.x, 'y':landmark.left_eyebrow_left_corner.y}
];
<!-- 将得到的图像绘制在Canvas对象中的代码如下:-->
canvas.width=image.width;
canvas.height=image.height;
var ctx=canvas.getContext("2d");
ctx.drawImage(image, 0, 0);
ctx.beginPath();
ctx.rect(rect.top, rect.left, rect.width, rect.height);
$.each(points, function (index, item) {
if (index === 0) {
ctx.moveTo(item.x, item.y);
} else {
ctx.lineTo(item.x, item.y);
}
});
ctx.closePath();
ctx.strokeStyle = "green";
ctx.stroke();
}
3. 人脸替换
待完成
4. 制作滤镜,更换肤色
待完成
总结
换脸H5中,还是有过程需要完成。当前主要涉及Face++的接口调用和Canvas图片处理能力。商用过程,还有很多情况需要考虑,比如人脸位置检测与校验、滤镜换肤。听说腾讯优图1个月左右会开放换脸API,敬请期待。