基于虹软的离线人脸识别
- 注册虹软账号,获取离线SDK
- 自定义人脸库(保存人脸关键点信息),并添加人脸到人脸库
- 获取登录客户的人脸
- 使用SDK解析人脸,获取关键点信息
- 登录人脸信息 与人脸库比对 比对成功或失败(对应登录成功或失败)
人脸识别示例:
-
添加用户(成功后提示,并在数据库插入一条数据)
在这里插入图片描述
在这里插入图片描述 - 查找用户(匹配成功后回填用户信息,可以根据业务跳转登录)
在这里插入图片描述
获取虹软SDK
先在 虹软官网 登录开发者账号(没有账号先注册后再登录)
在这里插入图片描述
创建人脸识别应用
创建SDK(以windows为例)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
SKD包文件内容
在这里插入图片描述
人脸识别工具类 创建FaceEngine 引擎时要指定依赖文件路径(为sdk压缩包中 libs文件夹下的dll文件路径)
package com.face.facetest.utils;
import com.arcsoft.face.*;
import com.arcsoft.face.enums.DetectMode;
import com.arcsoft.face.enums.DetectOrient;
import com.arcsoft.face.enums.ErrorInfo;
import com.arcsoft.face.toolkit.ImageInfo;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import javax.imageio.stream.FileImageOutputStream;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.arcsoft.face.toolkit.ImageFactory.getRGBData;
/**
* @Auther: zs
* @Date: 2020/4/7 15:51
* @Description:
*/
@Data
@Component
public class FaceUtils {
@Value("${face.appId}")
private String appId1;
@Value("${face.sdkKey}")
private String sdkKey1;
public static String appId;
public static String sdkKey;
@PostConstruct
public void init(){
appId = this.appId1;
sdkKey = this.sdkKey1;
}
//特征比对
public static float compare(FaceEngine faceEngine,byte[] sources,byte[] target){
FaceFeature targetFaceFeature = new FaceFeature();
targetFaceFeature.setFeatureData(target);
FaceFeature sourceFaceFeature = new FaceFeature();
sourceFaceFeature.setFeatureData(sources);
FaceSimilar faceSimilar = new FaceSimilar();
int errorCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
return faceSimilar.getScore();
}
//特征
public static byte[] feature(FaceEngine faceEngine,byte[] bytes,FaceInfo faceInfo){
ImageInfo imageInfo = getRGBData(bytes);
//特征提取
FaceFeature faceFeature = new FaceFeature();
int errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfo, faceFeature);
System.out.println("特征值大小:" + faceFeature.getFeatureData().length);
return faceFeature.getFeatureData();
}
//获取人脸位置
public static List<FaceInfo> detectFaces(FaceEngine faceEngine,byte[] bytes){
//人脸检测
ImageInfo imageInfo = getRGBData(bytes);
List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
int errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
return faceInfoList;
}
public static FaceEngine getFaceEngine(){
/*
* 此路径为sdk压缩包中 libs文件夹下的dll文件路径
* */
FaceEngine faceEngine = new FaceEngine("C:\\Users\\zs\\Desktop\\ArcSoft\\arcsoft_lib");
//激活引擎
int errorCode = faceEngine.activeOnline(appId, sdkKey);
if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
System.out.println("引擎激活失败");
}
ActiveFileInfo activeFileInfo=new ActiveFileInfo();
errorCode = faceEngine.getActiveFileInfo(activeFileInfo);
if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
System.out.println("获取激活文件信息失败");
}
//引擎配置
EngineConfiguration engineConfiguration = new EngineConfiguration();
engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
engineConfiguration.setDetectFaceMaxNum(10);
engineConfiguration.setDetectFaceScaleVal(16);
//功能配置
FunctionConfiguration functionConfiguration = new FunctionConfiguration();
functionConfiguration.setSupportAge(true);
functionConfiguration.setSupportFace3dAngle(true);
functionConfiguration.setSupportFaceDetect(true);
functionConfiguration.setSupportFaceRecognition(true);
functionConfiguration.setSupportGender(true);
functionConfiguration.setSupportLiveness(true);
functionConfiguration.setSupportIRLiveness(true);
engineConfiguration.setFunctionConfiguration(functionConfiguration);
//初始化引擎
errorCode = faceEngine.init(engineConfiguration);
if (errorCode != ErrorInfo.MOK.getValue()) {
System.out.println("初始化引擎失败");
}
return faceEngine;
}
}
注意:人脸识别的jar包需要添加依赖后才可正常使用,否则会报异常。springboot项目jar报启动时 可在:File->Project Structure->Modular 下添加依赖
数据库
在这里插入图片描述
保存人脸信息-页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/css/common.css" media="all">
</head>
<body class="align-center">
<h1 style="margin-top: 50px">添加用户信息</h1>
<br>
<div class="faceDiv">
<video id="video"></video>
<canvas id="canvas" style="display: none;"></canvas>
</div>
<br/><br/><br/>
用户名:<input id="name" />
<br/><br/><br/>
<button id="saveUser">保存</button>
</body>
<script src="/js/jquery-3.4.1.min.js" charset="utf-8"></script>
<script src="/js/face.js" charset="utf-8"></script>
<script>
openUserMedia();
$("#saveUser").click(function () {
var name = $("#name").val();
if(name){
var img = getFace();
$.ajax({
type:"post",
url:"/addUser",
data:{
"faceStr":img,
"name":name
},
success:function (rst) {
alert(rst.msg)
},
error:function () {
alert("连接服务器失败")
}
})
}else{
alert("姓名不能为空")
}
})
</script>
</html>
在这里插入图片描述
查找人脸信息-页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/css/common.css" media="all">
</head>
<body class="align-center">
<h1 style="margin-top: 50px">查找用户信息</h1>
<br>
<div class="faceDiv">
<video id="video"></video>
<canvas id="canvas" style="display: none;"></canvas>
</div>
<br/><br/><br/>
用户信息:<span id="userInfo"></span>
<br/><br/><br/>
<button id="searchUser">查找</button>
</body>
<script src="/js/jquery-3.4.1.min.js" charset="utf-8"></script>
<script src="/js/face.js" charset="utf-8"></script>
<script>
openUserMedia();
$("#searchUser").click(function () {
var img = getFace();
$.ajax({
type:"post",
url:"/searchUser",
data:{
"faceStr":img
},
success:function (rst) {
$("#userInfo").html(rst.msg)
},
error:function () {
alert("连接服务器失败")
}
})
})
</script>
</html>
在这里插入图片描述
页面获取摄像头JS(页面引用的face.js)
//成功回调函数
var video = document.getElementById("video");
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var mediaStreamTrack=null;
function success(stream){
//兼容webkit核心浏览器
//将视频流转化为video的源
mediaStreamTrack=stream;
try {
// video.src = CompatibleURL.createObjectURL(stream);
video.srcObject=stream;
}catch (e) {
console.log("访问用户媒体设备失败:",error.name,error.message);
}
video.play();//播放视频
}
//错误回调函数
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,300,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:300,height:300,facingMode: "user"}},success,error);
}else{
alert('你的浏览器不支持访问用户媒体设备');
}
}
//关闭摄像头
function offUserMedia() {
if(mediaStreamTrack!=null)
mediaStreamTrack.getTracks()[0].stop();
}
后台Controller
package com.face.facetest.controller;
import com.arcsoft.face.FaceEngine;
import com.arcsoft.face.FaceInfo;
import com.face.facetest.service.FaceInfoServiceImpl;
import com.face.facetest.utils.FaceUtils;
import com.face.facetest.utils.ImageUtils;
import com.face.facetest.vo.FaceVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
/**
* @Auther: zs
* @Date: 2020/4/7 15:47
* @Description:
*/
@RestController
public class IndexController {
@Autowired
private FaceInfoServiceImpl faceInfoService;
@RequestMapping("/addUser")
public Object addUser(HttpServletRequest request, FaceVo faceVo){
HashMap<Object, Object> result = new HashMap<>();
result.put("msg","异常");
if(faceVo.getFaceStr() != null && faceVo.getName() != null){
byte[] bytes = ImageUtils.base64ToByte(faceVo.getFaceStr());
FaceEngine faceEngine = FaceUtils.getFaceEngine();
List<FaceInfo> faceInfos = FaceUtils.detectFaces(faceEngine, bytes);
if(faceInfos != null && faceInfos.size() > 0){
byte[] feature = FaceUtils.feature(faceEngine, bytes, faceInfos.get(0));
com.face.facetest.entry.FaceInfo faceInfo = new com.face.facetest.entry.FaceInfo();
faceInfo.setName(faceVo.getName());
faceInfo.setFaceData(feature);
boolean save = faceInfoService.save(faceInfo);
if(save){
result.put("msg","添加成功");
}
}
faceEngine.unInit();
}
return result;
}
@RequestMapping("/searchUser")
public Object searchUser(HttpServletRequest request, FaceVo faceVo){
HashMap<Object, Object> result = new HashMap<>();
result.put("msg","异常");
if(faceVo.getFaceStr() != null){
byte[] bytes = ImageUtils.base64ToByte(faceVo.getFaceStr());
FaceEngine faceEngine = FaceUtils.getFaceEngine();
List<FaceInfo> faceInfos = FaceUtils.detectFaces(faceEngine, bytes);
if(faceInfos != null && faceInfos.size() > 0){
byte[] feature = FaceUtils.feature(faceEngine, bytes, faceInfos.get(0));
if(feature != null){
List<com.face.facetest.entry.FaceInfo> list = faceInfoService.list();
if(list != null){
for (com.face.facetest.entry.FaceInfo faceInfo : list) {
if(faceInfo.getFaceData() != null){
float compare = FaceUtils.compare(faceEngine, feature, faceInfo.getFaceData());
if(compare >= 0.8){
result.put("msg",faceInfo.getName());
}
}
}
}
}
}
faceEngine.unInit();
}
return result;
}
}
流程总结:
人脸识别流程(添加用户):
- 页面获取头像
- 后台获取头像,SDK解析获取关键点信息
- 保存数据库
人脸识别流程(查找用户):
- 获取头像信息
- 后台获取头像,SDK解析获取关键点信息
- 获取头像库的信息,比对相似值(官方推荐获取相似值大于0.8的),并获取用户唯一标识(此处名称为唯一标识,可根据业务自行指定)
- 根据唯一标示获取用户信息
- 根据用户信息按正常的登录流程走就可以了
网友评论