🧐 什么是活体检测?

活体检测(Liveness Detection)是判断摄像头前的人脸是否为“真实活人”的技术,广泛用于防止照片、视频攻击。常见场景包括:

  • 登录认证
  • 支付安全
  • 门禁系统

SmartJavaAI 为我们封装了活体检测能力,调用简单,无需搞懂底层模型。

---

🚀 快速开始

我们使用SmartJavaAI 封装的 Seetaface6模型来实现活体检测
官网地址:

SmartJavaAI是什么?

SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的 JAVA AI算法工具包,致力于帮助JAVA开发者零门槛使用各种AI算法模型,开发者无需深入了解底层实现,即可轻松在 Java 代码中调用人脸识别、目标检测、OCR 等功能。底层支持包括基于 DJL (Deep Java Library) 封装的深度学习模型,以及通过 JNI 接入的 C++/Python 算法,兼容多种主流深度学习框架如 PyTorch、TensorFlow、ONNX、Paddle 等,屏蔽复杂的模型部署与调用细节,开发者无需了解 AI 底层实现即可直接在 Java 项目中集成使用,后续将持续扩展更多算法,目标是构建一个“像 Hutool 一样简单易用”的 JAVA AI 通用工具箱

1、引入 Maven 依赖

在项目的pom.xml的dependencies中加入以下内容(全部功能),也可以根据需求单独引入人脸模块,具体可以查看 SmartJavaAI官方文档

<dependency>
    <groupId>cn.smartjavaai</groupId>
    <artifactId>smartjavaai-all</artifactId>
    <version>1.0.19</version>
</dependency>

2、模型简介下载

下载

静态活体检测(RGB)模型(Silent face-anti-spoofing、FaceLivenessDetection)

支持功能:

  • 检测图片中的人脸是否为来自认证设备端的近距离裸拍活体人脸对象(裸拍活体正面人脸是指真人未经重度PS、风格化、人工合成等后处理的含正面人脸)
模型名称 模型简介 模型开源网站
MiniVision 小视科技的静默活体检测 Github
IIC_FL(cv_manual_face-liveness_flrgb) 阿里通义工作室人脸活体检测模型-RGB 魔塔
SeetaFace6 中科视拓最新开放的开源免费的全栈人脸识别工具包 Github

3、获取活体检测模型:

LivenessConfig config = new LivenessConfig();
config.setModelEnum(LivenessModelEnum.SEETA_FACE6_MODEL);
//需替换为实际模型存储路径
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
LivenessDetModel livenessDetModel = LivenessModelFactory.getInstance().getModel(config);
LivenessConfig参数说明
字段名称 字段类型 默认值 说明
modelEnum LivenessModelEnum SEETA_FACE6_MODEL 模型枚举,目前支持活体检测的模型只有seetaface6模型
modelPath String NULL 手动指定离线模型路径
faceClarityThreshold float 0.3 人脸清晰度阈值,可选
realityThreshold float 0.8 人脸活体阈值,可选
frameCount int 10 视频检测帧数,可选(检测视频时有效)
device DeviceEnum CPU 指定运行设备,支持 CPU/GPU

⚠️ 注意事项
1、活体识别时,如果清晰度低的话,就会直接返回:未知(UNKNOWN)。清晰度满足阈值,则判断真实度,超过阈值则认为是真人,低于阈值是非活体。
2、在视频识别模式下,会计算视频帧数内的平均值再跟帧数比较。两个阈值都符合,越高的话,越是严格。

图片活体检测(多人脸)

DetectionResponse livenessStatusList = livenessDetModel.detect("src/main/resources/double_person.png");
log.info("活体检测结果:{}", JSONObject.toJSONString(livenessStatusList));

图片活体检测(分数最高人脸)

LivenessStatus livenessStatus = livenessDetModel.detectTopFace("src/main/resources/double_person.png");
log.info("活体检测结果:{}", JSONObject.toJSONString(livenessStatus));

图片多人脸活体检测(基于已检测出的人脸区域和关键点)

需要基于人脸检测结果

//人脸检测
//需替换为实际模型存储路径
String modelPath = "C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models";
FaceModelConfig faceDetectModelConfig = new FaceModelConfig();
faceDetectModelConfig.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);
faceDetectModelConfig.setModelPath(modelPath);
FaceModel faceDetectModel = FaceModelFactory.getInstance().getModel(faceDetectModelConfig);
DetectionResponse detectionResponse = faceDetectModel.detect("src/main/resources/double_person.png");
log.info("人脸检测结果:{}", JSONObject.toJSONString(detectionResponse));
//检测到人脸
if(detectionResponse != null && detectionResponse.getDetectionInfoList() != null && detectionResponse.getDetectionInfoList().size() > 0){
    //活体检测
    LivenessConfig config = new LivenessConfig();
    config.setModelEnum(LivenessModelEnum.SEETA_FACE6_MODEL);
    config.setModelPath(modelPath);
    //人脸清晰度阈值,可选,默认0.3,活体识别时,如果清晰度低的话,就会直接返回FUZZY,清晰度满足阈值,则判断真实度
    config.setFaceClarityThreshold(LivenessConstant.DEFAULT_FACE_CLARITY_THRESHOLD);
    //人脸活体阈值,可选,默认0.8,超过阈值则认为是真人,低于阈值是非活体
    config.setRealityThreshold(LivenessConstant.DEFAULT_REALITY_THRESHOLD);
    LivenessDetModel livenessDetModel = LivenessModelFactory.getInstance().getModel(config);
    List<LivenessStatus> livenessStatusList = livenessDetModel.detect("src/main/resources/double_person.png",detectionResponse);
    log.info("活体检测结果:{}", JSONObject.toJSONString(livenessStatusList));
}

图片单人脸活体检测(基于已检测出的人脸区域和关键点)

try {
    //人脸检测
    //需替换为实际模型存储路径
    String modelPath = "C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models";
    String imagePath = "src/main/resources/double_person.png";
    FaceModelConfig faceDetectModelConfig = new FaceModelConfig();
    faceDetectModelConfig.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);
    faceDetectModelConfig.setModelPath(modelPath);
    FaceModel faceDetectModel = FaceModelFactory.getInstance().getModel(faceDetectModelConfig);
    DetectionResponse detectionResponse = faceDetectModel.detect(imagePath);
    log.info("人脸检测结果:{}", JSONObject.toJSONString(detectionResponse));
    //检测到人脸
    if(detectionResponse != null && detectionResponse.getDetectionInfoList() != null && detectionResponse.getDetectionInfoList().size() > 0){
        //活体检测
        LivenessConfig config = new LivenessConfig();
        config.setModelEnum(LivenessModelEnum.SEETA_FACE6_MODEL);
        config.setModelPath(modelPath);
        //人脸清晰度阈值,可选,默认0.3,活体识别时,如果清晰度低的话,就会直接返回FUZZY,清晰度满足阈值,则判断真实度
        config.setFaceClarityThreshold(LivenessConstant.DEFAULT_FACE_CLARITY_THRESHOLD);
        //人脸活体阈值,可选,默认0.8,超过阈值则认为是真人,低于阈值是非活体
        config.setRealityThreshold(LivenessConstant.DEFAULT_REALITY_THRESHOLD);
        LivenessDetModel livenessDetModel = LivenessModelFactory.getInstance().getModel(config);
        BufferedImage image = ImageIO.read(new File(Paths.get(imagePath).toAbsolutePath().toString()));
        for (DetectionInfo detectionInfo : detectionResponse.getDetectionInfoList()){
            FaceInfo faceInfo = detectionInfo.getFaceInfo();
            LivenessStatus livenessStatus = livenessDetModel.detect(image, detectionInfo.getDetectionRectangle(), faceInfo.getKeyPoints());
            log.info("活体检测结果:{}", JSONObject.toJSONString(livenessStatus));
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}

视频活体检测

LivenessConfig config = new LivenessConfig();
config.setModelEnum(LivenessModelEnum.SEETA_FACE6_MODEL);
//需替换为实际模型存储路径
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
//人脸清晰度阈值,可选,默认0.3,活体识别时,如果清晰度低的话,就会直接返回FUZZY,清晰度满足阈值,则判断真实度
config.setFaceClarityThreshold(LivenessConstant.DEFAULT_FACE_CLARITY_THRESHOLD);
//人脸活体阈值,可选,默认0.8,超过阈值则认为是真人,低于阈值是非活体
config.setRealityThreshold(LivenessConstant.DEFAULT_REALITY_THRESHOLD);
/*视频检测帧数,可选,默认10,输出帧数超过这个number之后,就可以输出识别结果。
这个数量相当于多帧识别结果融合的融合的帧数。当输入的帧数超过设定帧数的时候,会采用滑动窗口的方式,返回融合的最近输入的帧融合的识别结果。
一般来说,在10以内,帧数越多,结果越稳定,相对性能越好,但是得到结果的延时越高。*/
config.setFrameCount(LivenessConstant.DEFAULT_FRAME_COUNT);
LivenessDetModel livenessDetModel = LivenessModelFactory.getInstance().getModel(config);
LivenessStatus livenessStatus = livenessDetModel.detectVideo("src/main/resources/girl.mp4");
log.info("视频活体检测结果:{}", JSONObject.toJSONString(livenessStatus));

视频活体检测(逐帧检测,基于已检测出的人脸区域和关键点)

try {
    FFmpegFrameGrabber grabber = new FFmpegFrameGrabber("src/main/resources/girl.mp4");
    grabber.start();
    // 获取视频总帧数
    int totalFrames = grabber.getLengthInFrames();
    log.info("视频总帧数:{},检测帧数:{}", totalFrames, config.getFrameCount());
    //活体检测结果
    LivenessStatus livenessStatus = LivenessStatus.UNKNOWN;
    // 逐帧处理视频
    for (int frameIndex = 0; frameIndex < totalFrames; frameIndex++) {
        // 获取当前帧
        Frame frame = grabber.grabImage();
        if (frame != null) {
            BufferedImage bufferedImage = Java2DFrameUtils.toBufferedImage(frame);
            LivenessStatus livenessStatusFrame = livenessDetModel.detectVideoByFrame(bufferedImage);
            //满足检测帧数之后停止检测
            if(livenessStatusFrame != LivenessStatus.DETECTING){
                livenessStatus = livenessStatusFrame;
            }
        }
    }
    log.info("视频活体检测结果:{}", JSONObject.toJSONString(livenessStatus));
    grabber.stop();
} catch (FFmpegFrameGrabber.Exception e) {
    throw new FaceException(e);
}
DetectionResponse字段说明
  • 返回并非json格式,仅用于字段讲解
{
  "detectionInfoList": [ // 检测信息列表
    {
      "detectionRectangle": { //矩形框
        "height": 174, // 矩形高度
        "width": 147, // 矩形宽度
        "x": 275, // 左上角横坐标
        "y": 143 // 左上角纵坐标
      },
      "faceInfo": { // 人脸信息
        "keyPoints": [ // 5个人脸关键点:循序依次为,左眼中心、右眼中心、鼻尖、左嘴角和右嘴角
          {
            "x": 339.5083751678467,
            "y": 192.76402664184573
          },
          {
            "x": 404.7374267578125,
            "y": 197.89914321899414
          },
          {
            "x": 388.9555263519287,
            "y": 231.50675201416016
          },
          {
            "x": 339.8661708831787,
            "y": 265.51241302490234
          },
          {
            "x": 397.7071800231933,
            "y": 269.7657699584961
          }
        ],
        "livenessStatus": "LIVE" //活体检测结果
      }
    }
  ]
}

⚠️ 注意事项
1、视频活体检测支持常见视频格式(推荐使用mp4),内部使用ffmpeg进行视频解析。
2、输入视频的有效帧数必须 > LivenessConfig 配置参数中 frameCount 的设定值(默认阈值:10帧)
3、若不满足帧数条件,接口将抛出异常
4、输入视频文件过大,会耗费内存,建议视频文件不要过大。
5、在视频活体检测模式下,检测帧数超过frameCount之后,就可以输出识别结果。这个数量相当于多帧识别结果融合的融合的帧数。当检测的帧数超过设定帧数的时候,会采用滑动窗口的方式,返回融合的最近检测的帧融合的识别结果。一般来说,在10以内,帧数越多,结果越稳定,相对性能越好,但是得到结果的延时越高。

LivenessStatus 活体检测返回结果枚举
枚举值 说明
LIVE 活体
NON_LIVE 非活体
UNKNOWN 未知,或者人脸清晰度低
DETECTING 视频模式,检测中

项目地址

  • 完整代码地址:examples
  • SmartJavaAI 开发文档:官方文档
  • SmartJavaAI Gitee开源地址:Gitee
  • SmartJavaAI Github开源地址:Github
  • SmartJavaAI GitCode开源地址:GitCode

Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐