前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >简单的说一下人脸识别的过程及前端实现

简单的说一下人脸识别的过程及前端实现

作者头像
何处锦绣不灰堆
发布2020-05-29 09:37:14
1.4K0
发布2020-05-29 09:37:14
举报
文章被收录于专栏:农历七月廿一农历七月廿一
写在前面

最近写项目的时候在做一个登录的操作,但是我们因为是多端的,有小程序,有PC,后期可能还有公众号等,所以我们的登录是很多种不同的登录方式的,有最基本的账号密码登录,有微信扫码登录,有工号刷卡登录,有手机验证码登录,当然还有逼格比较高的人脸识别登录,手机验证码登录其实是一个很简单的,所以我可能会在后期写一下处理的过程,今天我们大概说一下人脸识别的一个过程,当然因我不是写后端的,所以这里是不能贴后端的源码的,但是前端的处理还是可以写一下的。

业务需求

最近在做登录的模块,有人问了,我怎么做项目和别人不一样啊,怎么是反着的,别人都是登录先做好,再实现别的,其实这个是没什么的,我们是先简单的实现了一个账号密码的登录的过程,然后就开始实现里面具体的一些业务了,现在里面的已经做了一部分,可以进一步的完善我们的登录模块了,登录的方式很多种,其中一种就是人脸识别登录了,就是当用户点击人脸识别登录的时候,直接打开摄像头,看到自己以后进行比对,实现登录的一个过程。

实现过程

Created with Raphaël 2.2.0开始人脸照片(func) 后端 (png)比对人脸库结束yesno

就是这样一个简单的过程(其实是markdown画流程图不熟练),好吧,就简单的这样展示一下,其实人脸识别就是一个前端给照片,后端进行比对的一个过程,所以本质上说我画的也是对的。

前端代码

我把这调用摄像头和发送给后端图片文件封装成了一个组件,下面介绍一下组件怎么使用。

代码语言:javascript
复制
<template>
  <div class="videos" ref="videos">
    <video  id="video" class="vio" autoplay="autoplay" v-show="video_show"></video>
    <!--隐藏掉   为了发送照片-->
    <canvas id="canvas" width="498" height="238" v-show="canvas_show"></canvas>
  </div>
</template>

<script>
  export default {
    name: "Videos",
    props:{
      isOpen : false
    },
    data() {
      return {
        video_show : true,
        canvas_show : false,
        url : '',
        loading : true,
      }
    },
    watch:{
      isOpen(val){
        this.isOpen = val;
        console.info(val);
        if(val){
          this.camera_options();
        }
      }
    },
    methods: {
        camera_options(){
        let that = this;
        var constraints = {
          video: {
            width: 498,
            height: 238
          },
        };
        var videos = this.$refs.videos;
        console.info(videos);
        var promise = navigator.mediaDevices.getUserMedia(constraints);
        promise.then((MediaStream) => {
          /**
           * @desc MediaStream 返回参数
           * active: true
           * id: "ykCZTVor0KNVypRFZW8dFSwrFd9QuihhWmqA"
           * onactive: null
           * onaddtrack: null
           * oninactive: null
           * onremovetrack: null
           */
          console.info(MediaStream);
          video.srcObject = MediaStream;
          video.play();
        }).catch((error) => {
          console.info(error);
        });
        /**
         * @desc 倒计时以后进行拍照的操作
         */
        setTimeout(function() {
          let canvas = document.getElementById("canvas");
          console.info(canvas);
          canvas.getContext('2d').drawImage(video, 0, 0, 200, 100);
          console.info(typeof video);
          console.info(canvas.getContext('2d').drawImage(video, 0, 0, 200, 100));
          /**
           * @desc 拿到图片的base64
           * @param canvas base64
           */
          canvas = canvas.toDataURL("image/png");
          console.info(canvas);
          /**
           * @desc 拍照以后将video元素移除
           * @desc 拍照将base64转为file文件
           */
          if(canvas) {
            /**
             * 元素移除操作不进行,因为是直接发送照片,但是不进行照片的展示。
             */
            let blob = that.dataURLtoBlob(canvas);
            let file = that.blobToFile(blob, "imgName");
            if(blob){
              let url = that.url+'';
              that.$axios({
                   method : ' post',
                   url : url,
                   data : {

                   }
              }).then((res)=>{
                /**
                 * 判断是不是请求验证成功,如果成功直接登录,失败的话,直接重新发送
                 */
                 console.info(res);
              }).catch((err)=>{
                 console.info(err);
              })
            }
            console.info(file);
          } else {
            /**
             *
             */
          }
        }, 1000);
      },
      /**
       * 将图片转为file格式
       * @param {Object} dataurl 将拿到的base64的数据当做参数传递
       */
      dataURLtoBlob : function(dataurl) {
        let arr = dataurl.split(','),
            mime = arr[0].match(/:(.*?);/)[1],
            bstr = atob(arr[1]),
            n = bstr.length,
            u8arr = new Uint8Array(n);
        while(n--) {
            u8arr[n] = bstr.charCodeAt(n);
        }
        return new Blob([u8arr], {
            type: mime
        });
      },
      /**
       *
       * @param {Object} theBlob  文件
       * @param {Object} fileName 文件名字
       */
      blobToFile : function(theBlob, fileName) {
        theBlob.lastModifiedDate = new Date();
        theBlob.name = fileName;
        return theBlob;
      }
    },
  }
</script>

<style scoped>
  .videos {
    /*height: 238px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #CCCCCC;
    border-radius: 4px*/
  }
  #video{
    height: 238px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #CCCCCC;
    border-radius: 4px
  }
</style>

简单的解释一下我屎一样的代码:首先说一下我的需求,我因为是多种登录方式,所以需要注意的是用户登录的时候不确定点击哪一种登录,所以需要将扫描人脸作为其中一种验证的方式,那么用户点击别的登录方式的时候就不可以进行摄像头捕捉人像了,点击人脸识别的时候再调用,所以需要尽心父组件给子组件一个flag,来告诉他什么时候打开摄像头,什么时候关闭,所以我在开始的时候写了一个props,里面就是一个判断是否打开摄像头的flag,下面的是watch也就是一个监听事件,那么这个监听事件就是为了监听父组件是不是改变了打开摄像头的操作,下面的是methods也就是方法的实现,方法里面的注释应该写的还是很清楚的,这里就不一一的解释了。

这里需要说明几个点: 1.如果后端需要的是base64的文件,那么写到canvas = canvas.toDataURL(“image/png”);就可以结束了,那么我的代码多是应为后端需要的是一个file文件,所以我只能将base64文件转为file文件。 2.dataURLtoBlob、blobToFile这两个函数是为了转为base64转为文件用的,如果不需要转换的话,就可以直接不写这两个方法也是可以的。 3.当后端返回一个false的时候,直接重新调用该函数,这样就可以直接不停的给后端发照片,直到验证成功为止!

父组件的使用

我们引用组件的方式有多种,常见的是两种,第一是公共的引用,也就是在main.js中直接引用,另一种就是我这次用的,就是什么页面需要,就在什么页面中调用,调用的过程是:

代码语言:javascript
复制
import Videos from '@/components/login/Videos'
components : {
      'videos' : Videos
    },
代码语言:javascript
复制
<div class="login_sty" v-show="login_face">
        <!--扫脸登陆-->
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item prop="code">
              <el-input type="text" v-model="account.code" auto-complete="off" placeholder="请输入集团代码"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item>
              <el-select v-model="scheduleValue" placeholder="早班">
                <el-option v-for="item in schedule" :key="item.value" :label="item.label" :value="item.value">
                </el-option>
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <div style="height: 180px;text-align: center">
          <el-row :gutter="20">
            <el-col :span="24">
            <videos :isOpen="flag_camera"></videos>
            </el-col>
          </el-row>
        </div>
      </div>

我的点击事件是:

代码语言:javascript
复制
<el-row :gutter="20">
        <el-col :span="6"><span @click="login_type('login_wx')">微信扫码登录</span></el-col>
        <el-col :span="6"><span @click="login_type('login_face')">人脸识别登录</span></el-col>
        <el-col :span="6"><span @click="login_type('login_iphone')">手机验证码登录</span></el-col>
        <el-col :span="6"><span @click="login_type('login_cus_num')">工号卡刷卡登录</span></el-col>
      </el-row>

ok 写到这里基本就可以实现了,别的就没什么了!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-04-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 写在前面
  • 业务需求
  • 实现过程
  • 前端代码
  • 父组件的使用
相关产品与服务
验证码
腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档