虹软人脸识别-SpringBoot集成

tech2022-12-02  95

一、前言

人工智能时代的到来,相信大家已耳濡目染,虹软免费,离线开放的人脸识别 SDK,正推动着全行业进入刷脸时代。为了方便开发者接入,虹软提供了多种语言,多种平台的人脸识别SDK的支持,使用场景广泛。产品主要功能有:人脸检测、追踪、特征提取、特征比对、属性检测,活体检测,图像质量检测等。此外,虹软提供的是基于本地算法特征的离线识别SDK,提供全平台的离线支持。 作为一名刚接触人脸识别的初学者,对于虹软极为简洁,方便的SDK接入充满了好奇,想试图应用到web领域,而如今Java最火的web框架非SpringBoot莫属。但对于Java语言,虹软官网暂时还没有提供基于SpringBoot的集成Demo,因此便尝试写个将Java的人脸识别SDK和SpringBoot进行集成的样例,并写此文章进行记录,向广大初学开发者作分享。 此Demo采用Maven作为项目管理工具,并基于Windows x64,Java 8 以及 SpringBoot 2.1.6,SDK是基于虹软人脸识别 SDK3.0。

二、项目结构

SDK依赖Jar包 可从虹软官网获取 点击”免费获取” , ”登录“后 选择 具体“平台/版本/语言“ 获取。

三、项目依赖

​ pom.xml 依赖包括

SpringBoot-Web依赖SpringBoot-Devtools热部署依赖SpringBoot-Freemarker依赖,Hutool,Fastjson, Lombok,Commons-pool2,Guava虹软人脸识别SDK依赖Jar包SpringBoot-Maven插件 <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.8</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>4.6.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.59</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> <version>2.6.0</version> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>26.0-jre</version> </dependency> <dependency> <groupId>com.arcsoft.face</groupId> <artifactId>arcsoft-sdk-face</artifactId> <version>3.0.0.0</version> <scope>system</scope> <systemPath>${basedir}/lib/arcsoft-sdk-face-3.0.0.0.jar</systemPath> </dependency> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <includeSystemScope>true</includeSystemScope> <fork>true</fork> </configuration> </plugin> </plugins> </build>

四、项目流程

五、效果展示

在Application启动类 右击 选择 Run Application 即可运行程序,待程序启动完成后,访问 http://127.0.0.1:8089/

六、核心代码说明

1. application.properties 配置说明
#上传文件 最大值限制 spring.servlet.multipart.max-file-size=100MB #请求 最大值限制 spring.servlet.multipart.max-request-size=100MB #请求头 最大值限制 server.max-http-header-size=2MB #请求体 最大值限制 server.tomcat.max-http-post-size=50MB #项目访问端口 server.port=8089 #人脸识别引擎库路径 config.arcface-sdk.sdk-lib-path=d:/arcsoft_lib #sdk appId config.arcface-sdk.app-id=9iSfMeAhj********************Kes2TpSrd #sdk sdkKey config.arcface-sdk.sdk-key=BuRTH3hGs9*******************yP9xu6fiFG7G #人脸识别 引擎池大小 config.arcface-sdk.detect-pool-size=5 #人脸比对 引擎池大小 config.arcface-sdk.compare-pool-size=5 #关闭freemarker模板引擎缓存 spring.freemarker.cache=false #模板引擎更新延迟设置为0 spring.freemarker.settings.template_update_delay=0

​ 其中 人脸识别引擎库,APP_ID,SDK_KEY 可通过虹软官网”开发者中心“,进行 “登录”后 在“我的应用“中进行获取。

2. 项目实体类说明

1)UserRamCache 人脸信息存储类

public class UserRamCache { private static ConcurrentHashMap<String, UserInfo> userInfoMap = new ConcurrentHashMap<>(); public static void addUser(UserInfo userInfo) { userInfoMap.put(userInfo.getFaceId(), userInfo); } public static void removeUser(String faceId) { userInfoMap.remove(faceId); } public static List<UserInfo> getUserList() { List<UserInfo> userInfoList = Lists.newLinkedList(); for (UserInfo value : userInfoMap.values()) { userInfoList.add(value); } return userInfoList; } @Data public static class UserInfo { //人脸Id private String faceId; //人脸名称 private String name; //人脸特征值 private byte[] faceFeature; } }

此类拥有一个 UserInfo的内部类,用于封装人脸信息,userInfoMap以人脸名称为key,UserInfo对象为Value 存储 并提供相应增/删/查功能的方法。 2)ProcessInfo 人脸检测实体类

public class ProcessInfo { //年龄 private int age; //性别 private int gender; //是否活体 private int liveness; }

3)UserCompareInfo 人脸识别实体类 此类继承自 人脸信息存储类的人脸信息类(内部类)

public class UserCompareInfo extends UserRamCache.UserInfo { //人脸比对后的相似值 private Float similar; }

4)FaceDetectResDTO 人脸检测DTO封装类

public class FaceDetectResDTO { //人脸框 private Rect rect; //人脸角度 private int orient; //人脸Id private int faceId = -1; //年龄 private int age = -1; //性别 private int gender = -1; //是否为活体 private int liveness = -1; }

5)FaceRecognitionResDTO 人脸识别DTO封装类

public class FaceRecognitionResDTO { //人脸框 private Rect rect; //人脸名称 private String name; //人脸比对相似值 private float similar; }
3. FaceEngineFactory类 源码说明

​ 此类继承自BasePooledObjectFactory抽象类,为FaceEngine对象池。 1)成员变量说明

//SDK引擎库的路径 private String libPath; //SDK APP_ID private String appId; //SDK SDK_KEY private String sdkKey; //SDK 激活码 private String activeKey; //引擎配置类 private EngineConfiguration engineConfiguration;

2)create()方法

@Override public FaceEngine create() { FaceEngine faceEngine = new FaceEngine(libPath); int activeCode = faceEngine.activeOnline(appId, sdkKey); if (activeCode != ErrorInfo.MOK.getValue() && activeCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) { log.error("引擎激活失败" + activeCode); throw new BusinessException(ErrorCodeEnum.FAIL, "引擎激活失败" + activeCode); } int initCode = faceEngine.init(engineConfiguration); if (initCode != ErrorInfo.MOK.getValue()) { log.error("引擎初始化失败" + initCode); throw new BusinessException(ErrorCodeEnum.FAIL, "引擎初始化失败" + initCode); } return faceEngine; } 参数说明:无返回结果:FaceEngine人脸识别引擎代码流程解读: 此方法,通过libPath(SDK引擎库的路径)实例化FaceEngine对象,再根据APP_ID,SDK_KEY调用activeOnline()方法激活引擎 (联网状态下) 成功激活引擎后,根据EngineConfiguration引擎配置类 调用init()方法初始化引擎 。

3)wrap()方法

public PooledObject<FaceEngine> wrap(FaceEngine faceEngine) { return new DefaultPooledObject<>(faceEngine); } 参数说明:FaceEngine人脸识别引擎返回结果:PooledObject包装类代码流程解读: 此方法,通过PooledObject包装器对象 将faceEngine进行包装,便于维护引擎的状态。

4)destroyObject()方法

public void destroyObject(PooledObject<FaceEngine> p) throws Exception { FaceEngine faceEngine = p.getObject(); int result = faceEngine.unInit(); super.destroyObject(p); } 参数说明:PooledObject包装类返回结果:无代码流程解读: 此方法,从PooledObject包装器对象中获取faceEngine引擎,随后卸载引擎。
4. FaceEngineServiceImpl类 源码说明

1)成员变量说明

@Value("${config.arcface-sdk.sdk-lib-path}") public String sdkLibPath; @Value("${config.arcface-sdk.app-id}") public String appId; @Value("${config.arcface-sdk.sdk-key}") public String sdkKey; @Value("${config.arcface-sdk.detect-pool-size}") public Integer detectPooSize; @Value("${config.arcface-sdk.compare-pool-size}") public Integer comparePooSize; private ExecutorService compareExecutorService; //通用人脸识别引擎池 private GenericObjectPool<FaceEngine> faceEngineGeneralPool; //人脸比对引擎池 private GenericObjectPool<FaceEngine> faceEngineComparePool;

​ 此类的成员变量可通过@Value()注解获取配置文件中的相应配置。 2)init()方法

@PostConstruct public void init() { GenericObjectPoolConfig detectPoolConfig = new GenericObjectPoolConfig(); detectPoolConfig.setMaxIdle(detectPooSize); detectPoolConfig.setMaxTotal(detectPooSize); detectPoolConfig.setMinIdle(detectPooSize); detectPoolConfig.setLifo(false); EngineConfiguration detectCfg = new EngineConfiguration(); FunctionConfiguration detectFunctionCfg = new FunctionConfiguration(); //开启人脸检测功能 detectFunctionCfg.setSupportFaceDetect(true); //开启人脸识别功能 detectFunctionCfg.setSupportFaceRecognition(true); //开启年龄检测功能 detectFunctionCfg.setSupportAge(true); //开启性别检测功能 detectFunctionCfg.setSupportGender(true); //开启活体检测功能 detectFunctionCfg.setSupportLiveness(true); detectCfg.setFunctionConfiguration(detectFunctionCfg); //图片检测模式,如果是连续帧的视频流图片,那么改成VIDEO模式 detectCfg.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE); //人脸旋转角度 detectCfg.setDetectFaceOrientPriority(DetectOrient.ASF_OP_0_ONLY); //底层库算法对象池 faceEngineGeneralPool = new GenericObjectPool(new FaceEngineFactory(sdkLibPath, appId, sdkKey, null, detectCfg), detectPoolConfig); //初始化特征比较线程池 GenericObjectPoolConfig comparePoolConfig = new GenericObjectPoolConfig(); comparePoolConfig.setMaxIdle(comparePooSize); comparePoolConfig.setMaxTotal(comparePooSize); comparePoolConfig.setMinIdle(comparePooSize); comparePoolConfig.setLifo(false); EngineConfiguration compareCfg = new EngineConfiguration(); FunctionConfiguration compareFunctionCfg = new FunctionConfiguration(); //开启人脸识别功能 compareFunctionCfg.setSupportFaceRecognition(true); compareCfg.setFunctionConfiguration(compareFunctionCfg); //图片检测模式,如果是连续帧的视频流图片,那么改成VIDEO模式 compareCfg.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE); //人脸旋转角度 compareCfg.setDetectFaceOrientPriority(DetectOrient.ASF_OP_0_ONLY); //底层库算法对象池 faceEngineComparePool = new GenericObjectPool(new FaceEngineFactory(sdkLibPath, appId, sdkKey, null, compareCfg), comparePoolConfig); compareExecutorService = Executors.newFixedThreadPool(comparePooSize); } 参数说明:无返回结果:无代码流程解读: @PostConstruct注解:Spring在实例化该Bean之后 立刻去执行此方法。在此方法中,首先去实例化通用人脸识别引擎池配置对象并设置其对应属性,之后实例化EngineConfiguration(设置图像检测模式、人脸旋转角度)和FunctionConfiguration(用于功能配置,开启引擎相应功能,被EngineConfiguration所依赖),最后调FaceEngineFactory的构造方法去初始化引擎并获取对象池。人脸比对引擎池 同理。 3)detectFaces()方法 人脸检测 @Override public List<FaceInfo> detectFaces(ImageInfo imageInfo) { FaceEngine faceEngine = null; try { faceEngine = faceEngineGeneralPool.borrowObject(); if (faceEngine == null) { throw new BusinessException(ErrorCodeEnum.FAIL, "获取引擎失败"); } //人脸检测得到人脸列表 List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>(); //人脸检测 int errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList); if (errorCode == 0) { return faceInfoList; } else { log.error("人脸检测失败,errorCode:" + errorCode); } } catch (Exception e) { log.error("", e); } finally { if (faceEngine != null) { //释放引擎对象 faceEngineGeneralPool.returnObject(faceEngine); } } return null; } 参数说明:ImageInfo图像信息返回结果:List<FaceInfo> 人脸信息列表代码流程解读: 此方法,根据传入的ImageInfo图像信息,通过faceEngine引擎调用detectFaces()方法检测人脸信息(所需参数: 图像数据,图像宽度(4的倍数),图片高度,图像的颜色格式,存放检测到的人脸信息List),随后回收引擎对象。 注:detectFaces该功能依赖初始化的模式选择,初始化中detectFaceOrientPriority、detectFaceScaleVal、detectFaceMaxNum参数的设置,对能否检测到人脸以及检测到几张人脸都有决定性的作用。 4)extractFaceFeature()方法 人脸特征值提取 @Override public byte[] extractFaceFeature(ImageInfo imageInfo, FaceInfo faceInfo) { FaceEngine faceEngine = null; try { faceEngine = faceEngineGeneralPool.borrowObject(); if (faceEngine == null) { throw new BusinessException(ErrorCodeEnum.FAIL, "获取引擎失败"); } FaceFeature faceFeature = new FaceFeature(); //提取人脸特征 int errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfo, faceFeature); if (errorCode == 0) { return faceFeature.getFeatureData(); } else { log.error("特征提取失败,errorCode:" + errorCode); } } catch (Exception e) { log.error("", e); } finally { if (faceEngine != null) { //释放引擎对象 faceEngineGeneralPool.returnObject(faceEngine); } } return null; } 参数说明:ImageInfo图像信息,FaceInfo人脸信息返回结果:人脸特征值 字节数组代码流程解读: 此方法,根据传入的ImageInfo图像信息数据和FaceInfo人脸信息 通过faceEngine引擎调用extractFaceFeature()方法获取人脸特征数据(所需参数:图像数据,图像宽度(4的倍数),图像高度,图像的颜色格式,人脸信息,存放提取到的人脸特征信息),随后回收引擎对象。 注:extractFaceFeature()方法依赖detectFaces成功检测到人脸,将检测到的人脸,取单张人脸信息和使用的图像信息 传入该接口进行特征提取。 5)compareFace()方法 人脸相似度比对 @Override public Float compareFace(ImageInfo imageInfo1, ImageInfo imageInfo2) { List<FaceInfo> faceInfoList1 = detectFaces(imageInfo1); List<FaceInfo> faceInfoList2 = detectFaces(imageInfo2); if (CollectionUtil.isEmpty(faceInfoList1) || CollectionUtil.isEmpty(faceInfoList2)) { throw new BusinessException(ErrorCodeEnum.FAIL,"未检测到人脸"); } byte[] feature1 = extractFaceFeature(imageInfo1, faceInfoList1.get(0)); byte[] feature2 = extractFaceFeature(imageInfo2, faceInfoList2.get(0)); FaceEngine faceEngine = null; try { faceEngine = faceEngineGeneralPool.borrowObject(); if (faceEngine == null) { throw new BusinessException(ErrorCodeEnum.FAIL, "获取引擎失败"); } FaceFeature faceFeature1 = new FaceFeature(); faceFeature1.setFeatureData(feature1); FaceFeature faceFeature2 = new FaceFeature(); faceFeature2.setFeatureData(feature2); //提取人脸特征 FaceSimilar faceSimilar = new FaceSimilar(); int errorCode = faceEngine.compareFaceFeature(faceFeature1, faceFeature2, faceSimilar); if (errorCode == 0) { return faceSimilar.getScore(); } else { log.error("特征提取失败,errorCode:" + errorCode); } } catch (Exception e) { log.error("", e); } finally { if (faceEngine != null) { //释放引擎对象 faceEngineGeneralPool.returnObject(faceEngine); } } return null; } 参数说明:需要比对的两个 ImageInfo图像信息返回结果:人脸比对相似值代码流程解读: 此方法,根据传入的两个ImageInfo图像信息分别调用detectFaces()方法获取各自人脸信息,成功检测到人脸信息后,再调用extractFaceFeature()方法提取各自人脸特征值,成功获取到人脸特征值后,根据两个特征值再通过faceEngine引擎调用compareFaceFeature()方法进行比对(所需参数:人脸特征值1,人脸特征值2,比对模型,存放比对相似值结果), 最后获取人脸相似值返回 并回收引擎对象。 6)CompareFaceTask

​ FaceEngineServiceImpl的一个成员内部类,其实现Callable接口,用于完成线程任务

private class CompareFaceTask implements Callable<List<UserCompareInfo>> { //存储的人脸信息列表 private List<UserRamCache.UserInfo> userInfoList; //目标特征值 private FaceFeature targetFaceFeature; //相似度预期值 private float passRate; public CompareFaceTask(List<UserRamCache.UserInfo> userInfoList, FaceFeature targetFaceFeature, float passRate) { this.userInfoList = userInfoList; this.targetFaceFeature = targetFaceFeature; this.passRate = passRate; } @Override public List<UserCompareInfo> call() throws Exception { FaceEngine faceEngine = null; List<UserCompareInfo> resultUserInfoList = Lists.newLinkedList();//识别到的人脸列表 try { faceEngine = faceEngineComparePool.borrowObject(); for (UserRamCache.UserInfo userInfo : userInfoList) { FaceFeature sourceFaceFeature = new FaceFeature(); sourceFaceFeature.setFeatureData(userInfo.getFaceFeature()); FaceSimilar faceSimilar = new FaceSimilar(); faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar); if (faceSimilar.getScore() > passRate) {//相似值大于配置预期,加入到识别到人脸的列表 UserCompareInfo info = new UserCompareInfo(); info.setName(userInfo.getName()); info.setFaceId(userInfo.getFaceId()); info.setSimilar(faceSimilar.getScore()); resultUserInfoList.add(info); } } } catch (Exception e) { logger.error("", e); } finally { if (faceEngine != null) { faceEngineComparePool.returnObject(faceEngine); } } return resultUserInfoList; } } 参数说明:无返回结果:List<UserCompareInfo>人脸识别实体类列表代码流程解读: call()方法中遍历userInfoList中每个UserInfo获取特征值,并结合目标特征值 通过faceEngine引擎调用compareFaceFeature()方法获取相似度大小 ,将获取到的相似度大小和预期相似度进行比较,若大于配置的预期值,则加入到识别到人脸的列表,最后回收引擎对象。

7)faceRecognition()方法 人脸识别

@Override public List<UserCompareInfo> faceRecognition(byte[] faceFeature, List<UserRamCache.UserInfo> userInfoList, float passRate) { List<UserCompareInfo> resultUserInfoList = Lists.newLinkedList();//识别到的人脸列表 FaceFeature targetFaceFeature = new FaceFeature(); targetFaceFeature.setFeatureData(faceFeature); List<List<UserRamCache.UserInfo>> faceUserInfoPartList = Lists.partition(userInfoList, 1000);//分成1000一组,多线程处理 CompletionService<List<UserCompareInfo>> completionService = new ExecutorCompletionService(compareExecutorService); for (List<UserRamCache.UserInfo> part : faceUserInfoPartList) { completionService.submit(new CompareFaceTask(part, targetFaceFeature, passRate)); } for (int i = 0; i < faceUserInfoPartList.size(); i++) { List<UserCompareInfo> faceUserInfoList = null; try { faceUserInfoList = completionService.take().get(); } catch (InterruptedException | ExecutionException e) { } if (CollectionUtil.isNotEmpty(userInfoList)) { resultUserInfoList.addAll(faceUserInfoList); } } resultUserInfoList.sort((h1, h2) -> h2.getSimilar().compareTo(h1.getSimilar()));//从大到小排序 return resultUserInfoList; } 参数说明:人脸特征值 字节数组,List<UserRamCache.UserInfo>存储的人脸信息列表,相似度预期值返回结果:List<UserCompareInfo>人脸识别实体类列表代码流程解读: 此方法,根据传入的人脸特征值以及UserRamCache.UserInfo列表,先将UserRamCache.UserInfo分为每1000一组,再通过多线程处理,即上述CompareFaceTask类,处理完之后再将结果合并,按从大到小排序后返回。

8)process()方法 人脸属性检测

@Override public List<ProcessInfo> process(ImageInfo imageInfo, List<FaceInfo> faceInfoList) { FaceEngine faceEngine = null; try { //获取引擎对象 faceEngine = faceEngineGeneralPool.borrowObject(); if (faceEngine == null) { throw new BusinessException(ErrorCodeEnum.FAIL, "获取引擎失败"); } int errorCode = faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList, FunctionConfiguration.builder().supportAge(true).supportGender(true).supportLiveness(true).build()); if (errorCode == 0) { List<ProcessInfo> processInfoList = Lists.newLinkedList(); //性别列表 List<GenderInfo> genderInfoList = new ArrayList<GenderInfo>(); faceEngine.getGender(genderInfoList); //年龄列表 List<AgeInfo> ageInfoList = new ArrayList<AgeInfo>(); faceEngine.getAge(ageInfoList); //活体结果列表 List<LivenessInfo> livenessInfoList = new ArrayList<LivenessInfo>(); faceEngine.getLiveness(livenessInfoList); for (int i = 0; i < genderInfoList.size(); i++) { ProcessInfo processInfo = new ProcessInfo(); processInfo.setGender(genderInfoList.get(i).getGender()); processInfo.setAge(ageInfoList.get(i).getAge()); processInfo.setLiveness(livenessInfoList.get(i).getLiveness()); processInfoList.add(processInfo); } return processInfoList; } } catch (Exception e) { logger.error("", e); } finally { if (faceEngine != null) { //释放引擎对象 faceEngineGeneralPool.returnObject(faceEngine); } } return null; } 参数说明:ImageInfo图像信息,List<FaceInfo>人脸信息列表返回结果:List<ProcessInfo>人脸检测实体类列表代码流程解读: 此方法,根据传入的ImageInfo图像信息以及检测到的FaceInfo人脸信息列表,通过faceEngine引擎调用process()方法(所需参数:图像数据,图片宽度(4的倍数),图像高度,图像的颜色空间格式,人脸信息列表,需检测的属性),之后可从faceEngine对象获取 性别,年龄,是否活体等结果的列表,并将一系列列表结果遍历 设置于ProcessInfo对象返回,随后回收引擎对象。 注:process()支持检测AGE、GENDER、FACE3DANGLE、LIVENESS四种属性,若想检测这些属性,须在初始化引擎接口中对想要检测的属性进行设置。
5. FaceController类 源码说明

1)initFace()方法:初始化注册人脸

@PostConstruct public void initFace() throws FileNotFoundException { Map<String, String> fileMap = Maps.newHashMap(); fileMap.put("zhao1", "赵丽颖"); fileMap.put("yang1", "杨紫"); for (String f : fileMap.keySet()) { ClassPathResource resource = new ClassPathResource("static/images/" + f + ".jpg"); InputStream inputStream = null; try { inputStream = resource.getInputStream(); } catch (IOException e) { } ImageInfo rgbData = ImageFactory.getRGBData(inputStream); List<FaceInfo> faceInfoList = faceEngineService.detectFaces(rgbData); if (CollectionUtil.isNotEmpty(faceInfoList)) { byte[] feature = faceEngineService.extractFaceFeature(rgbData, faceInfoList.get(0)); UserRamCache.UserInfo userInfo = new UserCompareInfo(); userInfo.setFaceId(f); userInfo.setName(fileMap.get(f)); userInfo.setFaceFeature(feature); UserRamCache.addUser(userInfo); } } log.info("http://127.0.0.1:"+ port +"/"); } 参数说明:无返回结果:无代码流程解读: @PostConstruct注解表示Spring在实例化该Bean之后 立刻去执行此方法。首先去加载static/images/下的图片资源将其解析为ImageInfo类型的RGB图像信息数据,之后依次调用FaceEngineService类的detectFaces(),extractFaceFeature()方法提取人脸特征值,最后将人脸相关数据设置于UserRamCache.UserInfo对象中(此Demo仅将数据暂存于内存中,用户可根据需要,自行创建数据库相关表并持久化于磁盘中)。

2)faceAdd()方法 添加人脸

@RequestMapping(value = "/faceAdd", method = RequestMethod.POST) @ResponseBody public Response faceAdd(String file, String faceId, String name) { return null; } 参数说明:浏览器上传的图片信息,人脸Id,人脸名返回结果:Json格式代码流程解读: 此方法,可用于添加更多人脸信息,根据用户需要自行完善。

3)faceRecognition()方法 人脸识别

@RequestMapping(value = "/faceRecognition", method = RequestMethod.POST) @ResponseBody public Response<List<FaceRecognitionResDTO>> faceRecognition(String image) { List<FaceRecognitionResDTO> faceRecognitionResDTOList = Lists.newLinkedList(); byte[] bytes = Base64Util.base64ToBytes(image); ImageInfo rgbData = ImageFactory.getRGBData(bytes); List<FaceInfo> faceInfoList = faceEngineService.detectFaces(rgbData); if (CollectionUtil.isNotEmpty(faceInfoList)) { for (FaceInfo faceInfo : faceInfoList) { FaceRecognitionResDTO faceRecognitionResDTO = new FaceRecognitionResDTO(); faceRecognitionResDTO.setRect(faceInfo.getRect()); byte[] feature = faceEngineService.extractFaceFeature(rgbData, faceInfo); if (feature != null) { List<UserCompareInfo> userCompareInfos = faceEngineService.faceRecognition(feature, UserRamCache.getUserList(), 0.8f); if (CollectionUtil.isNotEmpty(userCompareInfos)) { faceRecognitionResDTO.setName(userCompareInfos.get(0).getName()); faceRecognitionResDTO.setSimilar(userCompareInfos.get(0).getSimilar()); } } faceRecognitionResDTOList.add(faceResDTOList); } } return Response.newSuccessResponse(faceRecognitionResDTOList); } 参数说明:浏览器上传的图片信息返回结果:Json格式 List<FaceRecognitionResDTO>人脸识别DTO列表代码流程解读: 此方法,先将请求上传的(base64编码后)的图片解析为ImageInfo类型的RGB图像信息数据,再依次调用FaceEngineService类的detectFaces(),extractFaceFeature(),faceRecognition()方法 与先前存于内存中的人脸信息进行比对,获取相似度最大的人脸信息,并将结果设置于FaceRecognitionResDTO后返回。

4)detectFaces() 方法 人脸检测

@RequestMapping(value = "/detectFaces", method = RequestMethod.POST) @ResponseBody public Response<List<FaceDetectResDTO>> detectFaces(String image) { byte[] bytes = Base64Util.base64ToBytes(image); ImageInfo rgbData = ImageFactory.getRGBData(bytes); List<FaceDetectResDTO> faceDetectResDTOS = Lists.newLinkedList(); List<FaceInfo> faceInfoList = faceEngineService.detectFaces(rgbData); if (CollectionUtil.isNotEmpty(faceInfoList)) { List<ProcessInfo> process = faceEngineService.process(rgbData, faceInfoList); for (int i = 0; i < faceInfoList.size(); i++) { FaceDetectResDTO faceDetectResDTO = new FaceDetectResDTO(); FaceInfo faceInfo = faceInfoList.get(i); faceDetectResDTO.setRect(faceInfo.getRect()); faceDetectResDTO.setOrient(faceInfo.getOrient()); faceDetectResDTO.setFaceId(faceInfo.getFaceId()); if (CollectionUtil.isNotEmpty(process)) { ProcessInfo processInfo = process.get(i); faceDetectResDTO.setAge(processInfo.getAge()); faceDetectResDTO.setGender(processInfo.getGender()); faceDetectResDTO.setLiveness(processInfo.getLiveness()); } faceDetectResDTOS.add(faceDetectResDTO); } } return Response.newSuccessResponse(faceDetectResDTOS); } 参数说明:浏览器上传的图片信息返回结果:Json格式List<FaceDetectResDTO>人脸检测DTO列表代码流程解读: 此方法,先将请求上传的(base64编码后)的图片解析为ImageInfo类型的RGB图像信息数据,再依次调用FaceEngineService类的detectFaces() process()方法获取人脸检测数据(年龄,性别,是否活体),并将结果设置于FaceDetectResDTO后返回。

5)compareFaces()方法 人脸比对

@RequestMapping(value = "/compareFaces", method = RequestMethod.POST) @ResponseBody public Response<Float> compareFaces(String image1, String image2) { byte[] bytes1 = Base64Util.base64ToBytes(image1); byte[] bytes2 = Base64Util.base64ToBytes(image2); ImageInfo rgbData1 = ImageFactory.getRGBData(bytes1); ImageInfo rgbData2 = ImageFactory.getRGBData(bytes2); Float similar = faceEngineService.compareFace(rgbData1, rgbData2); return Response.newSuccessResponse(smilar); } 参数说明:两张浏览器上传的图片信息返回结果:人脸比对相似值代码流程解读: 此方法,先将请求上传的(base64编码后)的图片解析为ImageInfo类型的RGB图像信息数据,之后通过FaceEngineService类的compareFace()方法进行人脸比对,获取人脸相似值并返回。

七、源码下载

若有想一起学习虹软SDK,感受人脸识别奥秘的同学,可通过点击此链接获取Demo源码。

最新回复(0)