🧐 什么是活体检测?
活体检测(Liveness Detection)是判断摄像头前的人脸是否为“真实活人”的技术,广泛用于防止照片、视频攻击。常见场景包括:
- 登录认证
- 支付安全
- 门禁系统
SmartJavaAI 为我们封装了活体检测能力,调用简单,无需搞懂底层模型。
🚀 快速开始
我们使用SmartJavaAI 封装的 Seetaface6模型来实现活体检测 官网地址:
1、引入 Maven 依赖
在项目的pom.xml的dependencies中加入以下内容(全部功能),也可以根据需求单独引入人脸模块,具体可以查看 SmartJavaAI官方文档
<dependency>
<groupId>cn.smartjavaai</groupId>
<artifactId>smartjavaai-all</artifactId>
<version>1.0.12</version>
</dependency>
2、模型下载
SmartJavaAI 默认使用的是 SeetaFace6
活体检测模型,首次使用前请先下载模型文件并解压到本地路径。
🔗 下载地址:
⚠️ 下载后请将模型路径配置到
LivenessConfig#setModelPath
中。
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