首先這是一個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
以上就結束了,有什麼相關的問題大家可以在下面留言,大家一起共同進步。
謝謝