全民刷军装背后的AI技术及简单实现
昨天有Design-AI-Lab用户后台留言,问为什么换军装的h5这么火,但没见到有技术文章分析如何实现。
我回复说,大概是比较简单吧,主要工作是图像合成。
后来,我亲自体验了下,反应速度比较慢,大概是因为火了吧,访问者太多;
关键的技术是人脸识别;
前端的话,canvas实现图像合成;
整个h5设计不算惊艳,只能算一般;
运营亮点是抓住热点事件,设计了激发用户分享的产品。
再细想一想,决定还是自己动手实现一个,试试整个技术的难度。
于是,通过开发者工具,阅读了
http://www.h5case.com.cn/case/people-cn/81/
的前端源码;
这个H5,
是由人民日报客户端&天天P图出品的;
技术实现: jQuery+Swiper,
Swiper负责简单的页面切换效果;
人脸与军装的图像的合成是后端操作的,前端只负责呈现。
二维码及相关的文字图样是通过html2canvas合成的。
1 关键技术
人脸识别,自动扣图,图像合成。
2 我的实现方案:
简易版本 UFace
暂时称之为UFace吧,说不准哪天我有兴致把它更进一步的完善,做个app之类的。
前端采用 jQuery;
后端采用Nodejs+express ;
人脸识别采用 百度AI的人脸检测;
安利下百度AI
http://ai.baidu.com/tech/face/detect
可以做人脸检测、对比、查找等工作。
2.1 先把nodejs环境准备下,
终端输入:
express -e ejs UFace
自动生成express的初始目录及文件;
2.2 调通全后端接口:
找到 views/index.ejs 文件,添加
<script src=“https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
找到routes/index.js文件,添加
router.post('/', function(req, res, next) {
res.send('UFace post ok')
});
终端输入
node bin/www
浏览器访问:
http://localhost:3000/
打开开发者工具,在console里调试接口,输入:
$.post("/", function(data) {
console.log(data);
});
看到控制台打印出:
UFace post ok
自此,我们的前后端调通了。
2.3 百度AI-人脸识别
在官方网站下载node SDK压缩包。
将下载的 api-node-sdk-version.zip 解压后,复制到工程文件夹中。
进入目录,运行 npm install 安装 sdk 依赖库。
在百度AI中申请好APPID;
继续到routes/index.js文件中,加入
var AipFace = require("baidu-ai").face;
var APP_ID = "994xxx7";
var API_KEY = "WqiVssssssxxvpC7xkAcK96Sf";
var SECRET_KEY = "4exxxxxHGOzy2bZThCyEM0h1";
//这三个key记得替换为你申请的appid
var client = new AipFace(APP_ID, API_KEY, SECRET_KEY);
上传本地的一张图片,调试下百度AI接口
var fs = require('fs');
var image = fs.readFileSync('assets/face/face.jpg');
var base64Img = new Buffer(image).toString('base64');
client.detect(base64Img).then(function(result) {
console.log(JSON.stringify(result));
});
终端打印出获取到的结果,接口获取成功。
2.4 前端上传一张图片,后端以此图片调用人脸识别,返回给前端结果
找到 views/index.ejs 文件,添加
<form id="uface">
<input type="file" name="files" id="upload">
<button type="button" onClick="uploadImg()">submit</button>
</form>
function uploadImg() {
var formData = new FormData();
formData.append("file", $("#upload")[0].files[0]);
$.ajax({
type: 'POST',
url: './file/uploading',
data: formData,
processData: false,
contentType: false,
success: function(res) {
var json = JSON.parse(res);
createFace(json);
//从后端获取到人脸检测到结果后,调用createFace函数,进行图片合成
}
});
};
function createFace(json) {
var jzimg = $('#jz')[0];
var img = $('#target')[0];
var canvas = $('#canvas')[0];
var ctx = canvas.getContext('2d');
var sx = json.result[0].location.left,
sy = json.result[0].location.top,
swidth = json.result[0].location.width,
sheight = json.result[0].location.height;
ctx.drawImage(img, sx, sy, swidth, sheight, 110, 160, 145, 125);
ctx.globalCompositeOperation = 'source-over';
ctx.drawImage(jzimg, 0, 0);
//globalCompositeOperation = 'source-over'; 这个是用来把抠出来到人脸,合成到军装里到关键设置,可以合成任意到图片,并保留图片到透明信息哦。
相当于ps里的图层叠加概念
};
后端获取前端提交的图片,并通过百度AI接口调取识别结果;
找到routes/index.js文件,添加
var multiparty = require('multiparty');
var util=require('util');
var fs = require('fs');
router.post('/file/uploading', function(req, res, next) {
var form = new multiparty.Form({
uploadDir: './public/files/'
});
form.parse(req, function(err, fields, files) {
var filesTmp = JSON.stringify(files, null, 2);
if (err) {
console.log('parse error: ' + err);
} else {
console.log('parse files: ' + filesTmp);
var inputFile = files.file[0];
var uploadedPath = inputFile.path;
var image = fs.readFileSync(uploadedPath);
var base64Img = new Buffer(image).toString('base64');
client.detect(base64Img).then(function(result) {
res.send(JSON.stringify(result));
});
};
});
});
3 实验结果
把这张图,传给百度AI,识别出人脸的坐标范围。
先准备好一张军装图,
合成结果见下图:
识别出人脸范围后,抠出来的人脸图如上。
合成的图像有点生硬,原因是2张图片的边缘没有进行融合,还有识别出来的人像图没有进行色调调整。
我们可以把之前准备好的军装图上做点处理,人脸中间增加带透明度的褐色部分,记得存为png格式。
再测试下结果,
是不是稍微好点,这里有个图像处理的问题,
为了更好的效果,我们需要把抠出来的人脸色调进行调整,并且进行一定的滤镜处理,使得人脸跟军装图融合后,较为统一。
在这里,我就暂时不做这一块处理啦。毕竟我只花了半天时间就实现了这个小demo。
下面还有一些合成的效果。
仅供娱乐。
哈哈哈
猜猜合成的图像都是哪些名人?欢迎留言
近期热文推荐 :
本公众号定期更新关于
设计师、程序员发挥创意
互相融合的指南、作品。
主要技术栈:
nodejs、react native、electron
欢迎关注,转发~
欢迎长按二维码
关注本号