当前位置:   article > 正文

uni-app项目+云函数+百度AI(人脸识别签到)_uniapp 百度云人脸签到

uniapp 百度云人脸签到

云函数方面 

打开uniclould控制台数据库为项目建表

        face_config 百度AI人脸识别配置表 

        userInfo 用户信息配置表 (人脸注册时需要唯一的用户id索引,所以建个表来自动生成注册用户的id)

face_config表结构

userInfo表结构

在项目创建的云函数列表内新建名为 face 的云函数

在face文件夹处鼠标右键使用命令窗口打开所在目录输入以下命令安装依赖

  1. npm i request -save
  2. npm i request-promise -save

face/index.js

  1. 'use strict';
  2. //链接数据库
  3. const db = uniCloud.database()
  4. //引入request模块
  5. const rq = require("request-promise")
  6. //声明百度AI配置表
  7. const Bai_Ai = db.collection('face_config')
  8. //用户列表
  9. const user_info = db.collection('userInfo')
  10. exports.main = async (event, context) => {
  11. //查询数据库中 百度AI配置信息
  12. let Bai_Ai_data =( await Bai_Ai.get()).data[0]
  13. //启动参数 type get 获取人脸信息供录入 signin 人脸注册
  14. let type=event.type
  15. //判断百度AI前面是否存在
  16. if(Bai_Ai_data.face_Access_Token.length>0){
  17. //人脸检测
  18. if(event.type=='get'){
  19. return new Promise((resolve,reject)=>{
  20. var options = {
  21. 'method': 'POST',
  22. 'url': 'https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=' + Bai_Ai_data.face_Access_Token ,
  23. 'headers': {
  24. 'Content-Type': 'application/json'
  25. },
  26. body: JSON.stringify({
  27. "image": event.face_image.substring(23),
  28. "image_type": "BASE64",
  29. "face_field": "quality",
  30. })
  31. };
  32. rq(options).then(res=>{
  33. //是否检测到人脸
  34. if(JSON.parse(res).error_msg=='SUCCESS'){
  35. //人脸是否完整
  36. if(JSON.parse(res).result.face_list[0].quality.completeness){
  37. //阈值判断+提示
  38. //左眼
  39. let left_eye=JSON.parse(res).result.face_list[0].quality.occlusion.left_eye
  40. //右眼
  41. let right_eye=JSON.parse(res).result.face_list[0].quality.occlusion.right_eye
  42. //鼻子
  43. let nose=JSON.parse(res).result.face_list[0].quality.occlusion.nose
  44. //嘴巴
  45. let mouth=JSON.parse(res).result.face_list[0].quality.occlusion.mouth
  46. //左脸
  47. let left_cheek=JSON.parse(res).result.face_list[0].quality.occlusion.left_cheek
  48. //右脸
  49. let right_cheek=JSON.parse(res).result.face_list[0].quality.occlusion.right_cheek
  50. //下巴
  51. let chin_contour=JSON.parse(res).result.face_list[0].quality.occlusion.chin_contour
  52. //图片质量可以
  53. 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){
  54. resolve(
  55. {
  56. code:'200',
  57. image:event.face_image
  58. }
  59. )
  60. }else{
  61. if(left_eye>0.6){
  62. resolve(
  63. {
  64. code:'400',
  65. message:'左眼被遮挡'
  66. }
  67. )
  68. }else if(right_eye>0.6){
  69. resolve(
  70. {
  71. code:'400',
  72. message:'右眼被遮挡'
  73. }
  74. )
  75. }else if(nose>0.7){
  76. resolve(
  77. {
  78. code:'400',
  79. message:'鼻子被遮挡'
  80. }
  81. )
  82. }else if(mouth>0.7){
  83. resolve(
  84. {
  85. code:'400',
  86. message:'嘴巴被遮挡'
  87. }
  88. )
  89. }else if(left_cheek>0.8){
  90. resolve(
  91. {
  92. code:'400',
  93. message:'左脸被遮挡'
  94. }
  95. )
  96. }else if(right_cheek>0.8){
  97. resolve(
  98. {
  99. code:'400',
  100. message:'右脸被遮挡'
  101. }
  102. )
  103. }else if(chin_contour>0.6){
  104. resolve(
  105. {
  106. code:'400',
  107. message:'下巴被遮挡'
  108. }
  109. )
  110. }
  111. }
  112. }else{
  113. resolve(
  114. {
  115. code:'400',
  116. message:'未检测到人脸'
  117. }
  118. )
  119. }
  120. }else{
  121. //未检出人脸 反馈前端
  122. resolve(
  123. {
  124. code:'400',
  125. message:'未检测到人脸q',
  126. }
  127. )
  128. }
  129. })
  130. })
  131. }
  132. //人脸注册
  133. if(event.type=='signin'){
  134. //加入人脸库
  135. //数据库注册用户信息 获取id
  136. return new Promise((resolve,reject)=>{
  137. //判断是否存在此人
  138. user_info.where({name:event.name}).get().then(res=>{
  139. if(res.data.length==0){
  140. user_info.add({name:event.name}).then(res=>{
  141. var _user_info_={
  142. name:event.name
  143. }
  144. var options = {
  145. 'method': 'POST',
  146. 'uri': 'https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add?access_token=' + Bai_Ai_data.face_Access_Token,
  147. 'headers': {
  148. 'Content-Type': 'application/json'
  149. },
  150. body: JSON.stringify({
  151. "group_id": "yj_face_arr",
  152. "image": event.face_image.substring(23),
  153. "image_type": "BASE64",
  154. "user_id": res.id,//必填
  155. "user_info":JSON.stringify(_user_info_)
  156. })
  157. };
  158. rq(options).then(res=>{
  159. resolve(
  160. {
  161. code:'200',
  162. message:'人脸注册成功'
  163. }
  164. )
  165. })
  166. })
  167. }else{
  168. resolve(
  169. {
  170. code:'400',
  171. message:'此用户已存在'
  172. }
  173. )
  174. }
  175. })
  176. })
  177. }
  178. //人脸 1:N 搜索
  179. if(event.type=='comparison'){
  180. return new Promise((resolve)=>{
  181. var options = {
  182. 'method': 'POST',
  183. 'url': 'https://aip.baidubce.com/rest/2.0/face/v3/search?access_token=' + Bai_Ai_data.face_Access_Token,
  184. 'headers': {
  185. 'Content-Type': 'application/json'
  186. },
  187. body: JSON.stringify({
  188. "group_id_list": "yj_face_arr",
  189. "image": event.face_image.substring(23),
  190. "image_type": "BASE64"
  191. })
  192. }
  193. rq(options).then(res=>{
  194. resolve(
  195. {
  196. code:'200',
  197. message:'人脸匹配成功',
  198. user_info:JSON.parse( JSON.parse(res).result.user_list[0].user_info )
  199. }
  200. )
  201. })
  202. })
  203. }
  204. }else{
  205. //不存在 生成签名
  206. console.log('签名不存在')
  207. var options = {
  208. 'method': 'POST',
  209. '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',
  210. 'headers': {
  211. 'Content-Type': 'application/json',
  212. 'Accept': 'application/json'
  213. }
  214. };
  215. rq(options).then(res=>{
  216. console.log(JSON.parse(res).access_token)
  217. //签名存入数据表
  218. Bai_Ai.doc('657bbf51652341901ba0e89b').update({
  219. 'face_Access_Token':JSON.parse(res).access_token
  220. })
  221. })
  222. }
  223. };

百度AI方面

开通人脸识别服务---应用列表--创建应用

可视化人脸库---新建用户组yj_face_arr

将应用的信息填入第一步创建好的数据表中  Access_token 为云函数内部生成并填入 

前端方面

pages文件下创建文件夹

face/new_file.nvue    

  1. <template>
  2. <view class="live-camera" :style="{ width: windowWidth, height: windowHeight }">
  3. <view class="preview" :style="{ width: windowWidth, height: windowHeight-80}">
  4. <live-pusher id="livePusher" ref="livePusher" class="livePusher" mode="FHD" beauty="1" whiteness="0"
  5. min-bitrate="1000" audio-quality="16KHz" :auto-focus="true" :muted="true"
  6. :enable-camera="true" :enable-mic="false" :zoom="false" orientation="horizontal" @statechange="statechange"
  7. :style="{ width: cameraWidth, height: cameraHeight }"></live-pusher>
  8. <!--提示语-->
  9. <cover-view class="remind">
  10. <text class="remind-text" style="">{{ message }}</text>
  11. </cover-view>
  12. <!--辅助线-->
  13. <cover-view class="outline-box" >
  14. <cover-image class="outline-img" :style="{width: windowWidth+20, height: windowHeight+150}" src="../../static/face2.png"></cover-image>
  15. </cover-view>
  16. </view>
  17. </view>
  18. </template>
  19. <script>
  20. import { pathToBase64, base64ToPath } from 'image-tools'
  21. export default {
  22. data() {
  23. return {
  24. //启动参数
  25. type:'',
  26. //提示
  27. message: '',
  28. //相机画面宽度
  29. cameraWidth: '',
  30. //相机画面宽度
  31. cameraHeight: '',
  32. //屏幕可用宽度
  33. windowWidth: '',
  34. //屏幕可用高度
  35. windowHeight: '',
  36. //流视频对象
  37. livePusher: null,
  38. //照片
  39. snapshotsrc: null,
  40. ifPhoto: false,
  41. };
  42. },
  43. onLoad(e) {
  44. //获取屏幕高度
  45. this.initCamera();
  46. this.type=e.type
  47. },
  48. onReady() {
  49. this.livePusher = uni.createLivePusherContext('livePusher', this);
  50. },
  51. onShow() {
  52. //开启预览并设置摄像头
  53. this.startPreview();
  54. },
  55. methods: {
  56. //获取屏幕高度
  57. initCamera() {
  58. let that = this
  59. uni.getSystemInfo({
  60. success: function(res) {
  61. that.windowWidth = res.windowWidth;
  62. that.windowHeight = res.windowHeight;
  63. that.cameraWidth = res.windowWidth;
  64. that.cameraHeight = res.windowWidth * 1.5;
  65. }
  66. });
  67. },
  68. //启动相机
  69. startPreview() {
  70. var that=this
  71. setTimeout(()=>{
  72. console.log(that.livePusher)
  73. that.livePusher.startPreview({
  74. success(res) {
  75. console.log('启动相机', res)
  76. }
  77. });
  78. },300)
  79. },
  80. //停止相机
  81. stopPreview() {
  82. let that = this
  83. this.livePusher.stopPreview({
  84. success(res) {
  85. that.statechange()
  86. console.log('停止相机', res)
  87. }
  88. });
  89. },
  90. //摄像头 状态
  91. statechange(e) {
  92. //拍照
  93. this.snapshot()
  94. },
  95. //抓拍
  96. snapshot() {
  97. let that = this
  98. console.log('拍照')
  99. that.message=''
  100. this.livePusher.snapshot({
  101. success(res) {
  102. that.snapshotsrc = res.message.tempImagePath;
  103. that.uploadingImg(res.message.tempImagePath)
  104. }
  105. });
  106. },
  107. // 图片上传
  108. uploadingImg(e) {
  109. let url = e
  110. let that = this
  111. //图片转base64
  112. pathToBase64(e).then(base64 => {
  113. //上传云端进行分析
  114. uniCloud.callFunction({
  115. name:'face',
  116. data:{
  117. type:that.type,
  118. face_image:base64
  119. }
  120. }).then(res=>{
  121. if(res.result.code=='200'){
  122. //如果是注册 则须保存人脸图片进行渲染
  123. if(that.type=='signin'){
  124. uni.setStorageSync('user_face',res.result.image)
  125. }
  126. //人脸 1:N 匹配 结果
  127. if(that.type=='comparison'){
  128. console.log(res)
  129. }
  130. uni.navigateBack()
  131. }else{
  132. that.message=res.result.message
  133. console.log('错误',res.result.message)
  134. //重新启动拍照
  135. setTimeout(()=>{
  136. that.snapshot()
  137. },100)
  138. }
  139. })
  140. })
  141. },
  142. //验证请求
  143. request(url) {
  144. let data = {
  145. token: this.userInfo.token,
  146. photo: url
  147. }
  148. },
  149. // 认证失败,重新认证
  150. anew(msg) {
  151. let that = this
  152. uni.showModal({
  153. content: msg,
  154. confirmText: '重新审核',
  155. success(res) {
  156. if (res.confirm) {
  157. // console.log('用户点击确定');
  158. that.getCount()
  159. } else if (res.cancel) {
  160. // console.log('用户点击取消');
  161. uni.navigateBack({
  162. delta: 1
  163. })
  164. }
  165. }
  166. })
  167. },
  168. }
  169. };
  170. </script>
  171. <style lang="scss">
  172. .live-camera {
  173. .preview {
  174. justify-content: center;
  175. align-items: center;
  176. .outline-box {
  177. position: absolute;
  178. top: 0;
  179. left: 0;
  180. bottom: 0;
  181. z-index: 99;
  182. align-items: center;
  183. justify-content: center;
  184. }
  185. .remind {
  186. position: absolute;
  187. bottom: 10px;
  188. width: 750rpx;
  189. z-index: 100;
  190. align-items: center;
  191. justify-content: center;
  192. .remind-text {
  193. color: #dddddd;
  194. font-weight: bold;
  195. }
  196. }
  197. }
  198. }
  199. </style>

face_sign_in/face_sign_in.vue

  1. <template>
  2. <view class="content">
  3. <view class="face-box" @click="getface">
  4. <image class="face-bg" src="../../static/face_bg.png" mode="" v-if="!image"></image>
  5. <view class="fb-msg" v-if="!image">
  6. 点击录入人脸信息
  7. </view>
  8. <image class="face" :src="image" mode="" v-if="image"></image>
  9. </view>
  10. <view class="top">
  11. <view class="t-l">
  12. 姓名:
  13. </view>
  14. <input class="t-r" placeholder="请输入姓名" type="text" @input="getuser_name" />
  15. </view>
  16. <view class="foot" hover-class="foot-hover" @click="getdata">
  17. 提交信息
  18. </view>
  19. </view>
  20. </template>
  21. <script>
  22. export default {
  23. data() {
  24. return {
  25. image:'',
  26. name:''
  27. }
  28. },
  29. onLoad() {
  30. },
  31. onShow() {
  32. var image=uni.getStorageSync('user_face')
  33. this.image=image
  34. },
  35. methods: {
  36. //获取人脸信息
  37. getface(){
  38. uni.navigateTo({
  39. url:"/pages/face/new_file?type=get"
  40. })
  41. },
  42. getuser_name(e){
  43. this.name=e.target.value
  44. },
  45. getdata(){
  46. var that=this
  47. if(that.image&&that.name){
  48. uniCloud.callFunction({
  49. name:'face',
  50. data:{
  51. type:'signin',
  52. face_image:that.image,
  53. name:that.name
  54. }
  55. }).then((res)=>{
  56. console.log('人脸信息注册接口',res)
  57. if(res.result.code=='200'){
  58. uni.showToast({
  59. icon:'none',
  60. title:res.result.message
  61. })
  62. setTimeout(()=>{
  63. uni.removeStorageSync('user_face')
  64. uni.navigateBack()
  65. },1000)
  66. }
  67. })
  68. }else{
  69. uni.showToast({
  70. icon:"none",
  71. title:'请完善信息'
  72. })
  73. }
  74. }
  75. }
  76. }
  77. </script>
  78. <style>
  79. .content {
  80. height: 100%;
  81. width:100%;
  82. display: flex;
  83. flex-direction: column;
  84. align-items: center;
  85. }
  86. .face-box{
  87. margin-top: 30rpx;
  88. border-radius: 10rpx;
  89. border:1px solid #64aff4;
  90. height: 500rpx;
  91. width: 400rpx;
  92. overflow: hidden;
  93. display: flex;
  94. flex-direction: column;
  95. align-items: center;
  96. position: relative;
  97. }
  98. .face-bg{
  99. height: 100%;
  100. width: 120%;
  101. }
  102. .face{
  103. height: 160%;
  104. width: 100%;
  105. }
  106. .fb-msg{
  107. position: absolute;
  108. bottom: 20rpx;
  109. color: #ffffff;
  110. }
  111. .top{
  112. width: 80%;
  113. margin-top: 100rpx;
  114. height: 100rpx;
  115. display: flex;
  116. align-items: center;
  117. justify-content: center;
  118. }
  119. .t-l{
  120. font-size: 32rpx;
  121. text-align: center;
  122. }
  123. .t-r{
  124. margin-left: 20rpx;
  125. height: 100%;
  126. width: 40%;
  127. border-radius: 10rpx;
  128. text-indent: 20rpx;
  129. border:1px solid #64aff4;
  130. }
  131. .foot{
  132. width: 400rpx;
  133. text-align: center;
  134. height: 120rpx;
  135. line-height: 120rpx;
  136. border-radius: 15rpx;
  137. margin-top: 50rpx;
  138. color: #ffffff;
  139. background-color: #64aff4;
  140. }
  141. .foot-hover{
  142. width: 400rpx;
  143. text-align: center;
  144. height: 120rpx;
  145. line-height: 120rpx;
  146. border-radius: 15rpx;
  147. margin-top: 50rpx;
  148. color: #ffffff;
  149. background-color: #487fb0;
  150. }
  151. </style>

index/index.vue

  1. <template>
  2. <view class="content">
  3. <image class="logo" src="/static/logo.png"></image>
  4. <view class="text-area">
  5. <text class="title" @click="zhuce">注册人脸信息</text>
  6. </view>
  7. <view class="text-area">
  8. <text class="title" @click="bidui">人脸1:N搜索信息</text>
  9. </view>
  10. </view>
  11. </template>
  12. <script>
  13. export default {
  14. data() {
  15. return {
  16. title: ''
  17. }
  18. },
  19. onLoad() {
  20. var that=this
  21. },
  22. methods: {
  23. zhuce(){
  24. console.log('????')
  25. uni.navigateTo({
  26. url:'/pages/face_sign_in/face_sign_in'
  27. })
  28. },
  29. bidui(){
  30. uni.navigateTo({
  31. url:'/pages/face/new_file?type=comparison'
  32. })
  33. }
  34. }
  35. }
  36. </script>
  37. <style>
  38. .content {
  39. display: flex;
  40. flex-direction: column;
  41. align-items: center;
  42. justify-content: center;
  43. }
  44. .logo {
  45. height: 200rpx;
  46. width: 200rpx;
  47. margin-top: 200rpx;
  48. margin-left: auto;
  49. margin-right: auto;
  50. margin-bottom: 50rpx;
  51. }
  52. .text-area {
  53. display: flex;
  54. justify-content: center;
  55. }
  56. .title {
  57. font-size: 36rpx;
  58. color: #8f8f94;
  59. }
  60. </style>

注意:需要配置云函数 Node.js 的版本

云函数文件下 package.json 内添加

本文只做了云函数调用百度AI的人脸检测,人脸库注册,人脸1:N搜索的功能 会这些大部分业务都不会有难度了

第一次写文章,有不足的大家多多担待,辛苦大家点个小赞,谢谢喽!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/703394
推荐阅读
相关标签
  

闽ICP备14008679号