百度AI平台

注册登录

  • 进入百度AI开放平台https://ai.baidu.com/进行注册并登录,最好进行实名认证
  • 然后进入控制台,找到人脸识别,点击【创建应用】,填写信息并创建

参数获取

  • 创建成功后,就会获取三个主要参数

  • 人脸识别核心思想
    • 首先先进行人脸注册,将我们注册好的照片上传到我们的人脸库中
    • 当我们想进行人脸登录时,后台再一次将我们的照片和人脸库中的照片进行比对,用户的匹配得分大于我们所设置的阈值时,我们此时可以认为两张人脸基本是一致的。表示登录成功
  • Base64编码:请求的图片需经过Base64编码,图片的base64编码指将图片数据编码成一串字符串,使用该字符串代替图像地址

项目应用

创建项目

  • 项目所集成的依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- https://mvnrepository.com/artifact/com.baidu.aip/java-sdk -->
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.41</version>
</dependency>

客户端连接

  • 创建com.xxx.baiduaiauth.baiduai包,新建连接客户端的类和工具类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.lzy.baiduaiauth.baiduai;
import com.baidu.aip.face.AipFace;
import org.springframework.stereotype.Component;

@Component
public class AiFaceObject {
public String APP_ID = "25xx50";
public String API_KEY = "me52jxxxxWxxCFsq";
public String SECRET_KEY = "vUuknxx2xxx3SuDMpV9zz3LT";
public String GROUD_LIST = "music"; // 人脸库分组

private AipFace client = new AipFace(APP_ID,API_KEY,SECRET_KEY);

public AipFace getClient(){
client.setConnectionTimeoutInMillis(2000);
client.setSocketTimeoutInMillis(60000);
return client;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package com.lzy.baiduaiauth.baiduai;

import com.baidu.aip.face.AipFace;
import com.baidu.aip.face.MatchRequest;
import com.lzy.baiduaiauth.pojo.Image;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;

@Component
public class AiFaceUtils {
@Autowired
AiFaceObject aiFaceObject;

// 人脸绑定的用户信息
public String faceuser(AipFace client, Image image){
HashMap<String, String> options = new HashMap<String, String>();
options.put("quality_control", "NORMAL");
options.put("liveness_control", "LOW");
options.put("max_user_num", "1");

String groupIdList = aiFaceObject.GROUD_LIST;//人脸库组名称(需要自己修改)
JSONObject res = client.search(image.getImgStr(), image.getImgType(), groupIdList, options);
return res.toString(2);
}

// 人脸图片对比
public String Facecomparison(AipFace client, Image imageU, Image imageC){
MatchRequest req1 = new MatchRequest(imageU.getImgStr(), imageU.getImgType());
MatchRequest req2 = new MatchRequest(imageC.getImgStr(), imageC.getImgType());
ArrayList<MatchRequest> requests = new ArrayList<MatchRequest>();
requests.add(req1);
requests.add(req2);
JSONObject res = client.match(requests);
return res.toString(2);
}

// 人脸脸部侦测
public String Facedetection(AipFace client, Image image){
HashMap<String, String> options= new HashMap<String, String>();
options.put("face_field", "age");
options.put("max_face_num", "1");
options.put("face_type", "LIVE");
JSONObject res=client.detect(image.getImgStr(), image.getImgType(), options);
return res.toString(2);
}

// 人脸登记信息
public String Faceregistrtion(AipFace client, String groupList, Image image){
HashMap<String, String> options = new HashMap<String, String>();
options.put("user_info", "user's info");
options.put("quality_control", "NORMAL");
options.put("liveness_control", "LOW");
JSONObject res = client.addUser(image.getImgStr(), image.getImgType(), groupList, image.getImgId(), options);
return res.toString(2);
}
}
  • 创建com.xxx.baiduaiauth.pojo,配置实体类ImageResultUser
1
2
3
4
5
6
7
8
9
package com.lzy.baiduaiauth.pojo;
import lombok.Data;

@Data
public class Image {
private String imgId;//对应用户id
private String imgStr;
private String imgType;
}
1
2
3
4
5
6
7
8
9
10
11
package com.lzy.baiduaiauth.pojo;
import lombok.Data;

@Data
public class Result {
private boolean start;
private String userId;
private String msg;
private int faceNum;
private String errorMsg;
}
1
2
3
4
5
6
7
8
package com.lzy.baiduaiauth.pojo;
import lombok.Data;

@Data
public class User {
private String userId;
private String username;
}

如何保证一个用户对应一张人脸呢,首先前端需要传入用户ID或者用户名,和Image实体类进行绑定,也就是说userID == imgID

业务逻辑

  • 创建com.xxx.baiduauth.service,编写注册和登录业务
1
2
3
4
5
6
7
8
9
package com.lzy.baiduaiauth.service;
import com.lzy.baiduaiauth.pojo.Image;
import com.lzy.baiduaiauth.pojo.Result;
import org.springframework.stereotype.Service;

@Service
public interface FaceRegister {
Result register(Image image);
}
1
2
3
4
5
6
7
8
9
package com.lzy.baiduaiauth.service;
import com.lzy.baiduaiauth.pojo.Image;
import com.lzy.baiduaiauth.pojo.Result;
import org.springframework.stereotype.Service;

@Service
public interface FaceSearch {
Result faceLogin(Image image);
}
  • 创建com.xxx.baiduauth.service.imp,编写注册和登录业务的实现类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.lzy.baiduaiauth.service.imp;
import com.baidu.aip.face.AipFace;
import com.lzy.baiduaiauth.baiduai.AiFaceObject;
import com.lzy.baiduaiauth.baiduai.AiFaceUtils;
import com.lzy.baiduaiauth.pojo.Image;
import com.lzy.baiduaiauth.pojo.Result;
import com.lzy.baiduaiauth.service.FaceRegister;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class FaceRegisterImp implements FaceRegister {
@Autowired
AiFaceObject aiFaceObject;
@Autowired
AiFaceUtils aiFaceUtils;

@Override
public Result register(Image image) {
Result message = new Result();
if(!search(image)) {
JSONObject result = faceRegister(image,aiFaceObject.GROUD_LIST);
int error_code = result.getInt("error_code");
if (error_code == 0){//注册成功
message.setStart(true);
message.setMsg("注册成功");
}else if (error_code==222202){
message.setStart(false);
message.setErrorMsg("请将脸部对准摄像头");
}else {
message.setStart(false);
message.setErrorMsg("错误代码"+result.getInt("error_code"));
}
}else {
message.setStart(false);
message.setErrorMsg("人脸数据已经被注册");
}
return message;
}

private JSONObject faceRegister(Image image,String groudList){
AipFace client= aiFaceObject.getClient();
String res = aiFaceUtils.Faceregistrtion(client,groudList,image);
JSONObject result = new JSONObject(res);
return result;
}
//在人脸库搜索人脸
private boolean search(Image image){
AipFace client= aiFaceObject.getClient();
String res=aiFaceUtils.faceuser(client, image);
JSONObject result = new JSONObject(res);
String errorMsg = result.getString("error_msg");
if ("SUCCESS".equals(errorMsg)){//成功
JSONArray faceList = result.getJSONObject("result").getJSONArray("user_list");
JSONObject user = faceList.getJSONObject(0);
double score = user.getDouble("score");
if (score > 80){//匹配相似度80以上
return true;
}
}
return false;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package com.lzy.baiduaiauth.service.imp;
import com.baidu.aip.face.AipFace;
import com.lzy.baiduaiauth.baiduai.AiFaceObject;
import com.lzy.baiduaiauth.baiduai.AiFaceUtils;
import com.lzy.baiduaiauth.pojo.Image;
import com.lzy.baiduaiauth.pojo.Result;
import com.lzy.baiduaiauth.service.FaceSearch;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class FaceSearchImp implements FaceSearch {
@Autowired
AiFaceObject aiFaceObject;
@Autowired
AiFaceUtils aiFaceUtils;

@Override
public Result faceLogin(Image image) {
Result detection = DetectionFace(image);
if (detection.isStart()){
Result search = search(image);
if (search.isStart()){
return search;
}else {
Result result = new Result();
result.setStart(false);
result.setErrorMsg("匹配不成功");
return result;
}
}else {
Result result = new Result();
result.setStart(false);
result.setErrorMsg("人脸不合格");
return result;
}
}

//检测人脸
private Result DetectionFace(Image image){
Result message = new Result();
AipFace client= aiFaceObject.getClient();
String res=aiFaceUtils.Facedetection(client, image);
JSONObject result = new JSONObject(res);
String errorMsg = result.getString("error_msg");
if ("SUCCESS".equals(errorMsg)){//成功
result = result.getJSONObject("result");
int faceNum = result.getInt("face_num");
JSONArray faceList = result.getJSONArray("face_list");
JSONObject subObj = faceList.getJSONObject(0);
double faceProbability = subObj.getDouble("face_probability");
if (faceNum==1 && faceProbability > 0.8){//登录的人唯一,是人的准确率0.8以上
message.setStart(true);
message.setFaceNum(faceNum);
message.setMsg("成功");
}else {
message.setStart(false);
message.setFaceNum(faceNum);
message.setErrorMsg("图片不能满足登录要求");
}
}else {
message.setStart(false);
message.setFaceNum(0);
message.setErrorMsg("匹配库不成功");
}
return message;
}

//在人脸库搜索人脸
private Result search(Image image){
Result message = new Result();
AipFace client= aiFaceObject.getClient();
String res=aiFaceUtils.faceuser(client, image);
JSONObject result = new JSONObject(res);
String errorMsg = result.getString("error_msg");
if ("SUCCESS".equals(errorMsg)){//成功
JSONArray faceList = result.getJSONObject("result").getJSONArray("user_list");
JSONObject user = faceList.getJSONObject(0);
double score = user.getDouble("score");
String userId = user.getString("user_id");
if (score > 80){//匹配相似度80以上
message.setStart(true);
message.setMsg("成功");
message.setUserId(userId);
}else {
message.setStart(false);
message.setErrorMsg("相似度过低");
}
}else {
message.setStart(false);
message.setErrorMsg("人脸库查询不成功");
}
return message;
}
}

请求处理

  • 创建com.xxx.baiduaiauth.controller,处理前端请求,调用业务层进行处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.lzy.baiduaiauth.controller;
import com.lzy.baiduaiauth.pojo.Image;
import com.lzy.baiduaiauth.pojo.Result;
import com.lzy.baiduaiauth.pojo.User;
import com.lzy.baiduaiauth.service.FaceRegister;
import com.lzy.baiduaiauth.service.FaceSearch;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpSession;

@Controller
public class LoginController {
@Autowired
FaceSearch faceSearch;
@Autowired
FaceRegister faceRegister;

@RequestMapping("/user/login")
@ResponseBody
public Result login(Image image, HttpSession session){
User user = new User();
Result result = faceSearch.faceLogin(image);
user.setUsername(result.getUserId());
session.setAttribute("user",user);
return result;
}

@RequestMapping("/user/register")
@ResponseBody
public Result register(Image image){
// image属性有 imgId,imgStr,imgType
Result result = faceRegister.register(image);
return result;
}

@RequestMapping({"/","/index"})
public String toLindex(){
return "index";
}

@RequestMapping("/user/success")
public String toSuccess(){
return "success";
}
}

前端视图

  • 首先主要通过JavaScriptAPI打开用户的摄像头,以下是脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
var video =null
var canvas = null
var context = null
var mediaStreamTrack=null;
function ParamsSetting(flag){
// 此处需要灵活处理 通过三元表达式,判断canvas是属于登录还是注册
video = flag===1?document.getElementById("video_login"):document.getElementById("video_register")
canvas = flag===1?document.getElementById("canvas_login"):document.getElementById("canvas_register")
context = canvas.getContext("2d");
mediaStreamTrack=null;
}
function success(stream){
//兼容webkit核心浏览器
// var CompatibleURL = window.URL || window.webkitURL;
//将视频流转化为video的源
mediaStreamTrack=stream;
try {
// video.src = CompatibleURL.createObjectURL(stream);
video.srcObject=stream;
}catch (e) {
console.log("访问用户媒体设备失败:",error.name,error.message);
}
video.play();//播放视频
//将视频绘制到canvas上
}
//错误回调函数
function error(error) {
console.log('访问用户媒体失败:',error.name,error.message);
}
function getUserMediaToPhoto(constraints,success,error) {
if(navigator.mediaDevices.getUserMedia){
//最新标准API
navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
}else if (navigator.webkitGetUserMedia) {
//webkit核心浏览器
navigator.webkitGetUserMedia(constraints,success,error);
}else if(navigator.mozGetUserMedia){
//firefox浏览器
navigator.mozGetUserMedia(constraints,success,error);
}else if(navigator.getUserMedia){
//旧版API
navigator.getUserMedia(constraints,success,error);
}
}

function getFace() {
context.drawImage(video, 0, 0, 180, 150);
this.img=canvas.toDataURL('image/jpg')
//获取完整的base64编码
this.img=img.split(',')[1];
return this.img;
}
function openUserMedia() {
if(navigator.mediaDevices.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia){
getUserMediaToPhoto({video:{width:480,height:320,facingMode: "user"}},success,error);
}else{
alert('你的浏览器不支持访问用户媒体设备');
}
}
function offUserMedia() {
$('.ui.modal').modal('hide');
if(mediaStreamTrack!=null)
mediaStreamTrack.getTracks()[0].stop();
}
  • 前端采用Semantic UI配合jQuery
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<html>
<html>
<meta charset="utf-8">
<title>首页</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css"/>
</head>
<body>
<button class="ui teal button" onclick="FaceLogin()">人脸识别</button>
<div class="ui divider"></div>
<button class="ui green button" onclick="FaceRegister()">人脸采集</button>

<!--人脸识别-->
<div class="ui modal faceLogin">
<div class="header">
人脸识别
</div>
<div class="content">
<!--拍摄-->
<div align="center">
<p class="tips"></p>
</div>
<div class="getFace">
<video id="video_login" class="video" name="login" width="900px" height="400px" autoplay="autoplay"></video>
<canvas id="canvas_login" class="canvas" name="login" width="900px" height="400px" style="display: none;"></canvas>
</div>
</div>
<div class="actions">
<button class="ui button" onclick="offUserMedia()">
<i class="stop icon"></i>
关闭摄像头
</button>
</div>
</div>

<!--人脸采集-->
<div class="ui modal faceRegister">
<div class="header">
人脸采集
</div>
<div class="content">
<!--拍摄-->
<div align="center">
<p class="tips"></p>
</div>
<div class="getFace">
<video id="video_register" class="video" name="register" width="900px" height="400px" autoplay="autoplay"></video>
<canvas id="canvas_register" class="canvas" name="register" width="900px" height="400px" style="display: none;"></canvas>
</div>
</div>
<div class="actions">
<div class="ui input">
<input type="text" placeholder="用户名" name="username" id="username">
</div>
<button class="ui button" onclick="offUserMedia()">
<i class="stop icon"></i>
关闭摄像头
</button>
</div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.js"></script>
<script src="getFace.js"></script>
<script>
let flag; // 1--登录 0--注册
function FaceLogin(){
$('.ui.modal.faceLogin').modal({
closable:false
}).modal('show');
flag = 1; // 登录
ParamsSetting(flag)
openUserMedia();
FaceLogin_Ajax();
}
function FaceRegister(){
$('.ui.modal.faceRegister').modal({
closable:false
}).modal('show');
flag = 0; // 注册
ParamsSetting(flag)
openUserMedia();
FaceRegister_Ajax();
}
/////////////////////////////////////发送请求//////////////////
function FaceLogin_Ajax() {
setTimeout(function () {
img = getFace();
$.ajax({
type:"post",
url:"http://localhost:8080/user/login",//后台接口
data:{
"imgStr":img,
"imgType":"BASE64"
},
dataType:"json",
success:function (data) {
console.log(data);
var start = data["start"]
if(start == true){
alert("用户id:"+data["userId"]+"登录"+data["msg"])
window.location.href="/user/success"
}
else{
console.log(data["errorMsg"])
FaceLogin_Ajax()
}
},
error:function () {
alert("连接服务器失败")
},
async:true
})
},500);
}
function FaceRegister_Ajax() {
setTimeout(function () {
img = getFace();
$.ajax({
type:"post",
url:"http://localhost:8080/user/register",//后台接口
data:{
"imgId":1, // 这里固定
"imgStr":img,
"imgType":"BASE64"
},
dataType:"json",
success:function (data) {
console.log(data);
var start = data["start"]
if(start == true){
alert(data["msg"])
}
else{
alert(data["errorMsg"])
FaceRegister_Ajax();
}
},
error:function () {
alert("连接服务器失败")
},
async:true
})
},500);
}
</script>
</body>
</html>