zoukankan      html  css  js  c++  java
  • 基于javaweb人脸识别注册登录系统

    ---恢复内容开始---

    现在是2019年,人脸识别技术已经相当成熟了,百度自2017年发布人脸识别技术,已经被广泛应用,不管从现在的iphoneX掀起的面部解锁到手机应用端的各种人脸认证,这一技术已经悄然升息的方便了我们的生活,但是在web端注册登录缺很少用到刷脸登录,第一个最主要的原因可能是安全隐私方面人们对大数据时代的误解。不多废话,下面通过调用百度api来实现人脸注册及登录,

    Web端人脸识别主要有三个技术思路:

    1.前端的人脸识别,例如使用Tensorflow.js,

    2.后台人脸识别,有很多开源或者免费的SDK可以使用,

    3.前后端结合,即结合以上两种方法,虽然系统复杂度提高,但对于系统的安全性,以及减轻服务器负担都有很大提升。

    (来自https://blog.csdn.net/scaped/article/details/81414406 )笔者为java实现

    下面先直接上效果图

    如果感到不适,请忽略掉背景图,以技术为准

    完了,还是暴露的我的丑照。。如有不适,请忽略......

    一、第一步,在百度云创建应用

    如上图,点击创建应用,在以下步骤需要用到这个API key 及Secret Key

    二、第二步、创建人脸库及创建用户组

     这里注意了,当你看到这篇博客时调用的百度云的v3版本,但是还是会用到v2版本的api,

     不管哪个版本,不管调用哪个api,人脸检测、人脸搜索、人脸对比,都需要首先获取access_token,

    获取token地址为

    https://aip.baidubce.com/oauth/2.0/

    后边需要三个参数

    也可以直接在浏览器地址替换成自己的api  key 及secret查看返回的数据,sccess_token的生效日期为一个月,每一个月需要重新获取,所以在程序中我们没必要重复获取

    从返回的json数据中我们可以看到获取到的token形式为24.71c5ac57b2.....一大长串

    第二步、在浏览器获取摄像头,并实时输出到video,再利用canvas截取当前图像
    <!doctype html>
    <html lang="en">
        <head>
            <title>GET VIDEO</title>
            <meta charset="utf-8">
        </head>
        <body>
        <input type="button" title="开启摄像头" value="开启摄像头" onclick="getMedia()" />
        <video id="video" width="500px" height="500px" autoplay="autoplay"></video>
        <canvas id="canvas" width="500px" height="500px"></canvas>
        <button id="snap" onclick="takePhoto()">拍照</button>
        <script>
            function getMedia() {
                let constraints = {
                    video: { 500, height: 500},
                    audio: true
                };
                //获得video摄像头区域
                let video = document.getElementById("video");
                //这里介绍新的方法,返回一个 Promise对象
                // 这个Promise对象返回成功后的回调函数带一个 MediaStream 对象作为其参数
                // then()是Promise对象里的方法
                // then()方法是异步执行,当then()前的方法执行完后再执行then()内部的程序
                // 避免数据没有获取到
                let promise = navigator.mediaDevices.getUserMedia(constraints);
                promise.then(function (MediaStream) {
                    video.srcObject = MediaStream;
                    video.play();
                });
            }
     
          function takePhoto() {
          //获得Canvas对象
          let video = document.getElementById("video");
          let canvas = document.getElementById("canvas");
          let ctx = canvas.getContext('2d');
          ctx.drawImage(video, 0, 0, 500, 500);
          }
    </script>
    </body>
    </html>
    这里主要思想就是调用系统摄像头,将视频流传入video标签内,就在网页上显示出了摄像头的效果,再通过canvas截图,将某一时刻的视频截为图片,
    后面再将图片转为base64格式传入后端,进行一系列人脸操作
    三、人脸对比、
    这里首先进行人脸比对,后续再写人脸库搜索,将两张图片的base64数据传入进行比对,得到一些列数据,根据返回的相似度来确定是否为一人
    注意:这里可能会出现错误,

    因为将图片的数据转成base64数据非常的长,超过了默认的长度,这里只需要修改tomcat的配置文件server.xml文件就OK

    <Connector connectionTimeout="20000" maxHttpHeaderSize="102400" maxPostSize="-1" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

    官网文档:
    https://cloud.baidu.com/doc/FACE/Face-Match.html#.E8.B0.83.E7.94.A8.E6.96.B9.E5.BC.8F

    注意从今日起调用v3版本的api,调用v2版本会报一些错误,两张图片对比如下:

    /**  
     * All rights Reserved, Designed By liufuqiang
     * @Title:  faceMatch.java   
     * @Package faceLogin   
     * @Description:    TODO
     * @author: LiuFuqiang     
     * @date:   2019年5月6日 下午7:07:22   
     * @version V1.0 
     * @Copyright: 2019 liufuqiang All rights reserved. 
     */
    package faceLogin;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import utils.Base64Util;
    import utils.FileUtil;
    import utils.GsonUtils;
    import utils.HttpUtil;
    
    /**
     * @author Administrator
     *
     */
    
    
    /**
    * 人脸对比
    */
    public class faceMatch {
    
        /**
        * 重要提示代码中所需工具类
        * FileUtil,Base64Util,HttpUtil,GsonUtils请从
        * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72
        * https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2
        * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
        * https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3
        * 下载
        */
        public static String match() {
            // 请求url
            String url = "https://aip.baidubce.com/rest/2.0/face/v3/match";
            try {
    
                byte[] bytes1 = FileUtil.readFileByBytes("【本地图片路径1】");
                byte[] bytes2 = FileUtil.readFileByBytes("【本地图片路径2】");
                String image1 = Base64Util.encode(bytes1);
                String image2 = Base64Util.encode(bytes2);
    
                List<Map<String, Object>> images = new ArrayList<>();
    
                Map<String, Object> map1 = new HashMap<>();
                map1.put("image", image1);
                map1.put("image_type", "BASE64");
                map1.put("face_type", "LIVE");
                map1.put("quality_control", "LOW");
                map1.put("liveness_control", "NORMAL");
    
                Map<String, Object> map2 = new HashMap<>();
                map2.put("image", image2);
                map2.put("image_type", "BASE64");
                map2.put("face_type", "LIVE");
                map2.put("quality_control", "LOW");
                map2.put("liveness_control", "NORMAL");
    
                images.add(map1);
                images.add(map2);
    
                String param = GsonUtils.toJson(images);
                AuthService auth = new AuthService();
                String accessToken = auth.getAuth();
                // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。
                
    
                String result = HttpUtil.post(url, accessToken, "application/json", param);
                String score=result.split(",")[5].split(":")[2];
                return score;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
       
    }

    所需要的工具包会在网址自行下载,

    找两张图片进行比对,会返回json数据,但是咱们将他转化成字符串了,

    新建servlet执行此java文件

    faceMatch match = new faceMatch();
    String score = match.match();
    System.out.println(score);

    我们找两张相似的图片进行比对,这里注意图片格式除了gif格式不支持,每张图片的大小不能超过2M

    result:{"error_code":0,"error_msg":"SUCCESS","log_id":304592874888025681,"timestamp":1557488802,"cached":0,"result":{"score":97.75291443,"face_list":[{"face_token":"8ea5f423bb1cf93b87ebce4ff2ac623b"},{"face_token":"31c258d65509177ba99aecf28dadc496"}]}}
    

     返回的数据如下,result里面score:97.75291443,推荐阈值为80基本上判断为同一个人,可能没找到和我长得相似的,不管调用哪种api要么相似度是90多要么相似度是10以下,很少出现中间的值,

    现在咱们比对的是两张固定的图片。那。。。要调用摄像头干鸡毛呢。。。将这两张图片的某一个图片地址base64换成前端base64的数据就可以了,

    修改上面java:

    faceMatch.java

    /**  
     * All rights Reserved, Designed By liufuqiang
     * @Title:  faceMatch.java   
     * @Package faceLogin   
     * @Description:    TODO
     * @author: LiuFuqiang     
     * @date:   2019年5月6日 下午7:07:22   
     * @version V1.0 
     * @Copyright: 2019 liufuqiang All rights reserved. 
     */
    package faceLogin;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import utils.Base64Util;
    import utils.FileUtil;
    import utils.GsonUtils;
    import utils.HttpUtil;
    
    /**
     * @author Administrator
     *
     */
    
    
    /**
    * 人脸对比
    */
    public class faceMatch {
    
        /**
        * 重要提示代码中所需工具类
        * FileUtil,Base64Util,HttpUtil,GsonUtils请从
        * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72
        * https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2
        * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
        * https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3
        * 下载
        */
        public static String match(String image2) {
            // 请求url
            String url = "https://aip.baidubce.com/rest/2.0/face/v3/match";
            try {
    
                byte[] bytes1 = FileUtil.readFileByBytes("C:\Users\Administrator\Desktop\liu8.png");
                /*byte[] bytes2 = FileUtil.readFileByBytes("C:\Users\Administrator\Desktop\liu6.png");*/
                String image1 = Base64Util.encode(bytes1);
                /*String image2 = Base64Util.encode(bytes2);*/
    
                List<Map<String, Object>> images = new ArrayList<>();
    
                Map<String, Object> map1 = new HashMap<>();
                map1.put("image", image1);
                map1.put("image_type", "BASE64");
                map1.put("face_type", "LIVE");
                map1.put("quality_control", "LOW");
                map1.put("liveness_control", "NORMAL");
    
                Map<String, Object> map2 = new HashMap<>();
                map2.put("image", image2);
                map2.put("image_type", "BASE64");
                map2.put("face_type", "LIVE");
                map2.put("quality_control", "LOW");
                map2.put("liveness_control", "NORMAL");
    
                images.add(map1);
                images.add(map2);
    
                String param = GsonUtils.toJson(images);
                AuthService auth = new AuthService();
                String accessToken = auth.getAuth();
                // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。
                
    
                String result = HttpUtil.post(url, accessToken, "application/json", param);
                String score=result.split(",")[5].split(":")[2];
                return score;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
       
    }

    jsp页面通过ajax执行上传数据到servlet

    index.jsp

    <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
    <%
        String path = request.getContextPath();
        String basePath = request.getScheme() + "://"
                + request.getServerName() + ":" + request.getServerPort()
                + path + "/";
    %>
     
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>demo01</title>
      
      <script src="http://www.jq22.com/jquery/1.11.1/jquery.min.js"></script>
      <script src="js/jquery-1.9.1.min.js"></script>
      <style type="text/css">
        .line{ 
    
        position: absolute; 
    
        top: 300px; left: -80px; 
    
        z-index: 2; 
    
        height: 15px;  300px; 
    
         background: linear-gradient(#33ffff, #66cccc,#99cccc); opacity: 0.7  /* 标准的语法 */
    
        /*动画效果*/
    
        animation: myScan 3s infinite alternate; 
    
        -webkit-animation: myScan 3s infinite alternate; 
    
    }
    @keyframes  myScan{
    
        from { top:5px; }
    
        to { top: 300px; }
    
    }
    
    -webkit-@keyframes  myScan{
    
        from { top:5px; }
    
        to { top: 600px; }
    
    }
    .box{background-image: url('image/bg2.jpg'); 100%;height: 640px;background-size:100%, 100%;}
    .video{250px;height:250px;margin:auto;background-image: url('image/faceBorder.png')}
    
    </style>
    </head>
    <body>
    <div class="box">
    <div class="right">
    <div class="video">
    
    <!-- <div class="line"></div> -->
    
     <video id="myVideo" src="" class="video" ></video>
    
    </div>
     <canvas id="myCanvas" width="600" height="400" hidden="hidden"></canvas>
     <script>
      var myVideo = document.getElementById('myVideo');
      navigator.mediaDevices.getUserMedia({
        video: true
      }).then(function (mediaStream) {
        myVideo.srcObject = mediaStream;
        myVideo.onloadedmetadata = function () {
          /* myVideo.controls = "controls"; 不显示控件*/
          myVideo.play();
        }
      });
     
     function jiance(){
         var canvas = document.getElementById('myCanvas').getContext('2d');
         canvas.drawImage(myVideo, 0, 0);
            var imgSrc = document.getElementById("myCanvas").toDataURL(
            "image/png").split("base64,")[1];
            $.ajax({
                type: "POST",
                url:'faceMatch',
                data:{
                    message:imgSrc
                },
                  success:function(score){
                      var scoreMatch = score.split(".")[0];
                      if(scoreMatch>80){
                          window.location="loginSuccess.jsp"
                     }
                      else{
                          
                          return;
                     }
                }
            })
        }
     setInterval("jiance()","1100");  //每隔一秒执行一次函数截图
        
    
        //将图片Base64 转成文件
     </script>
     <script type="text/javascript" color="120,148,255" opacity='0.8' zIndex="1" count="100" src="https://files.cnblogs.com/files/lfri/canvas-nest.js"></script>
     <div id="iframe">
     </div>
     </div>
    </body>
    </html>

    这里js函数将每一秒执行一次函数截一次图并传到后台来比对,可以在控制台看到程序一直在执行,并且返回分数,当返回的分数大于80分时跳转到登录成功页面

    但是现在只能将某一个人的图片文件手动写入java文件,感觉比较死,只能登录进去一个人。。

    在v2版本中出现人脸搜索,v3版本中出现了人脸查找

    但是人脸搜索肯定在某一个域里面进行检索,所以下面我们开始创建人脸库,并上传人脸图片到人脸库当中

     https://console.bce.baidu.com/ai/#/ai/face/facelib/groupList~appId=917240

    点击创建人脸库,创建用户组,人脸库也可以进行调用相应的api增删改差,这里咱们还是调用v2的人脸增删改查

    官方文档在百度云上会相应的有

    请求地址为

    https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add

    相应的参数为user_id,user_info,group_id,image_type,image,具体详细的可查看官方文档,

    /**  
     * All rights Reserved, Designed By liufuqiang
     * @Title:  faceAdd.java   
     * @Package faceLogin   
     * @Description:    TODO
     * @author: LiuFuqiang     
     * @date:   2019年5月8日 下午7:20:54   
     * @version V1.0 
     * @Copyright: 2019 liufuqiang All rights reserved. 
     */
    package faceLogin;
    
    /**
     * @author Administrator
     *
     */
    
    
    import java.net.URLEncoder;
    
    import utils.Base64Util;
    import utils.FileUtil;
    import utils.HttpUtil;
    
    /**
    * 人脸注册
    */
    public class faceAdd {
    
        /**
        * 重要提示代码中所需工具类
        * FileUtil,Base64Util,HttpUtil,GsonUtils请从
        * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72
        * https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2
        * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
        * https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3
        * 下载
        */
        public static String add() {
            // 请求url
            String url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add";
            try {
                // 本地文件路径
                String filePath = "C:\Users\Administrator\Desktop\liu1.png";
                byte[] imgData = FileUtil.readFileByBytes(filePath);
                String imgStr = Base64Util.encode(imgData);
                String imgParam = URLEncoder.encode(imgStr, "UTF-8");
    
                
    
                String param = "user_id=" + "userid9" + "&user_info=" + "userInfo5" + "&group_id=" + "testFaceLogin" + "&image_type=BASE64" + "&image=" + imgParam ;
                AuthService auth = new AuthService();
                
                // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。
                String accessToken = auth.getAuth();
    
                String result = HttpUtil.post(url, accessToken, param);
                System.out.println("addface:"+result);
                return result;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
       
    }

     这里可以根据前端实现图片上传功能,图片路径保存到数据库,再将图片转base64数据上传到人脸库,这里group_id为注册人脸库用户组时自己设置的,以实现注册功能,

    下面进行人脸搜索,在人脸库中搜索,返回相似度最大的某个人 的信息,

    /**  
     * All rights Reserved, Designed By liufuqiang
     * @Title:  faceAdd.java   
     * @Package faceLogin   
     * @Description:    TODO
     * @author: LiuFuqiang     
     * @date:   2019年5月8日 下午6:56:52   
     * @version V1.0 
     * @Copyright: 2019 liufuqiang All rights reserved. 
     */
    package faceLogin;
    
    /**
     * @author Administrator
     *
     */
    
    import java.util.*;
    
    
    import utils.GsonUtils;
    import utils.HttpUtil;
    
    /**
    * 人脸搜索
    */
    public class faceSearch {
    
        /**
        * 重要提示代码中所需工具类
        * FileUtil,Base64Util,HttpUtil,GsonUtils请从
        * https://ai.baidu.com/file/658A35ABAB2D404FBF903F64D47C1F72
        * https://ai.baidu.com/file/C8D81F3301E24D2892968F09AE1AD6E2
        * https://ai.baidu.com/file/544D677F5D4E4F17B4122FBD60DB82B3
        * https://ai.baidu.com/file/470B3ACCA3FE43788B5A963BF0B625F3
        * 下载
        */
        public static String search(String image) {
            // 请求url
            String url = "https://aip.baidubce.com/rest/2.0/face/v3/search";
            try {
                Map<String, Object> map = new HashMap<>();
                map.put("image", image); //图片base64数据
                map.put("liveness_control", "NORMAL");  //活体检测控制一般的
                map.put("group_id_list", "testFaceLogin");  //指定用户组group 人脸库总已经存在的用户组
                map.put("image_type", "BASE64");     //图片类型,这里转化过的base64
                map.put("quality_control", "LOW");   //图片质量控制
    
                String param = GsonUtils.toJson(map);
                AuthService auth = new AuthService();
                String accessToken = auth.getAuth();
                // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。
    
                String result = HttpUtil.post(url, accessToken, "application/json", param);
                String score = result.split(",")[9].split(":")[1];
                System.out.println(result);
                System.out.println(score);
                return score;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        
    }

    这里这个image路径为前端摄像头每一秒截图的base64数据。将注册进去的人脸进行搜索,会返回json数据

    {"error_code":0,"error_msg":"SUCCESS","log_id":304592874904990691,"timestamp":1557490499,"cached":0,"result":{"face_token":"636279d295ffaa2ce051f80ea41fb8fb","user_list":[{"group_id":"testFaceLogin","user_id":"userid9","user_info":"userInfo5","score":93.629905700684}]}}
    93.629905700684}]}}

    主要看user_list里面的内容,group_id为此用户所属用户组,user_id为上传时设置的用户id,user_info为上传时用户信息(这里建议将user_info为区别某一用户的唯一标识,在注册时将用户名、密码,user_info,人脸照片等数据存入数据库某张表里面,得到返回数据之后可根据user_info来判断登录用户为某个人,这样就可以区分用户)

    后面还有人脸库的更新、删除、将某用户从某一用户组到另一个用户组,这里不再一一介绍。最终项目目录如下图:

    根据自己需要自行修改,可能需要某些jar包有啥问题了,如果实在找不到了可以私信我。

    项目上传到Github : https://github.com/LiuFqiang/faceLogin

  • 相关阅读:
    APP设计资源
    browsersync实现网页实时刷新(修改LESS,JS,HTML时)
    Browsersync + Gulp.js
    用原生js对表格排序
    js深复制
    c++刷题(43/100)矩阵旋转打印
    将本地的mongodb迁移到阿里云
    c++刷题(39/100)笔试题3
    c++刷题(37/100)笔试题2
    c++刷题(33/100)笔试题1
  • 原文地址:https://www.cnblogs.com/LiuFqiang/p/10846973.html
Copyright © 2011-2022 走看看