人脸注册、人脸搜索使用百度AI接口。不支持H5活体检测(需要活体检测请参考百度AI-H5活体检测)
只是为了演示。所以是IP。最好用火狐浏览器访问。谷歌提示异常作者就不专门修改了。大家可以直接下载源码运行体验的
前期准备工作
1.http://ai.ai/注册账户 实名认证 创建人脸应用 保存APPID、APIKEY、SECRETKEY三个值备用
2.需要必须的Java经验(最好是会用SpringBoot、Maven)
3.https://trackingjs.com/了解一下trackingjs(进行视频中的人脸检测。更多功能自行阅读文档)
简易流程图
示例图(先看下效果)
用户名为空提示
百度AI人脸注册需要userid groupid 演示功能 直接写固定的值 userid是UUID生成的一个字符串。大家根据实际情况更改即可
图片不包含人脸
确保图片中包含人脸即可。未做活体检测。活体检测请参考百度AI官方文档的
人脸注册成功
人脸搜索
trackingjs提供人脸检测功能。需要完整面部 缺少下颚也是不行的。搜索是使用百度AI接口。成功搜索返回注册给的用户名称
无需用户主动拍照。只要摄像头中包含完整面部即可。同样也不支持活体检测
搭建SpringBoot项目
pom配置相关库
百度SDK、fastjson、thymeleaf必不可少
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
cn.xsshome
faceRecognition
jar
faceRecognition
http://maven.apache.org
org.springframework.boot
spring-boot-starter-parent
2.0.4.RELEASE
UTF-8
2.7.0
com.alibaba
fastjson
1.2.35
org.springframework
springloaded
1.2.6.RELEASE
org.springframework.boot
spring-boot-devtools
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.springframework.boot
spring-boot-starter-thymeleaf
log4j
log4j
1.2.17
com.baidu.aip
java-sdk
4.10.0
org.springframework.boot
spring-boot-maven-plugin
true
application.yml配置
server:
port: 8888
#只简单配置了项目启动端口
FaceManagerController(人脸注册、搜索)
package cn.xsshome.controller;
import java.util.HashMap;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baidu.aip.face.AipFace;
import cn.xsshome.common.FactoryUtil;
import cn.xsshome.vo.FacePageBean;
import cn.xsshome.vo.FacePageResponse;
import cn.xsshome.vo.response.FaceSerachResponse;
/**
* 人脸照片注册方法
* @author 小帅丶
*
*/
@Controller
@RequestMapping("/facemanager")
public class FaceManagerController {
//人脸模块对象
AipFace aipFace = FactoryUtil.getAipFace();
private static Logger log = LoggerFactory.getLogger(FaceManagerController.class);
/**
* 人脸注册
* @param facePageBean 请求的参数对象
* @param request
* @param response
* @return
*/
@PostMapping("/add")
@ResponseBody
public String addFace(FacePageBean facePageBean,HttpServletRequest request, HttpServletResponse response){
log.info("发送过来的参数{}",JSONObject.toJSONString(facePageBean));
FacePageResponse facePageResponse = new FacePageResponse();
if(facePageBean.getUser_info().equals("")||null==facePageBean.getUser_info()){
facePageResponse.setError_code("100");
facePageResponse.setError_msg("用户名称为空 请填写后重试");
return JSON.toJSONString(facePageResponse);
}else{
String groupId = "xsdemo";//记得替换成自己的或通过页面传递用户组id(由数字、字母、下划线组成),长度限制128B
String userId = UUID.randomUUID().toString().replace("-", "").toUpperCase();//用户id(由数字、字母、下划线组成),长度限制128B
HashMap options = new HashMap();
options.put("user_info","小帅丶");
org.json.JSONObject resultObject = aipFace.addUser(facePageBean.getImgdata(), "BASE64", groupId, userId, options);
log.info("注册返回的数据{}",resultObject.toString(2));
return resultObject.toString();
}
}
/**
* 人脸搜索
* @param facePageBean 请求的参数对象
* @param request
* @param response
* @return
*/
@PostMapping("/search")
@ResponseBody
public FacePageResponse searchFace(FacePageBean facePageBean,HttpServletRequest request, HttpServletResponse response){
FacePageResponse facePageResponse = new FacePageResponse();
log.info("发送过来的参数{}",JSONObject.toJSONString(facePageBean));
String groupIdList = "xsdemo";//用户组id(由数字、字母、下划线组成),长度限制128B
org.json.JSONObject resultObject = aipFace.search(facePageBean.getImgdata(), "BASE64", groupIdList, null);
//使用fastjson处理返回的内容 直接用javabean接收 方便取值
FaceSerachResponse faceSerachResponse = JSON.parseObject(resultObject.toString(), FaceSerachResponse.class);
if("0".equals(faceSerachResponse.getError_code())&&"SUCCESS".equals(faceSerachResponse.getError_msg())){
if(faceSerachResponse.getResult().getUser_list().get(0).getScore()>80f){
facePageResponse.setError_code(faceSerachResponse.getError_code());
facePageResponse.setError_msg(faceSerachResponse.getError_msg());
facePageResponse.setUser_info(faceSerachResponse.getResult().getUser_list().get(0).getUser_info());
}else{
facePageResponse.setError_code("555");
facePageResponse.setError_msg("人脸搜索失败,请重试或请先注册");
}
}else{
facePageResponse.setError_code("500");
facePageResponse.setError_msg(faceSerachResponse.getError_msg());
}
log.info("搜索返回的数据{}",resultObject.toString(2));
return facePageResponse;
}
}
页面代码
人脸注册页面
人脸注册body {
background: url('../img/AI3.jpg') no-repeat;
height: 100%;
width: 100%;
overflow: hidden;
background-size: cover;
}
人脸注册
拍照
用户名称:
上传
/*
var ctx = /*[[${#httpServletRequest.getScheme() + "://" + #httpServletRequest.getServerName() + ":" + #httpServletRequest.getServerPort() + #httpServletRequest.getContextPath()}]]*/;
var aVideo = document.getElementById('video');
var aCanvas = document.getElementById('canvas');
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia; //获取媒体对象(这里指摄像头)
navigator.getUserMedia({
video: true
}, gotStream, noStream); //参数1获取用户打开权限;参数二是一个回调函数,自动传入视屏流,成功后调用,并传一个视频流对象,参数三打开失败后调用,传错误信息
function gotStream(stream) {
// video.src = URL.createObjectURL(stream); // 老写法
aVideo.srcObject = stream;
aVideo.onerror = function() {
stream.stop();
};
stream.onended = noStream;
aVideo.onloadedmetadata = function() {
console.info('摄像头成功打开!');
};
}
function noStream(err) {
alert(err);
}
function Shoot() {
var context = canvas.getContext('2d');
//把当前视频帧内容渲染到画布上
context.drawImage(aVideo, 0, 5, 320,160);
}
//将图片下载到本地
function download() {
var userInfo = $('#user_info').val();
var dom = document.createElement("a");
dom.href = this.canvas.toDataURL("image/png");
dom.download = new Date().getTime() + ".png";
dom.click();
//删除字符串前的提示信息 "data:image/png;base64,"
var data = aCanvas.toDataURL();
var b64 = data.substring(22);
var path = ctx+"/facemanager/add";
var name = new Date().getTime() + ".png";
var context = canvas.getContext('2d');
$.ajax({
type : 'post',
dataType : 'json',
url : path,
data : {
imgdata:b64,
imgname:name,
user_info:userInfo,
},
success : function(result){
if(result.error_msg=='SUCCESS'){
layer.open({
title: '温馨提示',
content: '人脸用户注册成功',
yes: function(index, layero){
layer.close(index); //如果设定了yes回调,需进行手工关闭
}
});
}else{
layer.open({
title: '温馨提示',
content: "注册失败:"+result.error_msg,
yes: function(index, layero){
//把画布上的图清空
context.clearRect(0, 5, 320,160);
layer.close(index); //如果设定了yes回调,需进行手工关闭
}
});
}
}
})
}
人脸搜索页面
trackerTask.stop();为防止人脸搜索接口调用中 多次提交问题。
人脸识别请确保面部完整,未检测到请靠近摄像头
/*
var ctx = /*[[${#httpServletRequest.getScheme() + "://" + #httpServletRequest.getServerName() + ":" + #httpServletRequest.getServerPort() + #httpServletRequest.getContextPath()}]]*/
window.onload = function() {
var video = document.getElementById('video');
var canvas = document.getElementById('canvas');
var canvas1 = document.getElementById('canvas1');
var context = canvas.getContext('2d');
var tracker = new tracking.ObjectTracker('face');
tracker.setInitialScale(4);
tracker.setStepSize(2);
tracker.setEdgesDensity(0.1);
tracking.track('#video', tracker, { camera: true });
tracker.on('track', function(event) {
if(event.data.length===0){
console.info('无人脸');
context.clearRect(0, 0, canvas.width, canvas.height);
}else{
event.data.forEach(function(rect) {
context.strokeStyle = '#a64ceb';
context.strokeRect(rect.x, rect.y, rect.width, rect.height);
context.font = '11px Helvetica';
context.fillStyle = "#fff";
context.fillText('x: ' + rect.x + 'px', rect.x + rect.width + 5, rect.y + 11);
context.fillText('y: ' + rect.y + 'px', rect.x + rect.width + 5, rect.y + 22);
Shoot();
});
}
});
var gui = new dat.GUI();
gui.add(tracker, 'edgesDensity', 0.1, 0.5).step(0.01);
gui.add(tracker, 'initialScale', 1.0, 10.0).step(0.1);
gui.add(tracker, 'stepSize', 1, 5).step(0.1);
function Shoot() {
var trackerTask = tracking.track(video, tracker);
var context = canvas1.getContext('2d');
//把当前视频帧内容渲染到画布上
context.drawImage(video, 0, 5, 320, 140);
var dom = document.createElement("a");
dom.href = this.canvas.toDataURL("image/png");
dom.download = new Date().getTime() + ".png";
dom.click();
//删除字符串前的提示信息 "data:image/png;base64,"
var data = canvas1.toDataURL();
var b64 = data.substring(22);
var path = ctx+"/facemanager/search";
$.ajax({
type : 'post',
dataType : 'json',
url : path,
data : {
imgdata:b64
},
success : function(result){
if(result.error_code=='0'){
trackerTask.stop();
layer.open({
title: '温馨提示',
content: '欢迎 '+result.user_info,
yes: function(index, layero){
trackerTask.run();
layer.close(index); //如果设定了yes回调,需进行手工关闭
}
});
}else{
trackerTask.stop();
layer.open({
title: '温馨提示',
content: result.error_msg,
yes: function(index, layero){
trackerTask.run();
layer.close(index); //如果设定了yes回调,需进行手工关闭
}
});
}
}
})
}
};