虹软人脸识别
简介
最近公司项目新需求需要做视频监控+陌生人告警,产品经理和项目经理商量了一周,敲定试用海康威视摄像头+虹软人脸识别进行开发。
刚刚接手需求的时候,都不知道这两个大神是啥东西,百度了一上午,了解了一下两家公司和自己需要的一些技术文档。
首先,这篇文章我们先讲讲虹软人脸识别吧。
虹软科技股份有限公司提供计算机视觉行业算法服务及解决方案,致力于视觉技术的研发和应用,坚持以原创技术为核心驱动力,在全球范围内为智能手机、智能汽车、物联网等智能设备提供一站式视觉解决方案。
准备工作
注册用户
首先,我们要注册一个虹软的账号,申请一个应用。
创建应用
创建应用成功之后,我们需要添加SDK,这里我们已免费版的为例,后续介绍付费版
添加SDK
因为我们的开发环境是windows,服务器环境也是windows,所以这里我选择的是windows平台,这里可以自行进行选择,应该只是库文件的不同。
到这里,我们就能看到 APP_ID 和 SDK_KEY 两个值,后续需要这两个值进行虹软激活
SDK文档
SDK文档:https://ai.arcsoft.com.cn/product/arcface.html
我们下载SDK文档和Java案例之后能看到如下文件
libs目录文件:
- doc目录里面存放着虹软sdk的接口文档,我们在调用SDK时方便查阅
- libs目录存放了SDK jar包还有依赖的必要库文件
- samplecode目录存放了简单的示例代码
添加库文件
对windows操作系统熟悉的朋友,就知道其他程序依赖第三方库文件,需要配置到系统环境变量中。
在Path变量中添加库文件的路径即可
到这里,我们前期工作就差不多完成了
开发环境搭建
引入SDK
首先我们要引入虹软的jar包,因为他是第三方的jar包,没有存放到共有的Maven库中,我们需要手动导入到项目中去。
在Maven中引用
<!--虹软人脸识别sdk-->
<dependency>
<groupId>com.arcsoft.face</groupId>
<artifactId>arcsoft-sdk-face</artifactId>
<version>3.0.0.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/src/main/resources/lib/arcsoft-sdk-face-3.0.0.0.jar</systemPath>
</dependency>
虹软配置类
@Configuration
public class FaceEngineConfig {
@Value("${config.freesdk.app-id}")
private String appId;
@Value("${config.freesdk.sdk-key}")
private String sdkKey;
@Bean
public FaceEngine getFaceEngineInstance() {
FaceEngine mFaceEngine = new FaceEngine();
// 激活引擎
//在线激活
int activeCode = mFaceEngine.activeOnline(appId, sdkKey);
System.out.println("code======>" + activeCode);
if (activeCode != ErrorInfo.MOK.getValue() && activeCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
System.out.println("引擎激活失败");
} else {
System.out.println("引擎激活成功");
}
// 引擎配置
EngineConfiguration engineConfiguration = new EngineConfiguration();
engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_0_ONLY);
// 功能配置,这些配置可以查阅SDK文档,根据自己的需要进行修改
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);
// 初始化引擎
int initCode = mFaceEngine.init(engineConfiguration);
if (initCode != ErrorInfo.MOK.getValue()) {
System.out.println("000000=-----初始化引擎失败");
}
return mFaceEngine;
}
}
这里我们使用的是在线激活人脸引擎的方式,这里需要我们把刚刚申请到的appId和sdkKey输入进去
int activeCode = mFaceEngine.activeOnline(appId, sdkKey)
我们也可以查阅SDK文档,这里我们就已激活SDK为例。
到这里,我们就已经把虹软SDK 的bean导入进行了,方便我们后续的操作。
简单使用接口->单个人脸信息
我的需求是拿到海康威视的视频流然后逐帧拿到图片,获取到图片中人脸的信息,这里我们就以获取单个人脸特征信息为例
/**
* 抽取单个人脸特征
*
* @param f 人脸信息
* @param imageInfo 人脸图片信息
* @return 人脸特征
*/
public byte[] extractFaceFeatureList(FaceInfo f, ImageInfo imageInfo) {
FaceEngine faceEngine = null;
try {
// 获取引擎对象
faceEngine = imgFaceObjectPool.borrowObject();
FaceFeature faceFeature = new FaceFeature();
// 提取人脸特征
int code = faceEngine.extractFaceFeature(imageInfo.getRgbData(), imageInfo.getWidth(), imageInfo.getHeight(),
ImageFormat.CP_PAF_BGR24, f, faceFeature);
if (code != 0) {
logger.error("FACE:" + f.getFaceId() + "人脸特征抽取结果不可信" + code);
//return null;
}
return faceFeature.getFeatureData();
} catch (Exception e) {
logger.error("人脸特征抽取异常", e);
} finally {
if (faceEngine != null) {
// 释放引擎对象
imgFaceObjectPool.returnObject(faceEngine);
}
}
return null;
}
此接口获取到的人脸信息是一个二进制流的形式,我后续是把他存到数据库,项目启动的时候读到缓存中,方便进行人脸比对
faceFeature.getFeatureData()
int code = faceEngine.extractFaceFeature(imageInfo.getRgbData(), imageInfo.getWidth(), imageInfo.getHeight(),ImageFormat.CP_PAF_BGR24, f, faceFeature);
示例代码
在正式开发前也可以用示例代码进行一些简单的测试,看看满不满足你的需求
import com.arcsoft.face.*;
import com.arcsoft.face.enums.*;
import com.arcsoft.face.toolkit.ImageInfo;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import com.arcsoft.face.toolkit.ImageInfoEx;
import static com.arcsoft.face.toolkit.ImageFactory.getGrayData;
import static com.arcsoft.face.toolkit.ImageFactory.getRGBData;
public class FaceEngineTest {
public static void main(String[] args) {
//从官网获取
String appId = "";
String sdkKey = "";
FaceEngine faceEngine = new FaceEngine("D:\\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("初始化引擎失败");
}
//人脸检测
ImageInfo imageInfo = getRGBData(new File("d:\\aaa.jpg"));
List<FaceInfo> faceInfoList = new ArrayList<FaceInfo>();
errorCode = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
System.out.println(faceInfoList);
//特征提取
FaceFeature faceFeature = new FaceFeature();
errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList.get(0), faceFeature);
System.out.println("特征值大小:" + faceFeature.getFeatureData().length);
//人脸检测2
ImageInfo imageInfo2 = getRGBData(new File("d:\\ccc.jpg"));
List<FaceInfo> faceInfoList2 = new ArrayList<FaceInfo>();
errorCode = faceEngine.detectFaces(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(),imageInfo.getImageFormat(), faceInfoList2);
System.out.println(faceInfoList);
//特征提取2
FaceFeature faceFeature2 = new FaceFeature();
errorCode = faceEngine.extractFaceFeature(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo.getImageFormat(), faceInfoList2.get(0), faceFeature2);
System.out.println("特征值大小:" + faceFeature.getFeatureData().length);
//特征比对
FaceFeature targetFaceFeature = new FaceFeature();
targetFaceFeature.setFeatureData(faceFeature.getFeatureData());
FaceFeature sourceFaceFeature = new FaceFeature();
sourceFaceFeature.setFeatureData(faceFeature2.getFeatureData());
FaceSimilar faceSimilar = new FaceSimilar();
errorCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
System.out.println("相似度:" + faceSimilar.getScore());
//设置活体测试
errorCode = faceEngine.setLivenessParam(0.5f, 0.7f);
//人脸属性检测
FunctionConfiguration configuration = new FunctionConfiguration();
configuration.setSupportAge(true);
configuration.setSupportFace3dAngle(true);
configuration.setSupportGender(true);
configuration.setSupportLiveness(true);
errorCode = faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList, configuration);
//性别检测
List<GenderInfo> genderInfoList = new ArrayList<GenderInfo>();
errorCode = faceEngine.getGender(genderInfoList);
System.out.println("性别:" + genderInfoList.get(0).getGender());
//年龄检测
List<AgeInfo> ageInfoList = new ArrayList<AgeInfo>();
errorCode = faceEngine.getAge(ageInfoList);
System.out.println("年龄:" + ageInfoList.get(0).getAge());
//3D信息检测
List<Face3DAngle> face3DAngleList = new ArrayList<Face3DAngle>();
errorCode = faceEngine.getFace3DAngle(face3DAngleList);
System.out.println("3D角度:" + face3DAngleList.get(0).getPitch() + "," + face3DAngleList.get(0).getRoll() + "," + face3DAngleList.get(0).getYaw());
//活体检测
List<LivenessInfo> livenessInfoList = new ArrayList<LivenessInfo>();
errorCode = faceEngine.getLiveness(livenessInfoList);
System.out.println("活体:" + livenessInfoList.get(0).getLiveness());
//IR属性处理
ImageInfo imageInfoGray = getGrayData(new File("d:\\IR_480p.jpg"));
List<FaceInfo> faceInfoListGray = new ArrayList<FaceInfo>();
errorCode = faceEngine.detectFaces(imageInfoGray.getImageData(), imageInfoGray.getWidth(), imageInfoGray.getHeight(), imageInfoGray.getImageFormat(), faceInfoListGray);
FunctionConfiguration configuration2 = new FunctionConfiguration();
configuration2.setSupportIRLiveness(true);
errorCode = faceEngine.processIr(imageInfoGray.getImageData(), imageInfoGray.getWidth(), imageInfoGray.getHeight(), imageInfoGray.getImageFormat(), faceInfoListGray, configuration2);
//IR活体检测
List<IrLivenessInfo> irLivenessInfo = new ArrayList<>();
errorCode = faceEngine.getLivenessIr(irLivenessInfo);
System.out.println("IR活体:" + irLivenessInfo.get(0).getLiveness());
ImageInfoEx imageInfoEx = new ImageInfoEx();
imageInfoEx.setHeight(imageInfo.getHeight());
imageInfoEx.setWidth(imageInfo.getWidth());
imageInfoEx.setImageFormat(imageInfo.getImageFormat());
imageInfoEx.setImageDataPlanes(new byte[][]{imageInfo.getImageData()});
imageInfoEx.setImageStrides(new int[]{imageInfo.getWidth() * 3});
List<FaceInfo> faceInfoList1 = new ArrayList<>();
errorCode = faceEngine.detectFaces(imageInfoEx, DetectModel.ASF_DETECT_MODEL_RGB, faceInfoList1);
FunctionConfiguration fun = new FunctionConfiguration();
fun.setSupportAge(true);
errorCode = faceEngine.process(imageInfoEx, faceInfoList1, functionConfiguration);
List<AgeInfo> ageInfoList1 = new ArrayList<>();
int age = faceEngine.getAge(ageInfoList1);
System.out.println("年龄:" + ageInfoList1.get(0).getAge());
FaceFeature feature = new FaceFeature();
errorCode = faceEngine.extractFaceFeature(imageInfoEx, faceInfoList1.get(0), feature);
//引擎卸载
errorCode = faceEngine.unInit();
}
}
碰到的问题
在开发及上线过程中,碰到一些问题进行一些汇总
- 添加库文件的问题,在开发中,把代码提交到git上之后,同小组的开发人员拉代码之后因为没有添加库文件的原因报错,这时候添加了库文件没有重启idea,编译器没有及时生效,导致还是会继续报错。解决方案:重启idea
- 这里我们使用的是在线激活SDK的方法,查看SDK文档我们知道,在线激活需要服务器能够正常连接公网才行,但是有些项目的生产环境是无法连接公网的,这里我们就需要使用离线增值版的SDK,而虹软官网一般是100个SDK起卖的,一般的公司或者个人开发者是不需要这么大的量的。这里我解决方案就不在文档里说了,有需求的可以私聊我,我可以给你解决方案。
离线增值版激活
你在购买了之后,一般会教你怎么去激活,具体的激活是我买的那个老哥操作的,我说说我怎么配合进行操作吧
- 首先他会发一个生产机器激活文件的.exe文件给你,你执行之后就会生成一个文件,虹软后台会需要这个文件生成激活文档。特别注意,这个文件不要在自己的开发环境浪费了
- 之后他就会把这个激活文件发给你,在线的SDK和离线增值版的SDK是不一样的,我们需要把jar包进行替换,这里我是直接问那个老哥要的,没去官网找了。(毕竟我花了钱,能不干的事咱就不干),激活文件放到服务器一般不会去看的文件夹里,防止有人手痒给删了。
- 之后就是修改激活SDK的方式了,方法就是把激活文件的路径给它就好,如下:
String filePath = "F:\\86111149K3RK689A.dat";
int activeCode = mFaceEngine.activeOffline(filePath);