mirror of
https://github.com/geekwenjie/SmartJavaAI.git
synced 2026-09-10 03:28:49 +00:00
1、人脸模块:人脸查询支持 向量数据库Milvus 和 SQLite
2、人脸模块:FaceNet人脸模型也支持人脸注册,查询等功能 3、人脸模块:Seetaface6 自动下载人脸库 4、人脸模块:Seetaface6解决依赖库重复下载问题 5、人脸模块:支持手动加载人脸库 6、人脸模块:人脸识别相关功能支持更多参数
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<smartjavaai.version>1.0.15</smartjavaai.version>
|
||||
<smartjavaai.version>1.0.16</smartjavaai.version>
|
||||
<!--如果打包运行,需要替换成你的main-->
|
||||
<exec.mainClass>smartai.examples.face.facerec.RetinaFaceDemo</exec.mainClass>
|
||||
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
package smartai.examples.face.facerec;
|
||||
|
||||
import cn.smartjavaai.common.entity.DetectionResponse;
|
||||
import cn.smartjavaai.common.entity.FaceSearchResult;
|
||||
import cn.smartjavaai.common.entity.R;
|
||||
import cn.smartjavaai.face.config.FaceExtractConfig;
|
||||
import cn.smartjavaai.face.config.FaceModelConfig;
|
||||
import cn.smartjavaai.face.entity.FaceRegisterInfo;
|
||||
import cn.smartjavaai.face.entity.FaceResult;
|
||||
import cn.smartjavaai.face.entity.FaceSearchParams;
|
||||
import cn.smartjavaai.face.enums.FaceModelEnum;
|
||||
import cn.smartjavaai.face.enums.IdStrategy;
|
||||
import cn.smartjavaai.face.enums.SimilarityType;
|
||||
import cn.smartjavaai.face.factory.FaceModelFactory;
|
||||
import cn.smartjavaai.face.model.facerec.FaceModel;
|
||||
import cn.smartjavaai.face.vector.config.MilvusConfig;
|
||||
import cn.smartjavaai.face.vector.config.SQLiteConfig;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.milvus.param.MetricType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
@@ -21,7 +32,8 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* FaceNet人脸算法模型demo
|
||||
* 支持功能:人脸特征提取、人脸比对(1:1)
|
||||
* 支持系统:windows 64位,linux 64位,macOS M系列芯片
|
||||
* 支持功能:人脸特征提取、人脸比对(1:1)、人脸比对(1:N)、人脸注册
|
||||
* @author dwj
|
||||
* @date 2025/4/11
|
||||
*/
|
||||
@@ -29,106 +41,90 @@ import java.util.List;
|
||||
public class FaceNetDemo {
|
||||
|
||||
/**
|
||||
* 提取人脸特征(支持多人脸)
|
||||
* 默认使用检测模型:FACENET_FEATURE_EXTRACTION
|
||||
* 自动裁剪人脸 + 人脸对齐
|
||||
* 提取人脸特征(多人脸场景)
|
||||
* 默认使用检测模型:ULTRA_LIGHT_FAST_GENERIC_FACE
|
||||
* 自动裁剪人脸(处理耗时略有增加)
|
||||
* 注意事项:
|
||||
* 1、首次调用接口,可能会较慢。只要不关闭程序,后续调用会明显加快。若每次重启程序,则每次首次调用都将重新加载,仍会较慢。
|
||||
* 2、若人脸朝向不正,可开启人脸对齐以提升特征提取准确度。(方法参考自定义配置人脸特征提取)
|
||||
*/
|
||||
@Test
|
||||
public void testExtractFeatures(){
|
||||
try {
|
||||
//人脸特征提取模型
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.FACENET_FEATURE_EXTRACTION);
|
||||
config.setModelEnum(FaceModelEnum.FACENET_MODEL);
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
List<float[]> faceResult = faceModel.extractFeatures("src/main/resources/kana1.jpg");
|
||||
log.info("人脸特征提取结果:{}", JSONObject.toJSONString(faceResult));
|
||||
log.info("人脸特征提取模型加载成功");
|
||||
//提取图片中所有人脸特征
|
||||
R<DetectionResponse> faceResult = faceModel.extractFeatures("src/main/resources/face/iu_1.jpg");
|
||||
if(faceResult.isSuccess()){
|
||||
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(faceResult.getData()));
|
||||
}else{
|
||||
log.info("人脸特征提取失败:{}", faceResult.getMessage());
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取人脸特征(支持多人脸,自定义配置)
|
||||
* 自动裁剪人脸 + 人脸对齐
|
||||
* 提取人脸特征(自定义配置)
|
||||
* 注意事项:
|
||||
* 1、首次调用接口,可能会较慢。只要不关闭程序,后续调用会明显加快。若每次重启程序,则每次首次调用都将重新加载,仍会较慢。
|
||||
* 2、若人脸朝向不正,可开启人脸对齐以提升特征提取准确度。(方法参考自定义配置人脸特征提取)
|
||||
*/
|
||||
@Test
|
||||
public void testExtractFeaturesWithCustomConfig(){
|
||||
try {
|
||||
//人脸模型参数
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.FACENET_FEATURE_EXTRACTION);
|
||||
config.setModelEnum(FaceModelEnum.FACENET_MODEL);
|
||||
//人脸特征提取参数
|
||||
FaceExtractConfig extractConfig = new FaceExtractConfig();
|
||||
//人脸检测模型配置
|
||||
extractConfig.setDetectModel(FaceModelFactory.getInstance().getModel(new FaceModelConfig(FaceModelEnum.ULTRA_LIGHT_FAST_GENERIC_FACE)));
|
||||
//当关闭人脸裁剪时,程序将跳过人脸检测与裁剪流程,直接进行特征提取,适用于输入已为标准人脸区域的图像,有助于提升处理效率。
|
||||
extractConfig.setCropFace(true);
|
||||
//开启人脸对齐:适用于人脸不正的场景,开启将提升人脸特征准确度,关闭可以提升性能
|
||||
extractConfig.setAlign(true);
|
||||
//人脸检测模型配置,指定人脸检测模型:ULTRA_LIGHT_FAST_GENERIC_FACE
|
||||
FaceModelConfig detectModelConfig = new FaceModelConfig(FaceModelEnum.ULTRA_LIGHT_FAST_GENERIC_FACE);
|
||||
//设置人脸检测置信度阈值
|
||||
detectModelConfig.setConfidenceThreshold(0.98);
|
||||
extractConfig.setDetectModel(FaceModelFactory.getInstance().getModel(detectModelConfig));
|
||||
config.setExtractConfig(extractConfig);
|
||||
//人脸特征提取模型
|
||||
//获取人脸模型
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
List<float[]> faceResult = faceModel.extractFeatures("src/main/resources/kana1.jpg");
|
||||
log.info("人脸特征提取结果:{}", JSONObject.toJSONString(faceResult));
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取人脸特征(分数最高人脸)
|
||||
* 默认使用检测模型:FACENET_FEATURE_EXTRACTION
|
||||
* 自动裁剪人脸 + 人脸对齐
|
||||
*/
|
||||
@Test
|
||||
public void testExtractTopFaceFeature(){
|
||||
try {
|
||||
//人脸特征提取模型
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.FACENET_FEATURE_EXTRACTION);
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
float[] faceResult = faceModel.extractTopFaceFeature("src/main/resources/kana1.jpg");
|
||||
log.info("人脸特征提取结果:{}", JSONObject.toJSONString(faceResult));
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取人脸特征(分数最高人脸,自定义配置)
|
||||
* 自动裁剪人脸 + 人脸对齐
|
||||
*/
|
||||
@Test
|
||||
public void testExtractTopFaceFeatureWithCustomConfig(){
|
||||
try {
|
||||
//人脸模型参数
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.FACENET_FEATURE_EXTRACTION);
|
||||
//人脸特征提取参数
|
||||
FaceExtractConfig extractConfig = new FaceExtractConfig();
|
||||
//人脸检测模型配置
|
||||
extractConfig.setDetectModel(FaceModelFactory.getInstance().getModel(new FaceModelConfig(FaceModelEnum.ULTRA_LIGHT_FAST_GENERIC_FACE)));
|
||||
config.setExtractConfig(extractConfig);
|
||||
//人脸特征提取模型
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
float[] faceResult = faceModel.extractTopFaceFeature("src/main/resources/kana1.jpg");
|
||||
log.info("人脸特征提取结果:{}", JSONObject.toJSONString(faceResult));
|
||||
//特征提取(提取分数最高人脸特征),适用于单人脸场景
|
||||
R<float[]> featureResult = faceModel.extractTopFaceFeature("src/main/resources/face/iu_1.jpg");
|
||||
if(featureResult.isSuccess()){
|
||||
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(featureResult.getData()));
|
||||
}else{
|
||||
log.info("人脸特征提取失败:{}", featureResult.getMessage());
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 人脸比对(1:1)-在线模型
|
||||
* 图片参数:图片路径
|
||||
* 人脸比对1:1(基于图像直接比对)
|
||||
* 流程:从输入图像中裁剪分数最高的人脸 → 提取其人脸特征 → 比对两张图片中提取的人脸特征。(接口内自动完成)
|
||||
* 注意事项:
|
||||
* 1、首次调用接口,可能会较慢。只要不关闭程序,后续调用会明显加快。若每次重启程序,则每次首次调用都将重新加载,仍会较慢。
|
||||
* 2、若人脸朝向不正,可开启人脸对齐以提升特征提取准确度。(方法参考自定义配置人脸特征提取)
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void featureComparison(){
|
||||
try {
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.FACENET_FEATURE_EXTRACTION);//人脸模型
|
||||
config.setModelPath("/Users/wenjie/Documents/develop/face_model/face_feature.pt");
|
||||
//人脸模型
|
||||
config.setModelEnum(FaceModelEnum.FACENET_MODEL);
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
//自动裁剪人脸并比对人脸特征
|
||||
float similar = faceModel.featureComparison("src/main/resources/kana1.jpg","src/main/resources/kana2.jpg");
|
||||
//基于图像直接比对人脸特征
|
||||
float similar = faceModel.featureComparison("src/main/resources/face/iu_1.jpg","src/main/resources/face/iu_2.jpg");
|
||||
log.info("相似度:{}", similar);
|
||||
}
|
||||
catch (Exception e){
|
||||
@@ -137,27 +133,239 @@ public class FaceNetDemo {
|
||||
}
|
||||
|
||||
/**
|
||||
* 人脸比对(1:1)- 使用离线模型
|
||||
* 图片参数:图片路径
|
||||
* 人脸比对1:1(基于特征值比对)
|
||||
* 流程:从输入图像中裁剪分数最高的人脸 → 提取其人脸特征 → 比对两张图片中提取的人脸特征。
|
||||
* 注意事项:
|
||||
* 1、首次调用接口,可能会较慢。只要不关闭程序,后续调用会明显加快。若每次重启程序,则每次首次调用都将重新加载,仍会较慢。
|
||||
* 2、若人脸朝向不正,可开启人脸对齐以提升特征提取准确度。(方法参考自定义配置人脸特征提取)
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void featureComparison2(){
|
||||
try {
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
//人脸模型
|
||||
config.setModelEnum(FaceModelEnum.FACENET_MODEL);
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
//特征提取(提取分数最高人脸特征),适用于单人脸场景
|
||||
R<float[]> featureResult1 = faceModel.extractTopFaceFeature("src/main/resources/face/iu_1.jpg");
|
||||
if(featureResult1.isSuccess()){
|
||||
log.info("图片1人脸特征提取成功:{}", JSONObject.toJSONString(featureResult1.getData()));
|
||||
}else{
|
||||
log.info("图片1人脸特征提取失败:{}", featureResult1.getMessage());
|
||||
return;
|
||||
}
|
||||
//特征提取(提取分数最高人脸特征),适用于单人脸场景
|
||||
R<float[]> featureResult2 = faceModel.extractTopFaceFeature("src/main/resources/face/iu_2.jpg");
|
||||
if(featureResult2.isSuccess()){
|
||||
log.info("图片2人脸特征提取成功:{}", JSONObject.toJSONString(featureResult2.getData()));
|
||||
}else{
|
||||
log.info("图片2人脸特征提取失败:{}", featureResult2.getMessage());
|
||||
return;
|
||||
}
|
||||
//计算相似度
|
||||
float similar = faceModel.calculSimilar(featureResult1.getData(), featureResult2.getData());
|
||||
log.info("相似度:{}", similar);
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 人脸注册 + 人脸更新 + 人脸查询 + 人脸删除(使用向量数据库Milvus)
|
||||
* 流程:从输入图像中裁剪分数最高的人脸 → 提取其人脸特征 → 注册人脸
|
||||
* 注意事项:
|
||||
* 1、首次调用接口,可能会较慢。只要不关闭程序,后续调用会明显加快。若每次重启程序,则每次首次调用都将重新加载,仍会较慢。
|
||||
* 2、若人脸朝向不正,可开启人脸对齐以提升特征提取准确度。(方法参考自定义配置人脸特征提取)
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void searchFace(){
|
||||
try {
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
//人脸模型
|
||||
config.setModelEnum(FaceModelEnum.FACENET_MODEL);
|
||||
//初始化向量数据库:Milvus数据库配置
|
||||
MilvusConfig vectorDBConfig = new MilvusConfig();
|
||||
vectorDBConfig.setHost("127.0.0.1");
|
||||
vectorDBConfig.setPort(19530);
|
||||
//vectorDBConfig.setCollectionName("face5");
|
||||
//ID策略:自动生成
|
||||
vectorDBConfig.setIdStrategy(IdStrategy.AUTO);
|
||||
//索引类型:内积 (Inner Product) 不建议修改
|
||||
//vectorDBConfig.setMetricType(MetricType.IP);
|
||||
config.setVectorDBConfig(vectorDBConfig);
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
//等待加载人脸库结束
|
||||
while (!faceModel.isLoadFaceCompleted()){
|
||||
Thread.sleep(100);
|
||||
}
|
||||
log.info("====================人脸注册==========================");
|
||||
//特征提取(提取分数最高人脸特征),适用于单人脸场景
|
||||
R<float[]> featureResult = faceModel.extractTopFaceFeature("src/main/resources/face/iu_1.jpg");
|
||||
if(featureResult.isSuccess()){
|
||||
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(featureResult.getData()));
|
||||
}else{
|
||||
log.info("人脸特征提取失败:{}", featureResult.getMessage());
|
||||
return;
|
||||
}
|
||||
//人脸注册信息
|
||||
FaceRegisterInfo faceRegisterInfo = new FaceRegisterInfo();
|
||||
//设置人脸注册的自定义元数据,本例中使用 JSON 格式存储用户信息
|
||||
JSONObject metadataJson = new JSONObject();
|
||||
metadataJson.put("name", "iu");
|
||||
metadataJson.put("age", "25");
|
||||
faceRegisterInfo.setMetadata(metadataJson.toJSONString());
|
||||
//人脸注册,返回人脸库ID
|
||||
R<String> registerResult = faceModel.register(faceRegisterInfo, featureResult.getData());
|
||||
if(registerResult.isSuccess()){
|
||||
log.info("注册成功:ID-{}", registerResult.getData());
|
||||
}else{
|
||||
log.info("注册失败:{}", registerResult.getMessage());
|
||||
}
|
||||
/*log.info("====================人脸更新==========================");
|
||||
//更新人脸 只支持自定义ID:vectorDBConfig.setIdStrategy(IdStrategy.CUSTOM);
|
||||
FaceRegisterInfo updateInfo = new FaceRegisterInfo();
|
||||
//设置人脸注册的自定义元数据,本例中使用 JSON 格式存储用户信息
|
||||
JSONObject metadataJsonUpdate = new JSONObject();
|
||||
metadataJsonUpdate.put("name", "iu_update");
|
||||
metadataJsonUpdate.put("age", "25");
|
||||
updateInfo.setMetadata(metadataJsonUpdate.toJSONString());
|
||||
//更新必须设置ID,只有
|
||||
updateInfo.setId(registerResult.getData());
|
||||
faceModel.upsertFace(updateInfo, "src/main/resources/face/iu_2.jpg");
|
||||
log.info("更新人脸成功");*/
|
||||
log.info("====================人脸查询==========================");
|
||||
//特征提取(提取分数最高人脸特征),适用于单人脸场景
|
||||
R<float[]> featureResult2 = faceModel.extractTopFaceFeature("src/main/resources/face/iu_3.jpg");
|
||||
if(featureResult2.isSuccess()){
|
||||
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(featureResult2.getData()));
|
||||
}else{
|
||||
log.info("人脸特征提取失败:{}", featureResult2.getMessage());
|
||||
return;
|
||||
}
|
||||
FaceSearchParams faceSearchParams = new FaceSearchParams();
|
||||
faceSearchParams.setTopK(1);
|
||||
faceSearchParams.setThreshold(0.8f);
|
||||
|
||||
List<FaceSearchResult> faceSearchResults = faceModel.search(featureResult2.getData(), faceSearchParams);
|
||||
// R<DetectionResponse> faceSearchResults = faceModel.search("src/main/resources/face/iu_3.jpg", faceSearchParams);
|
||||
log.info("人脸查询结果:{}", JSONArray.toJSONString(faceSearchResults));
|
||||
log.info("====================人脸删除==========================");
|
||||
faceModel.removeRegister(registerResult.getData());
|
||||
log.info("人脸删除成功");
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 人脸注册 + 人脸更新 + 人脸查询 + 人脸删除(使用轻量数据库SQLite)
|
||||
* 流程:从输入图像中裁剪分数最高的人脸 → 提取其人脸特征 → 注册人脸
|
||||
* 注意事项:
|
||||
* 1、首次调用接口,可能会较慢。只要不关闭程序,后续调用会明显加快。若每次重启程序,则每次首次调用都将重新加载,仍会较慢。
|
||||
* 2、若人脸朝向不正,可开启人脸对齐以提升特征提取准确度。(方法参考自定义配置人脸特征提取)
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void searchFace2(){
|
||||
try {
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
//人脸模型
|
||||
config.setModelEnum(FaceModelEnum.FACENET_MODEL);
|
||||
//初始化向量数据库:Milvus数据库配置
|
||||
SQLiteConfig vectorDBConfig = new SQLiteConfig();
|
||||
vectorDBConfig.setDbPath("/Users/wenjie/Downloads/face.db");
|
||||
vectorDBConfig.setSimilarityType(SimilarityType.IP);
|
||||
config.setVectorDBConfig(vectorDBConfig);
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
//等待加载人脸库结束
|
||||
while (!faceModel.isLoadFaceCompleted()){
|
||||
Thread.sleep(100);
|
||||
}
|
||||
log.info("====================人脸注册==========================");
|
||||
//特征提取(提取分数最高人脸特征),适用于单人脸场景
|
||||
R<float[]> featureResult = faceModel.extractTopFaceFeature("src/main/resources/face/iu_1.jpg");
|
||||
if(featureResult.isSuccess()){
|
||||
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(featureResult.getData()));
|
||||
}else{
|
||||
log.info("人脸特征提取失败:{}", featureResult.getMessage());
|
||||
return;
|
||||
}
|
||||
//人脸注册信息
|
||||
FaceRegisterInfo faceRegisterInfo = new FaceRegisterInfo();
|
||||
//设置人脸注册的自定义元数据,本例中使用 JSON 格式存储用户信息
|
||||
JSONObject metadataJson = new JSONObject();
|
||||
metadataJson.put("name", "iu");
|
||||
metadataJson.put("age", "25");
|
||||
faceRegisterInfo.setMetadata(metadataJson.toJSONString());
|
||||
//可自定义 ID,若未设置则自动生成。
|
||||
//faceRegisterInfo.setId("00001");
|
||||
//人脸注册,返回人脸库ID
|
||||
R<String> registerResult = faceModel.register(faceRegisterInfo, featureResult.getData());
|
||||
if(registerResult.isSuccess()){
|
||||
log.info("注册成功:ID-{}", registerResult.getData());
|
||||
}else{
|
||||
log.info("注册失败:{}", registerResult.getMessage());
|
||||
}
|
||||
log.info("====================人脸更新==========================");
|
||||
FaceRegisterInfo updateInfo = new FaceRegisterInfo();
|
||||
//设置人脸注册的自定义元数据,本例中使用 JSON 格式存储用户信息
|
||||
JSONObject metadataJsonUpdate = new JSONObject();
|
||||
metadataJsonUpdate.put("name", "iu_update");
|
||||
metadataJsonUpdate.put("age", "25");
|
||||
updateInfo.setMetadata(metadataJsonUpdate.toJSONString());
|
||||
//更新必须设置ID,只有
|
||||
updateInfo.setId(registerResult.getData());
|
||||
faceModel.upsertFace(updateInfo, "src/main/resources/face/iu_2.jpg");
|
||||
log.info("更新人脸成功");
|
||||
log.info("====================人脸查询==========================");
|
||||
//特征提取(提取分数最高人脸特征),适用于单人脸场景
|
||||
R<float[]> featureResult2 = faceModel.extractTopFaceFeature("src/main/resources/face/iu_3.jpg");
|
||||
if(featureResult2.isSuccess()){
|
||||
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(featureResult2.getData()));
|
||||
}else{
|
||||
log.info("人脸特征提取失败:{}", featureResult2.getMessage());
|
||||
return;
|
||||
}
|
||||
FaceSearchParams faceSearchParams = new FaceSearchParams();
|
||||
faceSearchParams.setTopK(1);
|
||||
faceSearchParams.setThreshold(0.8f);
|
||||
List<FaceSearchResult> faceSearchResults = faceModel.search(featureResult2.getData(), faceSearchParams);
|
||||
log.info("人脸查询结果:{}", JSONArray.toJSONString(faceSearchResults));
|
||||
log.info("====================人脸删除==========================");
|
||||
faceModel.removeRegister(registerResult.getData());
|
||||
log.info("人脸删除成功");
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 使用离线模型
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void featureComparisonOffline(){
|
||||
try {
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.FACENET_FEATURE_EXTRACTION);//人脸模型
|
||||
config.setModelEnum(FaceModelEnum.FACENET_MODEL);//人脸模型
|
||||
//设置人脸识别模型文件路径,请根据实际情况替换为本地模型文件的绝对路径
|
||||
config.setModelPath("/Users/xxx/Documents/develop/face_model/face_feature.pt");
|
||||
//人脸特征提取参数
|
||||
FaceExtractConfig extractConfig = new FaceExtractConfig();
|
||||
FaceModelConfig detectModelConfig = new FaceModelConfig(FaceModelEnum.ULTRA_LIGHT_FAST_GENERIC_FACE);
|
||||
//设置人脸检测模型文件路径,请根据实际情况替换为本地模型文件的绝对路径
|
||||
detectModelConfig.setModelPath("/Users/xxx/Documents/develop/face_model/ultranet.pt");
|
||||
//人脸检测模型配置
|
||||
extractConfig.setDetectModel(FaceModelFactory.getInstance().getModel(detectModelConfig));
|
||||
config.setExtractConfig(extractConfig);
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
//自动裁剪人脸并比对人脸特征
|
||||
float similar = faceModel.featureComparison("src/main/resources/kana1.jpg","src/main/resources/kana2.jpg");
|
||||
log.info("相似度:{}", similar);
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
package smartai.examples.face.facerec;
|
||||
|
||||
import cn.smartjavaai.common.entity.DetectionResponse;
|
||||
import cn.smartjavaai.common.entity.FaceSearchResult;
|
||||
import cn.smartjavaai.common.entity.R;
|
||||
import cn.smartjavaai.face.config.FaceExtractConfig;
|
||||
import cn.smartjavaai.face.config.FaceModelConfig;
|
||||
import cn.smartjavaai.face.entity.FaceRegisterInfo;
|
||||
import cn.smartjavaai.face.entity.FaceResult;
|
||||
import cn.smartjavaai.face.entity.FaceSearchParams;
|
||||
import cn.smartjavaai.face.enums.FaceModelEnum;
|
||||
import cn.smartjavaai.face.enums.IdStrategy;
|
||||
import cn.smartjavaai.face.enums.SimilarityType;
|
||||
import cn.smartjavaai.face.factory.FaceModelFactory;
|
||||
import cn.smartjavaai.face.model.facerec.FaceModel;
|
||||
import cn.smartjavaai.face.utils.SimilarityUtil;
|
||||
import cn.smartjavaai.face.vector.config.MilvusConfig;
|
||||
import cn.smartjavaai.face.vector.config.SQLiteConfig;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.milvus.param.MetricType;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
@@ -21,7 +33,7 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* SeetaFace6人脸算法模型demo
|
||||
* 支持系统:windows 64位
|
||||
* 支持系统:windows 64位,linux 64位
|
||||
* 支持功能:人脸检测、人脸特征提取、人脸比对(1:1)、人脸比对(1:N)、人脸注册
|
||||
* @author dwj
|
||||
* @date 2025/4/11
|
||||
@@ -31,84 +43,56 @@ public class SeetaFace6Demo {
|
||||
|
||||
|
||||
/**
|
||||
* 人脸检测(自定义模型参数)
|
||||
* 图片参数:图片路径
|
||||
*/
|
||||
@Test
|
||||
public void testFaceDetectCustomConfig(){
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);//人脸模型
|
||||
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
DetectionResponse detectedResult = faceModel.detect("src/main/resources/largest_selfie.jpg");
|
||||
log.info("人脸检测结果:{}", JSONObject.toJSONString(detectedResult));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 人脸检测并绘制人脸框
|
||||
*/
|
||||
@Test
|
||||
public void testFaceDetectAndDraw(){
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);//人脸模型
|
||||
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
faceModel.detectAndDraw("src/main/resources/largest_selfie.jpg","output/largest_selfie_detected.png");
|
||||
}
|
||||
|
||||
/**
|
||||
* 人脸检测并绘制人脸框,返回BufferedImage
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testFaceDetectAndDraw2(){
|
||||
try {
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);//人脸模型
|
||||
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
BufferedImage image = null;
|
||||
String imagePath = "src/main/resources/largest_selfie.jpg";
|
||||
image = ImageIO.read(new File(Paths.get(imagePath).toAbsolutePath().toString()));
|
||||
//可以根据后续业务场景使用detectedImage
|
||||
BufferedImage detectedImage = faceModel.detectAndDraw(image);
|
||||
Assert.assertNotNull("detectedImage null", detectedImage);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 提取人脸特征(支持多人脸)
|
||||
* 自动裁剪人脸 + 人脸对齐
|
||||
* 提取人脸特征(多人脸场景)
|
||||
* 默认使用SEETA_FACE6_MODEL自己的检测模型
|
||||
* 注意事项:
|
||||
* 1、首次调用接口,可能会较慢。只要不关闭程序,后续调用会明显加快。若每次重启程序,则每次首次调用都将重新加载,仍会较慢。
|
||||
*/
|
||||
@Test
|
||||
public void testExtractFeatures(){
|
||||
try {
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(new FaceModelConfig(FaceModelEnum.SEETA_FACE6_MODEL,
|
||||
"C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models"));
|
||||
List<float[]> faceResult = faceModel.extractFeatures("src/main/resources/kana1.jpg");
|
||||
log.info("人脸特征提取结果:{}", JSONObject.toJSONString(faceResult));
|
||||
//人脸特征提取模型
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
//指定模型
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);
|
||||
//指定模型路径:请根据实际情况替换为本地模型文件的绝对路径(模型下载地址请查看文档)
|
||||
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
//提取图片中所有人脸特征
|
||||
R<DetectionResponse> faceResult = faceModel.extractFeatures("src/main/resources/face/iu_1.jpg");
|
||||
if(faceResult.isSuccess()){
|
||||
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(faceResult.getData()));
|
||||
}else{
|
||||
log.info("人脸特征提取失败:{}", faceResult.getMessage());
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 提取人脸特征(分数最高人脸)
|
||||
* 自动裁剪人脸 + 人脸对齐
|
||||
* 提取人脸特征(只提取图片中分数最高人脸特征)
|
||||
* 默认使用SEETA_FACE6_MODEL自己的检测模型
|
||||
* 注意事项:
|
||||
* 1、首次调用接口,可能会较慢。只要不关闭程序,后续调用会明显加快。若每次重启程序,则每次首次调用都将重新加载,仍会较慢。
|
||||
*/
|
||||
@Test
|
||||
public void testExtractTopFaceFeature(){
|
||||
public void testExtractFeatures2(){
|
||||
try {
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(new FaceModelConfig(FaceModelEnum.SEETA_FACE6_MODEL,
|
||||
"C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models"));
|
||||
float[] faceResult = faceModel.extractTopFaceFeature("src/main/resources/kana1.jpg");
|
||||
log.info("人脸特征提取结果:{}", JSONObject.toJSONString(faceResult));
|
||||
//人脸特征提取模型
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
//指定模型
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);
|
||||
//指定模型路径:请根据实际情况替换为本地模型文件的绝对路径(模型下载地址请查看文档)
|
||||
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
//提取图片中检测分数最高人脸特征
|
||||
R<float[]> faceResult = faceModel.extractTopFaceFeature("src/main/resources/face/iu_1.jpg");
|
||||
if(faceResult.isSuccess()){
|
||||
log.info("人脸特征提取成功:{}", faceResult.getData());
|
||||
}else{
|
||||
log.info("人脸特征提取失败:{}", faceResult.getMessage());
|
||||
}
|
||||
}catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -117,20 +101,66 @@ public class SeetaFace6Demo {
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 人脸比对(1:1)
|
||||
* 图片参数:图片路径
|
||||
* 人脸比对1:1(基于图像直接比对)
|
||||
* 流程:从输入图像中裁剪分数最高的人脸 → 提取其人脸特征 → 比对两张图片中提取的人脸特征。(接口内自动完成)
|
||||
* 注意事项:
|
||||
* 1、首次调用接口,可能会较慢。只要不关闭程序,后续调用会明显加快。若每次重启程序,则每次首次调用都将重新加载,仍会较慢。
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void featureComparison(){
|
||||
try {
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);//人脸模型
|
||||
//指定模型
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);
|
||||
//指定模型路径:请根据实际情况替换为本地模型文件的绝对路径(模型下载地址请查看文档)
|
||||
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
//自动裁剪人脸并比对人脸特征
|
||||
float similar = faceModel.featureComparison("src/main/resources/kana1.jpg","src/main/resources/kana2.jpg");
|
||||
//基于图像直接比对人脸特征
|
||||
float similar = faceModel.featureComparison("src/main/resources/face/iu_1.jpg","src/main/resources/face/iu_2.jpg");
|
||||
log.info("相似度:{}", similar);
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 人脸比对1:1(基于特征值比对)
|
||||
* 流程:从输入图像中裁剪分数最高的人脸 → 提取其人脸特征 → 比对两张图片中提取的人脸特征。
|
||||
* 注意事项:
|
||||
* 1、首次调用接口,可能会较慢。只要不关闭程序,后续调用会明显加快。若每次重启程序,则每次首次调用都将重新加载,仍会较慢。
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void featureComparison2(){
|
||||
try {
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
//指定模型
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);
|
||||
//指定模型路径:请根据实际情况替换为本地模型文件的绝对路径(模型下载地址请查看文档)
|
||||
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
//特征提取(提取分数最高人脸特征),适用于单人脸场景
|
||||
R<float[]> featureResult1 = faceModel.extractTopFaceFeature("src/main/resources/face/iu_1.jpg");
|
||||
if(featureResult1.isSuccess()){
|
||||
log.info("图片1人脸特征提取成功:{}", JSONObject.toJSONString(featureResult1.getData()));
|
||||
}else{
|
||||
log.info("图片1人脸特征提取失败:{}", featureResult1.getMessage());
|
||||
return;
|
||||
}
|
||||
//特征提取(提取分数最高人脸特征),适用于单人脸场景
|
||||
R<float[]> featureResult2 = faceModel.extractTopFaceFeature("src/main/resources/face/iu_2.jpg");
|
||||
if(featureResult2.isSuccess()){
|
||||
log.info("图片2人脸特征提取成功:{}", JSONObject.toJSONString(featureResult2.getData()));
|
||||
}else{
|
||||
log.info("图片2人脸特征提取失败:{}", featureResult2.getMessage());
|
||||
return;
|
||||
}
|
||||
//计算相似度
|
||||
float similar = faceModel.calculSimilar(featureResult1.getData(), featureResult2.getData());
|
||||
log.info("相似度:{}", similar);
|
||||
}
|
||||
catch (Exception e){
|
||||
@@ -140,81 +170,90 @@ public class SeetaFace6Demo {
|
||||
|
||||
|
||||
/**
|
||||
* 人脸比对(1:1)
|
||||
* 先特征提取,后比对人脸特征
|
||||
* 提取人脸特征图片参数:图片路径
|
||||
*/
|
||||
@Test
|
||||
public void featureExtractionAndCompare(){
|
||||
try {
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);//人脸模型
|
||||
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
//提取图像中最大人脸的特征
|
||||
float[] feature1 = faceModel.extractTopFaceFeature("src/main/resources/kana1.jpg");
|
||||
float[] feature2 = faceModel.extractTopFaceFeature("src/main/resources/kana2.jpg");
|
||||
if(feature1 != null && feature2 != null){
|
||||
float similar = faceModel.calculSimilar(feature1, feature2);
|
||||
log.info("相似度:{}", similar);
|
||||
}else{
|
||||
log.warn("人脸特征提取失败");
|
||||
}
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 注册人脸
|
||||
* 图片参数:图片路径
|
||||
*/
|
||||
@Test
|
||||
public void registerFace(){
|
||||
try {
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);//人脸模型
|
||||
//人脸库路径,从项目中 db/faces-data.db下载到本地
|
||||
config.setFaceDbPath("C:/Users/Administrator/Downloads/faces-data.db");
|
||||
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
//等待人脸库加载完毕
|
||||
Thread.sleep(1000);
|
||||
//注册kana1人脸,参数key建议设置为人名
|
||||
boolean isSuccss = faceModel.register("kana1","src/main/resources/kana1.jpg");
|
||||
log.info("注册结果:{}", isSuccss);
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 搜索人脸(1:N)
|
||||
* 图片参数:图片路径
|
||||
* 注意事项:请先注册人脸
|
||||
* 人脸注册 + 人脸更新 + 人脸查询 + 人脸删除(使用向量数据库Milvus)
|
||||
* 流程:从输入图像中裁剪分数最高的人脸 → 提取其人脸特征 → 注册人脸
|
||||
* 注意事项:
|
||||
* 1、首次调用接口,可能会较慢。只要不关闭程序,后续调用会明显加快。若每次重启程序,则每次首次调用都将重新加载,仍会较慢。
|
||||
* 2、若人脸朝向较正,可关闭人脸对齐以提升性能。(方法参考自定义配置人脸特征提取)
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void searchFace(){
|
||||
try {
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);//人脸模型
|
||||
//人脸库路径,从项目中 db/faces-data.db下载到本地
|
||||
config.setFaceDbPath("C:/Users/Administrator/Downloads/faces-data.db");
|
||||
//人脸模型
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);
|
||||
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
|
||||
//初始化向量数据库:Milvus数据库配置
|
||||
MilvusConfig vectorDBConfig = new MilvusConfig();
|
||||
vectorDBConfig.setHost("127.0.0.1");
|
||||
vectorDBConfig.setPort(19530);
|
||||
//vectorDBConfig.setCollectionName("face10");
|
||||
//ID策略:自动生成
|
||||
vectorDBConfig.setIdStrategy(IdStrategy.AUTO);
|
||||
//索引类型:内积 (Inner Product) 不建议修改
|
||||
vectorDBConfig.setMetricType(MetricType.COSINE);
|
||||
config.setVectorDBConfig(vectorDBConfig);
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
//等待人脸库加载完毕
|
||||
Thread.sleep(1000);
|
||||
FaceResult faceResult = faceModel.search("src/main/resources/kana1.jpg");
|
||||
if(faceResult != null){
|
||||
log.info("查询到人脸:{}", faceResult.toString());
|
||||
}else{
|
||||
log.info("未查询到人脸");
|
||||
|
||||
//等待加载人脸库结束
|
||||
while (!faceModel.isLoadFaceCompleted()) {
|
||||
Thread.sleep(50); // 避免 CPU 占用过高
|
||||
}
|
||||
|
||||
log.info("====================人脸注册==========================");
|
||||
//特征提取(提取分数最高人脸特征),适用于单人脸场景
|
||||
R<float[]> featureResult = faceModel.extractTopFaceFeature("src/main/resources/face/iu_1.jpg");
|
||||
if(featureResult.isSuccess()){
|
||||
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(featureResult.getData()));
|
||||
}else{
|
||||
log.info("人脸特征提取失败:{}", featureResult.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
//人脸注册信息
|
||||
FaceRegisterInfo faceRegisterInfo = new FaceRegisterInfo();
|
||||
//设置人脸注册的自定义元数据,本例中使用 JSON 格式存储用户信息
|
||||
JSONObject metadataJson = new JSONObject();
|
||||
metadataJson.put("name", "iu");
|
||||
metadataJson.put("age", "25");
|
||||
faceRegisterInfo.setMetadata(metadataJson.toJSONString());
|
||||
//人脸注册,返回人脸库ID
|
||||
R<String> registerResult = faceModel.register(faceRegisterInfo, featureResult.getData());
|
||||
if(registerResult.isSuccess()){
|
||||
log.info("注册成功:ID-{}", registerResult.getData());
|
||||
}else{
|
||||
log.info("注册失败:{}", registerResult.getMessage());
|
||||
}
|
||||
/*log.info("====================人脸更新==========================");
|
||||
//更新人脸 只支持自定义ID:vectorDBConfig.setIdStrategy(IdStrategy.CUSTOM);
|
||||
FaceRegisterInfo updateInfo = new FaceRegisterInfo();
|
||||
//设置人脸注册的自定义元数据,本例中使用 JSON 格式存储用户信息
|
||||
JSONObject metadataJsonUpdate = new JSONObject();
|
||||
metadataJsonUpdate.put("name", "iu_update");
|
||||
metadataJsonUpdate.put("age", "25");
|
||||
updateInfo.setMetadata(metadataJsonUpdate.toJSONString());
|
||||
//更新必须设置ID,只有
|
||||
updateInfo.setId(registerResult.getData());
|
||||
faceModel.upsertFace(updateInfo, "src/main/resources/face/iu_2.jpg");
|
||||
log.info("更新人脸成功");*/
|
||||
log.info("====================人脸查询==========================");
|
||||
//特征提取(提取分数最高人脸特征),适用于单人脸场景
|
||||
R<float[]> featureResult2 = faceModel.extractTopFaceFeature("src/main/resources/face/iu_2.jpg");
|
||||
if(featureResult2.isSuccess()){
|
||||
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(featureResult2.getData()));
|
||||
}else{
|
||||
log.info("人脸特征提取失败:{}", featureResult2.getMessage());
|
||||
return;
|
||||
}
|
||||
FaceSearchParams faceSearchParams = new FaceSearchParams();
|
||||
faceSearchParams.setTopK(1);
|
||||
faceSearchParams.setThreshold(0.8f);
|
||||
List<FaceSearchResult> faceSearchResults = faceModel.search(featureResult2.getData(), faceSearchParams);
|
||||
log.info("人脸查询结果:{}", JSONArray.toJSONString(faceSearchResults));
|
||||
log.info("====================人脸删除==========================");
|
||||
faceModel.removeRegister(registerResult.getData());
|
||||
log.info("人脸删除成功");
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
@@ -222,25 +261,80 @@ public class SeetaFace6Demo {
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除已注册人脸
|
||||
* 注意事项:请先注册人脸
|
||||
* 人脸注册 + 人脸更新 + 人脸查询 + 人脸删除(使用轻量数据库SQLite)
|
||||
* 流程:从输入图像中裁剪分数最高的人脸 → 提取其人脸特征 → 注册人脸
|
||||
* 注意事项:
|
||||
* 1、首次调用接口,可能会较慢。只要不关闭程序,后续调用会明显加快。若每次重启程序,则每次首次调用都将重新加载,仍会较慢。
|
||||
* 2、若人脸朝向较正,可关闭人脸对齐以提升性能。(方法参考自定义配置人脸特征提取)
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void removeRegisterFace(){
|
||||
public void searchFace2(){
|
||||
try {
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);//人脸模型
|
||||
//人脸库路径,从项目中 db/faces-data.db下载到本地
|
||||
config.setFaceDbPath("C:/Users/Administrator/Downloads/faces-data.db");
|
||||
//人脸模型
|
||||
config.setModelEnum(FaceModelEnum.SEETA_FACE6_MODEL);
|
||||
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
|
||||
//使用轻量数据库SQLite
|
||||
config.setVectorDBConfig(new SQLiteConfig());
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config);
|
||||
//等待人脸库加载完毕
|
||||
Thread.sleep(1000);
|
||||
//使用注册人脸时的key值删除,可一次性删除单个
|
||||
long num = faceModel.removeRegister("kana1");
|
||||
//删除全部人脸
|
||||
//long num = currentAlgorithm.clearFace();
|
||||
log.info("删除成功数量:" + num);
|
||||
log.info("====================人脸注册==========================");
|
||||
//特征提取(提取分数最高人脸特征),适用于单人脸场景
|
||||
R<float[]> featureResult = faceModel.extractTopFaceFeature("src/main/resources/face/iu_1.jpg");
|
||||
if(featureResult.isSuccess()){
|
||||
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(featureResult.getData()));
|
||||
}else{
|
||||
log.info("人脸特征提取失败:{}", featureResult.getMessage());
|
||||
return;
|
||||
}
|
||||
//人脸注册信息
|
||||
FaceRegisterInfo faceRegisterInfo = new FaceRegisterInfo();
|
||||
//设置人脸注册的自定义元数据,本例中使用 JSON 格式存储用户信息
|
||||
JSONObject metadataJson = new JSONObject();
|
||||
metadataJson.put("name", "iu");
|
||||
metadataJson.put("age", "25");
|
||||
faceRegisterInfo.setMetadata(metadataJson.toJSONString());
|
||||
//可自定义 ID,若未设置则自动生成。
|
||||
//faceRegisterInfo.setId("00001");
|
||||
//人脸注册,返回人脸库ID
|
||||
R<String> registerResult = faceModel.register(faceRegisterInfo, featureResult.getData());
|
||||
if(registerResult.isSuccess()){
|
||||
log.info("注册成功:ID-{}", registerResult.getData());
|
||||
}else{
|
||||
log.info("注册失败:{}", registerResult.getMessage());
|
||||
}
|
||||
log.info("====================人脸更新==========================");
|
||||
FaceRegisterInfo updateInfo = new FaceRegisterInfo();
|
||||
//设置人脸注册的自定义元数据,本例中使用 JSON 格式存储用户信息
|
||||
JSONObject metadataJsonUpdate = new JSONObject();
|
||||
metadataJsonUpdate.put("name", "iu_update");
|
||||
metadataJsonUpdate.put("age", "25");
|
||||
updateInfo.setMetadata(metadataJsonUpdate.toJSONString());
|
||||
//更新必须设置ID,只有
|
||||
updateInfo.setId(registerResult.getData());
|
||||
faceModel.upsertFace(updateInfo, "src/main/resources/face/iu_2.jpg");
|
||||
log.info("更新人脸成功");
|
||||
log.info("====================人脸查询==========================");
|
||||
//特征提取(提取分数最高人脸特征),适用于单人脸场景
|
||||
R<float[]> featureResult2 = faceModel.extractTopFaceFeature("src/main/resources/face/iu_3.jpg");
|
||||
if(featureResult2.isSuccess()){
|
||||
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(featureResult2.getData()));
|
||||
}else{
|
||||
log.info("人脸特征提取失败:{}", featureResult2.getMessage());
|
||||
return;
|
||||
}
|
||||
FaceSearchParams faceSearchParams = new FaceSearchParams();
|
||||
faceSearchParams.setTopK(1);
|
||||
faceSearchParams.setThreshold(0.62f);
|
||||
//等待加载人脸库结束
|
||||
while (!faceModel.isLoadFaceCompleted()) {
|
||||
Thread.sleep(50); // 避免 CPU 占用过高
|
||||
}
|
||||
List<FaceSearchResult> faceSearchResults = faceModel.search(featureResult2.getData(), faceSearchParams);
|
||||
log.info("人脸查询结果:{}", JSONArray.toJSONString(faceSearchResults));
|
||||
log.info("====================人脸删除==========================");
|
||||
faceModel.removeRegister(registerResult.getData());
|
||||
log.info("人脸删除成功");
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
@@ -248,4 +342,5 @@ public class SeetaFace6Demo {
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public class OcrDetectionDemo {
|
||||
//指定检测模型
|
||||
config.setModelEnum(CommonDetModelEnum.PADDLEOCR_V5_DET_MODEL);
|
||||
//指定模型位置,需要更改为自己的模型路径(下载地址请查看文档)
|
||||
config.setDetModelPath("/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
|
||||
config.setDetModelPath("/Users/wenjie/Documents/develop/ocr模型/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
|
||||
OcrCommonDetModel model = OcrModelFactory.getInstance().getDetModel(config);
|
||||
List<OcrBox> boxes = model.detect("src/main/resources/ocr_1.jpg");
|
||||
log.info("OCR检测结果:{}", JSONObject.toJSONString(boxes));
|
||||
|
||||
@@ -37,11 +37,11 @@ public class OcrDirectionDetDemo {
|
||||
//指定检测模型
|
||||
directionModelConfig.setDetModelEnum(CommonDetModelEnum.PADDLEOCR_V5_DET_MODEL);
|
||||
//指定检测模型位置,需要更改为自己的模型路径(下载地址请查看文档)
|
||||
directionModelConfig.setDetModelPath("/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
|
||||
directionModelConfig.setDetModelPath("/Users/wenjie/Documents/develop/ocr模型/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
|
||||
//指定文本方向检测模型
|
||||
directionModelConfig.setModelEnum(DirectionModelEnum.CH_PPOCR_MOBILE_V2_CLS);
|
||||
//指定文本方向检测模型路径,需要更改为自己的模型路径(下载地址请查看文档)
|
||||
directionModelConfig.setModelPath("/cls/ch_ppocr_mobile_v2.0_cls.onnx");
|
||||
directionModelConfig.setModelPath("/Users/wenjie/Documents/develop/ocr模型/ch_ppocr_mobile_v2.0_cls.onnx");
|
||||
OcrDirectionModel directionModel = OcrModelFactory.getInstance().getDirectionModel(directionModelConfig);
|
||||
List<OcrItem> itemList = directionModel.detect("src/main/resources/ocr_3.jpg");
|
||||
log.info("OCR方向检测结果:{}", JSONObject.toJSONString(itemList));
|
||||
|
||||
@@ -27,8 +27,7 @@ public class OcrRecognizeDemo {
|
||||
|
||||
/**
|
||||
* 文本识别
|
||||
* 本方法支持旋转角度范围为 -90 到 90 度的文字
|
||||
* 同时兼容印刷体和手写体文字。
|
||||
* 支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字
|
||||
* 流程:文本检测 -> 文本识别
|
||||
* 模型需要放在单独文件夹
|
||||
*/
|
||||
@@ -38,21 +37,20 @@ public class OcrRecognizeDemo {
|
||||
//指定检测模型
|
||||
recModelConfig.setDetModelEnum(CommonDetModelEnum.PADDLEOCR_V5_DET_MODEL);
|
||||
//指定检测模型位置,需要更改为自己的模型路径(下载地址请查看文档)
|
||||
recModelConfig.setDetModelPath("/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
|
||||
recModelConfig.setDetModelPath("/Users/wenjie/Documents/develop/ocr模型/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
|
||||
//指定识别模型
|
||||
recModelConfig.setRecModelEnum(CommonRecModelEnum.PADDLEOCR_V5_REC_MODEL);
|
||||
//指定识别模型位置,需要更改为自己的模型路径(下载地址请查看文档)
|
||||
recModelConfig.setRecModelPath("/PP-OCRv5_server_rec_infer/PP-OCRv5_server_rec.onnx");
|
||||
recModelConfig.setRecModelPath("/Users/wenjie/Documents/develop/ocr模型/PP-OCRv5_server_rec_infer/PP-OCRv5_server_rec.onnx");
|
||||
OcrCommonRecModel recModel = OcrModelFactory.getInstance().getRecModel(recModelConfig);
|
||||
OcrInfo ocrInfo = recModel.recognize("src/main/resources/general_ocr_002.png");
|
||||
OcrInfo ocrInfo = recModel.recognize("src/main/resources/ocr_1.jpg");
|
||||
log.info("OCR识别结果:{}", JSONObject.toJSONString(ocrInfo));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 文本识别(手写字)
|
||||
* 本方法支持旋转角度范围为 -90 到 90 度的文字
|
||||
* 同时兼容印刷体和手写体文字。
|
||||
* 支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字
|
||||
* 流程:文本检测 -> 文本识别
|
||||
* 模型需要放在单独文件夹
|
||||
*/
|
||||
@@ -74,8 +72,8 @@ public class OcrRecognizeDemo {
|
||||
|
||||
/**
|
||||
* 文本识别(带方向矫正)
|
||||
* 本方法支持任意角度文字识别
|
||||
* 同时兼容印刷体和手写体文字。
|
||||
* 支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字
|
||||
* 本方法支持多角度文字识别
|
||||
* 流程:文本检测 -> 方向检测 -> 方向矫正 -> 文本识别
|
||||
* 模型需要放在单独文件夹
|
||||
*/
|
||||
@@ -103,8 +101,7 @@ public class OcrRecognizeDemo {
|
||||
|
||||
/**
|
||||
* 文本识别并绘制结果
|
||||
* 本方法支持旋转角度范围为 -90 到 90 度的文字
|
||||
* 同时兼容印刷体和手写体文字。
|
||||
* 支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字
|
||||
* 流程:文本检测 -> 文本识别
|
||||
* 模型需要放在单独文件夹
|
||||
*/
|
||||
@@ -114,16 +111,19 @@ public class OcrRecognizeDemo {
|
||||
//指定检测模型
|
||||
recModelConfig.setDetModelEnum(CommonDetModelEnum.PADDLEOCR_V5_DET_MODEL);
|
||||
//指定检测模型位置,需要更改为自己的模型路径(下载地址请查看文档)
|
||||
recModelConfig.setDetModelPath("/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
|
||||
recModelConfig.setDetModelPath("/Users/wenjie/Documents/develop/ocr模型/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
|
||||
//指定识别模型
|
||||
recModelConfig.setRecModelEnum(CommonRecModelEnum.PADDLEOCR_V5_REC_MODEL);
|
||||
//directionModelConfig.setDirectionModelEnum(DirectionModelEnum.CH_PPOCR_MOBILE_V2_CLS);
|
||||
//指定识别模型位置,需要更改为自己的模型路径(下载地址请查看文档)
|
||||
recModelConfig.setRecModelPath("/PP-OCRv5_server_rec_infer/PP-OCRv5_server_rec.onnx");
|
||||
//directionModelConfig.setDirectionModelPath("/Users/wenjie/Documents/develop/ocr模型/ch_ppocr_mobile_v2.0_cls.onnx");
|
||||
recModelConfig.setRecModelPath("/Users/wenjie/Documents/develop/ocr模型/PP-OCRv5_server_rec_infer/PP-OCRv5_server_rec.onnx");
|
||||
//指定方向检测模型
|
||||
recModelConfig.setDirectionModelEnum(DirectionModelEnum.CH_PPOCR_MOBILE_V2_CLS);
|
||||
//指定方向模型位置,需要更改为自己的模型路径(下载地址请查看文档)
|
||||
recModelConfig.setDirectionModelPath("/Users/wenjie/Documents/develop/ocr模型/ch_ppocr_mobile_v2.0_cls.onnx");
|
||||
OcrCommonRecModel recModel = OcrModelFactory.getInstance().getRecModel(recModelConfig);
|
||||
int fontSize = 20;
|
||||
recModel.recognizeAndDraw("src/main/resources/general_ocr_002.png", "output/general_ocr_002_recognized.png", fontSize);
|
||||
int fontSize = 25;
|
||||
recModel.recognizeAndDraw("src/main/resources/ocr_4.jpg", "output/ocr_4_recognized.jpg", fontSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
BIN
examples/src/main/resources/face/iu_1.jpg
Normal file
BIN
examples/src/main/resources/face/iu_1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
BIN
examples/src/main/resources/face/iu_2.jpg
Normal file
BIN
examples/src/main/resources/face/iu_2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
BIN
examples/src/main/resources/face/iu_3.jpg
Normal file
BIN
examples/src/main/resources/face/iu_3.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 123 KiB |
Reference in New Issue
Block a user