最近公司要在一款软件产品中引入使用人脸识别进行身份认证的技术,于是开始调研应该使用哪家的技术。

首先调研的是虹软 arcsoft,以下是基本信息:

1. 该公司是目前国内人脸认证的头部提供商(图像人脸技术已有 20 年以上的历史积淀),只提供离线 SDK ,不支持在线 API;

2. 有免费版的离线 SDK,但是只能一年下载一次,更新一次;(已通过修改机器日期的方式验证过,一年后就不能用了)

3. 个人开发者,实名认证后可以免费激活 100 个设备;企业认证后,可以免费激活 5000 个设备;

4. 如果购买永久有效的离线 SDK,则至少一批次购买 100 个,每个 120元;

5. 该公司技术使用了 openCV 开发接口,在windows 平台上需要安装 visual studio 2013 开发环境,因为人脸比对过程中要调用 openCV 相关的 dll;

于是下载离线 SDK 后试用,折腾了大半天,过程曲折,详细记录下来以备遇到同样问题的同行们参考。

  • 一、官网下载离线开发 SDK 包

https://www.arcsoft.com.cn/

进入开发者中心。像其他开放平台类似,首先需要创建一个自己的应用,然后可以为该应用申请SDK,然后就可以下载开发SDK 包了。

我要用的是 JAVA 开发包,64位windows平台上的。其他还有linux平台的,可以按需选择。

请留意这页上每个你创建的应用都有一个AppID,每种平台的开发包,都有一个独立的SDK_KEY码,这两个信息是首次初始化时需要填入的。

  • 二、看看 SDK 包有哪些文件

首先来看看下载下来的开发包长啥样:

一个压缩包ArcSoft_ArcFace_Java_Windows_x64_V3.0.zip,解开后文件目录为:

其中最有用的部分是 libs 目录下的 4 文件

  • 三、开始使用 SDK 包测试

  1. Eclipse 中创建一个单独的工程,开始测试。

工程中配置编译环境时,一定要将SDK 包文件 arcsoft-sdk-face-3.0.0.0.jar 配置为编译jar路径。

2. 新建一个类com.yh.arcface.FaceEngineTest

将开发包中的测试代码类 FaceEngineTest.java 复制过来。

当然也可以用import导入,不过导入时常常会把中文字符转成了utf8码,看起来很费劲,所以索性就拷贝过来。

3. 准备测试目录和图片文件

单独创建一个测试目录C:\hanyanhua\arcsoft_lib,全部文件放这里。

网上找 3 张刘亦菲的照片,放在子目录img下,看看AI能不能将这 3 张图片认成一个人。

示例代码很简洁,也有足够注释,我们只需要修改示例代码中的“文件绝对路径”就可以了。编译、导出、运行,来看看效果。

public class FaceEngineTest {

public class FaceEngineTest {


    public static void main(String[] args) {

        //从官网获取 
        String appId = "";
        String sdkKey = "";

        int errorCode = 0;
        FaceEngine faceEngine = new FaceEngine("c:\\hanyanhua\\arcsoft_lib\\");
        /* 激活引擎(首次激活,后续这段就可以注释掉了) */
        errorCode = faceEngine.activeOnline(appId, sdkKey);

        if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
            System.out.println("引擎激活失败");
        }
        else {
        	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("获取激活文件信息失败");
        }
        else {
        	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("c:/hanyanhua/arcsoft_lib/img/lyf1.png"));
        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("c:/hanyanhua/arcsoft_lib/img/lyf2.png"));
        List<FaceInfo> faceInfoList2 = new ArrayList<FaceInfo>();
        errorCode = faceEngine.detectFaces(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(),imageInfo2.getImageFormat(), faceInfoList2);
        System.out.println(faceInfoList2);

        //特征提取2
        FaceFeature faceFeature2 = new FaceFeature();
        errorCode = faceEngine.extractFaceFeature(imageInfo2.getImageData(), imageInfo2.getWidth(), imageInfo2.getHeight(), imageInfo2.getImageFormat(), faceInfoList2.get(0), faceFeature2);
        System.out.println("特征值大小:" + faceFeature2.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("c:/hanyanhua/arcsoft_lib/img/lyf3.png"));
        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();

    }

  • 四、DEBUG扫雷过程
  1. 运行类 com.yh.arcface.FaceEngineTest

打开cmd窗口,进入测试目录。

> cd C:\hanyanhua\arcsoft_lib

执行类:

> java  com.yh.arcface.FaceEngineTest

报错:

看提示java命令找到了要执行的我们的测试类 com.yh.arcface.FaceEngineTest,但是执行到 26 行时找不到类 com/arcsoft/face/FaceEngine,从示例代码的第26行报出。

这个类应该是在开发接口的  arcsoft-sdk-face-3.0.0.0.jar 文件中定义的,所以我们需要用 -cp 参数指定。

于是增加java 命令的参数为:

> java -cp arcsoft-sdk-face-3.0.0.0.jar com.yh.arcface.FaceEngineTest

报错:

这是说java 命令找不到我们自己定义的测试类了,按道理来讲,我们的java 命令是在测试目录下执行的,java应该会在当前目录下找类,但是没有,证明我们增加的参数需要在指定 jar 的同时,保留当前目录。

于是修改命令为:

>java -cp .;arcsoft-sdk-face-3.0.0.0.jar com.yh.arcface.FaceEngineTest

报错:

看提示是加载 com.arcsoft.face.FaceEngine时找不到所依赖的dll文件,看来加载libarcsoft_face.dll会用到深层次的其他API。

于是仔细去读开发包的文档doc目录下的文件《ARCSOFT_ARC_FACE_JAVA_DEVELOPER'S_GUIDE.pdf》,寻找蛛丝马迹。

在第5页找到如下信息:

Windows平台需要安装 vcredist2013,这个库是微软 Visual Studio 2013 中带的openCV开发库。于是去下载Visual Studio 2013。微软官网下载太慢,在华军软件园中找到,下载,用了百度网盘,购买了单次提速包才终于把 5G多的Visual Studio 2013下载完成。

安装好Visual Studio 2013,重启机器,重新进入测试目录,再次执行:

>java -cp .;arcsoft-sdk-face-3.0.0.0.jar com.yh.arcface.FaceEngineTest

成功运行,输出如下:

我们看到虹软人脸给出的前两幅刘亦菲照片的相似度为 91.7%,超过 70% 即可判断为同一个人。

  1. 成功激活 SDK 后

成功执行后,我们看到测试目录下出现一个新文件:ArcFace64.dat

这个文件应该就是激活后的验证码文件,记录了验证成功、机器信息、激活日期。

有了这个文件后,示例代码中的激活部分就可以删除了。直接加载初始化后即可去做人脸识别。

删除这个文件后,需要再次激活,才能验证通过正常使用。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐