基於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: {width: 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; width: 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');width: 100%;height: 640px;background-size:100%, 100%;}
.video{width: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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM