微信小程序云开发可以免费调用云开发控制台的云存储,云函数,云计算,当然只是一定程度上可以免费调用。不过这也比较有意思,逼格也高,而且云开发可以让我们轻易的在小程序当中和用户进行交互,接下来让我们紧跟时代潮流,利用图灵完备打造出鼠于我们的一个AI人脸识别神器吧。
在此之前,我们需要安装几个东西。
进入GIT官网,点击这,根据自己的电脑系统版本下载,下载完成以后,打开命令行(cmd),输入命令git,如果成功显示出一大段我们看不懂的字符,那就对了。
进入NodeJS官网下载,点击,下载对应版本即可,下载完成以后,在自己的cmd上面输入node -v和npm -v即可,如果显示出版本,就证明安装成功了。
首先注册一个自己的腾讯云账号,点击进入官网,点击注册,注册完账号以后,还得实名认证才能够正常使用,这个过程很快的。
之后我们还得调用腾讯云的人脸识别API接口,我们就得先开通这个服务,点击产品->人工智能->人脸识别->立即使用即可。之后如果我们向调用腾讯云API的话,我们还得去控制台->访问管理创建API密匙,之后会出现APPID,SecretID,SecretKey,之后我们调用API需要使用。
创建的时候勾选小程序-云开发即可:
之后小程序会自动生成一个模板,我们看它不爽就全删了,自己重新创建。把所有文件删掉(处理project.config.json),重新打开开发工具,然后新建两个目录,一个事服务器(命名为server),一个是客户端(命名为client),建立完目录以后,再到配置文件project.config.json里面改动一下:就改动这两行
{
"miniprogramRoot": "client/", //客户端
"cloudfunctionRoot": "server/", //服务器
"setting": {
"urlCheck": true,
改动完以后,保存,然后重新打开开发工具,我们可以看见服务器目录出现了一个云图标:
这个时候我们的环境就准备好了。但是或许有点人会出现环境未知,不要怕,博主也是,你就点击:
点击里面的云开发选项就可以看到提示,教你创建环境。
功能设想:
客户端选择或者拍照图片进行上传,然后在小程序当中调用云存储函数上传到我们个人的云存储当中,并且云存储会返回一个文件ID到客户端。
客户端获取文件ID,调用云函数,云函数就会读取这个文件ID,在云存储当中找到这个文件图片的位置,并且进行读取,获得其真实的URL地址
将获取到的URL发送到腾讯云的人脸识别API,之后人脸识别API会返回图片的相关信息
我们将这些信息一一进行处理,然后发给客户端,并且进行显示。
优化显示界面
首先,我们右键选择server文件夹,然后选择建立NodeJS云函数,命名为FaceDetect(名字随意,只要容易辨认就好),建立完成以后,目录下面会自动生成index.js和package.json文件,其中index.js文件里面有官方给出的模板,我们把多余的代码删掉
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
// 云函数入口函数
exports.main = async (event, context) => {
}
这个我们暂时先放下,我们先去腾讯云,找到人脸识别的开发文档,点击这里
之后选择人脸检测与分析相关接口,即DetectFace。
在这个文档我们可以看到很多详细的信息,比如说面部属性和人脸质量信息的识别。当然这个部署最重要的,最重要的是我们该怎么用,用哪些。
首先我们看到输入参数:
里面的Action(接口名称)和Verxion(版本)是必填的,而我们需要识别的图片是云存储上传的图片,因此需要URL参数,而且我们获取的是人脸的属性信息,因此我们还需要参数NeedFaceAttributes.
再看到输出参数,里面有:
图片的宽高,人脸信息列表(最重要的),因此我们点击FaceInfo
里面有:
其中我们会用到FaceAttributesInfo即人脸属性信息,然后点击FaceAttributesInfo查看详细信息,发现里面有很多人脸信息输出,比如说头发信息,咦,头发信息还有一个文档可以点击,有什么呢,我们看看:FaceHairAttributesInfo
里面有头发的颜色,程度,刘海,信息看来十分具体。
以上是人脸识别API的参数分析,我们了解参数分析以后,后面的执行步骤才不会那么的懵逼。
进入这一页,我们可以看到相关的SDK,SDK用起来有些许麻烦,我们可以常常新鲜东西,API Explorer,即SDK版本的GUI界面,调用API十分方便:
里面有我们前面说到的SecretId和SecretKey,还有我们前面的输入参数URL和NeedFaceAttributes(人脸属性列表),我们把这些内容给填写了,其他的不管,URL我们可以随便从网上找一张人脸图片的地址,填入,然后后面那个Need什么的参数就填写1就OK了,之后我们点击右侧的在线调用进行测试,看我们的接口调用成功没,然后选择发送请求,会出现以下结果:
如果你出现了以下类似的结构,人脸信息,那么就对了,如果出现错误,那么就是你的人脸检测服务没启用或者没有实名认证,去上面看看吧。
之后选择代码生成,选择NodeJS,此时我们就当一个搬运工,把这里的代码复制即可:
接下来我们把复制的代码加到我们云函数的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("SecretId", "SecretKey"); //腾讯云的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":"输入你自己的样例图片的地址","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) => {
}
记住,把第二行代码多余的那些点点杠杠给删了,因为我们将会使用npm install的方式安装这几个依赖包。
右键选择云函数FaceDetect,然后选择使用终端打开,输入下面两行命令:
npm install tencentcloud-sdk-nodejs --save
npm install wx-server-sdk --save
很诡异的是,在你输入第一个命令的时候,安装成功了,但是输入第二个命令的时候却见鬼了,不管输入几次,都会报错:
npm ERR! Unexpected end of JSON input while parsing near '...-/buffer-2.1.11.tgz"}'
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\23521\AppData\Roaming\npm-cache\_logs\2020-02-04T07_54_43_051Z-debug.log
遇到这个错误不要怕,因为博主也为例这个bug花了很长的时间才解决,后面才发现,我们需要首先清理缓存,输入以下命令:
npm cache clean --force
之后我们把下载改为镜像下载(不是淘宝镜像哦),输入以下命令:
npm set registry https://registry.npmjs.org/
输入完上面那行命令以后,系统还会继续让你输入,此时已经改为镜像下载,你可以输入你的第二行下载命令了:
npm install wx-server-sdk --save
好!现在总算下载完了,下载完以后,你可别着急,测试一下看看,我们下载的东西是不是真的有用,在当前终端中输入node index.js.
如果出现了一些人脸的信息,那么就是下载成功了。依赖包下载这部总算圆满完成了。
现在我们进入到云存储环节,打开之前开发工具的云开发按钮,我们就可以看到云开发控制台,之后进入存储管理界面:
之后我们随便上传一张图片(前提是我们小程序image目录里面的,如果没有,可以建一个专门存放图片),上传以后,会出现一个文件的ID,复制一下。
接下来我们可以看到微信小程序开发的云存储文档,点击这里,我们在这里面可以看到一个函数,可以专门把云存储当中文件对应的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: fileList,
})
return result.fileList
}
这个时候咱们应该毫不犹豫的把它复制粘贴搬砖搬过来给我们用。
但是呢我们需要把第三行代码当中的cloud://xxx改成我们上面的文件ID ,我们可以把这几行代码放入到我们云函数的index.js文件当中的主函数:
exports.main = async (event, context) => {
const fileList = ['测试上传文件的ID']
const result = await cloud.getTempFileURL({
fileList,
})
return result.fileList
}
我们干完上面的操作以后,可以缓一口气了,右键选择我们的云函数FaceDetect,然后选择上次并部署所有文件,等待上传成功以后,我们可以在云开发控制台那选择云函数,并且选择云端测试按钮,进行相应的测试,看看我们的云函数是不是可以正常调用,输出结果是不是对的:
之后点击运行测试,如果运行结果当中顺利的出现了fileID和其对应的tempFileURL,就说明云函数部署成功,测试成功。
经过上述测试成功以后,我们进行代码整合:
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("你的SecretID", "SecretKey"); //腾讯云的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}' //拼接参数,由于人脸识别图片的URL会变化,所有URL采用变量
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 //一次次调用,fileList里面只有一个data.fileID,因此只需要fileList[0]
datas = await synDetectFace(url) //调用异步函数,向腾讯云API发起请求
return datas
}
服务端代码完成以后,我们上传到云函数,右键选择云函数,选择上次并部署所有文件,更新云函数。
右键选择client文件目录(存放各种页面的目录),然后新建一个app.json文件,app.js文件(这些是页面目录必须的文件),选择app.json文件,在里面加入代码:
{
"pages": [
"pages/index/index"
],
"window": {
"navigationBarBackgroundColor": "#333366",
"navigationBarTextStyle": "black",
"navigationBarTitleText": "容颜下的密码",
"backgroundColor": "#eeeeee",
"backgroundTextStyle": "light",
"enablePullDownRefresh": false
},
"cloud": true,
"sitemapLocation": "sitemap0.json"
}
保存文件,就会自动生成相关目录和文件,当然,如果没有生成,也别着急,你可以尝试把pages/index/index重新自己写一遍,然后保存,就可以出来了。
对于这个功能实现,我们需要在client下面生成的index.js文件里面写入一个相关的功能函数,并且于相关的上传按钮绑定起来即可。对于上传图片功能,开发文档里面讲的比较清楚,博主就负责整合这个资源给大家使用,点击这里进入,我们可以看到里面有各种参数,其中属性我们可以相应的选择好,当选择完图片以后,会把相应的输出结果放入到res当中,我们从res当中得到tempFilePaths,即当前上传图片的图片的本地临时文件路径列表 (本地路径),代码如下:
UploadImage(){
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success(res) {
const tempFilePaths = res.tempFilePaths
console.log(tempFilePaths)
}
})
},
当我们得到这个当前需要上传的文件临时存储路径以后,我们可以把它上传到云存储上面,得到对应的fileID,然后我们通过对应的函数得到URL,再调用云函数得到脸部信息即可,具体上传云存储的函数可以参考这里,根据这个文档提供的函数我们可以修改代码,在上传文件成功以后,获得相应的临时路径,然后调用这个路径,上传到云存储当中,加入随机数,生成随机的云路径,以便于更多的用户上传:
UploadImage:function(){
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+'.jpg', //云存储路径
filePath: tempFilePaths, // 文件路径
success: res => { //成功则回调
console.log(res.fileID) //生成对应的fileID
},
})
}
})
},
当然,在进入小程序调用云函数之前,我们必须得有一个初始化的环节,即在加载页面的时候,对云环境进行初始化:
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
wx.cloud.init({
env: 'test-ws9kn' //初始化的环境ID,之前建立云环境的时候的ID
})
},
接下来我们可以进行一个小小的测试,运行小程序,选择图片,如果上传成功以后,控制台打印出了文件的fileID,那么就证明测试成功。
具体可以参考微信开发者文档当中云函数,我们需要的参数有:name(调用的云函数的名字),data(云函数需要的参数,即fileID),因此在上传云存储成功以后,我们再调用云函数处理对应的fileID,得到我们需要的脸部信息,加入相应的代码,其它不变:
wx.cloud.uploadFile({
cloudPath: random+'.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)
},
})
},
我们继续进行小小的测试,运行小程序,上传我们需要进行人脸识别的图片,然后观察控制台,如果打印出了对应的人脸信息,那么测试成功。
根据上面输出的人脸信息,我们可以看到很多类型的人脸信息,我们具体可以看看腾讯云文档的内容
假设我们需要去看的参数有年龄,是否戴眼镜,是否戴帽子,是否戴口罩,性别,头发长度,是否有刘海,头发颜色等等。此时可以在WXML文件当中加入相应的组件:
颜值:{{Beauty}}
年龄:{{age}}
是否带眼镜:{{glasses}}
是否戴口罩:{{mask}}
是否戴帽子:{{hat}}
性别:{{gender}}
头发长度:{{hair_length}}
有无刘海:{{hair_bang}}
头发颜色:{{hair_color}}
当然此时前端界面能够看到的参数只有一些具体的数字或者true,false等等,为了更加人性化的设计,我们可以进行相应的改进,比如说gender小于50 的时候,性别为女,再比如说hair_length结果输出为0的时候我们可以把输出改为光头显示在界面上等等,具体改法,可以参考文档,可以利用if语句,switch语句进行改写:
//。。。。。上面代码不变,就在云函数调用成功以后,把信息显示在界面上,当然为了能够把信息显示在界面上就得调用setData函数,但是this不能使用,首先得在UploadImage函数开始的时候写入代码:var that = this 把this给that。
wx.cloud.callFunction({
name: 'Face_Detection',
data: {
fileID:res.fileID
},
success: res => {
that.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 3:
myThis.setData({
hair_color: "棕色"
});
break;
case 4:
myThis.setData({
hair_color: "灰白色"
});
break;
}
},
})
},
})
}
})
},
对应的如果前端页面的各种值需要随着函数而改变,就必须定义变量,需要在data当中声明这些变量:
/**
* 页面的初始数据
*/
data: {
Beauty: '请上传照片',
age: '请上传照片',
glasses: '请上传照片',
mask: '请上传照片',
hat: '请上传照片',
gender: '请上传照片',
hair_length: '请上传照片',
hair_bang: '请上传照片',
hair_color: '请上传照片',
首先得在前端加上图片组件,而图片会随着上传的图片而改变,因此图片地址src也需要变量处理:
并且把这个变量加入到data当中。
我们可以在上传函数执行成功,即上传图片,生成临时路径成功的时候,把临时路径赋值给这个地址变量:
//上面和下面的代码不变
const tempFilePaths = res.tempFilePaths[0] //上传文件的图片的本地临时文件路径列表 (本地路径)
console.log(tempFilePaths)
that.setData({
image_src: res.tempFilePaths[0]
})
wx.cloud.uploadFile({ //将图片上传到云存储
之后就可以显示出我们上传的图片了。
打开我们WXSS文件,根据我们的设计需要,设计相关的布局:
.info_view{
padding-left: 20px;
padding-top: 10px;
padding-right: 20px;
padding-bottom: 20px;
}
.info{
display: flex;
flex-direction: column;
color: blue;
}
.image_view{
display: flex;
justify-content: center;
background: blanchedalmond
}
.button_view{
display: flex;
padding-top: 20px;
padding-bottom: 20px;
}
.button_size{
width: 200px;
height: 50px;
}
博主还加了一个进度条(根据上传进度,时间,加入到上传进度当中具体参考API,并且这里的代码中,我们将wx.cloud.uploadFile存为名为uploadTask的变量,然后在最后调用onProgressUpdate(res)方法,并通过setData方法,将数据展示在前端
,识别状态栏(信息读取成功会在界面上显示加载成功,识别过程中会显示消息栏:加载中,具体参考这里)
整个AI人脸识别的小程序样例大概就出来了,界面可以进行相关的优化,这个大家可以根据自己的需要把界面优化,变得更加漂亮,博主写了这么久,也写不下去了,接下来就看大家自己去优化了,有想法就去做。我上面讲的也差不多了。这是我上传图片后的样例:
最后,看博主写了一天的博客了,博主不求什么打赏啥的,博主觉得转发这篇博客就是对博主最大的馈赠了,最后,祝大家新的一年里,越来越好!!!也欢迎大家关注我的个人博客,在下所有的文章都是从个人博客导入进来的,文章会首先更新在个人博客里。希望我的博客能够给大家带来收获!
与这篇文章一个系列的还有:
微信小程序从入门到入坑
天气之子