基于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: , height: },
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, , , , );
}
</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
基于javaweb人脸识别注册登录系统的更多相关文章
- java使用face++简单实现人脸识别注册登录
java使用face++简单实现人脸识别注册登录 前言 人脸识别,好高大上!!! 理解之后很简单. 支付宝使用的就是face++, 至于face++账号信息,apikey…..,本文不做讲述,网上很多 ...
- 一个基于Unix套接字的注册登录系统
2016/5/5 今天,我参考<Unix网络编程-卷1>第5章的TCP回射客户/服务器程序写了一个简单的注册登录系统,其功能如下:(1)注册.客户端向服务器发送个人信息请求注册,服务器查询 ...
- 基于JavaWeb实现的研究室综合系统
代码地址如下:http://www.demodashi.com/demo/14641.html 概述 基于JavaWeb实现的研究室综合系统,功能包括研究室成员注册.登陆,后台管理,相册功能,新闻模块 ...
- 基于虹软人脸识别,实现RTMP直播推流追踪视频中所有人脸信息(C#)
前言 大家应该都知道几个很常见的例子,比如在张学友的演唱会,在安检通道检票时,通过人像识别系统成功识别捉了好多在逃人员,被称为逃犯克星:人行横道不遵守交通规则闯红灯的路人被人脸识别系统抓拍放在大屏上以 ...
- 践行初心|方正璞华爱心捐赠人脸识别测温系统WelComID
近日,方正璞华向金鸡湖社区卫生服务中心捐赠了人脸识别测温系统.该设备集人员识别.体温检测等功能于一体,在人员进出的时候完成体温的检测,从而判断是否有异常人员等问题,有效节省人力成本.减少人员接触风险, ...
- php注册登录系统(一)-极简
序 登录注册系统是日常上网最普通的操作,我设了一个分类一步步完善注册登录系统,若有哪里错误请慧教 所用语言:php 数据库 :mysql 本次实现功能: 1.用户注册 2.用户登录 主要文件: 完整代 ...
- JavaWeb笔记——注册登录系统项目思路
功能: > 注册 > 登录 --------------------------------- JSP: * login.jsp --> 登录表单 * regist ...
- 注册登录系统项目思路 -- javaweb
功能: > 注册 > 登录 --------------------------------- JSP: * login.jsp --> 登录表单 * re ...
- Django+bootstrap+注册登录系统
转自:https://www.cnblogs.com/robindong/p/9610057.html Robin_D 博客园 首页 新随笔 联系 订阅 管理 随笔 - 10 文章 - 0 评论 ...
随机推荐
- css 实现水波纹,波浪动画效果
<div class="wave"> 水波纹效果 <div class="wave1"></div> <div cla ...
- Cobalt Strike特征修改
一.Teamserver模块端口信息 vim teamserver修改Cobalt Strike默认服务端50500端口为其他任意端口 二.SSL默认证书信息 Cobalt Strike默认SSL证书 ...
- nexus私服仓库搭建以及项目引用
第一步:使用ubunto下载安装nexus 并打开登录进入到nexus管理页面,默认账号为 admin 密码在 admin.password 中,首次登录会让你重新修改密码 第二步 配置自己本地 ...
- LinkedBlockingQueue 学习
LinkedBlockingQueue 链表队列,其元素构成为: static class Node<E> { E item; Node<E> next; Node(E x) ...
- grpc协议--客户端构造
由于服务端不在构造,已经构造完成不做构造 gRPC 接口名字为service,proto文件内有定义 1.本目录生成grpc文件 python -m grpc_tools.protoc -I. --p ...
- 初撩RESTful
1. 什么是RESTful? 一种软件架构风格,设计风格,用于客户端和服务端交互类的架构. 一组架构约束条件和原则 2. 什么是RESTful架构? 客户端通过http动词(get/post等)对服务 ...
- NOIP2019模拟2019.9.20】膜拜大会(外向树容斥,分类讨论)
传送门. 题解: 我果然是不擅长分类讨论,心态被搞崩了. 注意到\(m<=n-2\),意味着除了1以外的位置不可能被加到a[1]两遍. 先考虑个大概: 考虑若存在\(x,x-1,-,2\)(有序 ...
- Yii2中自定义表单样式
use yii\widgets\ActiveForm; <?php $form = ActiveForm::begin([ 'options' => ['class' => 'for ...
- 【hihocoder 1554】最短的 Nore0061
[链接]http://hihocoder.com/problemset/problem/1554 [题意] 中文题 [题解] DP; 设f[i][j][k]表示前i个字符,第一个串已经得到了前j个字符 ...
- 高级运维(二):搭建Nginx服务器、用户认证、基于域名的虚拟主机、SSL虚拟主机、Nginx反向代理
一.搭建Nginx服务器 目标: 在IP地址为192.168.4.5的主机上安装部署Nginx服务,并可以将Nginx服务器,要求编译时启用如下功能: 1> SSL加密功能 2> 设置Ng ...