小程序人脸打卡开发

最近做了一个小程序人脸识别的功能,主要就是前端做人脸检测, 后端调用人脸识别接口, 具体代码如下

// face-camera/index.wxml

      
      
      
        {{tipsText}}
      
  

face-camera/index.wxss

/* pages/jobs/moving-clock/sign/comp/face-camera/index.wxss */

.camera{
  /* width: 480rpx;
  height: 480rpx; */
  width: 29.56vh;
  height: 29.56vh;
  border-radius: 50%;
  overflow: hidden;
  position: relative;
  z-index: 2;
}
.tips{
  position: absolute;
  bottom: 0;
  height: 96rpx;
  width: 100%;
  background-color: rgba(0, 0, 0, 0.6);
}
.tips .text{
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 24rpx;
  color: #fff;
  text-align: center;
  height: 100%;
  width: 100%;
  font-weight: 400;
}

face-camera/index.js

// pages/jobs/moving-clock/sign/comp/face-camera/index.js
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    outTime: {
      type: Number,
      value: 15000
    },
    takePhotoIntervalTime: {
      type: Number,
      value: 1000
    },
    starting: {
      type: Boolean,
      value: false
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    ctx: null,
    tipsText: '',
    listener: null,
    startTime: 0
  },
  setTimeId: null,
  created() {
    const ctx = wx.createCameraContext();
    console.log('createCameraContext');
    wx.initFaceDetect({
      complete: (err) => {
        console.log('initFaceDetect', err);
      }
    });
    this.setData({
      ctx
    })
    this.handleOnCameraFrame((frame) => {
      if (this.data.starting) {
        console.log('frame', frame);
        this.handleWatchFaceData(frame);
      }
    });
  },
  lifetimes: {
    attached: function() {
      // 在组件实例进入页面节点树时执行
    },
    detached: function() {
      // 在组件实例被从页面节点树移除时执行
      wx.stopFaceDetect();
      let listener = this.data.listener;
      listener.stop();
    },
  },
  detached: function() {
    // 在组件实例被从页面节点树移除时执行
    wx.stopFaceDetect();
    let listener = this.data.listener;
    listener.stop();
  },

  /**
   * 组件的方法列表
   */
  methods: {
    handleOnCameraFrame(callback) {
      const that = this;
      const context = that.data.ctx;
      let listener = that.data.listener;
      let startTime = new Date().getTime();
      listener = context.onCameraFrame((frame) => {
        // console.log('frame', frame);
        const curTime = new Date().getTime()
        if (curTime - startTime >= 1000) {
          startTime = new Date().getTime();
          callback && callback(frame);
        }
      })
      listener.start({
        success: (res) => {
          console.log('listener.start', res);
        },
        fail: (err) => {
          console.log('listener.fail', err);
        }
      })
      this.setData({
        listener
      })
    },
    handleWatchFaceData(frame) {
      const that = this;
      let tipsText = '';
      wx.faceDetect({
        frameBuffer: frame.data,
        width:  frame.width,
        height: frame.height,
        enablePoint: true,
        enableConf: true,
        enableAngle: true,
        success: (faceData) => {
          console.log('faceDetect', faceData);
          let face = faceData

          if(faceData.x == -1 || faceData.y == -1) {
            tipsText = '检测不到人脸'
          }
          if(faceData.faceInfo && faceData.faceInfo.length > 1) {
            tipsText = '请保证只有一人做认证'
          } else {
            if(face.angleArray && (face.angleArray.pitch >= 0.3 || face.angleArray.roll >= 0.3 || face.angleArray.yaw >= 0.3)) {
              tipsText = '请平视摄像头'
            } else if(face.confArray && (face.confArray.global <= 0.8 || face.confArray.leftEye <= 0.8 || face.confArray.mouth <= 0.8 || face.confArray.nose <= 0.8 || face.confArray.rightEye <= 0.8)) {
              tipsText = '请勿遮挡五官'
            } else {
              tipsText = '请不要移动!'
              // 这里可以写自己的逻辑了
              if (that.data.startTime === 0) {
                that.takePhoto((res) => {
                  console.log('takePhoto', res);
                  that.setData({
                    startTime: new Date().getTime()
                  })
                  // 为了增强体验,不会造成闪拍,延迟三秒;
                  setTimeout(() => {
                    that.setData({
                      startTime: 0
                    })
                    that.triggerEvent('takePhoto', res);
                  }, 3000)
                })
              }
            }
          }
          that.setData({
            tipsText
          })
        },
        fail:function  (err)  {
          console.log(err)
          if(err.x == -1 || err.y == -1) {
            tipsText = '检测中,请面向摄像头'
          } else {
            tipsText = '网络错误,请退出页面重试'
          }
          // 这里可以写自己的逻辑了
          if (that.data.startTime === 0) {
              that.setData({
                startTime: new Date().getTime()
              })
              // 为了增强体验,不会造成闪拍,延迟5秒;
              setTimeout(() => {
                that.takePhoto((res) => {
                  console.log('takePhoto', res);
                  that.setData({
                    startTime: 0
                  })
                  that.triggerEvent('takePhoto', res);
                })
              }, 4000)
          }
          that.setData({
            tipsText
          })
        }
      })
    },
    handleStartDetect() {
    },
    handleVideo(callback) {
      // let that = this;
      const CameraContext = this.data.ctx;
      CameraContext.startRecord({
        timeout: 15,
        selfieMirror: true,
        success: (res) => {
          console.log('startRecord', res);
          callback && callback(res);
        },
        timeoutCallback: (e) => {
          const tempVideoPath = e.tempVideoPath;
          console.log('timeoutCallback', e);
        },
        complete: (e) => {
          console.log('complete', e);
        }
      })
    },

    // 拍照
    takePhoto(callback) {
        let that = this;
        const ctx = this.data.ctx;
        ctx.takePhoto({
            quality: 'high',
            success: (res) => {
                callback && callback(res);
            },
            fail: function (res) {
                wx.showToast({
                    title: '拍照错误',
                    icon: 'none',
                    duration: 2000
                });
            }
        })
    },
    error(e) {
        wx.$fn.showModal({
          title: '提示',
          context: '请允许小程序使用摄像头',
          confirmText: '知道了',
          mask: true,
          confirm: function() {
            wx.switchTab({
              url: '/pages/jobs/jobs',
            })
          },
        }, this);
    },
    getAuthInfo(callback) {
      let systemScopeMsgList = [];
      let obj = {
        cameraAuthorized: true,
        camera: true
      }
      // 可以通过 wx.getSetting 先查询一下用户是否授权了 "scope.record" 这个 scope
      wx.getSetting({
        success(settingRes) {
          console.log('settingRes', settingRes);
          if (settingRes.authSetting['scope.camera'] !== true) {
            systemScopeMsgList.push('摄像头未授权')
            obj.camera = false
          }
          wx.getSystemInfo({
            success (res) {
              console.log('getSystemInfo', res);
              const cameraAuthorized = res.cameraAuthorized; // 允许微信使用摄像头的开关
  
              if (!cameraAuthorized) {
                obj.cameraAuthorized = false
                systemScopeMsgList.push('微信使用摄像头的开关未开启');
              }
              // if (!res.model) {
              //   obj.model = false
              //   systemScopeMsgList.push('该机器为新机型,检测信息可能有误,如使用出现问题,请手动摄像头授权是否开启');
              // }
              obj.brand = res.brand;
              callback && callback(systemScopeMsgList, obj)
            }
          })
        }
      })
    }
  },
})

index.json
{
  "component": true,
  "usingComponents": {}
}


下面是使用方式

data: {
    isFaceStart: true,
isLoading: false,
serverUrl : 'http://xxx/xx/xx',
tabActiveId: 1
},
  curTimeTimeId: null,
  faceTimeId: null,

        



    handleTakePhoto(e) {
      const that = this;
      const res = e.detail || {};
      const { tempImagePath } = res;
      if (this.data.isLoading) {
        return false;
      }
      this.setData({
        isFaceStart: false,
        cameraFaceTime: 0,
        isLoading: true
      });
      clearInterval(this.faceTimeId);
      wx.showLoading()
      this.uploadMedia(this.data.serverUrl + "/api/xcxoperator/face/validate", tempImagePath).then(res => {
        console.log('sign-res', res);
        let msg = res.msg || (res.code === '200' ? '验证成功' : '验证失败');
        if (res.data && res.data.msg) {
          msg = res.data.msg;
        }
        if (res && res.code === '200') {
          wx.showModal({
            title: '打卡成功',
            context: msg,
            confirmText: '知道了',
            mask: true,
            confirm: function() {
              that.setData({
                isLoading: false
              })
              wx.switchTab({
                url: '/pages/home/index',
              })
            },
          }, that);
        } else {
          wx.showModal({
            title: '打卡失败',
            context: msg,
            confirmText: '知道了',
            mask: true,
            confirm: function() {
              // 防重复提交
              that.setData({
                  isLoading: false
                });
            },
          }, that);
        }
      })
    },
  
    uploadMedia: function (serverUrl, url) {
      return new Promise((resolve, reject) => {
        wx.uploadFile({
          url: serverUrl,
          name: 'file',
          header: {
            Cookie: wx.getStorageSync('Cookie')
          },
          formData: {
            'faceType': +this.data.tabActiveId
          },
          filePath: url,
          success: function (res) {
            console.log(res);
            const data = JSON.parse(res.data);
            wx.hideLoading()
            resolve(data);
          },
          fail: function () {
            wx.hideLoading()
            resolve({})
          }
        })
      })
    },

你可能感兴趣的:(小程序人脸打卡开发)