前期準備
Hbuilderx編輯器(代碼編輯器)
unicloud(云服務空間,本項目采用的是阿里云)
百度智能云 (人臉識別API,有免費測試資源可用)
Hbuilderx
1.創(chuàng)建項目,啟動云開發(fā),選擇阿里云
2.新建云函數
face --- 百度AI人臉識別業(yè)務
face_token --- 生成與更新百度AI所需要的access_token
getTable --- 獲取人臉簽到的用戶信息列表
注意:函數內部需要用到npm下載的依賴?
npm i request -save //內部請求api用
npm i request-promise -save //內部請求api用
npm i moment -save //解決云函數線上時間戳差異問題
3.新建前端頁面
face --- 人臉識別
face_sign_in --- 人臉庫注冊
index --- 各業(yè)務入口
table --- 登記表格
注意:內部需要用到npm下載的依賴?
npm i image-tools //圖片轉base64
npm i moment -save //傳遞時間獲取列表時需要
4.manifest.json -?App模塊配置 - 直播推流
?
云函數
face/index.js (云函數)
'use strict';
//鏈接數據庫
const db = uniCloud.database()
//引入request模塊
const rq = require("request-promise")
//引入moment 解決時間差異問題
const moment = require('moment')
//用戶列表
const user_info = db.collection('userInfo')
//登記表
const enroll = db.collection('enroll')
exports.main = async (event, context) => {
return new Promise((resolve)=>{
//啟動參數 type get 獲取人臉信息供錄入 signin 人臉注冊 comparison 人臉 1:N 搜索
let type=event.type
//判斷百度AI簽名是否正餐
uniCloud.callFunction({
name:'face_token'
}).then(res=>{
let access_token=res.result.access_token
if(res.result.code=='200'){
//人臉檢測
if(event.type=='get'){
resolve(get(event,access_token))
}
//人臉注冊
if(event.type=='signin'){
//加入人臉庫
//數據庫注冊用戶信息 獲取id
//判斷是否存在此人
user_info.where({name:event.name}).get().then(res=>{
if(res.data.length==0){
user_info.add({name:event.name}).then(res=>{
var _user_info_={
name:event.name
}
var options = {
'method': 'POST',
'uri': 'https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add?access_token=' + access_token,
'headers': {
'Content-Type': 'application/json'
},
body: JSON.stringify({
"group_id": "yj_face_arr",
"image": event.face_image.substring(23),
"image_type": "BASE64",
"user_id": res.id,//必填
"user_info":JSON.stringify(_user_info_)
})
};
rq(options).then(res=>{
resolve(
{
code:'200',
message:'人臉注冊成功'
}
)
})
})
}else{
resolve(
{
code:'400',
message:'此用戶已存在'
}
)
}
})
}
//人臉 1:N 搜索
if(event.type=='comparison'){
//先查看圖片質量
get(event,access_token).then(res=>{
// 圖片可以
if(res.code=='200'){
//開始匹配
var options = {
'method': 'POST',
'url': 'https://aip.baidubce.com/rest/2.0/face/v3/search?access_token=' + access_token,
'headers': {
'Content-Type': 'application/json'
},
body: JSON.stringify({
"group_id_list": "yj_face_arr",
"image": res.image.substring(23),
"image_type": "BASE64",
"match_threshold":80
})
}
rq(options).then(res=>{
if(JSON.parse(res).error_msg=='SUCCESS'){
Inenroll(JSON.parse(res).result.user_list[0]).then(res=>{
resolve(res)
})
}else{
resolve(
{
code:'500',
message:'暫無用戶信息',
}
)
}
})
}else{
// 圖片不行
resolve(res)
}
})
}
}
})
})
};
//人臉檢測
function get(event,access_token){
return new Promise(resolve=>{
var options = {
'method': 'POST',
'url': 'https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=' + access_token ,
'headers': {
'Content-Type': 'application/json'
},
body: JSON.stringify({
"image": event.face_image.substring(23),
"image_type": "BASE64",
"face_field": "quality",
})
};
rq(options).then(res=>{
resolve(feedback(res,event))
})
})
}
//閾值
function feedback(res,event){
//是否檢測到人臉
if(JSON.parse(res).error_msg=='SUCCESS'){
//人臉是否完整
if(JSON.parse(res).result.face_list[0].quality.completeness){
//閾值判斷+提示
//左眼
let left_eye=JSON.parse(res).result.face_list[0].quality.occlusion.left_eye
//右眼
let right_eye=JSON.parse(res).result.face_list[0].quality.occlusion.right_eye
//鼻子
let nose=JSON.parse(res).result.face_list[0].quality.occlusion.nose
//嘴巴
let mouth=JSON.parse(res).result.face_list[0].quality.occlusion.mouth
//左臉
let left_cheek=JSON.parse(res).result.face_list[0].quality.occlusion.left_cheek
//右臉
let right_cheek=JSON.parse(res).result.face_list[0].quality.occlusion.right_cheek
//下巴
let chin_contour=JSON.parse(res).result.face_list[0].quality.occlusion.chin_contour
//圖片質量可以
if(left_eye<=0.6&&right_eye<=0.6&&nose<=0.7&&mouth<=0.7&&left_cheek<=0.8&&right_cheek<=0.8&&chin_contour<=0.6){
return(
{
code:'200',
image:event.face_image,
}
)
}else{
if(left_eye>0.6){
return(
{
code:'400',
message:'左眼被遮擋'
}
)
}else if(right_eye>0.6){
return(
{
code:'400',
message:'右眼被遮擋'
}
)
}else if(nose>0.7){
return(
{
code:'400',
message:'鼻子被遮擋'
}
)
}else if(mouth>0.7){
return(
{
code:'400',
message:'嘴巴被遮擋'
}
)
}else if(left_cheek>0.8){
return(
{
code:'400',
message:'左臉被遮擋'
}
)
}else if(right_cheek>0.8){
return(
{
code:'400',
message:'右臉被遮擋'
}
)
}else if(chin_contour>0.6){
return(
{
code:'400',
message:'下巴被遮擋'
}
)
}
}
}else{
return(
{
code:'400',
message:'未檢測到人臉'
}
)
}
}else{
//未檢出人臉 反饋前端
return(
{
code:'400',
message:'未檢測到人臉',
}
)
}
}
//表格登記
function Inenroll(e){
return new Promise((resolve)=>{
//當前日期
var today=new Date().getTimezoneOffset()==0? moment().add(8, 'hours').format('YYYY-MM-DD') : moment().format('YYYY-MM-DD')
// 查詢數據庫是否存在
enroll.where({date:today}).get().then(res=>{
console.log(res)
//沒有今日數據
if(res.data.length==0){
var user_arr=[]
console.log(e)
user_arr.push({
name:JSON.parse(e.user_info).name,
user_id:e.user_id,
Intime:new Date().getTimezoneOffset()==0? moment().add(8, 'hours').format('HH:mm:ss') : moment().format('HH:mm:ss')
})
enroll.add({
date:today,
user_arr,
}).then(res=>{
resolve({
code:'200',
message:"——"+JSON.parse(e.user_info).name+"——"
})
})
}else{
//判斷今日是否已登記
if(!res.data[0].user_arr.find(obj=>obj.user_id===e.user_id)){
//未登記
var user_arr=res.data[0].user_arr
user_arr.push({
name:JSON.parse(e.user_info).name,
user_id:e.user_id,
Intime:new Date().getTimezoneOffset()==0? moment().add(8, 'hours').format('HH:mm:ss') : moment().format('HH:mm:ss')
})
enroll.doc(res.data[0]._id).update({
user_arr,
}).then(res=>{
resolve({
code:'200',
message:"——"+JSON.parse(e.user_info).name+"——"
})
})
}else{
//已登記
resolve({
code:'500',
message:"——"+JSON.parse(e.user_info).name+"——今日已登記"
})
}
}
})
})
}
face_token/index.js (云函數)?
'use strict';
//鏈接數據庫
const db = uniCloud.database()
//引入request模塊
const rq = require("request-promise")
//聲明百度AI配置表
const Bai_Ai = db.collection('face_config')
exports.main = async (event, context) => {
//查詢數據庫中 百度AI配置信息
let Bai_Ai_data =( await Bai_Ai.get()).data[0]
return new Promise((resolve)=>{
//當前時間戳 s
var timestamp =( Date.parse(new Date()))/1000;
//檢查苦衷有無簽名
if(Bai_Ai_data.face_Access_Token.length>0){
//檢查是否過期 有效期大于兩天
//此時的時間戳 + 60*60*24 < 失效期時間戳
if(timestamp+(60*60*24)<Bai_Ai_data.AT_Outdate){
resolve({
code:200,
access_token:Bai_Ai_data.face_Access_Token
})
}else{
getAccessToken(Bai_Ai,Bai_Ai_data,timestamp).then(res=>{
resolve({
code:200,
access_token:res
})
})
}
}else{
getAccessToken(Bai_Ai,Bai_Ai_data,timestamp).then(res=>{
resolve({
code:200,
access_token:res
})
})
}
})
};
/**
* 使用 AK,SK 生成鑒權簽名(Access Token)
* @return string 鑒權簽名信息(Access Token)
*/
function getAccessToken(Bai_Ai,Bai_Ai_data,timestamp) {
return new Promise((resolve, reject) => {
var options = {
'method': 'POST',
'url': 'https://aip.baidubce.com/oauth/2.0/token?client_id='+Bai_Ai_data.face_API_Key+'&client_secret='+Bai_Ai_data.face_Secret_Key+'&grant_type=client_credentials',
'headers': {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
};
rq(options).then(res=>{
Bai_Ai.doc(Bai_Ai_data._id).update({
'face_Access_Token':JSON.parse(res).access_token,
'AT_Indate':timestamp,
'AT_Outdate':timestamp+JSON.parse(res).expires_in
})
resolve(JSON.parse(res).access_token)
})
})
}
getTable/index.js (云函數)
'use strict';
//鏈接數據庫
const db = uniCloud.database()
//登記表
const enroll = db.collection('enroll')
//用戶列表
const user_info = db.collection('userInfo')
exports.main = async (event, context) => {
return new Promise((resolve)=>{
//獲取當日登記表數據
enroll.where({date:event.date}).get().then(res=>{
resolve(res.data[0])
})
})
};
頁面
face/index.nvue? 注意:此處是?nvue 文件
<template>
<view class="live-camera" :style="{ width: windowWidth, height: windowHeight }">
<view class="preview" :style="{ width: windowWidth, height: windowHeight}">
<live-pusher id="livePusher" ref="livePusher" class="livePusher" mode="FHD" beauty="1" whiteness="0"
min-bitrate="1000" audio-quality="16KHz" :auto-focus="true" :muted="true"
:enable-camera="true" :enable-mic="false" :zoom="false" orientation="horizontal" @statechange="statechange"
:style="{ width: cameraWidth, height: cameraHeight }"></live-pusher>
<!--提示語-->
<cover-view class="remind">
<text class="remind-text" style="">{{ message }}</text>
</cover-view>
<!--輔助線-->
<cover-view class="outline-box" >
<cover-image class="outline-img" :style="{width: windowWidth+20, height: windowHeight+150}" src="../../static/face2.png"></cover-image>
</cover-view>
</view>
</view>
</template>
<script>
import { pathToBase64, base64ToPath } from 'image-tools'
export default {
data() {
return {
//啟動參數
type:'',
//提示
message: '',
//相機畫面寬度
cameraWidth: '',
//相機畫面寬度
cameraHeight: '',
//屏幕可用寬度
windowWidth: '',
//屏幕可用高度
windowHeight: '',
//流視頻對象
livePusher: null,
//照片
snapshotsrc: null,
ifPhoto: false,
};
},
onLoad(e) {
//獲取屏幕高度
this.initCamera();
this.type=e.type
},
onReady() {
this.livePusher = uni.createLivePusherContext('livePusher', this);
},
onShow() {
//開啟預覽并設置攝像頭
this.startPreview();
},
methods: {
//獲取屏幕高度
initCamera() {
let that = this
uni.getSystemInfo({
success: function(res) {
that.windowWidth = res.windowWidth;
that.windowHeight = res.windowHeight;
that.cameraWidth = res.windowWidth;
that.cameraHeight = res.windowWidth * 1.5;
}
});
},
//啟動相機
startPreview() {
var that=this
setTimeout(()=>{
console.log(that.livePusher)
that.livePusher.startPreview({
success(res) {
console.log('啟動相機', res)
}
});
},100)
},
//停止相機
stopPreview() {
let that = this
this.livePusher.stopPreview({
success(res) {
that.statechange()
console.log('停止相機', res)
}
});
},
//攝像頭 狀態(tài)
statechange(e) {
//拍照
this.snapshot()
},
//抓拍
snapshot() {
let that = this
console.log('拍照')
that.message=''
setTimeout(()=>{
that.livePusher.snapshot({
success(res) {
that.snapshotsrc = res.message.tempImagePath;
that.uploadingImg(res.message.tempImagePath)
}
});
},100)
},
// 圖片上傳
uploadingImg(e) {
let url = e
let that = this
//圖片轉base64
pathToBase64(e).then(base64 => {
//上傳云端進行分析
uniCloud.callFunction({
name:'face',
data:{
type:that.type,
face_image:base64
}
}).then(res=>{
if(res.result.code=='200'){
console.log(res)
//如果是檢測 則須保存人臉圖片進行渲染
if(that.type=='get'){
uni.setStorageSync('user_face',res.result.image)
uni.showToast({
icon:'success',
})
setTimeout(()=>{
uni.navigateBack()
},500)
}
//人臉 1:N 匹配 結果
if(that.type=='comparison'){
uni.showToast({
icon:'success',
title:res.result.message
})
setTimeout(()=>{
uni.navigateBack()
},500)
}
}
if(res.result.code=='400'){
that.message=res.result.message
console.log('錯誤',res.result.message)
//重新啟動拍照
setTimeout(()=>{
that.snapshot()
},500)
}
if(res.result.code=='500'){
uni.showModal({
content:res.result.message,
success(e) {
if (e.confirm) {
// console.log('用戶點擊確定');
uni.navigateBack()
} else if (e.cancel) {
// console.log('用戶點擊取消');
uni.navigateBack()
}
}
})
}
})
})
},
//驗證請求
request(url) {
let data = {
token: this.userInfo.token,
photo: url
}
},
// 認證失敗,重新認證
anew(msg) {
let that = this
uni.showModal({
content: msg,
confirmText: '重新審核',
success(res) {
if (res.confirm) {
// console.log('用戶點擊確定');
that.getCount()
} else if (res.cancel) {
// console.log('用戶點擊取消');
uni.navigateBack({
delta: 1
})
}
}
})
},
}
};
</script>
<style lang="scss">
.live-camera {
.preview {
justify-content: center;
align-items: center;
.outline-box {
position: absolute;
top: 0;
left: 0;
bottom: 0;
z-index: 99;
align-items: center;
justify-content: center;
}
.remind {
position: absolute;
bottom: 10px;
width: 750rpx;
z-index: 100;
align-items: center;
justify-content: center;
.remind-text {
color: #dddddd;
font-weight: bold;
}
}
}
}
</style>
face_sign_in/index.vue
<template>
<view class="content">
<view class="face-box" @click="getface">
<image class="face-bg" src="../../static/face_bg.png" mode="" v-if="!image"></image>
<view class="fb-msg" v-if="!image">
點擊錄入人臉信息
</view>
<image class="face" :src="image" mode="" v-if="image"></image>
</view>
<view class="top">
<view class="t-l">
姓名:
</view>
<input class="t-r" placeholder="請輸入姓名" type="text" @input="getuser_name" />
</view>
<view class="foot" hover-class="foot-hover" @click="getdata">
提交信息
</view>
</view>
</template>
<script>
export default {
data() {
return {
image:'',
name:''
}
},
onLoad() {
},
onShow() {
var image=uni.getStorageSync('user_face')
this.image=image
},
methods: {
//獲取人臉信息
getface(){
uni.navigateTo({
url:"/pages/face/new_file?type=get"
})
},
getuser_name(e){
this.name=e.target.value
},
getdata(){
var that=this
if(that.image&&that.name){
uniCloud.callFunction({
name:'face',
data:{
type:'signin',
face_image:that.image,
name:that.name
}
}).then((res)=>{
console.log('人臉信息注冊接口',res)
if(res.result.code=='200'){
uni.showToast({
icon:'none',
title:res.result.message
})
setTimeout(()=>{
uni.removeStorageSync('user_face')
uni.navigateBack()
},1000)
}
})
}else{
uni.showToast({
icon:"none",
title:'請完善信息'
})
}
}
}
}
</script>
<style>
.content {
height: 100%;
width:100%;
display: flex;
flex-direction: column;
align-items: center;
}
.face-box{
margin-top: 30rpx;
border-radius: 10rpx;
border:1px solid #64aff4;
height: 500rpx;
width: 400rpx;
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
}
.face-bg{
height: 100%;
width: 120%;
}
.face{
height: 160%;
width: 100%;
}
.fb-msg{
position: absolute;
bottom: 20rpx;
color: #ffffff;
}
.top{
width: 80%;
margin-top: 100rpx;
height: 100rpx;
display: flex;
align-items: center;
justify-content: center;
}
.t-l{
font-size: 32rpx;
text-align: center;
}
.t-r{
margin-left: 20rpx;
height: 100%;
width: 40%;
border-radius: 10rpx;
text-indent: 20rpx;
border:1px solid #64aff4;
}
.foot{
width: 400rpx;
text-align: center;
height: 120rpx;
line-height: 120rpx;
border-radius: 15rpx;
margin-top: 50rpx;
color: #ffffff;
background-color: #64aff4;
}
.foot-hover{
width: 400rpx;
text-align: center;
height: 120rpx;
line-height: 120rpx;
border-radius: 15rpx;
margin-top: 50rpx;
color: #ffffff;
background-color: #487fb0;
}
</style>
index/index.vue
<template>
<view class="content">
<image class="logo" src="/static/logo.png"></image>
<view class="text-area">
<text class="title" @click="zhuce">注冊人臉信息</text>
</view>
<view class="text-area">
<text class="title" @click="bidui">人臉1:N搜索信息</text>
</view>
<view class="text-area">
<text class="title" @click="table">查看統(tǒng)計表</text>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: ''
}
},
onLoad() {
var that=this
// uniCloud.callFunction({
// name:'ceshi'
// })
},
methods: {
zhuce(){
uni.navigateTo({
url:'/pages/face_sign_in/face_sign_in'
})
},
bidui(){
uni.navigateTo({
url:'/pages/face/new_file?type=comparison'
})
},
table(){
uni.navigateTo({
url:'/pages/table/table'
})
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
height: 100rpx;
border:1px solid #4d9ae7;
display: flex;
padding: 0 30rpx;
border-radius: 20rpx;
margin-top: 40rpx;
align-items: center;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>
table/index.vue
<template>
<view class="content">
<uni-table border stripe emptyText="暫無更多數據" >
<!-- 表頭行 -->
<uni-tr>
<uni-th align="center">日期</uni-th>
<uni-th align="center">統(tǒng)計</uni-th>
</uni-tr>
<!-- 表格數據行 -->
<uni-tr>
<uni-td align="center">{{list?list.date:''}}</uni-td>
<uni-td align="center">{{list?list.user_arr.length:''}}</uni-td>
</uni-tr>
<uni-tr>
<uni-th align="center">時間</uni-th>
<uni-th align="center">姓名</uni-th>
</uni-tr>
<uni-tr v-for="(item,index) in list.user_arr" :key="index">
<uni-td align="center">{{item.Intime}}</uni-td>
<uni-td align="center">{{item.name}}</uni-td>
</uni-tr>
</uni-table>
</view>
</template>
<script>
import moment from "moment"
export default {
data() {
return {
list:''
}
},
onLoad() {
var that=this
var today=new Date().getTimezoneOffset()==0? moment().add(8, 'hours').format('YYYY-MM-DD') : moment().format('YYYY-MM-DD')
that.getTable(today)
},
methods: {
getTable(e){
var that=this
uniCloud.callFunction({
name:'getTable',
data:{
date:e
}
}).then((res)=>{
console.log(res)
that.list=res.result
})
}
}
}
</script>
<style>
.content {
height: 100%;
width:100%;
}
</style>
unicloud
數據庫
enroll --- 人臉登記表
face_config --- 百度AI配置表
userInfo --- 用戶信息表
?enroll 結構
face_config 結構
userInfo 結構
百度智能云
1.控制臺申請人臉識別免費配額并創(chuàng)建應用
2.可視化人臉庫中創(chuàng)建 yj_face_arr 用戶組
3.將應用信息在數據庫 face_config 表中配置好
效果 (平板電腦橫屏)
index/index.vue
face/index.nvue
face_sign_in/index.vue
table/index.vue
文章來源:http://www.zghlxwxcb.cn/news/detail-785777.html
溫馨提示:本章只對該業(yè)務做了基礎運用,好看的頁面效果需要各位道友自己整哦?。?!哥哥姐姐們給個三連吧!?。?!文章來源地址http://www.zghlxwxcb.cn/news/detail-785777.html
到了這里,關于uni-app+云函數+百度AI(人臉檢測,人臉庫注冊,人臉1:N搜索)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!