基於百度AI的人像識別開發的登錄模塊

首先這是一個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

以上就結束了,有什麼相關的問題大家可以在下面留言,大家一起共同進步。

謝謝

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章