微信小程序|基于小程序实现人脸数量检测
Posted 摔跤猫子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信小程序|基于小程序实现人脸数量检测相关的知识,希望对你有一定的参考价值。
一、文章前言
此文主要通过小程序实现检测图片中的人脸数量并标记出位置信息。
当近视的小伙伴看不清远处的人时,用小程序一键识别就可以在手机上看清楚啦,是不是很实用呢。
典型应用场景:如人脸属性分析,基于人脸关键点的加工分析,人脸营销活动等。
二、具体流程及准备
2.1、注册百度开放平台及微信公众平台账号。
2.2、下载及安装微信Web开发者工具。
2.3、如需通过SDK调用及需准
微信小程序 |基于百度AI从零实现人脸识别小程序
写在前面
针对互联网上已有的人脸识别小程序项目,很多只是基于手动拍照,然后上传到SDK进行识别。这一过程完全脱离实际场景!无法直接使用!
本文项目是基于微信摄像头中的实时视频帧数据
,通过实时动态识别小程序端所获取的照片帧,从而自动触发人脸识别和登录!完全贴合实际,真正的拿来即用!
一、需求背景
人脸识别是一个老生常谈的问题了,再继小程序的逐步普及化后,人脸识别的功能也变为了各大业务的家常菜。目前市面上已有的解决方案,一方面除了自研以外,对于本来就是小成本进行创业或者开发的个人以及初创型公司来说,接入一些专业的第三方的人脸识别接口不妨是一个优秀的解决方案。目前市面上常用的第三方支持技术有哪些,可以阅读本专栏的文章: 微信小程序 | 人脸识别的最终解决方案 – 里面做了详细的介绍和解读,相信能带你弄请这个方向的技术行情。
为此,这一次我们自己动手来实现一次全流程的人脸识别小程序
。 没有基础不用担心,本文就是带领大家从零到一开始搭建,细致到每个网页功能如何选择、代码如何编写,前后端的逻辑如何编写。只会前端或者后端的小伙伴也不用担心,本文提供全流程的操作指引,让零基础的前/后端小白都能轻松上手。 废话不多说相信看到上面酷炫的效果大家应该都按捺不住了,那就让我们开整把。
二、系统架构
2.1 系统技术栈
前端 | 后端 |
---|---|
- 语言:vue 2.0 | - 框架 : uni-app | - UI组件: uview | - 语言:python | - 框架: Flask |
2.2 系统架构图
2.3 系统请求时序图
2.4 详细接口请求时序图
三、项目实现
要使用百度智能云的api接口,就需要在控制台创建你的项目应用,通过项目应用去获取API Key``Secret Key ``Access_token
,这三个参数是后续调用api接口的必填参数,缺一不可!
3.1 开通百度智能云API
- 登录到百度智能云人脸识别控制台
- 选择相应的API接口并进行购买操作即可(其中我们选择的是
人脸比对
),其实为了方便我们可以一次性将所有的人脸识别相关的产品全部都进行一次购买,反正都是按量计费,不进行调用也就不用收钱了。
3.2 并获取API Key
-在开通了服务的基础上,由于要获取三大认证参数,再调用接口之前我们仍需要进行应用的创建。
- 由此即可获取到三大参数
3.3 搭建项目调试环境
本项目是继续uniapp
框架进行开发(采用uniapp框架开发的好处在于:在面对众多的小程序平台,我们只需要编写这一套代码就可以实现多平台的运行,极大程度的降低了开发成本!可以说是只要会一套小程序开发的流程,基本每个平台你都能拿下。
)
- 详细的开发环境搭建过程,可以参考:从零开始搭建uni-app框架的小程序开发环境
3.4 参考百度云SDK文档
- 人脸识别接口Pthon SDK文档:人脸接口文档地址
3.5 人脸对比接口详解
接口能力
- 两张人脸图片相似度对比:比对两张图片中人脸的相似度,并返回相似度分值;
- 多种图片类型:支持生活照、证件照、身份证芯片照、带网纹照四种类型的人脸对比;
- 活体检测:基于图片中的破绽分析,判断其中的人脸是否为二次翻拍(举例:如用户A用手机拍摄了一张包含人脸的图片一,用户B翻拍了图片一得到了图片二,并用图片二伪造成用户A去进行识别操作,这种情况普遍发生在金融开户、实名认证等环节。);
- 质量检测:返回模糊、光照等质量检测信息,用于辅助判断图片是否符合识别要求;
业务应用
用于比对多张图片中的人脸相似度并返回两两比对的得分,可用于判断两张脸是否是同一人的可能性大小。
典型应用场景:如人证合一验证,用户认证等,可与您现有的人脸库进行比对验证。
result = client.match([
'image': base64.b64encode(open('1.jpg', 'rb').read()).decode(),
'image_type': 'BASE64',
,
'image': base64.b64encode(open('2.jpg', 'rb').read()).decode(),
'image_type': 'BASE64',
])
请求参数
参数 | 必选 | 类型 | 说明 |
---|---|---|---|
image | 是 | string | 图片信息(总数据大小应小于10M),图片上传方式根据image_type来判断。 两张图片通过json格式上传,格式参考表格下方示例 |
image_type | 是 | string | 图片类型 BASE64:图片的base64值,base64编码后的图片数据,编码后的图片大小不超过2M;URL:图片的 URL地址( 可能由于网络等原因导致下载图片时间过长);FACE_TOKEN: 人脸图片的唯一标识,调用人脸检测接口时,会为每个人脸图片赋予一个唯一的FACE_TOKEN,同一张图片多次检测得到的FACE_TOKEN是同一个。 |
face_type | 否 | string | 人脸的类型LIVE表示生活照:通常为手机、相机拍摄的人像图片、或从网络获取的人像图片等,IDCARD表示身份证芯片照:二代身份证内置芯片中的人像照片, WATERMARK表示带水印证件照:一般为带水印的小图,如公安网小图 CERT表示证件照片:如拍摄的身份证、工卡、护照、学生证等证件图片 默认LIVE |
quality_control | 否 | string | 图片质量控制 NONE: 不进行控制 LOW:较低的质量要求 NORMAL: 一般的质量要求 HIGH: 较高的质量要求 默认 NONE |
liveness_control | 否 | string | 活体检测控制 NONE: 不进行控制 LOW:较低的活体要求(高通过率 低攻击拒绝率) NORMAL: 一般的活体要求(平衡的攻击拒绝率, 通过率) HIGH: 较高的活体要求(高攻击拒绝率 低通过率) 默认NONE |
返回参数
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
score | 是 | float | 人脸相似度得分 |
face_list | 是 | array | 人脸信息列表 |
+face_token | 是 | string | 人脸的唯一标志 |
返回示例
"score": 44.3,
"face_list": [ //返回的顺序与传入的顺序保持一致
"face_token": "fid1"
,
"face_token": "fid2"
]
3.6 人脸注册到人脸库功能实现
为了实现保存用户的人脸信息,用于验证人脸请求。一般都是有两种方案:
- 其一,是我们在自己的后台服务维护一套用户人脸信息库,然后在每次前端请求登入时进行读库操作,同时再调用
client.match()
方法对用户的登录信息进行比对。这样的做法可以实现高度自定义化,但是维护成本相对较高,主要包括数据的存储和可视化的展示
- 其二,百度SDK平台给我们提供了一套完整的用于维护用户人脸信息库API,而且还以
Group
分组的形式进行用户数据管理,这就使得对于用户的所归宿的不同组的权限进行区分。同样地,借助组的字段概念可以与业务系统打通,进而更为方便的管理用户。
3.6.1 前端代码实现
微信摄像头实时帧的获取与数据处理
要实现小程序端自动采集人脸数据并进行接口验证,就必须使用微信摄像头图像帧数据的采集与监听功能。
- 官方接口说明如下:
- 程序中实现思路如下:
1、调用
onCameraFrame
接口,生成帧数据监听器,然后使用listener.start()
启动监听服务。
2、在listen接口
中设置一个setInterVal()
时间循环任务,从而实现一个循环获取帧数据并循环上报并处理接口返回数据的任务,保证人脸登录的实时性!
3、特别地,对于获取到的帧数据,仍需要进行处理:将其转为Base64格式数据从而进行数据传输。
- 代码如下:
startFaceCapture()
console.log('=====show==facelogin=====')
var that = this
this.isAuthCamera = true
var i = 1;
const context = wx.createCameraContext()
console.log('=====load===')
const listener = context.onCameraFrame((frame) =>
// console.log('==获取帧动画===',that.flag)
if (frame && that.flag)
i++;
that.frameQueue.push(frame)
// console.log('==push任务',that.frameQueue.length)
that.flag = false
// console.log(i++, frame.data, frame.width, frame.height)
)
listener.start(
success: function(res)
console.log("开始监听");
let task = setInterval(function()
var timeStart = Date.now();
//在此处处理store[0](图像的数据);
// store.shift();
var frame = that.frameQueue.shift()
console.log("开始运行===",frame,that.flag);
that.flag = true;
if(frame != undefined)
let pngData = UPNG.encode([frame.data], frame.width, frame.height),
base64 = Base64Util.arrayBufferToBase64(pngData)
uni.request(
url: 'http://127.0.0.1:8099/faceAuth' ,
method: 'post',
data: openId:uni.getStorageSync("openId"),base64Img:base64 ,
dataType:'json',
header:
'content-type':'application/json'//自定义请求头信息
,
success:(res)=>
console.log('===result===',res)
clearInterval(task)
this.$refs.uToast.show(
...failTips,
complete()
)
,
fail:(err)=>
console.log("====执行失败===",err)
clearInterval(task)
that.isAuthCamera = false
uni.navigateTo(
url:'./login'
)
)
// if(i==2)
// clearInterval(task)
// that.isAuthCamera = false
//
, 2000);
)
,
3.6.1.1 首页登录界面源代码
<template>
<view>
<view class="content cover" :animation="animationBack">
<!-- <view class="bg"></view>
<view class="bg2"></view>
<view class="tips">
<text class="title">登录</text>
<text class="subtitle">欢迎再次回来~</text>
</view>
<view class="form-box">
<view class="btn"style="margin-top:10px;" @click='rotateFn(2)'>密码登录</view>
<view class="other">
<text>找回密码</text>
<text style="color:#00c6fc;">录入人脸</text>
</view>
</view> -->
<capture ref="faceLogin" @changeLoginMode="rotateFn(2)"></capture>
</view>
<view class="content cover" :animation="animationMain">
<view class="bg"></view>
<view class="bg2"></view>
<view class="tips">
<text class="title">登录</text>
<text class="subtitle">欢迎再次回来~</text>
</view>
<view class="form-box">
<view class="input-box">
<image class="left"
src="https://6e69-niew6-1302638010.tcb.qcloud.la/%E7%99%BB%E5%BD%95%E6%A0%B7%E5%BC%8F/%E7%99%BB%E5%BD%959/%E8%B4%A6%E5%8F%B7.png">
</image>
<input placeholder="请输入账号" />
<image class="right"
src="https://6e69-niew6-1302638010.tcb.qcloud.la/%E7%99%BB%E5%BD%95%E6%A0%B7%E5%BC%8F/%E7%99%BB%E5%BD%959/%E4%B8%8B%E6%8B%89.png">
</image>
</view>
<view class="input-box">
<image class="left"
src="https://6e69-niew6-1302638010.tcb.qcloud.la/%E7%99%BB%E5%BD%95%E6%A0%B7%E5%BC%8F/%E7%99%BB%E5%BD%959/%E5%AF%86%E7%A0%81.png">
</image>
<input placeholder="请输入密码" />
<image class="right"
src="https://6e69-niew6-1302638010.tcb.qcloud.la/%E7%99%BB%E5%BD%95%E6%A0%B7%E5%BC%8F/%E7%99%BB%E5%BD%959/%E6%98%BE%E7%A4%BA%E5%AF%86%E7%A0%81.png">
</image>
</view>
<view class="btn">登录</view>
<view class="btn" style="margin-top:10px;" @click='login()'>刷脸登录</view>
<view class="other">
<text>找回密码</text>
<text style="color:#00c6fc;">快速注册</text>
</view>
</view>
</view>
</view>
</template>
<script>
import capture from './capture.vue'
export default
components:
capture
,
data()
return
animationMain: null, //正
animationBack: null, //反
,
methods:
rotateFn(e)
this.animation_main = uni.createAnimation(
duration: 400,
timingFunction: 'linear'
)
this.animation_back = uni.createAnimation(
duration: 400,
timingFunction: 'linear'
)
// 点击正面
if (e == 1)
this.animation_main.rotateY(180).step()
this.animation_back.rotateY(0).step()
this.animationMain = this.animation_main.export()
this.animationBack = this.animation_back.export()
this.$refs.faceLogin.startFaceCapture()
else
this.animation_main.rotateY(0).step()
this.animation_back.rotateY(-180).step()
this.animationMain = this.animation_main.export()
this.animationBack = this.animation_back.export()
,
login()
var that = this;
if (uni.getStorageSync("openId") == undefined)
wx.login(
success(res)
console.log('===触发登录====', res)
if (res.code)
uni.request(
url: 'http://127.0.0.1:8000/miniapp/faceEngine/login/' + res.code,
method: 'get',
dataType: 'json',
success: (res) =>
console.log("====执行成功===", res)
that.rotateFn(1)
uni.setStorageSync("authed", true)
uni.setStorageSync("openId", res.data.openid)
,
fail: (err) =>
console.log("====执行失败===", err)
)
else
console.log('登录失败!')
)
else
that.rotateFn(1)
,
</script>
<style lang="scss">
page
margin: 0;
padding: 0;
min-height: 100vh;
position: relative;
background-color: rgb(118, 218, 255);
overflow: hidden;
page::before,
page::after
content: '';
position: absolute;
top: 90vh;
min-width: 300vw;
min-height: 300vw;
background-color: #76daff;
animation: rote 10s linear infinite;
page::before
left: -95%;
border-radius: 45%;
opacity: .5;
page::after
left: -95%;
border-radius: 46%;
@keyframes rote
from
transform: rotateZ(0);
to
transform: rotateZ(360deg);
.cover
position: absolute;
top: 0;
left: 0;
.content
width: 100vw;
height: 100vh;
background-color: #ffffff;
transition: all 1s;
backface-visibility: hidden;
.tips
padding-top: 200rpx;
padding-left: 80rpx;
display: flex;
flex-direction: column;
.title
line-height: 70rpx;
font-weight: bold;
font-size: 50rpx;
.subtitle
line-height: 70rpx;
font-size: 35rpx;
font-weight: bold;
color: #b0b0b1;
.bg
position: fixed;
top: -250rpx;
right: -250rpx;
width: 600rpx;
height: 600rpx开源项目3:微信小程序AR和Three.js实现全景图片3D查看器方向传感器旋转