最近几天很多人问我,这几天怎么发文慢了?
一是这几天确实比较忙,工作是饭碗,不能砸了吧,不然康哥吃啥,孩子的奶粉又得买了。靠工资肯定不够奶粉啊,还得有自己的一些其他项目,您说对吧,另外还在总结《SpringBoot2.x企业实战教程》,这本电子书从入门到实战项目,总共20章,此处就不具体说了,等写完之后,再来吹吧。总之最近有点忙。
二是在细心的总结有用的知识。康哥是一个重效率的人,公众号宁可不发文,也不会携带软文、烦文、广告,很多没技术含量的只为了点赞的文章,我们是纯、纯技术号。如果咱俩价值观一样,就分享下,是对康哥最大的支持。
好了,跑偏了,今天康哥总结了AV、不,AI的新的技术点【人脸识别】,上几期的图像识别、语音识别、车牌识别、网络爬虫没来得及看的同学,请点击这里。
需求: 登录使用人脸识别登录、人脸录入功能
技术点 & 开发工具: Myeclipse、JDK1.8、Tomcat8、SSM框架、HTTPS、JSON、jsp、百度云
人脸识别: 是基于人的脸部特征信息进行身份识别的一种生物识别技术。用摄像机或摄像头采集含有人脸的图像或视频流,并自动在图像中检测和跟踪人脸,进而对检测到的人脸进行脸部识别的一系列相关技术,通常也叫做人像识别、面部识别。
技术流程: 人脸图像采集及检测 人脸图像预处理 人脸图像特征提取 匹配与识别
识别算法: 基于人脸特征点的识别算法(Feature-based recognition algorithms) 基于整幅人脸图像的识别算法(Appearance-based recognition algorithms) 基于模板的识别算法(Template-based recognition algorithms) 利用神经网络进行识别的算法(Recognition algorithms using neural network) 基于光照估计模型理论 优化的形变统计校正理论 独创的实时特征识别理论
开发步骤:
1:首先开通百度云-AI-功能账号,并创建应用,如下图
2:创建应用之后,进入应用内,点击编辑,将人脸识别等功能进行授权
3:新建一个web project,如下图:
4:搭建SSM框架,导包并配置web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>FaceDemo</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
5:配置ApplicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"
xmlns:mvc="http://www.springframework.org/schema/mvc">
<context:annotation-config/>
<context:component-scan base-package="com.spring/web"></context:component-scan>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${mysql.driver}" />
<property name="url" value="${mysql.url}" />
<property name="username" value="${mysql.username}" />
<property name="password" value="${mysql.password}" />
<!-- 初始化连接大小 -->
<property name="initialSize" value="30" />
<!-- 连接池最大数量 -->
<property name="maxActive" value="1000" />
<!-- 连接池最大空闲 -->
<property name="maxIdle" value="50" />
<!-- 连接池最小空闲 -->
<property name="minIdle" value="30" />
<!-- 获取连接最大等待时间 -->
<property name="maxWait" value="36000" />
</bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:db.properties" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations" value="classpath:com/spring/web/entity/*.xml" />
</bean>
</beans>
6:添加登录页面index.jsp
<script>
$(document).ready(function() {
//粒子背景特效
$('body').particleground({
dotColor: '#5cbdaa',
lineColor: '#5cbdaa'
});
//验证码
createCode();
//测试提交,对接程序删除即可
$(".submit_btn").click(function(){
localhost.href="index.jsp";
});
});
</script>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
body {
height: 100vh;
background-position: center;
overflow: hidden;
}
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;
opacity: 0.7px;
}
#video {
}
#canvas {
display: none;
}
#btn {
width: 160px;
height: 50px;
background: #03a9f4;
margin: 70px auto 0;
text-align: center;
line-height: 50px;
color: #fff;
border-radius: 40px;
}
</style>
</head>
<body>
<form action="${pageContext.request.contextPath}/facelogin.action" method="get">
<dl class="admin_login">
<dt>
<strong>人脸识别登录管理系统</strong><em>开启摄像头,调试角度</em> <strong>请把你的脸放摄像头面前</strong>
</dt>
<div id="media">
<video id="video" width="350" height="200" autoplay></video>
<canvas id="canvas" width="400" height="300"></canvas>
</div>
<dd>
<input type="button" onclick="query()" value="立即登录" class="submit_btn" />
</dd>
</dl>
<script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
<script type="text/javascript">
//var 是定义变量
var canvans = document.getElementById("canvas");
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();
}
});
function query(){
//把流媒体数据画到convas画布上去
context.drawImage(video,0,0,400,300);
var imgData = canvans.toDataURL();
var imgData1 = imgData.split("base64,")[1];
$.ajax({
type:"post",
url:"${pageContext.request.contextPath}/facelogin.action",
data:{"img":imgData1},
success:function(data){
/* alert(data) */
var result = eval(data);
if(result){
alert("登录成功")
} else {
alert("面容识别失败,请继续验证");
}
}
});
}
function getBase64() {
var imgSrc = document.getElementById("canvas").toDataURL("image/png");
alert(imgSrc);
return imgSrc.split("base64,")[1];
};
</script>
</form>
</body>
</html>
7:添加人脸录入界面registe.jsp
<body>
<form action="${pageContext.request.contextPath}/registe.action" method="get">
<dl class="admin_login">
<dt>
<strong>人脸识别头像录入</strong>
<em></em>
请输入用户名:<input type="text" name="username" id="username" />
</dt>
<div id="media">
<video id="video" width="350" height="200" autoplay></video>
<canvas id="canvas" width="600" height="500"></canvas>
</div>
<dd>
<input type="button" onclick="registe()" value="立即注册" class="submit_btn" />
</dd>
</dl>
<script type="text/javascript">
var canvans = document.getElementById("canvas");
var video = document.getElementById("video"); //获取video标签
var context = canvas.getContext("2d");
var con ={
audio:false,
video:{
width:1980,
height:1980,
}
};
//导航 获取用户媒体对象
navigator.mediaDevices.getUserMedia(con)
.then(function(stream){
video.src = window.URL.createObjectURL(stream);
video.onloadmetadate = function(e){
video.play();
}
});
function registe(){
context.drawImage(video,0,0);
var imgData = canvans.toDataURL();
var imgData1 = imgData.split("base64,")[1];
var username = $("#username").val();
$.ajax({
type:"post",
url:"${pageContext.request.contextPath}/registe.action",
data: {"img":imgData1,"username":username},
success:function(data){
alert(data);
},error:function(msg){
alert("错误");
}
});
}
</script>
</form>
</body>
8:新建一张数据库表users,便于后续做登录信息的认证或者签到功能,结构如下:
CREATE TABLE `users` (
`id` int(50) NOT NULL AUTO_INCREMENT,
`username` varchar(100) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
`headphoto` varchar(5000) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
9:逆向工程生成这张表的接口和实体以及dao
10:添加如下结构的类
11:核心代码,其它类的代码,可联系康哥获取,或者参考文末的下载地址。
UserController.java:
/**
* 人脸识别后台控制器
* @author likang
* @date 2018年8月9日
*/
@Controller
public class UserControll {
private static String accessToken;
@Resource
private FaceService faceService;
/**
* 用户人脸识别头像录入(每个用户建议只允许录入一次)
* @param request
* @param response
* @param model
*/
@RequestMapping("/registe.action")
public @ResponseBody void registe(HttpServletRequest request, HttpServletResponse response, Model model) {
String img = request.getParameter("img"); // 图像数据
String username = request.getParameter("username"); // 用户名
// 注册百度云 人脸识别 提供的信息
String APP_ID = "11644574";
String API_KEY = "mGZF5fUuRpHk3QBBs3vsGRd7";
String SECRET_KEY = "wFI1UYM5eAE6HMp8qguq8mH9qaCTwgPf";
AipFace client = new AipFace(APP_ID, API_KEY, SECRET_KEY);
face(username, img, response, request, client);
}
/**
*作用: 1.将base64编码的图片保存
* 2.将图片路径保存在数据库里面
* 3.将人脸图片识别在人脸库中注册
*/
public void face(String username, String img, HttpServletResponse response, HttpServletRequest request,
AipFace client) {
Users user = new Users();
// 图片名称
String fileName = System.currentTimeMillis() + ".png";
String basePath = request.getSession().getServletContext().getRealPath("picture/");
// 往数据库里面插入注册信息
user.setUsername(username);
user.setHeadphoto("/picture/" + fileName);
faceService.save(user);
// 往服务器里面上传图片
GenerateImage(img, basePath + "/" + fileName);
// 给人脸库中加入一个脸
boolean flag = facesetAddUser(client, fileName, username,img);
try {
PrintWriter out = response.getWriter();
// 中文乱码,写个英文比较专业 哈哈
if (flag == false) {
out.print("Please aim at the camera!!");// 请把脸放好咯
} else {
out.print("Record the success of the image!!"); // 注册成功
}
} catch (IOException e) {
e.printStackTrace();
}
}
public boolean GenerateImage(String imgStr, String imgFilePath) {
if (imgStr == null) // 图像数据为空
return false;
Decoder decoder = Base64.getDecoder();
try {
// Base64解码
byte[] bytes = decoder.decode(imgStr);
for (int i = 0; i < bytes.length; ++i) {
if (bytes[i] < 0) {// 调整异常数据
bytes[i] += 256;
}
}
// 生成jpeg图片
OutputStream out = new FileOutputStream(imgFilePath);
out.write(bytes);
out.flush();
out.close();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean facesetAddUser(AipFace client, String path, String username, String img) {
String url = "https://aip.baidubce.com/rest/2.0/face/v3/faceset/user/add";
try {
Map<String, Object> map = new HashMap<>();
map.put("image", img);
map.put("group_id", "group_repeat");
map.put("user_id", "user1");
map.put("user_info", "abc");
map.put("liveness_control", "NORMAL");
map.put("image_type","BASE64");
map.put("quality_control", "LOW");
String param = GsonUtils.toJson(map);
// 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。
accessToken = GetTon.getToken();
String result = HttpUtil.post(url, accessToken, "application/json", param);
System.out.println(result);
JSONObject fromObject = JSONObject.fromObject(result);
Object errormsg = fromObject.get("error_msg");
if (errormsg.toString().equals("SUCCESS")) {
return true;
}
return false;
}catch (Exception e) {
e.printStackTrace();
}
return false;
}
public boolean search(String img) {
// 请求url
String url = "https://aip.baidubce.com/rest/2.0/face/v3/search";
try {
Map<String, Object> map = new HashMap<>();
map.put("image", img);
map.put("liveness_control", "NORMAL");
map.put("group_id_list", "group_repeat");
map.put("image_type", "BASE64");
map.put("quality_control", "LOW");
String param = GsonUtils.toJson(map);
// 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。
accessToken = GetTon.getToken();
String result = HttpUtil.post(url, accessToken, "application/json", param);
System.out.println(result);
JSONObject fromObject = JSONObject.fromObject(result);
JSONObject resultscore = fromObject.getJSONObject("result");
JSONArray jsonArray = resultscore.getJSONArray("user_list");
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject object = (JSONObject) jsonArray.get(i);
double resultList = object.getDouble("score");
System.out.println(resultList);
if (resultList >= 90) {
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 用户人脸识别登录功能
* @param request
* @param response
* @param model
* @return
*/
@RequestMapping("/facelogin.action")
public @ResponseBody String onListStudent(HttpServletRequest request, HttpServletResponse response, Model model) {
String img = request.getParameter("img"); // 图像数据
try {
boolean tag = search(img);
PrintWriter writer = response.getWriter();
if (tag) {
request.getSession().setAttribute("user", "likang");
writer.print(tag);
writer.close();
return null;
}else {
writer.print(tag);
writer.close();
}
} catch (Exception e) {
e.printStackTrace();
return "redirect:/404.jsp";
}
return null;
}
public boolean getResult(HttpServletRequest request, String imStr1, String imgStr2) {
accessToken = GetTon.getToken();
boolean flag = false;
// 请求url
String url = "https://aip.baidubce.com/rest/2.0/face/v3/match";
try {
byte[] bytes1 = FileUtil.readFileByBytes("");
byte[] bytes2 = FileUtil.readFileByBytes("");
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);
// 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间,
// 客户端可自行缓存,过期后重新获取。
String result = HttpUtil.post(url, accessToken, "application/json", param);
System.out.println(result);
// return result;
JSONObject fromObject = JSONObject.fromObject(result);
JSONArray jsonArray = fromObject.getJSONArray("result");
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject object = (JSONObject) jsonArray.get(i);
double resultList = object.getDouble("score");
if (resultList >= 90) {
flag = true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
}
12:将项目部署到tomcat应用服务器,访问使用
源码下载地址:
链接:https://pan.baidu.com/s/1FBQutG3HDhcXLZJlAsT1KQ 密码:5ofd