对于消费医疗来说,准确的识别用户的肤质状态,标示用户的五官,让用户了解自己的缺陷和亮点,是一个至关重要的需求点。如果能够给用户准确的指引,那么对于行业产品的销售和用户心智的建设,都会是一个很好的引导。洞察到了此类需求点,市面上已经有多家公司做了类似的产品。诸如你今天真好看、美图美妆,新氧,京东肌肤检测等。
本次我们的魔镜测肤项目,主要参考淘侧的美妆学院项目进行实现。如今已经投放在本地生活饿了么支付宝和口碑三端。日均pv大致1w+。这个项目目前也在进行二期规划和迭代中。能够检测出用户的肌肤问题,同时引导用户消费对应的本地侧商品。从最初的立项到推动,踩了许多坑,但也学习到了不少东西,但目前受限于native端的实现,一期效果并没有那么完美。二期做了一些优化,目前正在推进中。
一期的体验流程大致如下。
有两种方式可进入体验,
-
在或者支付宝口碑 丽人医美圆饼,在真好看频道右上角,体验【美了么测肤】参与互动,
-
或者直接 饿了么app扫码
3.二期现在的效果
项目之初-调研
最初,产品同学给出的竞品方案是新氧和京东的测肤流程。新氧无疑是拍照流程中做的最好的。具体优势在
-
拍照时,会将人脸圈出,有测肤和美妆等多个选项的选择。与用户有实时的活动
-
拿到照片后,通过更加完善测肤和五官接口,具有一个动画渲染过程,交互体验上更好。
而基于内部淘侧已经有团队实现过美妆学院,在巨人的肩膀上,我们复用了淘侧的测肤接口【1】。美妆学院也有过类似的文章总结,具体参考【2】。实际上,在医疗领域,测肤算法已经非常完善,只是在工程实践与行业应用上需要增强。譬如谷歌新推出的论文【3】显示其达到了专业皮肤科医生水准。
一期方案链路与效果
理想的测肤流程如下
-
一般来说,完美的交互体验链路应该是客户端接入人脸检测算法,提供jsApi,辅助拍摄,引导用户拍摄正脸照片,然后上传拿到照片链接返回给前端。参考淘侧接入文档【4】
-
前端通过调用测肤接口与五官检测接口的数据,利用Lottie或者svg对五官与测肤结果进行绘制。
由次链路推算
测肤链路涉及到的核心算法主要有三个
a.一部分是端上直接跑的人脸检测,用来引导用户拍照,需要app端同学接faceDetection,
b.另一部分是测肤算法,是在拍照完成后,将拍摄的照片链接发送给我们的服务端,我们服务的返回测肤结果,前端拿到测肤结果再在照片上画图。这一部分目前已经做了,调了淘宝的接口。
c.五官数据可通过两种方式实现。前端调用face-api.js,标注出照片上的五官和轮廓,作为测肤结果的补充。但目前这种方式并不可行,app本地跑模型数据过慢。因此可借助服务端,跑完模型后,返回五官数据。进行坐标点的绘制。
而一期受限于端内API,以及五官数据。实现了较为简化的版本。链路如下图所示。端内有较多的坑。只能采用迂回的方式,做了一些前端的处理,才能走通整个链路。其中有遇到一个点是base64格式的图片数据,上传到oss之后,饿了么安卓端不显示。因此转为blob进行处理。具体链路优化如下图。
一期方案
本次是唤起原生的相机来实现第一步功能。饿了么app侧是调用了windvane,支付宝侧为alipayJsBrige。在这种情况下,目前遇到了一些问题,失败率较高,造成此类失败检测的原因主要如下,如拍照不确定用户能把脸放在正中心,多少会有些影响结果,我们知道exif是根据手机的方向传感器来判断的,同时用户是否在躺着拍照时,尽管图片的exif=1,但实际上照片中人脸是歪的。如果这个在用户没有拍摄正脸照片时,不能及时引导。只能依赖测肤接口进行判断是否测肤成功,对应的返回测肤结果码。
为避免后人踩坑,因此列出端内坑点。
坑点1
端内无getUserMedia的API,最开始,拍照本想使用HTML5的getUserMedia API,利用【5】【6】来实现视频流与麦克风流的跟踪,可以在手机Chrome中尝试使用,而不同于普通浏览器内核,发现饿了么app没有这个API,果然,一顿操作猛如虎,达成目标-0.5。无奈,只能放弃。
坑点2
除了需要文件上传,还需要考虑拍照功能。一般对于Chrome浏览器而言,使用input上传文件是一种非常简单的方式。而使用input标签,在安卓机型下可以唤起相机,但iOS不行。后来准备采用pluload方案【7】进行文件上传,但发现还是结合不了唤起相机,同时引用的包过大,影响了项目加载速度。因此,最后我们采用axios直接提交form表单。oss采用服务端签名直传【8】主要是获取到签名之后,进行一个form表单的提交。这里注意的是,设置的Content-Type查看是否成功:按F12-network-点击对应的那个请求.formData的格式参考【9】
具体代码,
import axios from 'axios'
...
const formData = new FormData()
const suffix =localPath.slice(localPath.lastIndexOf('.')).indexOf('png') === -1 ? '.jpeg' : '.png'
const filename = `beauty-skin/${Date.now()}${suffix}`
// 获取签名
if (ossData.accessId && ossData.policy && ossData.signature) {
formData.append('key', filename)
formData.append('OSSAccessKeyId', ossData.accessId)
formData.append('policy', ossData.policy)
formData.append('signature', ossData.signature)
formData.append('file', imgData)
console.log('formData', formData)
const startTime = new Date().getTime()
return new Promise(resolve => {
axios.post(url, formData, { headers: { 'Content-Type': 'multipart/form-data' },}).then(
(res: { status: number }) => {
if (res.status === 204) {
record('face-tag', 'ossSuccess', 'CLK')
const imgUrlRes = `${url}/${filename}`
resolve(imgUrlRes)
}
})})}
...
坑点3
一般情况上传照片或图片有三种方式,base64格式,Blob流格式,或者file格式。一般来说,将本地图片转换成base64,然后通过普通的post请求发送到oss。操作简单,适合小图,以及如果想兼容低版本的ie没办法用此方法.而饿了么安卓端部分机型识别不了base64的照片。笔者查阅资料,发现原因可能出在base64编码出现换行【】,
https://blog.csdn.net/ly124100427/article/details/82683170
一个 data URL 是一个文件中的文件,相对于文档来说这个文件可能就非常的长。因为 data URL 也是 URL,所以 data 会用空白符(换行符, 制表符, 空格)来对它进行格式化。但如果数据是经过
base64 编码的,https://blog.csdn.net/weixin_30809333/article/details/101340037。
坑点4
歪脸照片的处理,发现人的脸是歪着的,于是判断图片需要进行旋转,然鹅,旋转不了,参考文章http://www.111com.net/wy/147313.htm。发现exit=1.但是在IOS真机测试的时候,发现图片预览的时候自动逆时针旋转了90度。引用了这个包来判断图片的方向。
https://npm.alibaba-inc.com/package/exif-image
坑点5
图片跨域问题。HTML 规范中图片有一个查看 CORS settings attributes来了解更多 crossorigin 属性的用法。
img.onload = () => {
const canvas = document.createElement('canvas') // 创建canvas DOM元素,并设置其宽高和图片一样
canvas.width = img.width
canvas.height = img.height
let ratio = 1
if ((img.width * img.height)
坑点6
转化为blob进行上传
重点参考 https://segmentfault.com/a/1190000023486410
回调参数将会在回调方法中传递,如果成功获取照片,则进入 success 回调;如果失败或被用户取消,则进入 failure 回调。
成功回调参数:
在此功能流程中,可调整的阈值有:
-
图片尺寸压缩的临界值:maxWidth 和 maxHeight(本质是canvas画布的尺寸)
-
导出图片的分辨率:本质是canvas.toDataURL()的参数设置
阈值调整后,性能相比于原来提升了50%,同时也保证了文字识别OCR的精度(实际上算法精度对图片分辨率的要求并不需要原图那么高,所以进行适当的压缩并不影响)。
性能提升50%体现在两方面:功能提升和体验提升。
-
功能提升
原图容量由8M及以上压缩至2M以下,iOS原图更是压缩至1M以下,容量压缩了70%左右。
-
体验提升
图片上传速度由原来的8.0s左右,提升至现在的2.0s~2.6s(3s以内,也取决于当时的网络状况和服务器的接口响应)。
-
项目本身所做的优化-solution沉淀,包体积缩小。沉淀fetch库与多端API。
-
监控与埋点。clue监控,aplus埋点
提高测肤检测率
目前测肤成功率较低,提高上传速度后,成功检测率由40%提升至75左右,但还是较低。想通过如下两种方式进行解决,一,标示人脸点,作出更加炫酷的动画,二,通过用户手动编辑图片,进行图片方向的修正与美颜,加滤镜等。提高测肤的成功率。
二期方案涉及链路
最近的二期链路步骤如下,主要的改动点在于
-
拍照API完善,分三端调用不同的拍照API,这一步主要解决原生相机不能框人脸,而新的API支持将人脸圈在一个范围中。
-
拍照得到h5之后,调用第三方的测肤和五官接口,获取更加精准的数据,利用Lottie动画,实现五官和测肤结果的渲染。涉及到的技术点主要有Lottie动画和测肤接口的结合。在不同的坐标点进行描绘。
利用相机的98点和俯仰角进行展示
拍照预览提示
动画部分采用lottie实现
如何与数据进行结合 -下次有机会分享
face-API.js
继续下一步的实现,face-API标注人脸轮廓与五官,参考文章,识别人的五官进行检测。https://www.cnblogs.com/neozhu/p/11771148.html
fabric.js
http://fabricjs.com/docs/fabric.Image.html通过用户手动传图 编辑与修正图的方向,从而进行提高测肤检测率。https://npm.alibaba-inc.com/package/fabricnpm包安装。
未来规划
抽出一个core引擎。将魔镜测肤应用到其他场景。
【1】淘侧测肤接口:https://yuque.antfin-inc.com/docs/share/68cdaaa8-3627-4c11-9ee8-dab22953a7b5?#
【2】2019美妆购物新体验之AI智能测肤总结: https://www.atatech.org/articles/158845?spm=ata.13261165.0.0.5fc1dd06CGvKMM
【3】 Google 最新推出的通用皮肤分析论文:https://arxiv.org/abs/1909.05382
【4】淘侧faceDetection接入文档,分端 ios:https://yuque.antfin-inc.com/genesis/alinndoc/gywzpd,安卓:https://yuque.antfin-inc.com/genesis/alinndoc/qedv3a
【5】getUserMedia API及HTML5 调用手机摄像头拍照https://segmentfault.com/a/1190000011793960
【6】简单但有趣的AR效果https://aotu.io/notes/2017/03/24/webar/index.html
【7】plupload上传文件 http://chaping.github.io/plupload/doc/
【8】JavaScript客户端签名直传https://help.aliyun.com/document_detail/31926.html?spm=a2c4g.11186623.6.1740.5b5643d3kyYsEg
【9】formData的格式-PostObject: https://help.aliyun.com/document_detail/31988.html?spm=a2c4g.11186623.2.2.6c7843d3gqDkuJ