# 人脸识别
# 简介
SmartJavaAI
人脸模块支持以下功能:
- 人脸检测
- 人脸特征提取(含人脸对齐)
- 1:1 人脸比对
- 1:N 人脸识别
- 人脸注册与查询
- 5点人脸关键点定位
- 人脸属性检测(性别、年龄、口罩、眼睛状态、脸部姿态)
- 人脸活体检测:图片、视频活体检测
# 能力展示
人脸检测 - 5点人脸关键点定位 | ![]() |
人脸比对1:1 - 人脸对齐 | ![]() |
人证核验 | ![]() |
人脸比对1:N - 人脸对齐- 人脸注册 - 人脸库查询 - 人脸库删除 | ![]() |
人脸属性检测 - 性别检测- 年龄检测 - 口罩检测 - 眼睛状态检测 - 脸部姿态检测 | ![]() |
活体检测 - 图片和视频活体检测 | ![]() |
# 准备工作
# 1、Maven引入
在项目的 pom.xml 中添加以下依赖以及平台依赖库,详细引入方式参考 Maven 引入。如需引入全部功能,请使用 smartjavaai-all 模块。
<dependency>
<groupId>cn.smartjavaai</groupId>
<artifactId>smartjavaai-face</artifactId>
<version>1.0.12</version>
</dependency>
# 2、人脸模型下载
如果在有网环境下使用,不需要下载模型(SeetaFace6模型除外)
模型名称 | 下载地址 | 兼容系统 | 支持设备 | 文件大小 | 适用场景 |
---|---|---|---|---|---|
retinaface | 下载 (opens new window) | Windows Linux MacOS | CPU/GPU | 110MB | 高精度人脸检测 |
ultralightfastgenericface | 下载 (opens new window) | Windows Linux MacOS | CPU/GPU | 1.7MB | 高速人脸检测 |
seetaface6 | 下载 (opens new window) | Windows Linux | CPU/GPU | 288MB | 人脸检测、人脸比对、人脸库注册、人脸库查询 |
facenet | 下载 (opens new window) | Windows Linux MacOS | CPU/GPU | 104MB | 人脸特征提取、人脸比对 |
# 3、人脸库下载
当前仅 SeetaFace6 支持人脸库操作功能,需手动下载 faces-data.db(SQLite 数据库)。程序运行过程中将自动读取与写入该数据库,用于存储人脸特征与唯一标识 key,实现注册、比对、查询等功能。
注意事项:
仅使用人脸库相关功能(人脸注册、人脸查询)才需要下载人脸库
# 人脸检测
# 获取默认检测模型:
- 默认模型:retinaface,联网自动下载
FaceModel faceModel = FaceModelFactory.getInstance().getModel();
# 获取检测模型(使用自定义模型配置)
FaceModelConfig config = new FaceModelConfig();
config.setModelEnum(FaceModelEnum.RETINA_FACE);//人脸模型
config.setConfidenceThreshold(FaceConfig.DEFAULT_CONFIDENCE_THRESHOLD);//置信度阈值
config.setNmsThresh(FaceConfig.NMS_THRESHOLD);//非极大抑制阈值
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
# FaceModelConfig参数说明
字段名称 | 字段类型 | 默认值 | 说明 |
---|---|---|---|
modelEnum | FaceModelEnum | RETINA_FACE | 人脸模型枚举 |
confidenceThreshold | double | 0.85 | 置信度阈值,分数低于这个值的结果将被过滤掉。值越高越严格,越低越宽松。 |
similarityThreshold | double | 0.62 | 相似度阈值 作用:判断是否为同一人脸 |
nmsThresh | double | 0.45 | 非极大抑制阈值,用于去除重复的人脸框,当两个框的重叠度超过该值时,只保留一个,建议使用默认值 |
modelPath | String | NULL | 手动指定离线模型路径 |
faceDbPath | String | NULL | 人脸库路径(注册/查询功能需配置) |
device | DeviceEnum | CPU | 指定运行设备,支持 CPU/GPU |
注意事项:
1、当使用 SeetaFace6 模型时,必须手动设置 modelPath,若启用人脸注册和查询功能,还需配置 faceDbPath。modelPath 为模型目录路径,无需包含具体文件名。
2、similarityThreshold目前只支持seetaface6模型使用
3、seetaface6模型不支持自定义confidenceThreshold
# FaceModelEnum人脸模型枚举说明
枚举值 | 说明 |
---|---|
RETINA_FACE | 高精度人脸检测模型 |
ULTRA_LIGHT_FAST_GENERIC_FACE | 轻量人脸检测模型 |
FACENET_FEATURE_EXTRACTION | 人脸特征提取模型 |
SEETA_FACE6_MODEL | seetaface6全功能人脸模型 |
# 人脸检测方法
DetectionResponse detect(String imagePath);
DetectionResponse detect(InputStream imageInputStream);
DetectionResponse detect(BufferedImage image);
DetectionResponse detect(byte[] imageData);
# 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"
},
"score": 0.9995993 // 置信度分值
}
]
}
# 检测并绘制人脸框
绘制人脸区域及5个人脸关键点:左眼中心、右眼中心、鼻尖、左嘴角和右嘴角
/**
* 检测并绘制人脸
* @param imagePath 图片输入路径(包含文件名称)
* @param outputPath 图片输出路径(包含文件名称)
*/
void detectAndDraw(String imagePath, String outputPath);
/**
* 检测并绘制人脸
* @param sourceImage
* @return
*/
BufferedImage detectAndDraw(BufferedImage sourceImage);
# 人脸特征提取
# 人脸特征提取(多人脸提取)
- FACENET_FEATURE_EXTRACTION 特征提取模型默认使用 ULTRA_LIGHT_FAST_GENERIC_FACE 作为人脸检测模型;如果使用 SEETAFACE6 模型提取人脸特征,由于 SEETAFACE6 本身支持人脸检测,因此检测阶段将直接使用 SEETAFACE6 完成。
- 自动裁剪人脸 + 人脸对齐
List<float[]> extractFeatures(String imagePath);
List<float[]> extractFeatures(InputStream inputStream);
List<float[]> extractFeatures(BufferedImage sourceImage);
List<float[]> extractFeatures(byte[] imageData);
# 人脸特征提取(分数最高人脸)
- FACENET_FEATURE_EXTRACTION 特征提取模型默认使用 ULTRA_LIGHT_FAST_GENERIC_FACE 作为人脸检测模型;如果使用 SEETAFACE6 模型提取人脸特征,由于 SEETAFACE6 本身支持人脸检测,因此检测阶段将直接使用 SEETAFACE6 完成。
- 自动裁剪人脸 + 人脸对齐
float[] extractTopFaceFeature(String imagePath);
float[] extractTopFaceFeature(BufferedImage sourceImage);
float[] extractTopFaceFeature(byte[] imageData);
# 进阶-使用自定义配置 人脸特征提取(多人脸提取)
- 可以设置人脸检测模型等参数,具体参看FaceExtractConfig字段说明
- 自动裁剪人脸 + 人脸对齐
List<float[]> extractFeatures(String imagePath, FaceExtractConfig config);
List<float[]> extractFeatures(BufferedImage sourceImage, FaceExtractConfig config);
List<float[]> extractFeatures(byte[] imageData, FaceExtractConfig config);
# 进阶-使用自定义配置 人脸特征提取(分数最高人脸)
- 可以设置人脸检测模型等参数,具体参看FaceExtractConfig字段说明
- 自动裁剪人脸 + 人脸对齐
float[] extractTopFaceFeature(String imagePath, FaceExtractConfig config);
float[] extractTopFaceFeature(BufferedImage sourceImage, FaceExtractConfig config);
float[] extractTopFaceFeature(byte[] imageData, FaceExtractConfig config);
# FaceExtractConfig参数说明
字段名称 | 字段类型 | 默认值 | 说明 |
---|---|---|---|
cropFace | boolean | true | 是否裁剪人脸 |
align | boolean | true | 是否对齐人脸 |
detectModelConfig | FaceModelConfig | 人脸检测模型配置 |
注意事项:
1、seetaface6模型不支持使用自定义参数提取人脸特征,默认会裁剪人脸及对齐人脸
2、由于人脸对齐前提是裁剪人脸区域,因此当 align=true 时,无论 cropFace 是否为 true,系统都会执行人脸裁剪操作。
# 人脸比对
# 人脸比对(特征提取+比对)
- 参数为图片路径、输入流、图片对象、图片字节数组
float featureComparison(String imagePath1, String imagePath2);
float featureComparison(BufferedImage sourceImage1, BufferedImage sourceImag2);
float featureComparison(InputStream inputStream1, InputStream inputStream2);
float featureComparison(byte[] imageData1, byte[] imageData2);
# 人脸比对(相似度计算)
- 参数为extractFeatures或extractTopFaceFeature的返回结果
/**
* 计算相似度
* @param feature1 图1特征
* @param feature2 图2特征
* @return
*/
float calculSimilar(float[] feature1, float[] feature2);
# 人脸注册
boolean register(String key, String imagePath);
boolean register(String key, InputStream inputStream);
boolean register(String key, BufferedImage sourceImage);
boolean register(String key, byte[] imageData);
# 人脸查询
FaceResult search(String imagePath);
FaceResult search(InputStream inputStream);
FaceResult search(BufferedImage sourceImage);
FaceResult search(byte[] imageData);
# FaceResult字段说明
字段名称 | 字段类型 | 说明 |
---|---|---|
key | String | 注册人脸的key值 |
similar | float | 相似度 |
# 人脸删除
- 参数为调用register方法时的key值
long removeRegister(String... keys);
# 清空人脸库
long clearFace();
# 活体检测
静默活体识别根据输入的图像数据、人脸位置和人脸特征点,对输入人脸进行活体的判断,并返回人脸活体的状态。
注意事项:
1、活体识别内容增加了对图像清晰度的判断,但是还是有对其他方面的质量要求,比如人脸分辨率128x128以上,光照均匀,自然表情等。其中主要影响识别精度的为光照环境
# 获取活体检测模型:
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 detect(String imagePath)
DetectionResponse detect(BufferedImage image)
DetectionResponse detect(byte[] imageData)
# 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" //活体检测结果
}
}
]
}
# 图片活体检测(多人脸)- 基于已检测出的人脸区域和关键点
仅返回活体检测结果
List<LivenessStatus> detect(String imagePath, DetectionResponse faceDetectionResponse)
List<LivenessStatus> detect(BufferedImage image,DetectionResponse faceDetectionResponse)
List<LivenessStatus> detect(byte[] imageData,DetectionResponse faceDetectionResponse)
# 图片活体检测(单人脸)- 基于已检测出的人脸区域和关键点
- imagePath:图片路径
- faceDetectionRectangle:人脸检测框(人脸检测返回结果)
- keyPoints:5个人脸关键点(人脸检测返回结果)
LivenessStatus detect(String imagePath, DetectionRectangle faceDetectionRectangle, List<Point> keyPoints)
LivenessStatus detect(BufferedImage image, DetectionRectangle faceDetectionRectangle, List<Point> keyPoints)
LivenessStatus detect(byte[] imageData, DetectionRectangle faceDetectionRectangle, List<Point> keyPoints)
# 图片活体检测(分数最高人脸)
检测图片中分数最高的人脸
LivenessStatus detectTopFace(BufferedImage image)
LivenessStatus detectTopFace(String imagePath)
LivenessStatus detectTopFace(byte[] imageData)
# 视频活体检测
活体检测分为图片模式和视频模式,两种工作模式的区别在于前者属于一帧就是可以返回识别结果,而后者要输入多个视频帧然后返回识别结果。
LivenessStatus detectVideo(InputStream videoInputStream)
LivenessStatus detectVideo(String videoPath)
注意事项:
1、视频活体检测支持常见视频格式(推荐使用mp4),内部使用ffmpeg进行视频解析。
2、输入视频的有效帧数必须 > LivenessConfig 配置参数中 frameCount 的设定值(默认阈值:10帧)
3、若不满足帧数条件,接口将抛出异常
4、输入视频文件过大,会耗费内存,建议视频文件不要过大。
# 视频活体检测(逐帧检测)
LivenessStatus detectVideoByFrame(BufferedImage frameImageData)
LivenessStatus detectVideoByFrame(byte[] frameImageData)
# 视频活体检测(逐帧检测) - 基于已检测出的人脸区域和关键点
LivenessStatus detectVideoByFrame(BufferedImage frameImage, DetectionRectangle faceDetectionRectangle, List<Point> keyPoints)
LivenessStatus detectVideoByFrame(byte[] frameData, DetectionRectangle faceDetectionRectangle, List<Point> keyPoints)
注意事项:
1、在视频活体检测模式下,检测帧数超过frameCount之后,就可以输出识别结果。这个数量相当于多帧识别结果融合的融合的帧数。当检测的帧数超过设定帧数的时候,会采用滑动窗口的方式,返回融合的最近检测的帧融合的识别结果。一般来说,在10以内,帧数越多,结果越稳定,相对性能越好,但是得到结果的延时越高。
# LivenessStatus 活体检测返回结果枚举
枚举值 | 说明 |
---|---|
LIVE | 活体 |
NON_LIVE | 非活体 |
UNKNOWN | 未知,或者人脸清晰度低 |
DETECTING | 视频模式,检测中 |
# 人脸属性检测
人脸属性检测包含:性别、年龄、口罩、眼睛状态(开闭)、脸部姿态(俯仰角,偏航角,翻滚角)
# 获取人脸属性检测模型:
FaceAttributeConfig config = new FaceAttributeConfig();
config.setModelEnum(FaceAttributeModelEnum.SEETA_FACE6_MODEL);
//需替换为实际模型存储路径
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
FaceAttributeModel faceAttributeModel = FaceAttributeModelFactory.getInstance().getModel(config);
# FaceAttributeConfig参数说明
字段名称 | 字段类型 | 默认值 | 说明 |
---|---|---|---|
modelEnum | FaceAttributeModelEnum | SEETA_FACE6_MODEL | 模型枚举,目前支持人脸属性检测的模型只有seetaface6模型 |
modelPath | String | NULL | 手动指定离线模型路径 |
enableAge | boolean | true | 是否启用年龄检测,可选 |
enableGender | boolean | true | 是否启用性别检测,可选 |
enableHeadPose | boolean | true | 是否启用人脸姿态检测,可选 |
enableEyeStatus | boolean | true | 是否启用眼睛状态检测,可选 |
enableMask | boolean | true | 是否启用口罩检测,可选 |
device | DeviceEnum | CPU | 指定运行设备,支持 CPU/GPU |
# 人脸属性检测(多人脸)
返回人脸检测信息+人脸属性
DetectionResponse detect(String imagePath)
DetectionResponse detect(BufferedImage image)
DetectionResponse detect(byte[] imageData)
# DetectionResponse字段说明
- 返回并非json格式,仅用于字段讲解
{
"detectionInfoList": [ // 检测信息列表
{
"detectionRectangle": { //矩形框
"height": 174, // 矩形高度
"width": 147, // 矩形宽度
"x": 275, // 左上角横坐标
"y": 143 // 左上角纵坐标
},
"faceInfo": { // 人脸信息
"faceAttribute": { //人脸属性
"age": 44, //年龄
"genderType": "FEMALE", //性别
"headPose": { //脸部姿态
"pitch": 12.958274,
"roll": 0.19592644,
"yaw": -4.166052
},
"leftEyeStatus": "OPEN",// 左眼开闭
"rightEyeStatus": "OPEN",//右眼开闭
"wearingMask": false //是否戴口罩
},
"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
}
]
}
}
]
}
# 人脸属性检测(多人脸)- 基于已检测出的人脸区域和关键点
仅返回人脸属性
List<FaceAttribute> detect(String imagePath, DetectionResponse faceDetectionResponse)
List<FaceAttribute> detect(BufferedImage image,DetectionResponse faceDetectionResponse)
List<FaceAttribute> detect(byte[] imageData,DetectionResponse faceDetectionResponse)
# 人脸属性检测(单人脸)- 基于已检测出的人脸区域和关键点
- imagePath:图片路径
- faceDetectionRectangle:人脸检测框(人脸检测返回结果)
- keyPoints:5个人脸关键点(人脸检测返回结果)
FaceAttribute detect(String imagePath, DetectionRectangle faceDetectionRectangle, List<Point> keyPoints)
FaceAttribute detect(BufferedImage image, DetectionRectangle faceDetectionRectangle, List<Point> keyPoints)
FaceAttribute detect(byte[] imageData, DetectionRectangle faceDetectionRectangle, List<Point> keyPoints)
# 人脸属性检测(分数最高人脸)
检测图片中分数最高的人脸
LivenessStatus detectTopFace(BufferedImage image)
LivenessStatus detectTopFace(String imagePath)
LivenessStatus detectTopFace(byte[] imageData)
# FaceAttribute 字段讲解
字段名称 | 字段类型 | 说明 |
---|---|---|
genderType | GenderType | 性别枚举 |
age | Integer | 年龄 |
leftEyeStatus | EyeStatus | 左眼状态 |
rightEyeStatus | EyeStatus | 右眼状态 |
wearingMask | Boolean | 是否带口罩 |
headPose | HeadPose | 姿态 |
# GenderType 性别枚举
枚举值 | 说明 |
---|---|
MALE | 男 |
FEMALE | 女 |
UNKNOWN | 未知 |
# EyeStatus 眼睛状态枚举
枚举值 | 说明 |
---|---|
OPEN | 睁眼 |
CLOSED | 闭眼 |
NON_EYE_REGION | 非眼部区域 |
UNKNOWN | 未知 |
# HeadPose 姿态检测结果字段讲解
字段名称 | 字段类型 | 说明 |
---|---|---|
pitch | Float | 上下(俯仰角),正值抬头,负值低头 (-90°~+90°) |
yaw | Float | 左右(偏航角),正值右偏,负值左偏(-90°~+90°) |
roll | Float | 倾斜(翻滚角),正值右倾,负值左倾(-90°~+90°) |
# 绘制人脸属性检测结果并导出图片
通过 SmartJavaAI 提供的工具类 FaceUtils,你可以轻松地将检测到的人脸框和属性信息绘制到图片上,并导出保存。示例代码如下:
image:待处理的原始图像对象。
detectionResponse:人脸检测与属性识别的响应结果。
第三个参数为导出的目标文件路径(支持 PNG/JPG 格式)。
该方法将自动在图像上绘制人脸框、性别、年龄等属性信息,并将结果保存到指定路径。
FaceUtils.drawBoxesWithFaceAttribute(image, detectionResponse,"C:/Users/Administrator/Downloads/double_person_.png");
# 完整示例代码
# 离线使用
1、首次运行,会自动下载模型及底层依赖库到缓存目录中。缓存路径请看文档:离线使用
2、seetaface6需要手动下载模型,其他模型调用都会自动下载,如果因网络问题下载失败,请手动下载模型,并放置到缓存目录中
3、可以在联网环境中运行程序一次,确保所需的依赖库已下载。然后将缓存目录复制到离线环境中相同的路径下,即可实现离线使用