首先这是一个java的SSM框架的项目,没学过java或没接触过SSM的可能不太适合。数据库用的是mysql

整体思路:使用HTML5的video和canvas来截取摄像头拍摄视频的图片base64数据,将拍摄的base64格式数据和之前在数据库中存好的人像数据上传到百度AI的处理中心,进行人像识别分析,并将结果回传,结果数据是json格式的,需要进行有效数据的提取,如果相似度达到90%,就判定为本人,登录验证通过。

数据库设计思路:数据表的结构很简单,一共有三个字段,id、data、username。但是有个问题,base64是非常长的一串数据,想想几万、几十万字符的数据直接存入数据库,是非常不明智的选择,当数据量稍微一多,会严重拖垮数据库的性能。所以正确操作可以将数据转成图片存到本地,数据库中只保存地址。但我作为演示操作,数据量小,就做了个错误的示范,我用longblob类型来保存的base64数据。

下面步入正题:

1.注册百度AI,进入控制台后,点击左侧导航菜单,进入人脸识别模块。

 

2.点击创建应用,然后添加你所要创建应用的一些信息,创建成功后会进入下图的界面

 3.记住你的API key和Secret key,后面会用到。

4.下面开始写代码,首先创建Particleground.jsp,这是用来人像登录的页面,代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>管理员登录</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">

    <link rel="stylesheet" type="text/css" href="source/css/style.css"/>
    <script type="text/javascript" src="source/js/jquery.min.js"></script>
    <script src="source/js/verificationNumbers.js"></script>
    <script src="source/js/Particleground.js"></script>

    <style type="text/css">
        body {
            height: 100%;
            background: #213838;
            overflow: hidden;
        }
        canvas {
            z-index: -1;
            position: absolute;
            display: none;
        }
        h1 {
            color: #fff;
            text-align: center;
            font-weight: 100;
            margin-top: 40px;
        }
        #media {
            width: 280px;
            height: 250px;
            margin: 10px auto 0;
            border-radius: 30px;
            overflow: hidden;
        }
    </style>
</head>

<body>
<div style="float:right;margin-right:80px;margin-top:40px;"><a href="login.jsp"><img src="source/images/return.png" alt=""></a></div>
<form action="" method="post" style="margin-top:100px;">
    <dl class="admin_login">
        <dt>
            <strong>云通WMS</strong><strong style="margin-top:10px;">请将脸放摄像头前</strong>
        </dt>
        <div id="media">
            <video id="video" width="530" height="300" autoplay></video>
            <canvas id="canvas" width="400" height="300"></canvas>
        </div>
        <%--<dd style="margin-top:20px;" >--%>
            <%--<input type="button" onclick="query()" value="立即登录"--%>
                   <%--class="submit_btn"/>--%>
        <%--</dd>--%>


    </dl>
</form>
<script type="text/javascript">
    //var 是定义变量
    var video = document.getElementById("video"); //获取video标签
    var context = canvas.getContext("2d");
    var con = {
        audio: false,
        video: {
            width: 1980,
            height: 1024,
        }
    };
    //获取用户媒体对象
    navigator.mediaDevices.getUserMedia(con).then(function (stream) {
            video.src = window.URL.createObjectURL(stream);
            video.onloadmetadate = function (e) {
                video.play();
            }
            setTimeout(query,1000);
        });

    function query() {
        //把流媒体数据画到convas画布上去
        context.drawImage(video, 0, 0, 400, 300);
        var baseData = getBase64();
        $.ajax({
            type: "post",
            url: "faceRecognition.do",
            async:true,
            contentType:"application/x-www-form-urlencoded",
            data: {"baseData": baseData},
            dataType:'json',
            success: function (data) {
                var result = eval(data);
                if (result) {
                    window.location.href="index.jsp";
                } else {
                    alert("面容识别失败,请继续验证");
                    window.location.href="faceRecognition.jsp";
                }
            }
        });
    }

    function getBase64() {
        var imgSrc = document.getElementById("canvas").toDataURL(
            "image/png");
        return imgSrc.split("base64,")[1];
    };
</script>
</body>
</html>

再创建faceEntry.jsp页面,这是用来进行人脸信息采集的页面,代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>人脸信息录入</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">

    <link rel="stylesheet" type="text/css" href="source/css/style.css"/>
    <script type="text/javascript" src="source/js/jquery.min.js"></script>
    <script src="source/js/verificationNumbers.js"></script>
    <script src="source/js/Particleground.js"></script>

    <style type="text/css">
        body {
            height: 100%;
            background: #213838;
            overflow: hidden;
        }
        canvas {
            z-index: -1;
            position: absolute;
            display: none;
        }
        h1 {
            color: #fff;
            text-align: center;
            font-weight: 100;
            margin-top: 40px;
        }
        #media {
            width: 280px;
            height: 250px;
            margin: 10px auto 0;
            border-radius: 30px;
            overflow: hidden;
        }
    </style>
</head>

<body>
<div style="float:right;margin-right:80px;margin-top:40px;"><a href="login.jsp"><img src="source/images/return.png" alt=""></a></div>
<form action="" method="post" style="margin-top:100px;">
    <dl class="admin_login">
        <dt>
            <strong>信息录入</strong><strong style="margin-top:10px;">请将脸放摄像头前</strong>
        </dt>
        <div id="media">
            <video id="video" width="530" height="300" autoplay></video>
            <canvas id="canvas" width="400" height="300"></canvas>
        </div>

    </dl>
</form>
<script type="text/javascript">
    //var 是定义变量
    var video = document.getElementById("video"); //获取video标签
    var context = canvas.getContext("2d");
    var con = {
        audio: false,
        video: {
            width: 1980,
            height: 1024,
        }
    };
    //获取用户媒体对象
    navigator.mediaDevices.getUserMedia(con)
        .then(function (stream) {
            video.src = window.URL.createObjectURL(stream);
            video.onloadmetadate = function (e) {
                video.play();
            }
            setTimeout(query,1000);
        });

    function query() {
        //把流媒体数据画到convas画布上去
        context.drawImage(video, 0, 0, 400, 300);
        var baseData = getBase64();
        $.ajax({
            type: "post",
            url: "faceEntry.do",
            async:true,
            contentType:"application/x-www-form-urlencoded",
            data: {"faceData": baseData},
            dataType:'json',
            success: function (json, textStatus) {
                var result = json.flag;
                if (result==0) {
                   alert("您的人脸录入数据已达上限")
                } else if(result==2){
                    alert("信息录入失败,请重新录入");
                }else{
                    window.location.href="index.jsp";
                }
            }
        });
    }

    function getBase64() {
        var imgSrc = document.getElementById("canvas").toDataURL(
            "image/png");
        return imgSrc.split("base64,")[1];
    };
</script>
</body>
</html>

上面JSP页面所依赖的css和js,我会上传到CSDN的资源下载中,在本文的最后会附上链接,我看看能不能设置成免费,尽量分低一点。

5.刚才让记住的两个KEY是为了获取token的,下面是获取token的一个工具类:

package com.hanpeng.utils;

import net.sf.json.JSONObject;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class GetToken {

   public static String getToken() {
      BufferedReader br = null;
      StringBuffer sb = new StringBuffer();

      String authHost = "https://aip.baidubce.com/oauth/2.0/token?";

      String clientId = "PfaxdmuNuNyGhTcbtD2vkcuf";
      String clientSecret = "dV7hZSmDWoNIIuBUNbtzC0XKmVy0v3tw";
      String getAccessTokenUrl = authHost
            + "grant_type=client_credentials"
            + "&client_id=" + clientId
            + "&client_secret=" + clientSecret;
      try {
         URL url = new URL(getAccessTokenUrl);
         HttpURLConnection connection = (HttpURLConnection) url
               .openConnection();
         connection.setRequestMethod("POST");
         connection.connect();
         br = new BufferedReader(new InputStreamReader(
               connection.getInputStream()));
         String line = "";
         while ((line = br.readLine()) != null) {
            sb.append(line);
         }
         br.close();
      } catch (Exception e) {
         e.printStackTrace();
      }
      JSONObject jsonObject = JSONObject.fromObject(sb.toString());
      String token = jsonObject.getString("access_token");
      return token;
   }
}

6.下面是LoginController层

//百度人脸识别登录验证
@RequestMapping("faceRecognition")
void faceRecognition(HttpServletRequest request, HttpServletResponse response, String baseData) throws IOException {
    System.out.println(baseData);
    PrintWriter writer = response.getWriter();
    HttpSession session = request.getSession();
    boolean flag = false;
    List<FaceRecognition> list = service.getBaseList();
    for (FaceRecognition faceRecognition : list) {
        String image2 = faceRecognition.getFace_base64();
        if (service.getResult(baseData, image2)) {
            flag = true;
            session.setAttribute("username", faceRecognition.getUsername());
            break;
        }
    }
    writer.print(flag);
    writer.close();
}

//百度人脸信息录入(返回的状态码:0:用户人脸数据存储已达上限,1:人脸信息录入成功, 2:人脸信息录入失败(照片不合格))
@RequestMapping("faceEntry")
public void faceEntry(HttpServletRequest request, HttpServletResponse response, String faceData) throws IOException {
    HttpSession session = request.getSession();
    String username = (String) session.getAttribute("username");
    PrintWriter writer = response.getWriter();
    //检测该用户下的人脸信息数据是否超过5条
    if (service.queryCountByFaceInfo(username,5)) {
        //进行人脸信息录入
        if (service.getFaceResult(faceData)) {
            writer.write("{\"flag\":\"1\"}");
            FaceRecognition faceRecognition = new FaceRecognition(username, faceData);
            service.insertFaceInfo(faceRecognition);
        }else{
            writer.write("{\"flag\":\"2\"}");
        }
    }else {
        writer.write("{\"flag\":\"0\"}");
    }
    writer.close();
}

7.下面是LoginService接口类

public interface LoginService {

    public List<Admin> Login(String username, String password);

    public List<FaceRecognition> getBaseList();

    public boolean getResult(String image1, String image2) throws IOException;

    public boolean getFaceResult(String image) throws IOException;

    public void insertFaceInfo(FaceRecognition faceRecognition);

    public boolean queryCountByFaceInfo(String username, int n);

    public List<Map<String, ?>> userInfo(String userName);

    public void upDate(String date, String userName);

    public void modifyPassWord(String userName, String passWord);
}

8.下面是LoginService类的实现类LoginServiceImpl类,我只挑了和人脸识别相关的方法:

//人脸识别检测
@Override
public boolean getResult(String image1, String image2) throws IOException {
    boolean flag = false;
    // 请求url
    String url = "https://aip.baidubce.com/rest/2.0/face/v3/match";

    try {
        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);

        // 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。
        String accessToken = GetToken.getToken();

        String result = HttpUtil.post(url, accessToken, "application/json", param);
        System.out.println(result);

        //用json提取result中的有效数据
        JSONObject myJson = new JSONObject(result);
        int error = myJson.getInt("error_code");
        if (error == 0) {
            JSONObject resultList = (JSONObject) myJson.get("result");
            double score = resultList.getDouble("score");
            System.out.println(score);
            if (score >= 90) {
                flag = true;
            }
        }
            return flag;
        } catch(Exception e){
            e.printStackTrace();
        }
    return flag;
}

//人脸信息录入
@Override
public boolean getFaceResult(String image) throws IOException {
    boolean flag = false;
    // 请求url
    String url = "https://aip.baidubce.com/rest/2.0/face/v3/detect";
    try {
        Map<String, Object> map = new HashMap<>();
        map.put("image", image);
        map.put("face_field", "faceshape,facetype");
        map.put("image_type", "BASE64");

        String param = GsonUtils.toJson(map);
        String accessToken = GetToken.getToken();
        String result = HttpUtil.post(url, accessToken, "application/json", param);
        JSONObject myJson = new JSONObject(result);
        int error = myJson.getInt("error_code");
        if(error==0){
            flag = true;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return flag;
}


//新增人脸数据
@Override
public void insertFaceInfo(FaceRecognition faceRecognition) {
    dao.insertFaceInfo(faceRecognition);
}

//检测该用户的人脸信息数据是否大于N
@Override
public boolean queryCountByFaceInfo(String username,int n) {
    if(dao.queryCountByFaceInfo(username)<=4){
        return true;
    }
    return false;
}

注意,上述代码引入了几个帮助类:Base64Util、FileUtil、GsonUtils、HttpUtil。这几个类都会在我上传到CSDN的资源下载中,在本文的最后会附上链接,我看看能不能设置成免费,尽量分低一点。

9.下面是LoginDao:

public interface LoginDao {
   List<Admin> queryByNameAndPassword(@Param("username") String username, @Param("password") String password);

   List<FaceRecognition> getBaseList();

   void insertFaceInfo(FaceRecognition faceRecognition);

   int queryCountByFaceInfo(@Param("username") String username);

   List<Map<String, ?>> queryUserInfo(@Param("userName") String userName);

   void upDate(@Param("date") String date, @Param("userName") String userName);

   void modifyPassWord(@Param("userName") String userName, @Param("passWord") String passWord);

}

10.下面是mapping文件,loginDao.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "mybatis-3-mapper.dtd" >
<mapper namespace="com.hanpeng.dao.LoginDao">
   
   <!-- 按照用户名和密码查询,返回用户id -->
   <select id="queryByNameAndPassword" parameterType="String" resultType="com.hanpeng.bean.Admin">
      select * from admin where admin_username=#{username} and admin_password=#{password}
   </select>
   <!--查询人脸识别本地库中的数据-->
   <select id="getBaseList" resultType="com.hanpeng.bean.FaceRecognition">
      select * from face_Recognition
   </select>
   <!--新增人脸数据-->
   <insert id="insertFaceInfo" parameterType="com.hanpeng.bean.FaceRecognition">
      insert into face_Recognition(face_base64,username) values(#{face_base64},#{username})
   </insert>
   <!--检测该用户的人脸信息数据是否大于N-->
   <select id="queryCountByFaceInfo" parameterType="String" resultType="int">
      select count(*) from face_Recognition where username=#{username}
   </select>
   <!-- 按照用户名查询用户信息,返回Map -->
   <select id="queryUserInfo" parameterType="String" resultType="Map">
      select * from user where username=#{userName}
   </select>
   <!-- 更新用户登录的时间 -->
   <update id="upDate" parameterType="String">
   update user set date=#{date} where username=#{userName}
   </update>
   <!-- 修改用户密码 -->
   <update id="modifyPassWord" parameterType="String">
   update user set password=#{passWord} where username=#{userName}
   </update>
</mapper>

这是资源下载的地址:https://download.csdn.net/download/qq_33609401/10818905

以上就结束了,有什么相关的问题大家可以在下面留言,大家一起共同进步。

谢谢

 

 

Logo

更多推荐