原文作者:张诚
原文链接:https://www.techeek.cn/wx-wxcloud-AIface
发表日期:一月 30日 2019, 10:43:49 上午
更新日期:January 31st 2019, 2:44:27 pm
版权声明:本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可,转载请注明出处。
无服务器开发人脸识别小程序
从2006年AWS发布的第一个云服务S3开始,存储,计算等IT基础设施的能力纷纷被以服务的方式提供给用户。过去十年,云服务深刻的改变了社会获取和使用计算能力的方式,云服务自身也以极快的速度演进,新的服务形态不断涌现,无服务器计算(serverless computing)就是其中之一。国内各大厂商也在近两年推出了自家的无服务器计算产品,比如腾讯云的无服务器云函数 SCF,阿里云的函数计算等产品。
前言
前段时间我还在想,如果小程序能使用无服务器计算产品那该多好,过不奇然,最近微信与腾讯云联合开发的原生 serverless 云服务产品——小程序 · 云开发,其具备简化运维、高效鉴权等优势,让你零门槛快速上线小程序。为此,我决定尝试下这种新的开发方式,看看是不是真的如官方所说。
那么,用什么项目去尝试呢?看了下自己以前写的文章,发现这篇如何在小程序中实现人脸识别功能文章关注量还挺多,况且腾讯云人脸识别API于2019年1月25日全量更新为了最新的3.0版本,API调用方式及也有较大变化。我完全可以用最新版的API结合云开发去体验下这个过程。
当然,最大的优势在于省钱!!!小程序 · 云开发这款产品还在免费阶段,同时腾讯云人脸识别服务每月为各个接口提供 1 万次 的免费调用,很划算。
这篇文章将分享我开发过程中的一些思路,如何考虑产品应用性,如何优化逻辑等问题。同时也会分享整个的开发过程,从怎么注册账户到怎么调用API,以及代码是如何一点一点拼接的。大家也可以将这篇文章看为一篇教程,我会从0~1分享整个项目的开发过程。当然,如果你是一名Developer,请直接使用我撰写好的代码,已经分享到了GitHub,欢迎大家参阅!
那么,我们就开始吧!
准备
在撰写代码之前,我们需要先准备一下小程序的开发环境,所需要的环境有Git
、NodeJS
、npm
、微信开发者工具
。同时,因为要调用腾讯云人脸识别API,我们还需要注册腾讯云的账号,同时还需要注册腾讯云的API密钥。
安装Git
git是一个分布式版本控制软件,开发小程序的时候做好代码版本控制非常重要,如果代码写错,可以使用Git快速恢复。安装Git较为简单,我们只需要打开Git官网,点击右侧的Download 2.20.1 for Windows
,当然,版本号和系统都可能不同,大家按照自己的系统及最新的版本号下载即可。
下载完成后双击打开安装包,然后一路点击下一步直至安装完成。安装完成后我们按键盘上的Win
+R
,然后输入CMD
打开命令提示符窗口,然后在命令提示符窗口中输入git
,如果你看到类似下面的截图,证明你的Git安装成功,可以进行下一步了。
安装NodeJS和npm
NodeJS是一个可以跨平台在服务端运行JavaScript的运行环境,我们小程序云开发所使用的服务端环境就是NodeJS,为了优化并测试代码,建议在本地安装NodeJS运行环境。npm是Node包管理器,通过npm包管理器,我们可以非常方便的安装云开发所需要的环境。
首先,我们打开NodeJS官网,下载NodeJS安装包。
下载完成后双击打开,并一路下一步安装。
安装完成后,打开命令提示符,试试node
命令和npm
命令是否正常。
看到如图类似的内容,证明你的node
和npm
都已经安装成功了。
搭建小程序开发环境
开发小程序的第一步,你需要拥有一个小程序帐号,通过这个帐号你就可以管理你的小程序。
申请账号
点击 https://mp.weixin.qq.com/wxopen/waregister?action=step1 根据指引填写信息和提交相应的资料,就可以拥有自己的小程序帐号。
如果你注册过小程序,可以点击右侧的立即登录。如果没有的话,请重新注册,值得注意的是,邮箱必须填写未在微信公众平台、未在微信开放平台、个人未绑定的邮箱,不然这里是无法注册的。密码请填写你能记住的密码即可。
现在登录https://mp.weixin.qq.com/,点击左侧的设置——开发设置,在这里,我们就能看到你小程序的AppID了。
当小程序的ID拿到之后,我们就可以下载安装开发工具了。
安装开发工具
现在,打开 开发者工具下载页面 ,根据自己的操作系统下载对应的安装包进行安装。
我这里使用的是Windows 64位操作系统,所以我点击Windwos 64位
按钮进行下载。下载完成后,右键,然后以管理员身份运行安装文件。
之后,一路点击下一步安装即可。
接下来,就可以开始运行开发者工具了。使用前需要我们扫描二维码才能开始使用,请打开微信,然后点击发现——扫一扫,扫描开发者工具展示的二维码,之后在手机上点击登录即可。
- 关于小程序的快速搭建,我在如何快速搭建微信小程序有相关介绍,感兴趣的小伙伴欢迎阅读。
人脸识别API申请
您需要在 访问管理 创建密钥,点击图中的新建密钥,即可创建密钥。
创建完成后,点击SecretKey的显示按钮,显示当前SecretKey,然后将APPID
、SecretId
、SecretKey
记录下了,后面教程中使用。
现在,开发小程序所需要的所有环境就已经搭建完成,我们可以开始创建一个新的项目了。
创建云开发项目
首先,我们新建一个云开发的项目,注意AppID
是你自己在小程序AppID,同时不要勾选建立云开发模版。
接下来,我们新建两个目录,一个目录(client)存放小程序的客户端,一个目录(server)存放小程序云开发的服务端,如图。
接下来,打开配置文件project.config.json
,我们需要新增两行文件。
"cloudfunctionRoot": "server/",
"miniprogramRoot": "client/",
cloudfunctionRoot
参数填写你新建的云开发服务器的文件目录,miniprogramRoot
填写你小程序客户端的目录,如图。
当你的server
文件夹图标变成了☁的样式,证明我们云开发环境就搭建完成了。
- 对于云函数的具体使用,我在如何进行小程序云函数开发这篇文章中做了详细的介绍,感兴趣请阅读。
项目开发思考
在开始写代码之前,我们先理一下思路。什么东西放在服务端,什么东西放在客户端?
从安全角度考虑,我们在腾讯云申请到的API密钥是不能暴漏的,否则别人可以通过抓包去获取我们的ID,从而滥用造成经济上的损失,接下来就是为了识别人脸而上传的图片文件,用户数据十分重要,图片千万不能暴漏。小程序官方也提供了一些如数据库、存储、云函数所相关的能力,我们可以通云开发提供的云函数能力将腾讯的API密钥存放在服务端运行,同样的,也可以使用期所提供的云存储和数据库存放用户的图片及数据。
从产品开发角度考虑,希望产品运行足够的快,减少客户端与服务器的通讯次数,降低运维压力,增加并发数,同时,也要考虑到后期维护,所以代码尽可能的精简。
具体思路是这样子的:
- 客户端选择完图片,然后在小程序端调用云存储上传API上传图片到云存储,之后由云存储返回一个文件的ID到客户端。
- 客户端获取文件上传后的ID,调用云函数,在云函数端去读取云存储的文件,读取其真实的URL地址。
- 将获取到的地址在云函数端发送至腾讯云人脸识别API,等待人脸识别接口返回相关内容。
- 人脸识别API返回内容后,云函数原封不动的将数据发回给客户端。
- 客户端做解析,并展示给前端。
整个过程云函数只与客户端通讯两次,同时将人脸识别API调用及用户图片存放在服务端,保证密钥及资料的安全,能够达到我们的要求。
- 对于云存储的使用,我在如何进行小程序云存储开发有相关的讲解,请参阅。云存储可以在小程序的客户端调用,也可以在云函数的服务端调用。项目架构中,我们在客户端上传了相关文件,之后获取URL地址等操作均是在服务端完成的。
服务端开发
首先,我们先开发服务端,因为服务端作为架构的中心枢纽,负责接收和发送数据,非常重要。当开发完服务端,撰写客户端数据处理的时候,才能事半功倍。
新建云函数
接下来,我们开始新建云函数,在server
文件夹上面点击右键,选择新建NodeJS云函数
,然后输入你要建立云函数的名称,我这里命名为Face_Detection
。
新建完成后,系统会自动生成index.js
和package.json
文件。其中index.js
是官方给出的Demo文件,我们将生成的代码稍微处理下,只保留最基本的模版。
云函数 - index.js
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
}
腾讯云人脸识别API
我们打开腾讯云人脸识别的官网,先看看官方文档的API怎么调用。
我们看到官方给了7中人脸相关的接口,因为我们只做最基本的人脸检测,所以,选择人脸检测与分析相关接口
。
点击人脸检测与分析DetectFace
接口,查看API文档。我们看到接口提供了人脸(Face)的位置、相应的面部属性和人脸质量信息,位置包括 (x,y,w,h),面部属性包括性别(gender)、年龄(age)、表情(expression)、魅力(beauty)、眼镜(glass)、发型(hair)、口罩(mask)和姿态 (pitch,roll,yaw),人脸质量信息包括整体质量分(score)、模糊分(sharpness)、光照分(brightness)和五官遮挡分(completeness)等信息的识别,那么我们的小程序所返回的相关数据也逃不出这几个内容,所以,给用户展示的信息建议也从这里面的参数中选取。向下拉,查看请求相关参数。
请求参数如图,必填的是Action
和Version
,分别对应接口名称及版本号,按照文档,我们这里选择DetectFace
和2018-03-01
。其他数据是选填的,如MaxFaceNum
人脸数,Url
图片的地址等。我们项目架构中由云存储所分享的是图片的地址,所以URL
参数是必要的。同时我们想获取图片的人脸属性信息,所以按照表内容的内容,NeedFaceAttributes
参数也是必要的。
输入参数看完了,我们看看输出参数。
输出参数有4组,分别是图片的宽高,人脸的信息以及请求的ID。当然,最重要的还是我们的FaceInfos
参数,我看点击蓝色的FaceInfos
,看看具体有什么内容。
数据蛮多的,这里的FaceAttributesInfo
参数我们会用到,因为在输入参数中,我们需要NeedFaceAttributes
,所以当NeedFaceAttributes
参数等于1
的时候,FaceAttributesInfo
参数才会返回相关的数据,我们点开FaceAttributesInfo
参数看看。
这里就是返回参数的具体数据了,有性别,年龄,微笑程度等信息,具体大家请看描述。我们看到还有一个Hair
参数,是头发的长度、刘海、发色等信息,点开FaceHairAttributesInfo
看看。
这里就是该接口的相关信息及所有的参数了,心里大概有个底就可以了。
腾讯云人脸识别SDK
继续向下看文档,我们发现,API中给我们提供了相关的SDK。因为我们客户端的代码是NodeJS的,官方也提供了相关的SDK,那么就直接使用吧!
咦,等下,API Explorer
是什么,点击去看看,原来,这是官方给我们提供的一个GUI页面,通过简单的设置,即可生成API调用的代码,能显著降低使用云 API 的难度。
我们就用这个工具来生成我们NodeJS端的代码吧!(注:当然,这里也可自己写相关代码去调用API,但是文档中对签名验证这块讲的模糊不清,所以我还是打算使用SDK)
点开API Explorer工具,我们看到一个页面,我们看到框内有我们前面所准备的SecretId
和SecretKey
,同时也有前文中我们提到的输入参数Url
、NeedFaceAttributes
等。等下,必填Action
和Version
参数去哪里了?
原来,当我们进入人脸识别的页面后,系统已经自动帮我们填写好了Action
和Version
参数,我们只需要直接使用就行了。
我们填写下SecretId
和SecretKey
这两个参数,然后Url
参数中,我们填入一张人脸的图片,这里大家可以自己去搜索下,然后将图片的地址粘贴到这里就可以。最后,将NeedFaceAttributes
参数为1
,根据文档,我们要返回人脸属性。Region
参数大区可以不填,文档中已经说明。
如图,当填写完后,我们点击代码生成,然后选择NodeJS
,系统会自动生成我们所需要的代码。(这里有个BUG,URL地址不识别冒号,希望官方修复)
我们点击右侧的在线调用,然后点击发送请求,看看是否返回了正常的数据。
如图,这样的数据就是正常的响应结果。如果显示说您未开通人脸识别服务,请前往这里开启。我们回到代码生成页面,复制NodeJS环境的所有代码。
const tencentcloud = require("../../../../tencentcloud-sdk-nodejs");
const IaiClient = tencentcloud.iai.v20180301.Client;
const models = tencentcloud.iai.v20180301.Models;
const Credential = tencentcloud.common.Credential;
const ClientProfile = tencentcloud.common.ClientProfile;
const HttpProfile = tencentcloud.common.HttpProfile;
let cred = new Credential("AKIDypUyGMo2czFdu0La5NSK0UlpiPtEAuLa", "BAxXw99wa5OUOJ3bw52mPq57wa2HKAoG");
let httpProfile = new HttpProfile();
httpProfile.endpoint = "iai.tencentcloudapi.com";
let clientProfile = new ClientProfile();
clientProfile.httpProfile = httpProfile;
let client = new IaiClient(cred, "", clientProfile);
let req = new models.DetectFaceRequest();
let params = '{"Url":"https://img.ltn.com.tw/Upload/liveNews/BigPic/600_phprquLjl.jpg","NeedFaceAttributes":1}'
req.from_json_string(params);
client.DetectFace(req, function(errMsg, response) {
if (errMsg) {
console.log(errMsg);
return;
}
console.log(response.to_json_string());
});
我们分析下代码,第一行代码是引入名为tencentcloud-sdk-nodejs
的包文件,这个是腾讯云SDK所依赖的文件。后面几行代码就是声明人脸识别的相关版本,定义HTTP请求等。之后的cred
是声明我们的在腾讯云的相关密钥,注意你使用的时候改成自己的,httpProfile.endpoint
是我们的接口地址,接下来是重点,params
参数是我们人人脸识别特有的接口,后续要增加或删除相关参数都在这里操作。最后的内容是回调函数,并通过console.log
控制台输出,那么如何在小程序端调用呢?
我们稍微修改下代码。
云函数 - index.js
const cloud = require('wx-server-sdk')// 云函数入口文件
const tencentcloud = require("tencentcloud-sdk-nodejs"); //腾讯云API 3.0 SDK
cloud.init() // 云开发初始化
var synDetectFace = function (url) { //调用人脸识别API函数
const IaiClient = tencentcloud.iai.v20180301.Client; //API版本
const models = tencentcloud.iai.v20180301.Models; //API版本
const Credential = tencentcloud.common.Credential;
const ClientProfile = tencentcloud.common.ClientProfile;
const HttpProfile = tencentcloud.common.HttpProfile;
let cred = new Credential("AKIDypUyGMo2czFdu0La5NSK0UlpiPtEAuLa", "BAxXw99wa5OUOJ3bw52mPq57wa2HKAoG"); //腾讯云的SecretId和SecretKey
let httpProfile = new HttpProfile();
httpProfile.endpoint = "iai.tencentcloudapi.com"; //腾讯云人脸识别API接口
let clientProfile = new ClientProfile();
clientProfile.httpProfile = httpProfile;
let client = new IaiClient(cred, "", clientProfile);
let req = new models.DetectFaceRequest();
let params = '{"Url":"https://img.ltn.com.tw/Upload/liveNews/BigPic/600_phprquLjl.jpg","NeedFaceAttributes":1}'
req.from_json_string(params);
client.DetectFace(req, function (errMsg, response) {
if (errMsg) {
console.log(errMsg);
return;
}
console.log(response.to_json_string());
});
}
synDetectFace();
// 云函数入口函数
exports.main = async (event, context) => {
}
这里,我们将官方所给的代码封装成名为synDetectFace
的函数,然后在最后通过synDetectFace()
去调用这个函数。exports.main
暂时留空,我们先做第一步测试。注意删掉tencentcloud
参数中多余的../../../../
因为后面我们将用npm包管理器安装这个依赖,无需多余的../../../../
。
接下来,我们需要安装相关的依赖文件,因为不管是运行云开发还是运行腾讯云SDK都需要相关的依赖文件,这里,我们就需要用到NodeJS
运行环境和npm
包管理器了。在我们的云函数目录上面右键,选择在终端中打开
。
然后输入下面的命令,通过npm
包管理器,安装云函数和腾讯云SDK的依赖文件。
npm install tencentcloud-sdk-nodejs --save
npm install wx-server-sdk --save
这两行命令即可安装我们需要的依赖文件,如图所示。
不要关闭这个窗口,我们对我们的人脸识别接口进行测试,看看能否正常返回数据,运行下面的命令。
node index.js
如果看到类似的内容,就证明你的代码配置没有错误,可以进行下一步了。
云存储API调用
根据上面的架构,我们在服务端获取到文件的ID后,使用文件ID去云存储文件的URL地址,目前我们在云存储端还没有文件。那么,第一步,将文件上传到云存储。还好,云开发控制台可以直接上传文件,打开控制台,点击存储管理
,如图。
我们在这里随便上传一个文件,建议上传一张人脸的照片,已方便我们后续测试。上传之后点击右侧的复制按钮,复制文件的ID。
接下来,我们打开小程序云存储上传文档,调用getTempFileURL
接口,然后将ID传送给云存储。等待云存储返回URL地址,这里我们直接复制官方文档给出的代码。
const cloud = require('wx-server-sdk')
exports.main = async (event, context) => {
const fileList = ['cloud://xxx', 'cloud://yyy']
const result = await cloud.getTempFileURL({
fileList,
})
return result.fileList
}
将代码中的cloud://xxx
更换为刚才复制的文件ID。
const fileList = ['cloud://test-f97abe.7465-test-f97abe/demo.jpg']
现在,打开我们云函数的index.js
文件,将上面的代码整合到其中,并将返回的内容result.fileList
打印到控制台。
云函数 - index.js
const cloud = require('wx-server-sdk')// 云函数入口文件
const tencentcloud = require("tencentcloud-sdk-nodejs"); //腾讯云API 3.0 SDK
cloud.init() // 云开发初始化
var synDetectFace = function (url) { //调用人脸识别API函数
const IaiClient = tencentcloud.iai.v20180301.Client; //API版本
const models = tencentcloud.iai.v20180301.Models; //API版本
const Credential = tencentcloud.common.Credential;
const ClientProfile = tencentcloud.common.ClientProfile;
const HttpProfile = tencentcloud.common.HttpProfile;
let cred = new Credential("AKIDypUyGMo2czFdu0La5NSK0UlpiPtEAuLa", "BAxXw99wa5OUOJ3bw52mPq57wa2HKAoG"); //腾讯云的SecretId和SecretKey
let httpProfile = new HttpProfile();
httpProfile.endpoint = "iai.tencentcloudapi.com"; //腾讯云人脸识别API接口
let clientProfile = new ClientProfile();
clientProfile.httpProfile = httpProfile;
let client = new IaiClient(cred, "", clientProfile);
let req = new models.DetectFaceRequest();
let params = '{"Url":"https://img.ltn.com.tw/Upload/liveNews/BigPic/600_phprquLjl.jpg","NeedFaceAttributes":1}'
req.from_json_string(params);
client.DetectFace(req, function (errMsg, response) {
if (errMsg) {
console.log(errMsg);
return;
}
console.log(response.to_json_string());
});
}
synDetectFace();
// 云函数入口函数
exports.main = async (event, context) => {
const fileList = ['cloud://test-f97abe.7465-test-f97abe/demo.jpg']
const result = await cloud.getTempFileURL({
fileList,
})
return result.fileList
}
接下来,我们部署下云函数,让其在云开发端运行,我们看看能不能正常读取到我们所需要的文件。在云函数上右键,选择上传并部署:所有文件
,这一步,我们将我们刚刚写的代码及所需要的依赖环境部署在服务端。
当弹出的对话框显示上传并部署完成后,我们就可以打开云开发的控制台进行测试了。
点击云函数按钮,选择我们刚刚上传的云函数,然后单击右侧的测试。
当点击运行测试
按钮后,查看当前返回结果,如果显示成功,返回结果内有你提交的文件ID及文件的URL地址,证明我们云存储在服务端的调用执行成功。
- 对于云存储的使用,我在如何进行小程序云存储开发有相关的讲解,请参阅。
云函数代码整合
既然腾讯云人脸API和云函数端的云存储API已经调用并测试成功,那么就需要我们整合下两个代码,因为现在咱们服务端的代码是分离的,况且代码中传入的图片也不是我们想要的图片。
云函数 - index.js(最终版)
const cloud = require('wx-server-sdk') //小程序云开发SDK
const tencentcloud = require("tencentcloud-sdk-nodejs"); //腾讯云API 3.0 SDK
cloud.init() //云开发初始化
var synDetectFace = function(url) { //人脸识别API
const IaiClient = tencentcloud.iai.v20180301.Client; //API版本
const models = tencentcloud.iai.v20180301.Models; //API版本
const Credential = tencentcloud.common.Credential;
const ClientProfile = tencentcloud.common.ClientProfile;
const HttpProfile = tencentcloud.common.HttpProfile;
let cred = new Credential("AKIDypUyGMo2czFdu0La5NSK0UlpiPtEAuLa", "BAxXw99wa5OUOJ3bw52mPq57wa2HKAoG"); //腾讯云的SecretId和SecretKey
let httpProfile = new HttpProfile();
httpProfile.endpoint = "iai.tencentcloudapi.com"; //腾讯云人脸识别API接口
let clientProfile = new ClientProfile();
clientProfile.httpProfile = httpProfile;
let client = new IaiClient(cred, "", clientProfile); //调用就近地域
let req = new models.DetectFaceRequest();
let params = '{"Url":"' + url + '","NeedFaceAttributes":1}' //拼接参数
req.from_json_string(params);
return new Promise(function(resolve, reject) { //构造异步函数
client.DetectFace(req, function(errMsg, response) {
if (errMsg) {
reject(errMsg)
} else {
resolve(response);
}
})
})
}
exports.main = async(event, context) => {
const data = event
const fileList = [data.fileID] //读取来自客户端的fileID
const result = await cloud.getTempFileURL({
fileList, //向云存储发起读取文件临时地址请求
})
const url = result.fileList[0].tempFileURL
datas = await synDetectFace(url) //调用异步函数,向腾讯云API发起请求
return datas
}
我们将两个代码进行了整合,并增加了相关的备注。
首先,将腾讯云人脸识别API整体封装成为一个名为synDetectFace
异步函数,该函数携带名为url
的变量,当调用函数的时候,我们传入url
参数,函数会通过Promise
方式将人脸识别返回的内容重新返回给调用端。
接下来,为了方便云函数的调用,我们将客户端传过来的内容(文件ID)存为变量data
,并向云存储发起URL请求,将请求的返回值传到异步函数synDetectFace(url)
,此时,该函数会向腾讯云发起AI识别请求,返回的请求值最终会返回给客户端。
**修改完代码,别忘了部署在服务端。**到这一步,我们服务端的开发工作就全部搞定了。
客户端开发
服务端开发完成后,我们已经完成了三分之二的代码,接下来就是撰写客户端的代码。关掉server
文件夹。打开client
文件夹,然后新建一个名为app.json
的文件,如图。
将下面的代码复制到app.json
文件中。
{
"pages": [
"pages/index/index"
],
"window": {
"navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "人脸识别Demo",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light",
"enablePullDownRefresh": false
},
"cloud": true
}
保存完成后,系统将自动生成相关目录及文件。
选择图片API
根据流程,我们的第一步就是选择图片了,小程序官方也提供了图片选择API,废话不多说,我们直接看代码。首先,打开index.js
文件,注意,这里选择的是客户端的文件,不是服务端的。
客户端 - index.js
// pages/index/index.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
同样,官方也提供了一堆已经存在的函数,为了方便我们撰写代码,我们删除用不到的内容。
客户端 - index.js
Page({
data: {
},
onLoad: function (options) {
}
})
data
存放我们一些静态数据,以便前端调用,onLoad
是小程序的初始化执行函数,当小程序页面加载成功后会自动调用该函数,我们后续会用到。
接下来我们新建一个函数,这个函数用于当用户在前端点击某个按钮的时候,会执行该函数,我们将其命名为UploadImage
。
客户端 - index.js
Page({
data: {
},
UploadImage(){
},
onLoad: function (options) {
}
})
参考小程序官方的文档中的示例代码,修改代码如下。
客户端 - index.js
Page({
data: {
},
UploadImage(){
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths
console.log(tempFilePaths)
}
})
},
onLoad: function (options) {
}
})
参考官方的文档,参数中,我们定一个图片的张数,图片的尺寸、来源。之后该API回调返回tempFilePaths
临时图片地址。
- 关于图片API的具体使用,可以参考如何使用小程序媒体组件这篇文章,文章中有较为详细的介绍。
后端函数写完了,我们需要点击一个按钮执行上传,撰写下前端,打开index.wxml
文件,修改代码如下。
客户端 - index.wxml
<button type="primary" bindtap="UploadImage">上传照片</button>
当用户点击图中的上传照片按钮的时候,会自动调用我们在后端撰写的UploadImage
函数,如图。
当我们选择照片后,会在控制台输出当前文件的临时地址,有了临时地址,接下来一步就是将临时地址传给云存储的API,让其将文件上传。
云存储上传文件API
同选择图片API一样,微信官方文档中也提供了相关的实例代码。我们可以直接使用,先看代码。
客户端 - index.js
Page({
data: {
},
UploadImage() {
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
wx.cloud.uploadFile({
cloudPath: 'example.jpg',
filePath: tempFilePaths, // 文件路径
success: res => {
console.log(res.fileID)
},
fail: err => {
}
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
当上传图片API返回tempFilePaths
参数后,我们需要将其传入云存储上传文件的目录。,根据文档,filePath
参数就是文件资源的目录。我们直接将返回tempFilePaths
参数放在该参数下,当选择完图片,会自动调用该API上传名为example.jpg
的图片文件,同时我们上传的文件只有一张,也就是临时目录的第一张,所以返回的参数应改为res.tempFilePaths[0]
。
根据文档要求,在调用云开发之前,我们还必须初始化,才能正常使用。所以代码中我们调用了wx.cloud.init
方法,并填写了env
参数,这里的参数请改为你自己的,打开云开发控制台可查看到你的环境ID
。
上传成功后,返回回调内容,并在控制台打印出其文件ID。
控制台第一行是我们选择图片后的临时地址,第二行上传到云存储后的文件ID。
调用云函数API
当云存储调用完成后,我们拿到了文件的ID,下一步就是真正的调用云函数了,我们将文件ID传给云函数,并等待云函数返回人脸识别的结果。看一下官方的文档。
我们必须填写的有云函数的名字,选填的有data
和config
,由于我们不更改局部配置文件,所以config
用不到。但是我们需要将我们的文件ID传送给服务端,所以要填写的还有data
参数。
参考官方代码,我们调用下上面撰写的Face_Detection
云函数。
客户端 - index.js
Page({
data: {
},
UploadImage() {
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
wx.cloud.uploadFile({
cloudPath: 'example.jpg',
filePath: tempFilePaths, // 文件路径
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
console.log(res.result)
},
})
},
fail: err => {
}
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
这里的代码逻辑是,当我们图片上传完成后,通过返回的文件ID去调用名为Face_Detection
的云函数,该函数在服务端进行一系列操作后,将数据返回给客户端,最终通过控制台打印出来。
如果看到类似的结果,证明客户端基本的请求操作已经写完,这里返回的内容就是我们人脸识别后腾讯云API所返回的数据,我们可以进行下一步操作了。
当然,这里代码中有一个BUG,就是所有上传的图片名称都是example.jpg
,一个人使用当然不会造成什么问题,但如果多个人并发使用这个小程序,就会产生一个很大的BUG,同一时间内请求的图片地址相同,那么返回的结果也相同,更有可能造成云存储系统BUG。
为此,我将图片的名称变更为一个随机数,这个同一时间内随机数的内容不同,那么图片请求的时候就不会有多大问题,修改代码如下。
客户端 - index.js
Page({
data: {
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 文件路径
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
console.log(res.result)
},
})
},
fail: err => {
}
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
我们新增了一个名为random
的随机数,这个随机数是当前的UTC时间与4位随机数相加而得到的一个结果,然后将这个随机数存为我们的图片文件的名称。这样写的好处是,在同1秒内,最多可以支持1000张图片的并发。
返回值优化
接下来,我们将返回的数据展示在前端,先随便找一个参数返回在前端。先简单测试下,我们将部分数据输出到控制台。首先,我们看看腾讯云人脸识别返回的参数列表。
简单点,我们返回人脸Beauty
参数到控制台吧,参考人脸识别返回的json数据,修改上面代码中的console.log(res.result)
返回参数。
console.log(res.result.FaceInfos[0].FaceAttributesInfo.Beauty)
再次上传一遍数据,看看返回结果变成什么了。
这里返回的就是当前的魅力值,接下来,我们将这里的魅力数据传到前端。我们可以使用官方的setData
方法。修改整体代码如下。
客户端 - index.js
Page({
data: {
Beauty:""
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
var myThis = this
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 文件路径
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
console.log(res.result.FaceInfos[0].FaceAttributesInfo.Beauty)
myThis.setData({
Beauty: res.result.FaceInfos[0].FaceAttributesInfo.Beauty
})
},
})
},
fail: err => {
}
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
客户端 - index.wxml
<button type="primary" bindtap="UploadImage">上传照片</button>
<text>{{Beauty}}</text>
我们在data
中,新增一个Beauty
变量,然后在下面的UploadImage
函数中,使用myThis.setData
函数改变变量Beauty
数据。最后,我们在index.wxml
文件中去显示这个返回的内容。
当然,返回的一个参数没有多大用,我们将后台的所有数据都返回到前端,并参考腾讯云官方的文档,优化下首页显示。
客户端 - index.js
Page({
data: {
age: "请上传照片",
glasses: "请上传照片",
beauty: "请上传照片",
mask: "请上传照片",
hat: "请上传照片",
gender: "请上传照片",
hair_length: "请上传照片",
hair_bang: "请上传照片",
hair_color: "请上传照片",
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
var myThis = this
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 文件路径
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
myThis.setData({
age: res.result.FaceInfos[0].FaceAttributesInfo.Age,
glasses: res.result.FaceInfos[0].FaceAttributesInfo.Glass,
beauty: res.result.FaceInfos[0].FaceAttributesInfo.Beauty,
mask: res.result.FaceInfos[0].FaceAttributesInfo.Mask,
hat: res.result.FaceInfos[0].FaceAttributesInfo.Hat,
gender:res.result.FaceInfos[0].FaceAttributesInfo.Gender,
hair_length: res.result.FaceInfos[0].FaceAttributesInfo.Hair.Length,
hair_bang: res.result.FaceInfos[0].FaceAttributesInfo.Hair.Bang,
hair_color: res.result.FaceInfos[0].FaceAttributesInfo.Hair.Bang
})
},
})
},
fail: err => {
}
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
客户端 - index.wxml
<button type="primary" bindtap="UploadImage">上传照片</button>
<text class="text_size">性别:{{gender}}</text>
<text class="text_size">年龄:{{age}}</text>
<text class="text_size">颜值:{{beauty}}</text>
<text class="text_size">是否带眼镜:{{glasses}}</text>
<text class="text_size">是否有帽子:{{hat}}</text>
<text class="text_size">是否有口罩:{{mask}}</text>
<text class="text_size">头发长度:{{hair_length}}</text>
<text class="text_size">有无刘海:{{hair_bang}}</text>
<text class="text_size">头发颜色:{{hair_color}}</text>
如图,我们已经将所需要的数据展示在前端了。但是展示的不够完美,很多数据给用户展示用户也无法看懂。比如性别:0
、头发长度:3
、有无刘海:1
等。参考腾讯云API文档,我们将这里的数据使用switch
和if
语句做下判断,不同的数据返回不同的内容,让用户看明白。
客户端 - index.js
Page({
data: {
age: "请上传照片",
glasses: "请上传照片",
beauty: "请上传照片",
mask: "请上传照片",
hat: "请上传照片",
gender: "请上传照片",
hair_length: "请上传照片",
hair_bang: "请上传照片",
hair_color: "请上传照片",
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
var myThis = this
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 文件路径
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
myThis.setData({
age: res.result.FaceInfos[0].FaceAttributesInfo.Age,
glasses: res.result.FaceInfos[0].FaceAttributesInfo.Glass,
beauty: res.result.FaceInfos[0].FaceAttributesInfo.Beauty,
mask: res.result.FaceInfos[0].FaceAttributesInfo.Mask,
hat: res.result.FaceInfos[0].FaceAttributesInfo.Hat,
})
if (res.result.FaceInfos[0].FaceAttributesInfo.Gender < 50) {
myThis.setData({
gender: "女"
});
} else {
myThis.setData({
gender: "男"
});
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Length) {
case 0:
myThis.setData({
hair_length: "光头"
});
break;
case 1:
myThis.setData({
hair_length: "短发"
});
break;
case 2:
myThis.setData({
hair_length: "中发"
});
break;
case 3:
myThis.setData({
hair_length: "长发"
});
break;
case 4:
myThis.setData({
hair_length: "绑发"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Bang) {
case 0:
myThis.setData({
hair_bang: "有刘海"
});
break;
case 1:
myThis.setData({
hair_bang: "无刘海"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Color) {
case 0:
myThis.setData({
hair_color: "黑色"
});
break;
case 1:
myThis.setData({
hair_color: "金色"
});
break;
case 0:
myThis.setData({
hair_color: "棕色"
});
break;
case 1:
myThis.setData({
hair_color: "灰白色"
});
break;
}
},
})
},
fail: err => {
}
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
现在,我们已经将返回的内容正常显示在前端了。
交互优化
接下来,我们可以优化前端了。
文本优化
首先,最难看的莫过于这里交错的文字了,这里就需要修改index.wxss
文件。
客户端 - index.wxss
.text_viwe_size{
padding-top: 20px;
padding-bottom: 30px;
padding-left: 30px;
padding-right: 30px;
}
.text_size{
display:flex;
color: #444444;
}
我们定义一下文本显示框的大小,并定义文本显示方式和色彩。然后,修改index.wxml
文件,让其引用index.wxss
文件。
客户端 - index.wxml
<button type="primary" bindtap="UploadImage">上传照片</button>
<view class='text_viwe_size'>
<text class="text_size">性别:{{gender}}</text>
<text class="text_size">年龄:{{age}}</text>
<text class="text_size">颜值:{{beauty}}</text>
<text class="text_size">是否带眼镜:{{glasses}}</text>
<text class="text_size">是否有帽子:{{hat}}</text>
<text class="text_size">是否有口罩:{{mask}}</text>
<text class="text_size">头发长度:{{hair_length}}</text>
<text class="text_size">有无刘海:{{hair_bang}}</text>
<text class="text_size">头发颜色:{{hair_color}}</text>
</view>
上传进度
参考小程序官方的文档,调用progress
组件,我们新增一个进度条组件,打开index.wxml
文件,先在前端显示相关内容。
客户端 - index.wxml
<button type="primary" bindtap="UploadImage">上传照片</button>
<view class='progress_view_size'>
<progress percent="{{progress}}" show-info />
<text class="text_size">上传进度</text>
</view>
<view class='text_viwe_size'>
<text class="text_size">性别:{{gender}}</text>
<text class="text_size">年龄:{{age}}</text>
<text class="text_size">颜值:{{beauty}}</text>
<text class="text_size">是否带眼镜:{{glasses}}</text>
<text class="text_size">是否有帽子:{{hat}}</text>
<text class="text_size">是否有口罩:{{mask}}</text>
<text class="text_size">头发长度:{{hair_length}}</text>
<text class="text_size">有无刘海:{{hair_bang}}</text>
<text class="text_size">头发颜色:{{hair_color}}</text>
</view>
当然,前端展示了还无法显示当前进度,我们需要在后端调用返回相关进度,然后再向前端展示。
客户端 - index.js
Page({
data: {
age: "请上传照片",
glasses: "请上传照片",
beauty: "请上传照片",
mask: "请上传照片",
hat: "请上传照片",
gender: "请上传照片",
hair_length: "请上传照片",
hair_bang: "请上传照片",
hair_color: "请上传照片",
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
var myThis = this
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
var uploadTask = wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 文件路径
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
myThis.setData({
age: res.result.FaceInfos[0].FaceAttributesInfo.Age,
glasses: res.result.FaceInfos[0].FaceAttributesInfo.Glass,
beauty: res.result.FaceInfos[0].FaceAttributesInfo.Beauty,
mask: res.result.FaceInfos[0].FaceAttributesInfo.Mask,
hat: res.result.FaceInfos[0].FaceAttributesInfo.Hat,
})
if (res.result.FaceInfos[0].FaceAttributesInfo.Gender < 50) {
myThis.setData({
gender: "女"
});
} else {
myThis.setData({
gender: "男"
});
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Length) {
case 0:
myThis.setData({
hair_length: "光头"
});
break;
case 1:
myThis.setData({
hair_length: "短发"
});
break;
case 2:
myThis.setData({
hair_length: "中发"
});
break;
case 3:
myThis.setData({
hair_length: "长发"
});
break;
case 4:
myThis.setData({
hair_length: "绑发"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Bang) {
case 0:
myThis.setData({
hair_bang: "有刘海"
});
break;
case 1:
myThis.setData({
hair_bang: "无刘海"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Color) {
case 0:
myThis.setData({
hair_color: "黑色"
});
break;
case 1:
myThis.setData({
hair_color: "金色"
});
break;
case 0:
myThis.setData({
hair_color: "棕色"
});
break;
case 1:
myThis.setData({
hair_color: "灰白色"
});
break;
}
},
})
},
fail: err => {
}
})
uploadTask.onProgressUpdate((res) => {
myThis.setData({
progress: res.progress //上传进度
})
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
这里的代码中,我们将wx.cloud.uploadFile
存为名为uploadTask
的变量,然后在最后调用onProgressUpdate(res)
方法,并通过setData
方法,将数据展示在前端。接下来,优化下wxss
的代码,将前端修改漂亮点。
客户端 - index.wxss
.text_viwe_size{
padding-top: 20px;
padding-bottom: 30px;
padding-left: 30px;
padding-right: 30px;
}
.text_size{
display:flex;
color: #444444;
}
.progress_view_size{
padding-left: 30px;
padding-right: 30px;
}
显示识别图片
现在展示端还不够完美,人脸识别,当然是要将用户的照片展示在前端,我们在index.wxml
文件中插入图片。
客户端 - index.wxml
<view class="image_viwe_size">
<image src="{{image_src}}" style="width: 200px; height: 200px;"></image>
</view>
<view class='button_viwe_size'>
<button class="button_size" type="primary" bindtap="UploadImage">上传照片</button>
</view>
<view class='progress_view_size'>
<progress percent="{{progress}}" show-info />
<text class="text_size">上传进度</text>
</view>
<view class='text_viwe_size'>
<text class="text_size">性别:{{gender}}</text>
<text class="text_size">年龄:{{age}}</text>
<text class="text_size">颜值:{{beauty}}</text>
<text class="text_size">是否带眼镜:{{glasses}}</text>
<text class="text_size">是否有帽子:{{hat}}</text>
<text class="text_size">是否有口罩:{{mask}}</text>
<text class="text_size">头发长度:{{hair_length}}</text>
<text class="text_size">有无刘海:{{hair_bang}}</text>
<text class="text_size">头发颜色:{{hair_color}}</text>
</view>
然后,我们需要在后端去写image_src
图片地址,做展示,打开index.js
文件,在data
中指定图片地址。同时,当用户点击图片上传按钮的时候,我们将图片地址替换为上传的临时文件。
客户端 - index.js
Page({
data: {
age: "请上传照片",
glasses: "请上传照片",
beauty: "请上传照片",
mask: "请上传照片",
hat: "请上传照片",
gender: "请上传照片",
hair_length: "请上传照片",
hair_bang: "请上传照片",
hair_color: "请上传照片",
image_src:"https://cdn-img.easyicon.net/image/2019/panda-index.svg"
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
var myThis = this
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
myThis.setData({
image_src: res.tempFilePaths[0]
});
var uploadTask = wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 文件路径
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
myThis.setData({
age: res.result.FaceInfos[0].FaceAttributesInfo.Age,
glasses: res.result.FaceInfos[0].FaceAttributesInfo.Glass,
beauty: res.result.FaceInfos[0].FaceAttributesInfo.Beauty,
mask: res.result.FaceInfos[0].FaceAttributesInfo.Mask,
hat: res.result.FaceInfos[0].FaceAttributesInfo.Hat,
})
if (res.result.FaceInfos[0].FaceAttributesInfo.Gender < 50) {
myThis.setData({
gender: "女"
});
} else {
myThis.setData({
gender: "男"
});
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Length) {
case 0:
myThis.setData({
hair_length: "光头"
});
break;
case 1:
myThis.setData({
hair_length: "短发"
});
break;
case 2:
myThis.setData({
hair_length: "中发"
});
break;
case 3:
myThis.setData({
hair_length: "长发"
});
break;
case 4:
myThis.setData({
hair_length: "绑发"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Bang) {
case 0:
myThis.setData({
hair_bang: "有刘海"
});
break;
case 1:
myThis.setData({
hair_bang: "无刘海"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Color) {
case 0:
myThis.setData({
hair_color: "黑色"
});
break;
case 1:
myThis.setData({
hair_color: "金色"
});
break;
case 0:
myThis.setData({
hair_color: "棕色"
});
break;
case 1:
myThis.setData({
hair_color: "灰白色"
});
break;
}
},
})
},
fail: err => {
}
})
uploadTask.onProgressUpdate((res) => {
myThis.setData({
progress: res.progress //上传进度
})
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
最后,优化下前端的index.wxss
文件。
客户端 - index.wxss
.image_viwe_size{
display:flex;
justify-content: center;
background: #FFFFFF;
}
.image_size{
width: 300px;
}
.button_viwe_size{
display:flex;
padding-top: 10px;
padding-bottom: 10px;
}
.button_size{
height:50px;
width: 200px;
}
.text_viwe_size{
padding-top: 20px;
padding-bottom: 30px;
padding-left: 30px;
padding-right: 30px;
}
.text_size{
display:flex;
color: #444444;
}
.progress_view_size{
padding-left: 30px;
padding-right: 30px;
}
现在,整个UI好看多了。
识别状态展示
现在,我们已经有了上传图片进度条,但是用户上传图片后没有相关提示信息给用户,用户也不知道图片上传后是返回结果是不是正常的。那么,怎么去优化这块呢?幸好微信官方给我们提供了交互接口,我们直接调用就行,直接上代码。
客户端 - index.js
Page({
data: {
age: "请上传照片",
glasses: "请上传照片",
beauty: "请上传照片",
mask: "请上传照片",
hat: "请上传照片",
gender: "请上传照片",
hair_length: "请上传照片",
hair_bang: "请上传照片",
hair_color: "请上传照片",
image_src:"https://cdn-img.easyicon.net/image/2019/panda-index.svg"
},
UploadImage() {
var random = Date.parse(new Date()) + Math.ceil(Math.random() * 1000)
var myThis = this
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
wx.showLoading({
title: '加载中...',
});
const tempFilePaths = res.tempFilePaths[0]
console.log(tempFilePaths)
myThis.setData({
image_src: res.tempFilePaths[0]
});
var uploadTask = wx.cloud.uploadFile({
cloudPath: random + '.png',
filePath: tempFilePaths, // 文件路径
success: res => {
console.log(res.fileID)
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
wx.hideLoading()
wx.showToast({
title: '成功',
icon: 'success',
duration: 500
})
myThis.setData({
age: res.result.FaceInfos[0].FaceAttributesInfo.Age,
glasses: res.result.FaceInfos[0].FaceAttributesInfo.Glass,
beauty: res.result.FaceInfos[0].FaceAttributesInfo.Beauty,
mask: res.result.FaceInfos[0].FaceAttributesInfo.Mask,
hat: res.result.FaceInfos[0].FaceAttributesInfo.Hat,
})
if (res.result.FaceInfos[0].FaceAttributesInfo.Gender < 50) {
myThis.setData({
gender: "女"
});
} else {
myThis.setData({
gender: "男"
});
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Length) {
case 0:
myThis.setData({
hair_length: "光头"
});
break;
case 1:
myThis.setData({
hair_length: "短发"
});
break;
case 2:
myThis.setData({
hair_length: "中发"
});
break;
case 3:
myThis.setData({
hair_length: "长发"
});
break;
case 4:
myThis.setData({
hair_length: "绑发"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Bang) {
case 0:
myThis.setData({
hair_bang: "有刘海"
});
break;
case 1:
myThis.setData({
hair_bang: "无刘海"
});
break;
}
switch (res.result.FaceInfos[0].FaceAttributesInfo.Hair.Color) {
case 0:
myThis.setData({
hair_color: "黑色"
});
break;
case 1:
myThis.setData({
hair_color: "金色"
});
break;
case 0:
myThis.setData({
hair_color: "棕色"
});
break;
case 1:
myThis.setData({
hair_color: "灰白色"
});
break;
}
},
})
},
fail: err => {
}
})
uploadTask.onProgressUpdate((res) => {
myThis.setData({
progress: res.progress //上传进度
})
})
}
})
},
onLoad: function (options) {
wx.cloud.init({
env: 'test-f97abe'
})
}
})
图片文件选择成功后,我们调用wx.showLoading
接口,展示加载中的提示框。当云函数回调成功后,我们立刻调用wx.hideLoading
隐藏加载中的提示框。同时,我们调用wx.showToast
接口,显示消息成功提示框。
现在,我们就完成了一款人脸识别小程序产品的开发,并能够正常展示给用户。
总结
项目终于写完了,你学会了整体的小程序·云开发并通过腾讯云人脸识别流程了吗?希望这篇文章能给你带来一些新的经验和想法!
当然,这里的项目还有一些问题,比如图片上传到云存储后会一直存在,没有清空缓存的机制。比如一秒内用户最大并发是1000,因为图片我们设置的随机数最大是1000,后面建议将随机数改为读取图片的md5
值然后显示出来。这些BUG我也会慢慢去优化,喜欢请关注(Star)我的小程序人脸识别项目(https://github.com/Techeek/WX_TencentAI_Face)。
感谢您阅读我的文章,如果有什么新的意见或者建议,请在评论区留言。BUG反馈请在Github提交Issues。