百度人脸识别_SpringBoot整合离线SDK
一、前言
- 建议使用低版本 SDK : Baidu_Face_Offline_SDK_Windows_Java_6.1.3
- 目前已知8.x版本对服务端不兼容,存在运行过程中,第一次调用sdk能够正常执行,第二次时出现JVM异常。
- SDK不支持多线程,一般都用于设备端,如人脸闸机上的面板机设备。
- 自定义库文件路径,与项目分离。
- 整合springBoot项目,实现启动初始化SDK,按需调用。
二、SDK 引入并配置
- 解压程序,查看对应操作系统的文件夹,将src目录下的文件移动到我们的项目中。请不要修改此目录结构。
- 给Face.java类添加注解,实现条件实例化。
@Slf4j
@Component
@Conditional(FaceSdkEnableCondition.class)
public class Face {
// *******以下为人脸sdk api接口*********
- 修改Face.java类加载库的方式,以及初始化。
- 新增 Environment 类动态获取库路径。
- 更换 System.load() 加载库文件。
- 使用
@PostConstruct
注解,当类对象被创建时,自动完成初始化工作。 - 使用
@PreDestroy
注解,当类对象被销毁时,自动完成释放内存工作。
// ********* 以下为系统加载库文件及opencv **********
private static String libPath;
public Face(){ }
@Autowired
public Face(Environment env) {
// 初始化libPath
libPath = env.getProperty("face-sdk.libPath",String.class);
// 加载dll文件
System.load(libPath + "BaiduFaceApi.dll");
System.load(libPath + "opencv_java320.dll");
}
Face api = null;
/* sdk初始化 */
@PostConstruct
public void init() {
log.info("离线SDK开始初始化");
log.info("SDK路径:{}",libPath);
api = new Face();
int res = api.sdkInit(libPath);
if (res != 0) {
log.info("sdk init fail and error = {}\n", res);
return;
}
log.info("离线SDK初始化完成");
}
/* sdk释放内存 */
@PreDestroy
private void destroy() {
if(api != null){
api.sdkDestroy();
}
log.info("离线SDK销毁");
}
- 配置条件启动类相关
package cn.dyina.config;
public class FaceSdkEnableCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
// 根据face-sdk.enable属性来决定是否创建 Face bean
return "true".equals(env.getProperty("face-sdk.enable"));
}
}
-
配置路径存放库文件
face-sdk: enable: true # 路径请务必使用双斜杆 libPath: D:\\FaceLib\\ imagesPath: D:\\FaceImages\\
- 请将SDK文件的所有.dll文件拷贝到
libPath
目录下。 - 请将SDK文件下的opencv-jar、models、license文件夹拷贝到
libPath
目录下。 - 请登录 百度智能云 控制中心,注册并获取离线识别SDK序列号,替换license\license.key内的序列号。
- 请将SDK文件的所有.dll文件拷贝到
-
安装maven依赖,以解决打包异常
- 请修改并在项目终端执行以下的命令,将opencv-jar下的opencv-320.jar依赖安装到maven仓库。
mvn install:install-file -DgroupId=cn.dyina(jar包的groupId) -DartifactId=opencv-jar(jar包的artifactId) -Dversion=1.0(jar的版本号) -Dpackaging=jar -Dfile=D:\FaceLib\opencv-jar\opencv-320.jar(jar包的具体路径)
- 添加maven依赖
<!-- 本地依赖 opencv-jar--> <dependency> <groupId>cn.dyina</groupId> <artifactId>opencv-jar</artifactId> <version>1.0</version> </dependency>
三、项目使用
- 在SpringBoot启动类上,添加包扫描。
@SpringBootApplication(scanBasePackages = {"cn.dyina","com.jni"})
public class SpringBootBaiDuFaceSdkApplication {
//...
}
- 编写service、controller。(以下示例代码仅提供参考,请根据自己的业务需求进行编写。)
@Slf4j
@Service
public class FaceService {
@Value("${face-sdk.imagesPath}")
String imagesPath;
public String registerFace(String fileName, String nickName) {
// 注册人脸图片
String ip_nickName = fileName.replaceFirst("[.][^.]+$", "");
// 获取人脸特征值
Mat mat = Imgcodecs.imread(imagesPath + fileName);
long matAddr = mat.getNativeObjAddr();
// 填充人脸信息 后期将从数据库获取
String userInfo = nickName;
String userId = ip_nickName.replace(".","");
String groupId = "Face";
// 用人脸特征值注册
JSONObject res = JSONObject.parseObject(Face.userAddByMat(matAddr, userId, groupId, userInfo));
log.info("user add result is:{}", res);
return res.getString("msg");
}
public String identifyFace(String fileName) {
// 调用人脸sdkAPI
Face.loadDbFace();
Mat mat1 = Imgcodecs.imread(imagesPath + fileName);
long mat1Addr = mat1.getNativeObjAddr();
int type = 0;
// 和人脸库里面的人脸特征值比较(人脸识别)
JSONObject res = JSONObject.parseObject(Face.identifyWithAllByMat(mat1Addr, type));
log.info("identify res is:{}", res);
if (!res.getString("errno").equals("0")) {
return res.getString("msg");
}
// 获取人脸识别信息
double score = res.getJSONObject("data")
.getJSONArray("result")
.getJSONObject(0)
.getDouble("score");
String userId = res.getJSONObject("data")
.getJSONArray("result")
.getJSONObject(0)
.getString("user_id");
if (score > 80) {
String nickName = userId.split("_")[1];
return nickName;
} else {
log.info("根据图片获取人员信息失败");
return "Match score is low";
}
}
}
/**
* 人脸识别 页面相关接口
*/
@Slf4j
@RestController
@CrossOrigin(origins = "*", maxAge = 3600)
public class FaceController {
@Autowired
private FaceService faceService;
@Value("${face-sdk.imagesPath}")
String imagesPath;
/**
* 人脸注册
* @param file
* @param ip
* @param nickName
* @return
* @throws IOException
*/
@PostMapping("/faceRegister")
public R<String> faceRegister(@RequestParam("photo") MultipartFile file,
@RequestParam("ip") String ip,
@RequestParam("nickName") String nickName) throws IOException {
String photo = Base64.getEncoder().encodeToString(file.getBytes());
String fileName = ip + "_" + nickName + ".jpg";
Base64ToImage.saveImage(imagesPath, fileName, photo);
// 人脸注册
String res = faceService.registerFace(fileName, nickName);
if(!res.equals("success")){
return R.error(res,null);
}
return R.success(null);
}
/**
* 检测人脸
* @param photo
* @param ip
* @return
*/
@PostMapping("/faceDetection")
public R<String> faceDetection(@RequestParam("photo") String photo, @RequestParam("ip") String ip) {
String fileName = ip +".jpg"; // 临时存储,用于检测
Base64ToImage.saveImage(imagesPath, fileName, photo);
String res = faceService.identifyFace(fileName);
return R.success(res);
}
/**
* 查询用户组人脸
* @param groupId
* @return
*/
@GetMapping("/getAllFace")
public R<List> getAllFace(@RequestParam("groupId") String groupId){
log.info("====>> getAllFace");
List<String> userIdList = faceService.getAllFace(groupId);
return R.success(userIdList);
}
}
后记
-
com.jni.face
包下,除了Face.java类,其他都是示例程序,可以视情况删除。 -
models 文件夹里的模型可以按情况删除,详细可以查看文档。
-
项目启动后,你的控制台应该会收到SDK初始化的信息。并且你的
libPath
目录下应该生成db文件夹,人脸数据将存储在这里。(db文件夹将生成在库文件所在目录。删除face.db后,初始化SDK时会自动生成,不需要额外操作。) -
有生产需求的,但设备量不多,可以咸鱼买序列号。(官网最低100个起购)