Mini program face recognition—detect face images and obtain images

wxml

<view>
  <view class="flex white">
    <!-- 镜头翻转 -->
    <view bindtap="reverse">镜头翻转</view>
    <view bindtap="clickScanCode">扫二维码</view>
  </view>
  <view class="head-image-box w-100 text-center position-relative">
    <!-- resolution:获取人脸图片后的清晰度 low:-->
    <camera device-position="{
    
    {devicePosition ?'back': 'front'}}" class="camera" flash="off" resolution='low' />
    <view class="title">{
    
    {
    
     tipsText }}1</view>
    <image src="{
    
    {faceImage}}" mode="" />
    <cover-view class="cover-box" wx:if="{
    
    {isShow}}">
      <!-- <cover-image class="image-box" src="@/static/images/camera_verify.png"></cover-image> -->

      <!-- cover-view 不支持动画所以只能变通的形式实现 -->
      <!-- <cover-image :style="'transform: translateY('+translateY+'rpx);'" class="line" src="@/static/images/bg_line.png"></cover-image> -->
      <!-- <cover-view class="line"></cover-view> -->
    </cover-view>
    <canvas id="myCanvas" canvas-id="myCanvas" :style="'width:'+screenWidth+'px;'+'height:'+screenHeight+'px'"></canvas>
  </view>
</view>

js

// pages/face/index.js
Page({
    
    

  /**
   * 页面的初始数据
   */
  data() {
    
    
    return {
    
    
      isShow: false,
      tipsText: '', // 错误文案提示
      tempImg: '', // 本地图片路径
      cameraEngine: null, // 相机引擎
      devicePosition: false, // 摄像头朝向
      isAuthCamera: true, // 是否拥有相机权限
      isVerify: false,
      translateY: -24,
      timer: null,
      isFlag: true,
      origin: null,
      base64: "",
      personId: "",
      isFlag2: true,
      screenWidth: 375,
      screenHeight: 640,
      faceImage: '', //人脸图片
    }
  },

  onShow: function () {
    
    
    this.setData({
    
    
      isVerify: false,
      tipsText: "",
      isFlag: true,
    })

    this.lineAnimation();
  },
  onLoad(options) {
    
    
    this.initData();
  },
  onUnload() {
    
    
    this.clearTimer();
  },
  onHide() {
    
    
    this.clearTimer();
  },
  clearTimer() {
    
    
    if (this.data.timer) {
    
    
      clearInterval(this.data.timer);
      this.setData({
    
    
        timer: null,
      })
    }
    this.setData({
    
    
      isFlag: false,
    })
  },
  // 初始化相机引擎
  initData() {
    
    
    // #ifdef MP-WEIXIN
    // 1、初始化人脸识别
    wx.initFaceDetect();
    // 2、创建 camera 上下文 CameraContext 对象
    this.setData({
    
    
      cameraEngine: wx.createCameraContext(),
      isShow: true,
    })


    // 3、获取 Camera 实时帧数据
    const listener = this.data.cameraEngine.onCameraFrame((frame) => {
    
    
      console.log(888888888, frame.data, frame.width, frame.height)
      if (this.data.isVerify) return

      //动态设置canvas的宽高,不设置会导致部分机型人脸不完整导致不能识别-----很重要!很重要!很重要!
      if (this.data.isFlag2) {
    
    
        this.setData({
    
    
          isFlag2: false,
          screenWidth: frame.width,
          screenHeight: frame.height,
        })
      }
      // 4、人脸识别,使用前需要通过 wx.initFaceDetect 进行一次初始化,推荐使用相机接口返回的帧数据
      wx.faceDetect({
    
    
        frameBuffer: frame.data,
        width: frame.width,
        height: frame.height,
        enablePoint: true,
        enableConf: true,
        enableAngle: true,
        enableMultiFace: true,
        success: async (faceData) => {
    
    
          console.log(1111, faceData)
          let face = faceData.faceInfo[0]
          if (face.x == -1 || face.y == -1) {
    
    
            this.setData({
    
    
              tipsText: '检测不到人'
            })
          }
          if (faceData.faceInfo.length > 1) {
    
    
            this.setData({
    
    
              tipsText: '请保证只有一个人'
            })
          } else {
    
    
            const {
    
    
              pitch,
              roll,
              yaw
            } = face.angleArray;
            const standard = 0.5
            if (Math.abs(pitch) >= standard || Math.abs(roll) >= standard ||
              Math.abs(yaw) >= standard) {
    
    
              this.setData({
    
    
                tipsText: '请平视摄像头'
              })
            } else if (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) {
    
    
              this.setData({
    
    
                tipsText: '请勿遮挡五官'
              })
            } else {
    
    
              if (this.isVerify) return
              //人脸位置校验
              var centerWidth = 250;
              var centerHeight = 250;
              if (face.x > (frame.width - centerWidth) / 2 && face.x < (frame
                  .width - centerWidth) / 2 + centerWidth && face.y > (frame
                  .height - centerHeight) / 2 && face.y < (frame.height -
                  centerHeight) / 2 + centerHeight) {
    
    
                this.setData({
    
    
                  tipsText: '校验中...',
                  isVerify: true
                })
                // 太快获取的人脸可能比较抽象,给用户一个准备时间
                setTimeout(async () => {
    
    
                  let img = await this.changeDataToBase64(
                    frame);
                  this.setData({
    
    
                    base64: img
                  })
                  this.searchUserFace();
                }, 300)
              } else {
    
    
                this.setData({
    
    
                  tipsText: '请将人脸对准中心位置'
                })
              }
            }
          }
        },
        fail: (err) => {
    
    
          console.log(2222, err)
          if (this.isVerify) return
          if (err.x == -1 || err.y == -1) {
    
    
            this.setData({
    
    
              tipsText: '检测不到人'
            })
          } else {
    
    
            this.setData({
    
    
              tipsText: err.errMsg || '网络错误,请退出页面重试'
            })
          }
        },
      })
    })
    // 5、开始监听帧数据
    listener.start()
    this.setData({
    
    
      listener: listener
    })
    // #endif
  },
  reverse() {
    
    
    let a = this.data.devicePosition
    this.setData({
    
    
      devicePosition: !a
    })
  },
  clickScanCode() {
    
    
    // 只允许通过相机扫码
    // #ifdef MP-WEIXIN
    wx.scanCode({
    
    
      onlyFromCamera: true,
      success: (res) => {
    
    
        var data = JSON.parse(res.result.replace(/\ufeff/g, ""));
      }
    });
    // #endif
  },
  changeDataToBase64(frame) {
    
    
    console.log(4444, frame)
    return new Promise((resolve, reject) => {
    
    
      var data = new Uint8Array(frame.data);
      var clamped = new Uint8ClampedArray(data);
      let that = this;
      var width = this.data.screenWidth;
      var height = frame.height * this.data.screenWidth / frame.width;

      wx.canvasPutImageData({
    
    
        canvasId: 'myCanvas',
        x: 0,
        y: 0,
        width: frame.width,
        height: frame.height,
        data: clamped,
        success(res) {
    
     // 转换临时文件
          console.log(5555, res)
          wx.canvasToTempFilePath({
    
    
            x: 0,
            y: 0,
            width: width,
            height: height,
            canvasId: 'myCanvas',
            fileType: 'jpg',
            destWidth: width,
            destHeight: height, // 精度修改  
            quality: 0.5,
            success(res) {
    
    
              console.log(666, res)
              // 临时文件转base64
              wx.getFileSystemManager().readFile({
    
    
                filePath: res.tempFilePath, //选择图片返回的相对路径 
                encoding: 'base64', //编码格式  
                success: res => {
    
    
                  console.log(7777, res)
                  // 保存base64
                  resolve(res.data);
                }
              })
            },
            fail(res) {
    
    
              console.log(8888, res)
              reject(false);
            }
          });
        },
        fail(error) {
    
    
          console.log(error);
        }
      })
    })
  },

  searchUserFace() {
    
    
    // 1.人脸识别错误 把isVerify设置为true继续识别
    // 2.人脸识别成功,做对应的逻辑
    console.log(333, this.data.base64)
    this.setData({
    
    
      faceImage: 'data:image/jpeg;base64,' + this.data.base64,
      tipsText: '校验成功'
    })
    wx.stopFaceDetect(); //关闭人脸识别
    this.data.listener.stop(); //关闭camera摄像头监听
    return
    var params = {
    
    
      faceImage: this.data.base64,
    }
    searchFaces(params).then(res => {
    
    
      console.log(444, res)
      if (res.code == 200) {
    
    
        wx.stopFaceDetect(); //关闭人脸识别
        this.data.listener.stop(); //关闭camera摄像头监听
        this.clickPushDetail(res.data.personCode);
        this.setData({
    
    
          tipsText: '校验成功'
        })
      }
    }).catch(error => {
    
    
      setTimeout(() => {
    
    
        this.setData({
    
    
          isVerify: 'false'
        })
      }, 500)
      this.setData({
    
    
        tipsText: '暂未查找到相关人员'
      })
    })
  },
  clickPushDetail() {
    
    
    // 跳转到其他页面
  },

  lineAnimation() {
    
    
    if (this.timer) return
    this.setData({
    
    
      timer: setInterval(() => {
    
    
        this.setData({
    
    
          translateY: this.data.translateY + 8
        })
        if (this.data.translateY >= 460) {
    
    
          this.setData({
    
    
            translateY: 10
          })
        }
      }, 40)
    })

  },


  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {
    
    

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {
    
    

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {
    
    

  }
})

css

/* pages/face/index.wxss */
page {
    
    
  background-color: #000000;
}

.camera-change-image {
    
    
  width: 52rpx;
  margin-left: 40rpx;
}

.scan-image {
    
    
  width: 48rpx;
}

.update-box {
    
    
  color: #ffffff;
}

.operation-box {
    
    
  position: fixed;
  width: 100%;
  bottom: calc(120rpx + env(safe-area-inset-bottom));

}

.icon-box {
    
    
  width: 76rpx;
  height: 76rpx;

}

first {
    
    
  width: 72rpx;
  height: 72rpx;
}

.head-image-box {
    
    
  position: absolute;
  top: 10vh;
  color: white;


}

.camera {
    
    
  width: 750rpx;
  height: 872rpx;
  position: relative;
  z-index: 10;
}

#myCanvas {
    
    
  position: absolute;
  z-index: 1;
  top: -10000px;
}

.title {
    
    
  font-size: 40rpx;
  margin-top: 60rpx;
}

.cover-box {
    
    
  position: absolute;
  top: 40%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 500rpx;
  height: 500rpx;
}

.image-box {
    
    
  width: 100%;
  height: 100%;
}

.line {
    
    
  position: absolute;
  top: 0rpx;
  left: 8rpx;
  right: 8rpx;
  width: auto;
  height: 30rpx;
  z-index: 2;
}

Guess you like

Origin blog.csdn.net/weixin_43848576/article/details/135012779