从零玩转人脸识别之RGB人脸活体检测

从零玩转RGB人脸活体检测

前言

本期教程人脸识别第三方平台为虹软科技,本文章讲解的是人脸识别RGB活体追踪技术,免费的功能很多可以自行搭配,希望在你看完本章课程有所收获。

从零玩转人脸识别之RGB人脸活体检测

ArcFace 离线SDK,包含人脸检测、性别检测、年龄检测、人脸识别、图像质量检测、RGB活体检测、IR活体检测等能力,初次使用时需联网激活,激活后即可在本地无网络环境下工作,可根据具体的业务需求结合人脸识别SDK灵活地进行应用层开发。

从零玩转人脸识别之RGB人脸活体检测

功能介绍

1. 人脸检测

对传入的图像数据进行人脸检测,返回人脸的边框以及朝向信息,可用于后续的人脸识别、特征提取、活体检测等操作;

  • 支持IMAGE模式和VIDEO模式人脸检测。
  • 支持单人脸、多人脸检测,最多支持检测人脸数为50。

2.人脸追踪

对来自于视频流中的图像数据,进行人脸检测,并对检测到的人脸进行持续跟踪。(我们是实时的所以就只能使用第三方操作,先不使用这个)

3.人脸特征提取

提取人脸特征信息,用于人脸的特征比对。

4.人脸属性检测

人脸属性,支持检测年龄、性别以及3D角度。

人脸3D角度:俯仰角(pitch), 横滚角(roll), 偏航角(yaw)。

从零玩转人脸识别之RGB人脸活体检测

5.活体检测

离线活体检测,静默式识别,在人脸识别过程中判断操作用户是否为真人,有效防御照片、视频、纸张等不同类型的作弊攻击,提高业务安全性,让人脸识别更安全、更快捷,体验更佳。支持单目RGB活体检测、双目(IR/RGB)活体检测,可满足各类人脸识别终端产品活体检测应用。

开造

访问地址: https://ai.arcsoft.com.cn/technology/faceTracking.html 进入开发者中心进行注册以及认证个人信息
1. 点击我的应用 > 新建应用

从零玩转人脸识别之RGB人脸活体检测
2.填写信息立即创建 点击 添加SDK

从零玩转人脸识别之RGB人脸活体检测
3.选中免费版人脸识别

从零玩转人脸识别之RGB人脸活体检测
4. 填写授权码信息
选择平台先选择windows的根据你的电脑配置来 是64位还是32位的, 语言选择Java

从零玩转人脸识别之RGB人脸活体检测

从零玩转人脸识别之RGB人脸活体检测
5. 介绍sdk文件

从零玩转人脸识别之RGB人脸活体检测

一、创建Springboot工程:ArcFace

1. maven依赖


            org.springframework.boot
            spring-boot-starter-web

            org.springframework.boot
            spring-boot-configuration-processor
            true

            org.springframework.boot
            spring-boot-starter-test
            test

            org.springframework.boot
            spring-boot-starter-thymeleaf

            com.arcsoft.face
            arcsoft-sdk-face
            3.0.0.0
            system
            ${basedir}/lib/arcsoft-sdk-face-3.0.0.0.jar

2.创建lib文件夹将sdk复制

进来记得add依赖有小箭头就行

从零玩转人脸识别之RGB人脸活体检测

3.复制到测试类当中

从零玩转人脸识别之RGB人脸活体检测

从零玩转人脸识别之RGB人脸活体检测

4.填写好对应的appId和sdkKey

从零玩转人脸识别之RGB人脸活体检测

5.复制算法库路径

从零玩转人脸识别之RGB人脸活体检测

从零玩转人脸识别之RGB人脸活体检测

6.启动测试

我进行删除了一些功能就示范特征、活体检测, 其他的可自己试一试

从零玩转人脸识别之RGB人脸活体检测

体验到此结束,可以自己多玩玩

二、改造ArcFace工程

效果图

从零玩转人脸识别之RGB人脸活体检测

从零玩转人脸识别之RGB人脸活体检测

1. 创建FaceRecognitionUtils

package top.yangbuyi.utils;

import com.arcsoft.face.*;
import com.arcsoft.face.enums.*;
import com.arcsoft.face.toolkit.ImageFactory;
import com.arcsoft.face.toolkit.ImageInfo;
import com.arcsoft.face.toolkit.ImageInfoEx;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * @program: ArcFace
 * @ClassName: FaceRecognitionUtils
 * @create: 2021-07-01 11:00
 * @author: Yang shuai
 * @FaceRecognitionUtils: 人脸识别简易版$实现人脸检测活体是否为人脸,追踪人脸
 **/
public class FaceRecognitionUtils {

    /**
     * APP ID,请先在虹软开发者中心注册、认证之后创建应用获取
     */
    @Value("crm.appId")
    private static String APP_ID = "";
    /**
     * SDK KEY,请先在虹软开发者中心注册、认证之后创建应用获取
     */
    @Value("crm.sdk")
    private static String SDK_KEY = "";
    /**
     * dll插件库地址
     * linx 和 win 是不一样的
     */
    @Value("crm.face")
    private static String FACE_ENGINE = "WIN64";

    private final static Logger logger = LogManager.getLogger(FaceRecognitionUtils.class.getName());

    // 人脸引擎
    private static FaceEngine faceEngine = new FaceEngine(FACE_ENGINE);

    // 创建引擎功能对象(用于初始化引擎)
    private static FunctionConfiguration functionConfiguration1 = new FunctionConfiguration();

    // 创建引擎功能对象(用于人脸检测)
    private static FunctionConfiguration functionConfiguration2 = new FunctionConfiguration();

    static {
        // 初始化引擎功能(用于初始化引擎)
        {
            // 是否支持年龄检测功能
            functionConfiguration1.setSupportAge(true);
            // 是否支持3D检测功能
            functionConfiguration1.setSupportFace3dAngle(true);
            // 是否支持人脸检测功能
            functionConfiguration1.setSupportFaceDetect(true);
            // 是否支持人脸识别功能
            functionConfiguration1.setSupportFaceRecognition(true);
            // 是否支持性别检测功能
            functionConfiguration1.setSupportGender(true);
            // 是否支持RGB活体检测功能
            functionConfiguration1.setSupportLiveness(true);
            // 是否支持IR活体检测功能
            functionConfiguration1.setSupportIRLiveness(true);
        }
        // 初始化引擎功能(用于人脸检测)
        {
            // 是否支持年龄检测功能
            functionConfiguration2.setSupportAge(true);
            // 是否支持3D检测功能
            functionConfiguration2.setSupportFace3dAngle(true);
            // 是否支持性别检测功能
            functionConfiguration2.setSupportGender(true);
            // 是否支持RGB活体检测功能
            functionConfiguration2.setSupportLiveness(true);
        }
    }

    /**
     * 在线激活SDK
     *
     * @return
     */
    public static void sdkActivation() {
        int errorCode = faceEngine.activeOnline(APP_ID, SDK_KEY);
        if (errorCode != ErrorInfo.MOK.getValue() && errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
            // SDK激活失败
            logger.error("在线激活SDK失败!错误码:" + errorCode);
        } else {
            // SDK激活成功
            logger.info("在线激活SDK成功!");
        }

    }

    /**
     * 初始化引擎
     *
     * @param detectMode   检测模式(推荐IMAGE 模式)
     * @param detectOrient 人脸检测角度(推荐人脸检测角度,逆时针0度)
     * @param faceMaxNum   人脸检测最大数量(推荐10)
     * @param faceScaleVal 最小人脸比例(VIDEO模式推荐16;IMAGE模式推荐32)
     */
    public static void InitializeTheEngine(DetectMode detectMode, DetectOrient detectOrient, int faceMaxNum, int faceScaleVal) {
        // 创建引擎配置类
        EngineConfiguration engineConfiguration = new EngineConfiguration();
        // 设置detectMode参数
        engineConfiguration.setDetectMode(detectMode);
        // 设置detectFaceOrientPriority参数
        engineConfiguration.setDetectFaceOrientPriority(detectOrient);
        // 设置人脸检测最大数量
        engineConfiguration.setDetectFaceMaxNum(faceMaxNum);
        // 设置detectFaceScaleVal参数为:识别的最小人脸比例 = 图片长边 / 人脸框长边的比值
        engineConfiguration.setDetectFaceScaleVal(faceScaleVal);
        // 配置引擎功能
        engineConfiguration.setFunctionConfiguration(functionConfiguration1);
        // 检测角度
//      engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);

        // 初始化引擎
        int errorCode = faceEngine.init(engineConfiguration);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 引擎初始化失败
            logger.error("引擎初始化失败!错误码:" + errorCode);
        } else {
            // 引擎初始化成功
            logger.info("引擎初始化成功!");
        }
    }

    /**
     * 人脸检测(传入分离的图像信息数据)
     *
     * @param imageInfo    图像信息
     * @param faceInfoList 人脸信息列表
     * @return 检测结果,检测成功或是失败!
     */
    public static boolean faceDetection1(ImageInfo imageInfo, List faceInfoList) {
        int errorCode = faceEngine.detectFaces(imageInfo.getImageData(),
                imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(),
                faceInfoList);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 人脸检测失败
            logger.error("人脸检测失败!错误码:" + errorCode);
            return false;
        } else {
            // 人脸检测成功
            logger.info("人脸检测成功!");
            return true;
        }
    }

    /**
     * 人脸检测(传入ImageInfoEx图像信息数据)
     *
     * @param imageInfo    图像信息
     * @param faceInfoList 人脸信息列表
     * @return 检测结果,检测成功或是失败!
     */
    public static boolean faceDetection2(ImageInfo imageInfo, List faceInfoList) {
        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});
        int errorCode = faceEngine.detectFaces(imageInfoEx,
                DetectModel.ASF_DETECT_MODEL_RGB, faceInfoList);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 人脸检测失败
            logger.error("人脸检测失败!错误码:" + errorCode);
            return false;
        } else {
            // 人脸检测成功
            logger.info("人脸检测成功!");
            return true;
        }
    }

    /**
     * 人脸特征提取,是否检测到人脸
     *
     * @param imageInfo
     * @return
     */
    public static byte[] extractFaceFeature(ImageInfo imageInfo) {
        try {
            //人脸检测得到人脸列表
            List faceInfoList = new ArrayList();
            //人脸检测
            int i = faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);

            if (faceInfoList.size() > 0) {
                FaceFeature faceFeature = new FaceFeature();
                //提取人脸特征
                faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList.get(0), faceFeature);
                return faceFeature.getFeatureData();
            }
        } catch (Exception e) {
            logger.error("", e);
        }

        return null;
    }

    /**
     * 人脸特征提取(传入分离的图像信息数据)
     *
     * @param imageInfo 图像信息
     * @param faceInfo  人脸信息
     * @return 人脸特征
     */
    public static FaceFeature faceFeatureExtraction1(ImageInfo imageInfo, FaceInfo faceInfo) {
        FaceFeature faceFeature = new FaceFeature();
        int errorCode = faceEngine.extractFaceFeature(imageInfo.getImageData(),
                imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(),
                faceInfo, faceFeature);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 人脸特征提取失败
            logger.error("人脸特征提取失败!错误码:" + errorCode);
            return null;
        } else {
            // 人脸特征提取成功
            logger.info("人脸特征提取成功!");
            return faceFeature;
        }
    }

    /**
     * 人脸特征提取(传入ImageInfoEx图像信息数据)
     *
     * @param imageInfo 图像信息
     * @param faceInfo  人脸信息
     * @return 人脸特征
     */
    public static FaceFeature faceFeatureExtraction2(ImageInfo imageInfo, FaceInfo faceInfo) {
        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});

        // 创建人脸特征对象
        FaceFeature faceFeature = new FaceFeature();
        int errorCode = faceEngine.extractFaceFeature(imageInfoEx, faceInfo, faceFeature);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 人脸特征提取失败
            logger.error("人脸特征提取失败!错误码:" + errorCode);
            return null;
        } else {
            // 人脸特征提取成功
            logger.info("人脸特征提取成功!");
            return faceFeature;
        }
    }

    /**
     * 人脸特征比对
     *
     * @param targetFaceFeature 目标人脸特征
     * @param sourceFaceFeature 来源人脸特征
     * @param compareModel      比对模型
     * @return 比对相似度
     */
    public static Float faceFeatureComparison(FaceFeature targetFaceFeature, FaceFeature sourceFaceFeature, CompareModel compareModel) {
        // 创建比对相似度对象
        FaceSimilar faceSimilar = new FaceSimilar();
        int errorCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, compareModel, faceSimilar);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 人脸特征比对失败
            logger.error("人脸特征比对失败!错误码:" + errorCode);
            return null;
        } else {
            // 人脸特征比对成功
            logger.info("人脸特征比对成功!");
            return faceSimilar.getScore();
        }
    }

    /**
     * 人脸特征比对(默认LIFE_PHOTO比对模型)
     *
     * @param targetFaceFeature 目标人脸特征
     * @param sourceFaceFeature 来源人脸特征
     * @return 比对相似度
     */
    public static Float faceFeatureComparison(FaceFeature targetFaceFeature, FaceFeature sourceFaceFeature) {
        // 创建比对相似度对象
        FaceSimilar faceSimilar = new FaceSimilar();
        int errorCode = faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature,
                faceSimilar);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 人脸特征比对失败
            logger.error("人脸特征比对失败!错误码:" + errorCode);
            return null;
        } else {
            // 人脸特征比对成功
            logger.info("人脸特征比对成功!");
            return faceSimilar.getScore();
        }
    }

    /**
     * 人脸属性检测(传入分离的图像信息数据)
     *
     * @param imageInfo    图像信息
     * @param faceInfoList 人脸信息列表
     * @return 检测结果,检测成功或是失败!
     */
    public static boolean faceAttributeDetection1(ImageInfo imageInfo, List faceInfoList) {
        int errorCode = faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(),
                imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList, functionConfiguration2);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 人脸属性检测失败
            logger.error("人脸属性检测失败!错误码:" + errorCode);
            return false;
        } else {
            // 人脸属性检测成功
            logger.info("人脸属性检测成功!");
            return true;
        }
    }

    /**
     * 人脸属性检测(传入ImageInfoEx图像信息数据)
     *
     * @param imageInfo    图像信息
     * @param faceInfoList 人脸信息列表
     * @return 检测结果,检测成功或是失败!
     */
    public static boolean faceAttributeDetection2(ImageInfo imageInfo, List faceInfoList) {
        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});
        int errorCode = faceEngine.process(imageInfoEx, faceInfoList,
                functionConfiguration2);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 人脸属性检测失败
            logger.error("人脸属性检测失败!错误码:" + errorCode);
            return false;
        } else {
            // 人脸属性检测成功
            logger.info("人脸属性检测成功!");
            return true;
        }
    }

    /**
     * 获取年龄信息
     * 注意:人脸属性检测之后方可调用
     *
     * @return 获取结果,获取失败或是成功!
     */
    public static boolean getAgeInfo(List ageInfoList) {
        int errorCode = faceEngine.getAge(ageInfoList);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 获取年龄信息失败
            logger.error("获取年龄信息失败!错误码:" + errorCode);
            return false;
        } else {
            // 已成功获取年龄信息
            logger.info("已成功获取年龄信息!");
            return true;
        }
    }

    /**
     * 获取性别(0为男性,1为女性。)
     * 注意:人脸属性检测之后方可调用
     *
     * @return 获取结果,获取失败或是成功!
     */
    public static boolean getGender(List genderInfoList) {
        // 性别检测
        int errorCode = faceEngine.getGender(genderInfoList);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 获取性别失败
            logger.error("获取性别失败!错误码:" + errorCode);
            return false;
        } else {
            // 已成功获取年龄信息
            logger.info("已成功获取性别!");
            return true;
        }
    }

    /**
     * 获取人脸三维角度信息
     * 人脸3D角度:俯仰角(pitch), 横滚角(roll), 偏航角(yaw)。
     * 注意:人脸属性检测之后方可调用
     *
     * @return 获取结果,获取失败或是成功!
     */
    public static boolean getFace3DAngle(List face3DAngleList) {
        // 人脸三维角度检测
        int errorCode = faceEngine.getFace3DAngle(face3DAngleList);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 获取人脸三维角度信息失败
            logger.error("获取人脸三维角度信息失败!错误码:" + errorCode);
            return false;
        } else {
            // 已成功获取人脸三维角度信息
            logger.info("已成功获取人脸三维角度信息!");
            return true;
        }
    }

    /**
     * 获取RGB活体信息
     * RGB活体值,未知=-1 、非活体=0 、活体=1、超出人脸=-2
     * 注意:人脸属性检测之后方可调用
     *
     * @return 获取结果,获取失败或是成功!
     */
    public static boolean getLiveness(List livenessInfoList) {
        // RGB活体检测
        int errorCode = faceEngine.getLiveness(livenessInfoList);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 获取RGB活体信息失败
            logger.error("获取RGB活体信息失败!错误码:" + errorCode);
            return false;
        } else {
            // 已成功获取RGB活体信息
            logger.info("已成功获取RGB活体信息!");
            return true;
        }
    }

    private static String base64Process(String base64Str) {
        if (!StringUtils.isEmpty(base64Str)) {
            String photoBase64 = base64Str.substring(0, 30).toLowerCase();
            int indexOf = photoBase64.indexOf("base64,");
            if (indexOf > 0) {
                base64Str = base64Str.substring(indexOf + 7);
            }

            return base64Str;
        } else {
            return "";
        }
    }

    /**
     * IR活体检测(传入分离的图像信息数据)
     * 注意:
     * 引擎需要支持IR活体检测功能
     *
     * @return 检测结果,检测成功或是失败!
     */
    public static boolean detectionLiveness_IR1(String string) throws IOException {
        // 创建图像信息
//      ImageInfo imageInfoGray = getGrayData(file);
        byte[] decode = Base64.decode(base64Process(string));
        BufferedImage bufImage = ImageIO.read(new ByteArrayInputStream(decode));
        ImageInfo imageInfoGray = ImageFactory.bufferedImage2ImageInfo(bufImage);

        // 创建人脸信息列表
        List faceInfoListGray = new ArrayList();
        // 人脸检测(传入分离的图像信息数据)
        int errorCode1 = faceEngine.detectFaces(imageInfoGray.getImageData(),
                imageInfoGray.getWidth(), imageInfoGray.getHeight(),
                imageInfoGray.getImageFormat(), faceInfoListGray);
        // 创建引擎功能实例对象
        FunctionConfiguration configuration = new FunctionConfiguration();
        // 设置引擎支持IR活体检测
        configuration.setSupportIRLiveness(true);
        // IR活体检测
        int errorCode2 = faceEngine.processIr(imageInfoGray.getImageData(),
                imageInfoGray.getWidth(), imageInfoGray.getHeight(),
                imageInfoGray.getImageFormat(), faceInfoListGray, configuration);
        if (errorCode1 != ErrorInfo.MOK.getValue() || errorCode2 != ErrorInfo.MOK.getValue()) {
            String errorCode = errorCode1 == 0 ? errorCode2 + "" : errorCode1 + "";
            // IR活体检测失败
            logger.error("IR活体检测失败!错误码:" + errorCode);
            return false;
        } else {
            // IR活体检测成功
            logger.info("IR活体检测成功!");
            return true;
        }
    }

    /**
     * IR活体检测(传入ImageInfoEx图像信息数据)
     * 注意:
     * 引擎需要支持年龄检测功能
     *
     * @param imageInfo 图像信息
     * @return 检测结果,检测成功或是失败!
     */
    public static boolean detectionLiveness_IR2(ImageInfo imageInfo) {
        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 faceInfoList1 = new ArrayList<>();
        int errorCode1 = faceEngine.detectFaces(imageInfoEx,
                DetectModel.ASF_DETECT_MODEL_RGB, faceInfoList1);
        FunctionConfiguration fun = new FunctionConfiguration();
        fun.setSupportAge(true);
        int errorCode2 = faceEngine.processIr(imageInfoEx, faceInfoList1,
                fun);
        if (errorCode1 != ErrorInfo.MOK.getValue() || errorCode2 != ErrorInfo.MOK.getValue()) {
            String errorCode = errorCode1 == 0 ? errorCode2 + "" : errorCode1 + "";
            // IR活体检测失败
            logger.error("IR活体检测失败!错误码:" + errorCode);
            return false;
        } else {
            // IR活体检测成功
            logger.info("IR活体检测成功!");
            return true;
        }
    }

    /**
     * 获取IR活体信息
     * IR活体值,未知=-1 、非活体=0 、活体=1、超出人脸=-2
     *
     * @return 获取结果,获取失败或是成功!
     */
    public static boolean getIrLiveness(List irLivenessInfo) {
        // IR活体检测
        int errorCode = faceEngine.getLivenessIr(irLivenessInfo);
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 获取IR活体信息失败
            logger.error("获取IR活体信息失败!错误码:" + errorCode);
            return false;
        } else {
            // 已成功获取IR活体信息
            logger.info("已成功获取IR活体信息!");
            return true;
        }
    }

    /**
     * 销毁SDK引擎
     */
    public static void destroyTheSDKEngine() {
        int errorCode = faceEngine.unInit();
        if (errorCode != ErrorInfo.MOK.getValue()) {
            // 销毁SDK引擎失败
            logger.error("销毁SDK引擎失败!错误码:" + errorCode);
        } else {
            // 销毁SDK引擎成功
            logger.info("销毁SDK引擎成功!");
        }
    }

}

2.创建ErrorCodeEnum

package top.yangbuyi.constant;

/**
 * 错误代码枚举
 *
 * @author yang buyi
 * @date 2021/07/02
 */
public enum ErrorCodeEnum {

    MOK(0, "成功"),
    UNKNOWN(1, "未知错误"),
    INVALID_PARAM(2, "无效参数"),
    UNSUPPORTED(3, "引擎不支持"),
    NO_MEMORY(4, "内存不足"),
    BAD_STATE(5, "状态错误"),
    USER_CANCEL(6, "用户取消相关操作"),
    EXPIRED(7, "操作时间过期"),
    USER_PAUSE(8, "用户暂停操作"),
    BUFFER_OVERFLOW(9, "缓冲上溢"),
    BUFFER_UNDERFLOW(10, "缓冲下溢"),
    NO_DISKSPACE(11, "存贮空间不足"),
    COMPONENT_NOT_EXIST(12, "组件不存在"),
    GLOBAL_DATA_NOT_EXIST(13, "全局数据不存在"),
    NO_FACE_DETECTED(14, "未检出到人脸"),
    FACE_DOES_NOT_MATCH(15, "人脸不匹配"),
    INVALID_APP_ID(28673, "无效的AppId"),
    INVALID_SDK_ID(28674, "无效的SdkKey"),
    INVALID_ID_PAIR(28675, "AppId和SdkKey不匹配"),
    MISMATCH_ID_AND_SDK(28676, "SdkKey 和使用的SDK 不匹配"),
    SYSTEM_VERSION_UNSUPPORTED(28677, "系统版本不被当前SDK所支持"),
    LICENCE_EXPIRED(28678, "SDK有效期过期,需要重新下载更新"),
    APS_ENGINE_HANDLE(69633, "引擎句柄非法"),
    APS_MEMMGR_HANDLE(69634, "内存句柄非法"),
    APS_DEVICEID_INVALID(69635, " Device ID 非法"),
    APS_DEVICEID_UNSUPPORTED(69636, "Device ID 不支持"),
    APS_MODEL_HANDLE(69637, "模板数据指针非法"),
    APS_MODEL_SIZE(69638, "模板数据长度非法"),
    APS_IMAGE_HANDLE(69639, "图像结构体指针非法"),
    APS_IMAGE_FORMAT_UNSUPPORTED(69640, "图像格式不支持"),
    APS_IMAGE_PARAM(69641, "图像参数非法"),
    APS_IMAGE_SIZE(69642, "图像尺寸大小超过支持范围"),
    APS_DEVICE_AVX2_UNSUPPORTED(69643, "处理器不支持AVX2指令"),
    FR_INVALID_MEMORY_INFO(73729, "无效的输入内存"),
    FR_INVALID_IMAGE_INFO(73730, "无效的输入图像参数"),
    FR_INVALID_FACE_INFO(73731, "无效的脸部信息"),
    FR_NO_GPU_AVAILABLE(73732, "当前设备无GPU可用"),
    FR_MISMATCHED_FEATURE_LEVEL(73733, "待比较的两个人脸特征的版本不一致"),
    FACEFEATURE_UNKNOWN(81921, "人脸特征检测错误未知"),
    FACEFEATURE_MEMORY(81922, "人脸特征检测内存错误"),
    FACEFEATURE_INVALID_FORMAT(81923, "人脸特征检测格式错误"),
    FACEFEATURE_INVALID_PARAM(81924, "人脸特征检测参数错误"),
    FACEFEATURE_LOW_CONFIDENCE_LEVEL(81925, "人脸特征检测结果置信度低"),
    ASF_EX_BASE_FEATURE_UNSUPPORTED_ON_INIT(86017, "Engine不支持的检测属性"),
    ASF_EX_BASE_FEATURE_UNINITED(86018, "需要检测的属性未初始化"),
    ASF_EX_BASE_FEATURE_UNPROCESSED(86019, "待获取的属性未在process中处理过"),
    ASF_EX_BASE_FEATURE_UNSUPPORTED_ON_PROCESS(86020, "PROCESS不支持的检测属性,例如FR,有自己独立的处理函数"),
    ASF_EX_BASE_INVALID_IMAGE_INFO(86021, "无效的输入图像"),
    ASF_EX_BASE_INVALID_FACE_INFO(86022, "无效的脸部信息"),
    ASF_BASE_ACTIVATION_FAIL(90113, "人脸比对SDK激活失败,请打开读写权限"),
    ASF_BASE_ALREADY_ACTIVATED(90114, "人脸比对SDK已激活"),
    ASF_BASE_NOT_ACTIVATED(90115, "人脸比对SDK未激活"),
    ASF_BASE_SCALE_NOT_SUPPORT(90116, "detectFaceScaleVal 不支持"),
    ASF_BASE_VERION_MISMATCH(90117, "SDK版本不匹配"),
    ASF_BASE_DEVICE_MISMATCH(90118, "设备不匹配"),
    ASF_BASE_UNIQUE_IDENTIFIER_MISMATCH(90119, "唯一标识不匹配"),
    ASF_BASE_PARAM_NULL(90120, "参数为空"),
    ASF_BASE_SDK_EXPIRED(90121, "SDK已过期"),
    ASF_BASE_VERSION_NOT_SUPPORT(90122, "版本不支持"),
    ASF_BASE_SIGN_ERROR(90123, "签名错误"),
    ASF_BASE_DATABASE_ERROR(90124, "数据库插入错误"),
    ASF_BASE_UNIQUE_CHECKOUT_FAIL(90125, "唯一标识符校验失败"),
    ASF_BASE_COLOR_SPACE_NOT_SUPPORT(90126, "输入的颜色空间不支持"),
    ASF_BASE_IMAGE_WIDTH_NOT_SUPPORT(90127, "输入图像的byte数据长度不正确"),
    ASF_NETWORK_BASE_COULDNT_RESOLVE_HOST(94209, "无法解析主机地址"),
    ASF_NETWORK_BASE_COULDNT_CONNECT_SERVER(94210, "无法连接服务器"),
    ASF_NETWORK_BASE_CONNECT_TIMEOUT(94211, "网络连接超时"),
    ASF_NETWORK_BASE_UNKNOWN_ERROR(94212, "未知错误");

    private Integer code;
    private String description;

    ErrorCodeEnum(Integer code, String description) {
        this.code = code;
        this.description = description;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public static ErrorCodeEnum getDescriptionByCode(Integer code) {
        for (ErrorCodeEnum errorCodeEnum : ErrorCodeEnum.values()) {
            if (code.equals(errorCodeEnum.getCode())) {
                return errorCodeEnum;
            }
        }
        return ErrorCodeEnum.UNKNOWN;
    }

}

3.创建ArcFaceController

package top.yangbuyi.controller;

import com.arcsoft.face.*;
import com.arcsoft.face.enums.DetectMode;
import com.arcsoft.face.enums.DetectOrient;
import com.arcsoft.face.toolkit.ImageFactory;
import com.arcsoft.face.toolkit.ImageInfo;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import top.yangbuyi.constant.ErrorCodeEnum;
import top.yangbuyi.utils.FaceRecognitionUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: ArcFace
 * @ClassName: ArcFaceController
 * @create: 2021-07-01 14:30
 * @author: Yang Shuai
 * @since&#xFF1A; JDK1.8
 * @ArcFaceController: &#x4EBA;&#x8138;&#x6D3B;&#x4F53;&#x68C0;&#x6D4B;$
 **/

@RestController
@Slf4j
@RequestMapping("arcFace")
public class ArcFaceController {

    /**
     * &#x4EBA;&#x8138;&#x8BC6;&#x522B;&#x68C0;&#x6D4B;
     *
     * @param url base64 &#x5730;&#x5740;
     * @param oId &#x7EC4;&#x7EC7;&#x67B6;&#x6784; ID
     * @param uid &#x5F53;&#x524D;&#x767B;&#x5F55;&#x68C0;&#x6D4B;&#x7684;&#x7528;&#x6237;ID
     * @return
     */
    @RequestMapping(value = "arcFaceSearch", method = RequestMethod.POST)
    public Map arcFaceSearch(@RequestParam String url, @RequestParam Integer oId, @RequestParam Integer uid) {
        // &#x524D;&#x7AEF;&#x5C55;&#x793A;&#x539F;&#x56FE;
        String urlTemp = url;

        // ...&#x4E1A;&#x52A1;
        final HashMap<string, object> stringObjectHashMap = new HashMap<>(14);
        stringObjectHashMap.put("success", false);

        // &#x521D;&#x59CB;&#x5316;&#x5F15;&#x64CE;
        FaceRecognitionUtils.InitializeTheEngine(DetectMode.ASF_DETECT_MODE_IMAGE, DetectOrient.ASF_OP_0_ONLY, 10, 32);

        if (!StringUtils.isEmpty(url)) {
            String photoBase64 = url.substring(0, 30).toLowerCase();
            int indexOf = photoBase64.indexOf("base64,");
            if (indexOf > 0) {
                url = url.substring(indexOf + 7);
            }
            // &#x5F00;&#x59CB;&#x8F6C;&#x7801;
            byte[] decode = Base64.decode(url);
            BufferedImage bufImage = null;
            try {
                bufImage = ImageIO.read(new ByteArrayInputStream(decode));
            } catch (IOException e) {
                e.printStackTrace();
                return stringObjectHashMap;
            }

            // &#x83B7;&#x53D6;&#x56FE;&#x7247;&#x4FE1;&#x606F;
            ImageInfo imageInfo = ImageFactory.bufferedImage2ImageInfo(bufImage);

            //&#x4EBA;&#x8138;&#x7279;&#x5F81;&#x83B7;&#x53D6;
            byte[] bytes = FaceRecognitionUtils.extractFaceFeature(imageInfo);
            // &#x6821;&#x9A8C;&#x662F;&#x5426;&#x663E;&#x793A;&#x51FA;&#x4EBA;&#x8138;
            if (bytes == null) {
                System.out.println(ErrorCodeEnum.NO_FACE_DETECTED.getDescription());
                stringObjectHashMap.put("msg", ErrorCodeEnum.NO_FACE_DETECTED.getDescription());
                return stringObjectHashMap;
            }

            // &#x521B;&#x5EFA;&#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x4EBA;&#x8138;&#x4FE1;&#x606F;&#x5BF9;&#x8C61;&#x5217;&#x8868;
            List<faceinfo> faceInfoList1 = new ArrayList<>();

            // &#x68C0;&#x6D4B;&#x56FE;&#x50CF;&#x4E2D;&#x4EBA;&#x8138;
            FaceRecognitionUtils.faceDetection1(imageInfo, faceInfoList1);

            // &#x68C0;&#x6D4B;&#x56FE;&#x50CF;&#x4E2D;&#x4EBA;&#x8138;&#x5C5E;&#x6027;
            FaceRecognitionUtils.faceAttributeDetection1(imageInfo, faceInfoList1);

            // &#x68C0;&#x6D4B;&#x4EBA;&#x8138;&#x7279;&#x5F81;

            /* &#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x4EBA;&#x8138;&#x5E74;&#x9F84; */
            {
                // &#x521B;&#x5EFA;&#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x4EBA;&#x8138;&#x5E74;&#x9F84;&#x5217;&#x8868;
                List<ageinfo> ageInfoList1 = new ArrayList<>();
                // &#x68C0;&#x6D4B;&#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x4EBA;&#x8138;&#x5E74;&#x9F84;&#x5217;&#x8868;
                FaceRecognitionUtils.getAgeInfo(ageInfoList1);
                // &#x5C06;&#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x5E74;&#x9F84;&#x5217;&#x8868;&#x6253;&#x5370;&#x5230;&#x63A7;&#x5236;&#x53F0;
                if (ageInfoList1.size() > 0) {
                    stringObjectHashMap.put("age", ageInfoList1.get(0).getAge());
                }
            }

            /* &#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x4EBA;&#x8138;&#x6027;&#x522B; */
            // &#x521B;&#x5EFA;&#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x4EBA;&#x8138;&#x6027;&#x522B;&#x5217;&#x8868;
            List<genderinfo> genderInfoList1 = new ArrayList<>();
            // &#x68C0;&#x6D4B;&#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x4EBA;&#x8138;&#x6027;&#x522B;&#x5217;&#x8868;
            FaceRecognitionUtils.getGender(genderInfoList1);
            // &#x5C06;&#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x6027;&#x522B;&#x5217;&#x8868;&#x6253;&#x5370;&#x5230;&#x63A7;&#x5236;&#x53F0;
            if (genderInfoList1.size() > 0) {
                stringObjectHashMap.put("gender", genderInfoList1.get(0).getGender() == 0 ? "&#x7537;" : "&#x5973;");
            }

            /* &#x56FE;&#x50CF;1&#x4E2D;&#x7684;&#x4EBA;&#x8138;&#x4E09;&#x7EF4;&#x89D2;&#x5EA6; */
            // &#x521B;&#x5EFA;&#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x4EBA;&#x8138;&#x4E09;&#x7EF4;&#x89D2;&#x5EA6;&#x4FE1;&#x606F;&#x5217;&#x8868;
            List<face3dangle> face3DAngleList1 = new ArrayList<>();
            // &#x83B7;&#x53D6;&#x56FE;&#x50CF;1&#x4E2D;&#x7684;&#x4EBA;&#x8138;&#x4E09;&#x7EF4;&#x89D2;&#x5EA6;&#x4FE1;&#x606F;&#x5217;&#x8868;
            FaceRecognitionUtils.getFace3DAngle(face3DAngleList1);
            // &#x5C06;&#x56FE;&#x50CF;&#x4E2D;&#x7684;&#x4EBA;&#x8138;&#x4E09;&#x7EF4;&#x89D2;&#x5EA6;&#x4FE1;&#x606F;&#x5217;&#x8868;&#x6253;&#x5370;&#x5230;&#x63A7;&#x5236;&#x53F0;
            if (face3DAngleList1.size() > 0) {
                List<map<string, object>> td = new ArrayList<>();
                Map<string, object> map = new HashMap<>();
                map.put("&#x4FEF;&#x4EF0;&#x89D2;", face3DAngleList1.get(0).getPitch());
                map.put("&#x6A2A;&#x6EDA;&#x89D2;", face3DAngleList1.get(0).getRoll());
                map.put("&#x504F;&#x822A;&#x89D2;", face3DAngleList1.get(0).getYaw());
                td.add(map);
                stringObjectHashMap.put("ThreeDimensional", td);
            }

            /* &#x56FE;&#x50CF;1&#x4E2D;&#x7684;&#x4EBA;&#x8138;RGB&#x6D3B;&#x4F53;&#x503C; */
            // &#x521B;&#x5EFA;&#x56FE;&#x50CF;&#x4E2D;&#x7684;RGB&#x6D3B;&#x4F53;&#x4FE1;&#x606F;&#x5217;&#x8868;
            List<livenessinfo> livenessInfoList1 = new ArrayList<>();
            // &#x83B7;&#x53D6;&#x56FE;&#x50CF;1&#x4E2D;&#x7684;RGB&#x6D3B;&#x4F53;&#x4FE1;&#x606F;&#x5217;&#x8868;
            FaceRecognitionUtils.getLiveness(livenessInfoList1);
            // &#x5C06;&#x56FE;&#x50CF;&#x4E2D;&#x7684;RGB&#x6D3B;&#x4F53;&#x4FE1;&#x606F;&#x5217;&#x8868;&#x6253;&#x5370;&#x5230;&#x63A7;&#x5236;&#x53F0;
            if (livenessInfoList1.size() > 0) {
                stringObjectHashMap.put("RgbLiveness", livenessInfoList1.get(0).getLiveness());
            }

            /**
             * &#x6CE8;&#x610F;&#xFF1A; &#x6D3B;&#x4F53;&#x53EA;&#x80FD;&#x652F;&#x6301;&#x4E00;&#x4E2A;&#x4EBA;&#x8138;&#x5426;&#x5219;&#x8FD4;&#x56DE;&#x672A;&#x77E5;
             * &#x6240;&#x4EE5;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x8FDB;&#x884C;&#x4F7F;&#x7528;&#x4ED6;&#x6765;&#x5224;&#x65AD;&#x662F;&#x5426;&#x6709;&#x591A;&#x4E2A;&#x4EBA;&#x68C0;&#x6D4B; &#x76F4;&#x63A5;&#x5224;&#x5B9A;&#x5931;&#x8D25;
             */
            if (livenessInfoList1.size() > 0 && livenessInfoList1.get(0).getLiveness() == 1) {
                stringObjectHashMap.put("success", true);
                stringObjectHashMap.put("baseUrl", urlTemp);
            }
        } else {
            stringObjectHashMap.put("data", "url,&#x4E0D;&#x5141;&#x8BB8;&#x4E3A;&#x7A7A;");
        }
        return stringObjectHashMap;
    }

}

</livenessinfo></string,></map<string,></face3dangle></genderinfo></ageinfo></faceinfo></string,>

4. 创建路由跳转前端页面 RouteController

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

/**
 * @program: ArcFace
 * @ClassName: RouteController
 * @create: 2021-07-02 09:14
 * @author: Yang Shuai
 * @since: JDK1.8
 * @RouteController: $
 **/

@Controller
public class RouteController {

    @GetMapping("/")
    public String yby() {
        // ...业务
        return "index";
    }

}

三. 前端人脸追踪插件

访问地址: https://trackingjs.com/

里面有demo可观看我就不带大家查看了

从零玩转人脸识别之RGB人脸活体检测

1. 创建前端index.html

js请下载demo获取,连接在最下面

    人脸检测

        #regcoDiv {
            width: 100%;
            height: 530px;
            position: relative;
            background: #eee;
            overflow: hidden;
            border-bottom-right-radius: 10px;
            border-bottom-left-radius: 10px;

            /*-webkit-animation: twinkling 1s infinite ease-in-out;*/
            /*-webkit-animation-duration: 1s;*/
            /*animation-duration: 1s;*/
            /*-webkit-animation-fill-mode: both;*/
            /*animation-fill-mode: both*/
        }

        video, canvas {
            margin-left: 230px;
            /*margin-top: 120px;*/
            position: absolute;
        }

        .className {
            -webkit-animation: twinkling 1s infinite ease-in-out
        }

        .animated {
            -webkit-animation-duration: 1s;
            animation-duration: 1s;
            -webkit-animation-fill-mode: both;
            animation-fill-mode: both
        }

        @-webkit-keyframes twinkling {
            0% {
                background: #eee;
            }

            35% {
                background: #08e800;
            }

            56% {
                background: #1f25d4;
            }

            100% {
                background: #eee;
            }
        }

        @keyframes twinkling {
            0% {
                background: #eee;
            }

            35% {
                background: #08e800;
            }

            56% {
                background: #1f25d4;
            }

            100% {
                background: #eee;
            }
        }

                    摄像头识别

                    提交

    getMedia2()

    $("#imageDivComp").click(function () {
        $("#chooseFileComp").click();
    });
    var t1;

    /**
     * 开始画摄像头
     */
    function getMedia2() {
        $("#regcoDiv").empty();
        let vedioComp = "<video id='video2' width='500px' height='500px'  autoplay='autoplay' playsinline webkit-playsinline='true' ></video><canvas id='canvas2' width='500px' height='500px'></canvas>";
        $("#regcoDiv").append(vedioComp);
        let constraints = {
            video: {width: 500, height: 500},
            audio: true
        };
        //获得video摄像头区域
        let video = document.getElementById("video2");
        // 这里介绍新的方法,返回一个 Promise对象
        // 这个Promise对象返回成功后的回调函数带一个 MediaStream 对象作为其参数
        // then()是Promise对象里的方法
        // then()方法是异步执行,当then()前的方法执行完后再执行then()内部的程序
        // 避免数据没有获取到
        let promise = navigator.mediaDevices.getUserMedia(constraints);
        promise.then(function (MediaStream) {
            video.srcObject = MediaStream;
            video.play();
        });

        /**
         * 模拟手机端 三秒主动提交检测
         * @type {number}
         */
        t1 = window.setInterval(function () {
            chooseFileChangeComp()
        }, 3000)

    }

    /**
     * 提交检测 请求接口
     */
    function chooseFileChangeComp() {
        let regcoDivComp = $("#regcoDiv");
        if (regcoDivComp.has('video').length) {
            let video = document.getElementById("video2");
            let canvas = document.getElementById("canvas2");
            let ctx = canvas.getContext('2d');
            ctx.drawImage(video, 0, 0, 500, 500);
            var base64File = canvas.toDataURL();
            var formData = new FormData();
            formData.append("url", base64File);
            formData.append("oId", 1);
            formData.append("uid", 1);
            $.ajax({
                type: "post",
                url: "/arcFace/arcFaceSearch",
                data: formData,
                contentType: false,
                processData: false,
                async: false,
                success: function (text) {
                    var res = JSON.stringify(text)
                    if (text.success == true && text.RgbLiveness == 1) {
                        console.log(text);
                        clearInterval(t1);
                        console.log(text.baseUrl);
                    } else {
                        console.log(text);
                    }

                },
                error: function (error) {

                    alert(JSON.stringify(error))
                }
            });
        }
    }

    /**
     * 人脸追踪画框
     **/
    window.onload = function () {
        let video = document.getElementById("video2");
        let canvas = document.getElementById("canvas2");
        let context = canvas.getContext('2d');

        var tracker = new tracking.LandmarksTracker();
        tracker.setInitialScale(4);
        tracker.setStepSize(2);
        tracker.setEdgesDensity(0.1);

        tracking.track(video, tracker);

        tracker.on('track', function (event) {

            context.clearRect(0, 0, canvas.width, canvas.height);

            if (!event.data) return;
            // 画框样式
            event.data.faces.forEach(function (rect) {
                context.strokeStyle = '#eb4c4c';
                context.strokeRect(rect.x, rect.y, rect.width, rect.height);
                context.font = '16px Helvetica';
                context.fillStyle = "#000";
                context.lineWidth = '5';
                context.fillText('人脸横向: ' + rect.x + 'px', rect.x + rect.width + 5, rect.y + 11);
                context.fillText('人脸纵向: ' + rect.y + 'px', rect.x + rect.width + 5, rect.y + 50);
            });

            /**
             * 人脸追踪 颗粒
             */
            event.data.landmarks.forEach(function (landmarks) {
                for (var l in landmarks) {
                    context.beginPath();
                    context.fillStyle = "#fff";
                    context.arc(landmarks[l][0], landmarks[l][1], 1, 0, 2 * Math.PI);
                    context.fill();
                }
            });

        });
        // 这里如果报错  不用管
        var gui = new dat.GUI();
        gui.add(tracker, 'edgesDensity', 0.1, 0.5).step(0.01).listen();
        gui.add(tracker, 'initialScale', 1.0, 10.0).step(0.1).listen();
        gui.add(tracker, 'stepSize', 1, 5).step(0.1).listen();
    };

四. 人脸识别追踪就到这里啦,具体的代码已经提交到gitee请前往获取Java项目 ArcFace

点击前往获取demo

Original: https://www.cnblogs.com/Yangbuyi/p/14998010.html
Author: yangbuyi(.top)
Title: 从零玩转人脸识别之RGB人脸活体检测

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/592900/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • MongoDB 分片规则

    生命本身毫无意义,只有死亡才能让你邃晓人性的真谛! Ideal is the beacon. Without ideal, there is no secure direction…

    Java 2023年6月9日
    096
  • Java入门

    一、Java 1.1 为什么Java是平台无关性(可以跨平台) 二、Java环境 2.1、JRE 2.2、JDK 2.3、JVM 三、Java编译和运行的机制 四、Java基础 4…

    Java 2023年6月7日
    0119
  • Macbook中VMWare的Centos7虚拟机配置静态IP并允许上网的配置方法

    一、检查Macbook本身的配置 1、打开【系统偏好设置】-【网络】- 选中【Wi-Fi】项(如果您是WIFI上网请选择此项)- 点右侧【高级】 选择【TCP/IP】选项卡,记录好…

    Java 2023年5月30日
    0100
  • WIN DLL劫持提权

    WIN DLL劫持提权 原理: Windows程序启动的时候需要DLL。如果这些DLL 不存在,则可以通过在应用程序要查找的位置放置恶意DLL来提权。通常,Windows应用程序有…

    Java 2023年6月6日
    0102
  • 1、什么是注解

    Annotation JDK5.0 始引入的新技术 0 An n otationxe 0 An n otation 的作用 1、不是程序本身, 可以对程序作出解释. ( 这一点和注…

    Java 2023年6月8日
    077
  • 单线程的Redis有哪些慢动作?

    前言 为什么 Redis 这么火? 键和值的保存形式? 为什么哈希表操作变慢了? 集合的操作效率? 有哪些数据结构? 不同操作的复杂度? 总结 现在一提到 Redis的第一反应就是…

    Java 2023年6月14日
    092
  • Java Happens-Before原则

    Happens-Before原则核心就是表达 在一些条件下,前面的操作对于后面的操作是可见的。它有六个条件,或者说是六条原则。 一、线程中的顺序性原则 这个最容易理解,这个原则是指…

    Java 2023年5月29日
    088
  • springboot支持http2

    现在http/3都出来了,但是很多项目还是没有采用https,这个是说不过去的。 http3在2022/06/06 正式发布,具体见https://www.163.com/dy/a…

    Java 2023年6月9日
    091
  • 【深入Java虚拟机】二 类加载与双亲委派

    https://blog.csdn.net/zhangliangzi/article/details/51338291 -参考 双亲委派过程:当一个类加载器收到类加载任务时,立即将…

    Java 2023年5月29日
    0104
  • SpringBoot2.x集成springSecurity和OAuth2.0启动错误处理

    当启用@EnableAuthorizationServer注解时,启动项目报错 报错信息 因为SpringBoot2.x已经将 security.oauth2的自动配置类sprin…

    Java 2023年5月30日
    078
  • R2DBC正式孵化成功,利好Spring Webflux

    2022年4月25日, R2DBC社区宣布具有普遍可用性的 1.0.0.RELEASE正式发布。 R2DBC致力于为反应式编程 API操作关系型数据库带来规范支持, R2DBC不同…

    Java 2023年6月8日
    096
  • 共读《redis设计与实现》-数据结构篇

    准备将之前攒下的书先看一遍,主要是有个大概的了解,以后用的时候也知道在哪里找。所以准备开几篇共读的帖子,激励自己多看一些书。 Redis 基于 &#x7B80;&#…

    Java 2023年6月7日
    089
  • mapstruct使用详解

    我们都知道,随着一个工程的越来越成熟,模块划分会越来越细,其中实体类一般存于 domain 之中,但 domain 工程最好不要被其他工程依赖,所以其他工程想获取实体类数据时就需要…

    Java 2023年6月5日
    089
  • docker 安装mysql5.7

    docker 安装mysql5.7 前言 MySQL 是目前最流行的关系型数据库管理系统,开发者是瑞典MySQL AB公司。目前MySQL被广泛地应用在Internet上的中小型网…

    Java 2023年6月15日
    081
  • java log4j 打日志到控制台同时打印到不同文件

    1.pom配置 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation…

    Java 2023年5月29日
    061
  • 云服务发布springboot项目踩过的坑

    参考文档: !!千万要卸载openJDK!!! 云服务器部署springboot项目,其他博主参考文档:https://blog.csdn.net/m0_54853420/arti…

    Java 2023年6月6日
    065
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球