编者注:本文作者 爪哇日记
基于虹软的离线人脸识别
·注册虹软账号,获取离线SDK
·自定义人脸库(保存人脸关键点信息),并添加人脸到人脸库
·获取登录客户的人脸
·使用SDK解析人脸,获取关键点信息
·登录人脸信息 与人脸库比对 比对成功或失败(对应登录成功或失败)
虹软视觉开放平台ai.arcsoft.com.cn![74e9b7ad371889ebf3cd339973967bb5.png](https://i-blog.csdnimg.cn/blog_migrate/829d842b341972ea19c59ab77a20aa5e.jpeg)
人脸识别示例:
·添加用户(成功后提示,并在数据库插入一条数据)
![8a6d097eef47cd8c4177be85fbb05a6a.png](https://i-blog.csdnimg.cn/blog_migrate/00e795bd60d15b1afad0ddedef115edb.png)
![1e46d0fdd4b0e0cacd21e75e469315d5.png](https://i-blog.csdnimg.cn/blog_migrate/4187d9af16fc7da0125713399061a8c3.png)
·查找用户(匹配成功后回填用户信息,可以根据业务跳转登录)
![f2a72636e52f4e1e50d35f1b8c4bc77c.png](https://i-blog.csdnimg.cn/blog_migrate/7b0b38afd37b65f6ede7c8b0e36cc7be.jpeg)
获取虹软SDK
先在*虹软官网*登录开发者账号(没有账号先注册后再登录)
创建人脸识别应用
![90fcf68c6cba5ee030d725e22ac0223a.png](https://i-blog.csdnimg.cn/blog_migrate/ed936cfd49f11047f095268b99b97b85.png)
创建SDK(以windows为例)
![bbb9641004eefb813daa9adfdb79e64a.png](https://i-blog.csdnimg.cn/blog_migrate/8f090bfb0721040d8815696723250fd7.jpeg)
![928acba6a18270ee2d36abd78349b56d.png](https://i-blog.csdnimg.cn/blog_migrate/4907f0b1512c50ce3657826a3b43d44f.jpeg)
![956090504fe08234e32ce06082dc1c22.png](https://i-blog.csdnimg.cn/blog_migrate/c99c69bb9015c7f59fa9a4a95e0f93f7.jpeg)
SKD包文件内容
![437679f9ab65f9f1cf7539dbf1e2211c.png](https://i-blog.csdnimg.cn/blog_migrate/085d21a31b04b35ddd0fc3022d7117f1.png)
人脸识别工具类 创建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:UserszsDesktopArcSoftarcsoft_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 下添加依赖
![fed5e3842647a6cc44605bfd9291f8cd.png](https://i-blog.csdnimg.cn/blog_migrate/d58e67b6470f9a75a11bbbb906cde581.jpeg)
数据库
![76d59724570d0b53b83d4093bbbaee10.png](https://i-blog.csdnimg.cn/blog_migrate/51d28e1b5663041771ca040c0c67b9ba.png)
保存人脸信息-页面
<!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>
![77ed169ef72b2a660872359e5e2f9170.png](https://i-blog.csdnimg.cn/blog_migrate/33463b9a4595654584e53508aad44f09.jpeg)
查找人脸信息-页面
<!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>
![b2dae7e937b920f702a9c30ceca13520.png](https://i-blog.csdnimg.cn/blog_migrate/7d5512d86956e0d70eb8b0f45322be2d.jpeg)
页面获取摄像头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的),并获取用户唯一标识(此处名称为唯一标识,可根据业务自行指定)
·根据唯一标示获取用户信息
·根据用户信息按正常的登录流程走就可以了
SDK下载链接:
虹软视觉开放平台ai.arcsoft.com.cn![74e9b7ad371889ebf3cd339973967bb5.png](https://i-blog.csdnimg.cn/blog_migrate/829d842b341972ea19c59ab77a20aa5e.jpeg)
项目下载地址:https://github.com/15225845996/face-test.git
原文链接:https://blog.csdn.net/zfs_zs/article/details/105365014
搜索公众号:【爪哇日记】关注最新文章