【人脸识别】 新增多种人脸识别模型

【底层优化】 支持自由选择 OpenCV 或 BufferedImage 作为图像引擎

【通用图像】 全部模型启用 Image 输入,支持各类图片格式与 Image 的互转

【模型管理】 优化模型生命周期,关闭后可重新创建

【人脸识别】 支持在人脸查询结果中绘制姓名标注

【人脸检测】 新增人脸裁剪功能

【修复】 修复若干已知问题,提升系统稳定性
This commit is contained in:
dengwenjie
2025-10-02 16:26:42 +08:00
parent 1b50e2b943
commit dfa8cf9bb4
133 changed files with 6635 additions and 3532 deletions

View File

@@ -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.24</smartjavaai.version>
<smartjavaai.version>1.0.25</smartjavaai.version>
<!--如果打包运行需要替换成你的main-->
<exec.mainClass>smartai.examples.face.facedet.FaceDetDemo</exec.mainClass>
@@ -220,35 +220,6 @@
<!-- linux aarch64 平台 (保留对应平台的配置,可以减小包大小)-->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>${javacv.version}</version>
<classifier>${javacv.platform.linux-arm64}</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>6.1.1-1.5.10</version>
<classifier>${javacv.platform.linux-arm64}</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>openblas</artifactId>
<version>0.3.26-1.5.10</version>
<classifier>${javacv.platform.linux-arm64}</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv</artifactId>
<version>4.9.0-1.5.10</version>
<classifier>${javacv.platform.linux-arm64}</classifier>
</dependency>
</dependencies>
@@ -278,7 +249,21 @@
</plugins>
</build>
<repositories>
<!-- <repository>-->
<!-- <id>aliyunmaven</id>-->
<!-- <name>阿里云公共仓库</name>-->
<!-- <url>https://maven.aliyun.com/repository/public</url>-->
<!-- <releases>-->
<!-- <enabled>true</enabled>-->
<!-- </releases>-->
<!-- <snapshots>-->
<!-- <enabled>false</enabled>-->
<!-- </snapshots>-->
<!-- </repository>-->
<repository>
<id>central</id>
<url>https://repo1.maven.org/maven2/</url>

View File

@@ -1,11 +1,14 @@
package smartai.examples.face.attribute;
import ai.djl.modality.cv.Image;
import cn.smartjavaai.common.config.Config;
import cn.smartjavaai.common.cv.SmartImageFactory;
import cn.smartjavaai.common.entity.DetectionInfo;
import cn.smartjavaai.common.entity.DetectionResponse;
import cn.smartjavaai.common.entity.R;
import cn.smartjavaai.common.entity.face.FaceAttribute;
import cn.smartjavaai.common.entity.face.FaceInfo;
import cn.smartjavaai.common.utils.ImageUtils;
import cn.smartjavaai.face.config.FaceAttributeConfig;
import cn.smartjavaai.face.config.FaceDetConfig;
import cn.smartjavaai.face.enums.FaceAttributeModelEnum;
@@ -38,6 +41,8 @@ public class FaceAttributeDetDemo {
@BeforeClass
public static void beforeAll() throws IOException {
//将图片处理的底层引擎切换为 OpenCV
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -47,13 +52,13 @@ public class FaceAttributeDetDemo {
FaceAttributeConfig config = new FaceAttributeConfig();
config.setModelEnum(FaceAttributeModelEnum.SEETA_FACE6_MODEL);
//需替换为实际模型存储路径
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
config.setModelPath("C:/Users/DengWenJie/Downloads/sf3.0_models/sf3.0_models");
return FaceAttributeModelFactory.getInstance().getModel(config);
}
public FaceDetModel getFaceDetModel() {
//需替换为实际模型存储路径
String modelPath = "C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models";
String modelPath = "C:/Users/DengWenJie/Downloads/sf3.0_models/sf3.0_models";
FaceDetConfig faceDetectModelConfig = new FaceDetConfig();
faceDetectModelConfig.setModelEnum(FaceDetModelEnum.SEETA_FACE6_MODEL);
faceDetectModelConfig.setModelPath(modelPath);
@@ -68,10 +73,12 @@ public class FaceAttributeDetDemo {
public void testFaceAttributeDetect(){
try {
FaceAttributeModel faceAttributeModel = getFaceAttributeModel();
DetectionResponse detectionResponse = faceAttributeModel.detect("src/main/resources/iu_1.jpg");
////创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
DetectionResponse detectionResponse = faceAttributeModel.detect(image);
//绘制并导出人脸属性图片,小人脸仅有人脸框
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/iu_1.jpg").toAbsolutePath().toString()));
FaceUtils.drawBoxesWithFaceAttribute(image, detectionResponse,"C:/Users/Administrator/Downloads/double_person_.png");
BufferedImage bufferedImage = ImageUtils.toBufferedImage(image);
FaceUtils.drawBoxesWithFaceAttribute(bufferedImage, detectionResponse,"C:/Users/Administrator/Downloads/double_person_.png");
log.info("人脸属性检测结果:{}", JSONObject.toJSONString(detectionResponse));
} catch (Exception e) {
e.printStackTrace();
@@ -85,7 +92,9 @@ public class FaceAttributeDetDemo {
public void testFaceAttributeDetect2(){
try {
FaceAttributeModel faceAttributeModel = getFaceAttributeModel();
FaceAttribute faceAttribute = faceAttributeModel.detectTopFace("src/main/resources/iu_1.jpg");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
FaceAttribute faceAttribute = faceAttributeModel.detectTopFace(image);
log.info("人脸属性检测结果:{}", JSONObject.toJSONString(faceAttribute));
} catch (Exception e) {
e.printStackTrace();
@@ -101,8 +110,8 @@ public class FaceAttributeDetDemo {
try {
FaceDetModel faceDetModel = getFaceDetModel();
FaceAttributeModel faceAttributeModel = getFaceAttributeModel();
//人脸检测
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/iu_1.jpg").toAbsolutePath().toString()));
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
R<DetectionResponse> detectionResponse = faceDetModel.detect(image);
if(detectionResponse.isSuccess()){
log.info("人脸检测结果:{}", JSONObject.toJSONString(detectionResponse.getData()));

View File

@@ -3,6 +3,7 @@ package smartai.examples.face.expression;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import cn.smartjavaai.common.config.Config;
import cn.smartjavaai.common.cv.SmartImageFactory;
import cn.smartjavaai.common.entity.DetectionInfo;
import cn.smartjavaai.common.entity.DetectionRectangle;
import cn.smartjavaai.common.entity.DetectionResponse;
@@ -11,6 +12,7 @@ import cn.smartjavaai.common.entity.face.ExpressionResult;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.common.enums.face.FacialExpression;
import cn.smartjavaai.common.enums.face.LivenessStatus;
import cn.smartjavaai.common.utils.BufferedImageUtils;
import cn.smartjavaai.common.utils.ImageUtils;
import cn.smartjavaai.common.utils.OpenCVUtils;
import cn.smartjavaai.face.config.FaceDetConfig;
@@ -60,6 +62,8 @@ public class ExpressionRecDemo {
@BeforeClass
public static void beforeAll() throws IOException {
//将图片处理的底层引擎切换为 OpenCV
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -75,7 +79,7 @@ public class ExpressionRecDemo {
//人脸检测模型SmartJavaAI提供了多种模型选择(更多模型,请查看文档)切换模型需要同时修改modelEnum及modelPath
config.setModelEnum(FaceDetModelEnum.MTCNN);
//下载模型并替换本地路径下载地址https://pan.baidu.com/s/10l22x5fRz_gwLr8EAHa1Jg?pwd=1234 提取码: 1234
config.setModelPath("/Users/wenjie/Documents/develop/face_model");
config.setModelPath("/Users/wenjie/Documents/develop/model/face_model/mtcnn");
//只返回相似度大于该值的人脸,需要根据实际情况调整,分值越大越严格容易漏检,分值越小越宽松容易误识别
config.setConfidenceThreshold(0.5f);
//用于去除重复的人脸框,当两个框的重叠度超过该值时,只保留一个
@@ -106,7 +110,9 @@ public class ExpressionRecDemo {
public void testExpressionDetect() {
try {
ExpressionModel model = getExpressionModel();
R<ExpressionResult> result = model.detectTopFace("src/main/resources/emotion/happy.png");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/emotion/happy.png");
R<ExpressionResult> result = model.detectTopFace(image);
if(result.isSuccess()){
log.info("识别结果:{}", JSONObject.toJSONString(result.getData().getExpression().getDescription()));
}else{
@@ -125,7 +131,9 @@ public class ExpressionRecDemo {
public void testExpressionDetect2() {
try {
ExpressionModel model = getExpressionModel();
R<DetectionResponse> result = model.detect("src/main/resources/emotion/happy.png");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/emotion/happy.png");
R<DetectionResponse> result = model.detect(image);
if(result.isSuccess()){
//log.info("识别结果:{}", JSONObject.toJSONString(result.getData()));
for (DetectionInfo detectionInfo : result.getData().getDetectionInfoList()) {
@@ -149,7 +157,8 @@ public class ExpressionRecDemo {
try {
FaceDetModel faceDetModel = getFaceDetModel();
ExpressionModel model = getExpressionModel();
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/emotion/happy.png").toAbsolutePath().toString()));
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/emotion/happy.png");
R<DetectionResponse> detResult = faceDetModel.detect(image);
if(detResult.isSuccess()){
R<List<ExpressionResult>> result = model.detect(image, detResult.getData());
@@ -178,7 +187,8 @@ public class ExpressionRecDemo {
try {
FaceDetModel faceDetModel = getFaceDetModel();
ExpressionModel model = getExpressionModel();
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/emotion/happy.png").toAbsolutePath().toString()));
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/emotion/happy.png");
R<DetectionResponse> detResult = faceDetModel.detect(image);
if(detResult.isSuccess()){
for (DetectionInfo detectionInfo : detResult.getData().getDetectionInfoList()) {
@@ -204,15 +214,16 @@ public class ExpressionRecDemo {
public void testExpressionDetectAndDraw(){
try {
ExpressionModel model = getExpressionModel();
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/emotion/surprise.png").toAbsolutePath().toString()));
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/emotion/surprise.png");
R<DetectionResponse> result = model.detect(image);
if(result.isSuccess()){
//log.info("识别结果:{}", JSONObject.toJSONString(result.getData()));
for (DetectionInfo detectionInfo : result.getData().getDetectionInfoList()) {
log.info("识别结果:{}", JSONObject.toJSONString(detectionInfo.getFaceInfo().getExpressionResult().getExpression().getDescription()));
ImageUtils.drawImageRectWithText(image, detectionInfo.getDetectionRectangle(), detectionInfo.getFaceInfo().getExpressionResult().getExpression().getDescription(), Color.red);
ImageUtils.drawRectAndText(image, detectionInfo.getDetectionRectangle(), detectionInfo.getFaceInfo().getExpressionResult().getExpression().getDescription());
}
ImageUtils.saveImage(image, "output/detect.jpg");
ImageUtils.save(image, "output/detect.jpg");
}else{
log.info("识别失败:{}", result.getMessage());
}
@@ -225,7 +236,7 @@ public class ExpressionRecDemo {
* 摄像头表情识别
* 注意事项:如果视频比较卡,可以使用轻量的人脸检测模型
*/
@Test
// @Test
public void testExpressionDetectCamera(){
try {
ExpressionModel expressionModel = getExpressionModel();
@@ -264,7 +275,7 @@ public class ExpressionRecDemo {
JOptionPane.showConfirmDialog(null, "Failed to capture image from WebCam.");
}
ViewerFrame frame = new ViewerFrame(width, height);
ImageFactory factory = ImageFactory.getInstance();
SmartImageFactory factory = SmartImageFactory.getInstance();
Size size = new Size(width, height);
while (capture.isOpened()) {
@@ -273,19 +284,18 @@ public class ExpressionRecDemo {
}
Mat resizeImage = new Mat();
Imgproc.resize(image, resizeImage, size);
Image img = factory.fromImage(resizeImage);
BufferedImage bufferedImage = OpenCVUtils.mat2Image(resizeImage);
R<DetectionResponse> detectedResult = expressionModel.detect(bufferedImage);
Image img = factory.fromMat(resizeImage);
R<DetectionResponse> detectedResult = expressionModel.detect(img);
if(!detectedResult.isSuccess()){
log.debug("识别失败:{}", detectedResult.getMessage());
continue;
}
for(DetectionInfo detectionInfo : detectedResult.getData().getDetectionInfoList()){
DetectionRectangle detectionRectangle = detectionInfo.getDetectionRectangle();
String text = detectionInfo.getFaceInfo().getExpressionResult().getExpression().getDescription() + ":" + detectionInfo.getFaceInfo().getExpressionResult().getScore();
ImageUtils.drawImageRectWithText(bufferedImage, detectionRectangle, text, Color.red);
String text = detectionInfo.getFaceInfo().getExpressionResult().getExpression().getLabel() + ":" + detectionInfo.getFaceInfo().getExpressionResult().getScore();
ImageUtils.drawRectAndText(img, detectionRectangle, text);
}
frame.showImage(bufferedImage);
frame.showImage(ImageUtils.toBufferedImage(img));
}
capture.release();

View File

@@ -2,7 +2,9 @@ package smartai.examples.face.facedet;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import ai.djl.util.JsonUtils;
import cn.smartjavaai.common.config.Config;
import cn.smartjavaai.common.cv.SmartImageFactory;
import cn.smartjavaai.common.entity.DetectionInfo;
import cn.smartjavaai.common.entity.DetectionRectangle;
import cn.smartjavaai.common.entity.DetectionResponse;
@@ -17,6 +19,7 @@ import cn.smartjavaai.face.enums.FaceDetModelEnum;
import cn.smartjavaai.face.factory.FaceDetModelFactory;
import cn.smartjavaai.face.model.facedect.FaceDetModel;
import cn.smartjavaai.face.model.liveness.LivenessDetModel;
import cn.smartjavaai.face.utils.FaceUtils;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import nu.pattern.OpenCV;
@@ -51,6 +54,8 @@ public class FaceDetDemo {
@BeforeClass
public static void beforeAll() throws IOException {
//将图片处理的底层引擎切换为 OpenCV
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -67,7 +72,7 @@ public class FaceDetDemo {
//人脸检测模型SmartJavaAI提供了多种模型选择(更多模型,请查看文档)切换模型需要同时修改modelEnum及modelPath
config.setModelEnum(FaceDetModelEnum.MTCNN);
//下载模型并替换本地路径下载地址https://pan.baidu.com/s/10l22x5fRz_gwLr8EAHa1Jg?pwd=1234 提取码: 1234
config.setModelPath("/Users/wenjie/Documents/develop/face_model");
config.setModelPath("/Users/wenjie/Documents/develop/model/face_model/mtcnn");
//只返回相似度大于该值的人脸,需要根据实际情况调整,分值越大越严格容易漏检,分值越小越宽松容易误识别
config.setConfidenceThreshold(0.5f);
//用于去除重复的人脸框,当两个框的重叠度超过该值时,只保留一个
@@ -104,7 +109,7 @@ public class FaceDetDemo {
//人脸检测模型SmartJavaAI提供了多种模型选择(更多模型,请查看文档)切换模型需要同时修改modelEnum及modelPath
config.setModelEnum(FaceDetModelEnum.YOLOV5_FACE_320);
//下载模型并替换本地路径下载地址https://pan.baidu.com/s/10l22x5fRz_gwLr8EAHa1Jg?pwd=1234 提取码: 1234
config.setModelPath("/Users/wenjie/Documents/develop/face_model/yolo-face/yolov5face-n-0.5-320x320.onnx");
config.setModelPath("/Users/wenjie/Documents/develop/model/face_model/yolo-face/yolov5face-n-0.5-320x320.onnx");
//只返回相似度大于该值的人脸,需要根据实际情况调整,分值越大越严格容易漏检,分值越小越宽松容易误识别
config.setConfidenceThreshold(0.5f);
//用于去除重复的人脸框,当两个框的重叠度超过该值时,只保留一个
@@ -137,9 +142,16 @@ public class FaceDetDemo {
public void testFaceDetect(){
try {
FaceDetModel faceModel = getFaceDetModel();
R<DetectionResponse> detectedResult = faceModel.detect(imgPath);
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile(imgPath);
R<DetectionResponse> detectedResult = faceModel.detect(image);
if(detectedResult.isSuccess()){
log.info("人脸检测结果:{}", JSONObject.toJSONString(detectedResult.getData()));
//裁剪人脸保存
for (DetectionInfo detectionInfo : detectedResult.getData().getDetectionInfoList()) {
Image faceImage = FaceUtils.cropFace(image, detectionInfo.getDetectionRectangle());
ImageUtils.save(faceImage, "output/face_" + detectionInfo.getDetectionRectangle().getX() + "_" + detectionInfo.getDetectionRectangle().getY() + ".jpg");
}
}else{
log.info("人脸检测失败:{}", detectedResult.getMessage());
}
@@ -156,7 +168,12 @@ public class FaceDetDemo {
public void testFaceDetectAndDraw(){
try {
FaceDetModel faceModel = getFaceDetModel();
faceModel.detectAndDraw("src/main/resources/largest_selfie.jpg","output/largest_selfie_detected.png");
R<DetectionResponse> detectedResult = faceModel.detectAndDraw("src/main/resources/largest_selfie.jpg","output/largest_selfie_detected.png");
if(detectedResult.isSuccess()){
log.info("人脸检测成功:{}", JsonUtils.toJson(detectedResult.getData()));
}else{
log.info("人脸检测失败:{}", detectedResult.getMessage());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -170,15 +187,14 @@ public class FaceDetDemo {
public void testFaceDetectAndDraw2(){
try {
FaceDetModel faceModel = getFaceDetModel();
BufferedImage image = null;
String imagePath = "src/main/resources/largest_selfie.jpg";
image = ImageIO.read(new File(Paths.get(imagePath).toAbsolutePath().toString()));
//可以根据后续业务场景使用detectedImage
R<BufferedImage> detectedImage = faceModel.detectAndDraw(image);
if(detectedImage.isSuccess()){
log.info("人脸检测成功");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile(imgPath);
R<DetectionResponse> detectionResponseR = faceModel.detectAndDraw(image);
if(detectionResponseR.isSuccess()){
log.info("人脸检测成功:{}", JsonUtils.toJson(detectionResponseR.getData()));
ImageUtils.save(detectionResponseR.getData().getDrawnImage(), "output/iu_1_detect.png");
}else{
log.info("人脸检测失败:{}", detectedImage.getMessage());
log.info("人脸检测失败:{}", detectionResponseR.getMessage());
}
} catch (Exception e) {
throw new RuntimeException(e);
@@ -187,31 +203,6 @@ public class FaceDetDemo {
}
/**
* 人脸检测GPU模式
*/
@Test
public void testDetectFaceGPU(){
try {
FaceDetConfig config = new FaceDetConfig();
//人脸检测模型SmartJavaAI提供了多种模型选择(更多模型,请查看文档)切换模型需要同时修改modelEnum及modelPath
config.setModelEnum(FaceDetModelEnum.MTCNN);
//下载模型并替换本地路径下载地址https://pan.baidu.com/s/10l22x5fRz_gwLr8EAHa1Jg?pwd=1234 提取码: 1234
config.setModelPath("/Users/wenjie/Documents/develop/face_model");
//只返回相似度大于该值的人脸,需要根据实际情况调整,分值越大越严格容易漏检,分值越小越宽松容易误识别
config.setConfidenceThreshold(0.5f);
config.setDevice(DeviceEnum.GPU);
FaceDetModel faceModel = FaceDetModelFactory.getInstance().getModel(config);
R<DetectionResponse> detectedResult = faceModel.detect(imgPath);
if(detectedResult.isSuccess()){
log.info("人脸检测结果:{}", JSONObject.toJSONString(detectedResult.getData()));
}else{
log.info("人脸检测失败:{}", detectedResult.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 人脸检测(Seetaface6)
@@ -221,7 +212,9 @@ public class FaceDetDemo {
public void testFaceDetectSeetaface6(){
try {
FaceDetModel faceModel = getSeetaface6DetModel();
R<DetectionResponse> detectedResult = faceModel.detect(imgPath);
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile(imgPath);
R<DetectionResponse> detectedResult = faceModel.detect(image);
if(detectedResult.isSuccess()){
log.info("人脸检测结果:{}", JSONObject.toJSONString(detectedResult.getData()));
}else{
@@ -276,7 +269,7 @@ public class FaceDetDemo {
JOptionPane.showConfirmDialog(null, "Failed to capture image from WebCam.");
}
ViewerFrame frame = new ViewerFrame(width, height);
ImageFactory factory = ImageFactory.getInstance();
SmartImageFactory factory = SmartImageFactory.getInstance();
Size size = new Size(width, height);
while (capture.isOpened()) {
@@ -285,9 +278,8 @@ public class FaceDetDemo {
}
Mat resizeImage = new Mat();
Imgproc.resize(image, resizeImage, size);
Image img = factory.fromImage(resizeImage);
BufferedImage bufferedImage = OpenCVUtils.mat2Image(resizeImage);
R<DetectionResponse> detectedResult = faceModel.detect(bufferedImage);
Image img = factory.fromMat(resizeImage);
R<DetectionResponse> detectedResult = faceModel.detect(img);
if(!detectedResult.isSuccess()){
log.debug("识别失败:{}", detectedResult.getMessage());
continue;
@@ -298,11 +290,10 @@ public class FaceDetDemo {
if(detectionInfo.getScore() > 0){
text = detectionInfo.getScore() + "";
}
ImageUtils.drawImageRectWithText(bufferedImage, detectionRectangle, text, Color.red);
ImageUtils.drawRectAndText(img, detectionRectangle, text);
}
frame.showImage(bufferedImage);
frame.showImage(ImageUtils.toBufferedImage(img));
}
capture.release();
System.exit(0);
} catch (Exception e) {

View File

@@ -1,10 +1,13 @@
package smartai.examples.face.facerec;
import cn.smartjavaai.common.config.Config;
import ai.djl.modality.cv.Image;
import cn.smartjavaai.common.cv.SmartImageFactory;
import cn.smartjavaai.common.entity.DetectionResponse;
import cn.smartjavaai.common.entity.R;
import cn.smartjavaai.common.entity.face.FaceSearchResult;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.common.utils.BufferedImageUtils;
import cn.smartjavaai.common.utils.ImageUtils;
import cn.smartjavaai.face.config.FaceDetConfig;
import cn.smartjavaai.face.config.FaceRecConfig;
import cn.smartjavaai.face.constant.FaceDetectConstant;
@@ -18,7 +21,6 @@ import cn.smartjavaai.face.factory.FaceDetModelFactory;
import cn.smartjavaai.face.factory.FaceRecModelFactory;
import cn.smartjavaai.face.model.facedect.FaceDetModel;
import cn.smartjavaai.face.model.facerec.FaceRecModel;
import cn.smartjavaai.face.utils.SimilarityUtil;
import cn.smartjavaai.face.vector.config.MilvusConfig;
import cn.smartjavaai.face.vector.config.SQLiteConfig;
import cn.smartjavaai.face.vector.entity.FaceVector;
@@ -28,6 +30,7 @@ import lombok.extern.slf4j.Slf4j;
import org.junit.BeforeClass;
import org.junit.Test;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.List;
@@ -45,6 +48,8 @@ public class FaceRecDemo {
@BeforeClass
public static void beforeAll() throws IOException {
//将图片处理的底层引擎切换为 OpenCV
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -61,7 +66,7 @@ public class FaceRecDemo {
//人脸检测模型SmartJavaAI提供了多种模型选择(更多模型,请查看文档)切换模型需要同时修改modelEnum及modelPath
config.setModelEnum(FaceDetModelEnum.MTCNN);
//下载模型并替换本地路径下载地址https://pan.baidu.com/s/10l22x5fRz_gwLr8EAHa1Jg?pwd=1234 提取码: 1234
config.setModelPath("/Users/wenjie/Documents/develop/face_model");
config.setModelPath("/Users/wenjie/Documents/develop/model/face_model/mtcnn");
//只返回相似度大于该值的人脸,需要根据实际情况调整,分值越大越严格容易漏检,分值越小越宽松容易误识别
config.setConfidenceThreshold(0.5f);
//用于去除重复的人脸框,当两个框的重叠度超过该值时,只保留一个
@@ -116,19 +121,19 @@ public class FaceRecDemo {
* 也可以使用其他模型具体其他模型参数可以查看文档http://doc.smartjavaai.cn/face.html
* @return
*/
public FaceRecModel getHighAccuracyFaceRecModel(){
public FaceRecModel getFaceRecModel(){
FaceRecConfig config = new FaceRecConfig();
//高精度模型,速度慢
config.setModelEnum(FaceRecModelEnum.ELASTIC_FACE_MODEL);
config.setModelEnum(FaceRecModelEnum.INSIGHT_FACE_IRSE50_MODEL);
//模型路径请下载模型并替换为本地路径https://pan.baidu.com/s/10l22x5fRz_gwLr8EAHa1Jg?pwd=1234 提取码: 1234
config.setModelPath("/Users/wenjie/Documents/develop/model/elasticface.pt");
config.setModelPath("/Users/wenjie/Documents/develop/model/face_model/recognition/InsightFace/model_ir_se50.pt");
//裁剪人脸如果图片已经是裁剪过的则请将此参数设置为false
config.setCropFace(true);
//开启人脸对齐:适用于人脸不正的场景,开启将提升人脸特征准确度,关闭可以提升性能
config.setAlign(true);
config.setDevice(device);
//指定人脸检测模型
config.setDetectModel(getProFaceDetModel());
config.setDetectModel(getFaceDetModel());
return FaceRecModelFactory.getInstance().getModel(config);
}
@@ -141,9 +146,9 @@ public class FaceRecDemo {
public FaceRecModel getHighSpeedFaceRecModel(){
FaceRecConfig config = new FaceRecConfig();
//模型枚举
config.setModelEnum(FaceRecModelEnum.SEETA_FACE6_LIGHT_MODEL);
config.setModelEnum(FaceRecModelEnum.INSIGHT_FACE_MOBILE_FACENET_MODEL);
//模型路径请下载模型并替换为本地路径https://pan.baidu.com/s/10l22x5fRz_gwLr8EAHa1Jg?pwd=1234 提取码: 1234
config.setModelPath("/Users/xxx/Documents/develop/model/sf3.0_models");
config.setModelPath("/Users/wenjie/Documents/develop/model/face_model/recognition/InsightFace/model_mobilefacenet.pt");
//裁剪人脸如果图片已经是裁剪过的则请将此参数设置为false
config.setCropFace(true);
//开启人脸对齐:适用于人脸不正的场景,开启将提升人脸特征准确度,关闭可以提升性能
@@ -161,8 +166,9 @@ public class FaceRecDemo {
public FaceRecModel getFaceRecModelWithDbConfig(){
FaceRecConfig config = new FaceRecConfig();
//高精度模型,速度慢,追求速度请更换高速模型具体其他模型参数可以查看文档http://doc.smartjavaai.cn/face.html
config.setModelEnum(FaceRecModelEnum.ELASTIC_FACE_MODEL);//人脸识别模型
config.setModelPath("/Users/xxx/Documents/develop/model/elasticface.pt");
config.setModelEnum(FaceRecModelEnum.INSIGHT_FACE_IRSE50_MODEL);
//模型路径请下载模型并替换为本地路径https://pan.baidu.com/s/10l22x5fRz_gwLr8EAHa1Jg?pwd=1234 提取码: 1234
config.setModelPath("/Users/wenjie/Documents/develop/model/face_model/recognition/InsightFace/model_ir_se50.pt");
//裁剪人脸如果图片已经是裁剪过的则请将此参数设置为false
config.setCropFace(true);
//开启人脸对齐:适用于人脸不正的场景,开启将提升人脸特征准确度,关闭可以提升性能
@@ -175,9 +181,9 @@ public class FaceRecDemo {
MilvusConfig vectorDBConfig = new MilvusConfig();
vectorDBConfig.setHost("127.0.0.1");
vectorDBConfig.setPort(19530);
//vectorDBConfig.setUsername("root");
//vectorDBConfig.setPassword("Milvus");
//vectorDBConfig.setCollectionName("face5");
// vectorDBConfig.setUsername("root");
// vectorDBConfig.setPassword("Milvus");
// vectorDBConfig.setCollectionName("face6");
//ID策略自动生成
vectorDBConfig.setIdStrategy(IdStrategy.AUTO);
//索引类型:内积 (Inner Product) 不建议修改
@@ -193,8 +199,9 @@ public class FaceRecDemo {
public FaceRecModel getFaceRecModelWithSQLiteConfig(){
FaceRecConfig config = new FaceRecConfig();
//高精度模型,速度慢, 追求速度请更换高速模型具体其他模型参数可以查看文档http://doc.smartjavaai.cn/face.html
config.setModelEnum(FaceRecModelEnum.ELASTIC_FACE_MODEL);//人脸检测模型
config.setModelPath("/Users/wenjie/Documents/develop/model/elasticface.pt");
config.setModelEnum(FaceRecModelEnum.INSIGHT_FACE_IRSE50_MODEL);
//模型路径请下载模型并替换为本地路径https://pan.baidu.com/s/10l22x5fRz_gwLr8EAHa1Jg?pwd=1234 提取码: 1234
config.setModelPath("/Users/wenjie/Documents/develop/model/face_model/recognition/InsightFace/model_ir_se50.pt");
//裁剪人脸如果图片已经是裁剪过的则请将此参数设置为false
config.setCropFace(true);
//开启人脸对齐:适用于人脸不正的场景,开启将提升人脸特征准确度,关闭可以提升性能
@@ -221,9 +228,11 @@ public class FaceRecDemo {
public void testExtractFeatures(){
try {
//高精度模型,速度慢, 追求速度请更换高速模型: getHighSpeedFaceRecModel
FaceRecModel faceRecModel = getHighAccuracyFaceRecModel();
FaceRecModel faceRecModel = getFaceRecModel();
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
//提取图片中所有人脸特征
R<DetectionResponse> faceResult = faceRecModel.extractFeatures("src/main/resources/iu_1.jpg");
R<DetectionResponse> faceResult = faceRecModel.extractFeatures(image);
if(faceResult.isSuccess()){
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(faceResult.getData()));
}else{
@@ -246,15 +255,59 @@ public class FaceRecDemo {
public void featureComparison(){
try {
//高精度模型,速度慢, 追求速度请更换高速模型: getHighSpeedFaceRecModel
FaceRecModel faceRecModel = getHighAccuracyFaceRecModel();
FaceRecModel faceRecModel = getFaceRecModel();
//基于图像直接比对人脸特征
R<Float> similarResult = faceRecModel.featureComparison("src/main/resources/iu_1.jpg","src/main/resources/iu_2.jpg");
if(similarResult.isSuccess()){
//相似度阈值不同模型不同,具体参看文档
log.info("人脸比对相似度:{}", JSONObject.toJSONString(similarResult.getData()));
//不同模型的相似度标准不同。当前阈值仅适用于 insight_face 模型,切换模型时请相应调整阈值,详情请参考文档。
if(similarResult.getData() >= 0.62f){
log.info("识别为同一人");
}else{
log.info("识别为不同人");
}
}else{
log.info("人脸比对失败:{}", similarResult.getMessage());
}
}
catch (Exception e){
e.printStackTrace();
}
}
/**
* 人脸比对11基于图像直接比对
* 流程:从输入图像中裁剪分数最高的人脸 → 提取其人脸特征 → 比对两张图片中提取的人脸特征。(接口内自动完成)
* 注意事项:
* 1、首次调用接口可能会较慢。只要不关闭程序后续调用会明显加快。若每次重启程序则每次首次调用都将重新加载仍会较慢。
* 2、若人脸朝向不正可开启人脸对齐以提升特征提取准确度。方法参考自定义配置人脸特征提取
* @throws Exception
*/
@Test
public void featureComparison3(){
try {
//高精度模型,速度慢, 追求速度请更换高速模型: getHighSpeedFaceRecModel
FaceRecModel faceRecModel = getFaceRecModel();
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image1 = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
Image image2 = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_2.jpg");
//基于图像直接比对人脸特征
R<Float> similarResult = faceRecModel.featureComparison(image1, image2);
if(similarResult.isSuccess()){
//相似度阈值不同模型不同,具体参看文档
log.info("人脸比对相似度:{}", JSONObject.toJSONString(similarResult.getData()));
//不同模型的相似度标准不同。当前阈值仅适用于 insight_face 模型,切换模型时请相应调整阈值,详情请参考文档。
if(similarResult.getData() >= 0.62f){
log.info("识别为同一人");
}else{
log.info("识别为不同人");
}
}else{
log.info("人脸比对失败:{}", similarResult.getMessage());
}
}
catch (Exception e){
e.printStackTrace();
@@ -273,9 +326,11 @@ public class FaceRecDemo {
public void featureComparison2(){
try {
//高精度模型,速度慢, 追求速度请更换高速模型: getHighSpeedFaceRecModel
FaceRecModel faceRecModel = getHighAccuracyFaceRecModel();
FaceRecModel faceRecModel = getFaceRecModel();
//特征提取(提取分数最高人脸特征),适用于单人脸场景
R<float[]> featureResult1 = faceRecModel.extractTopFaceFeature("src/main/resources/iu_1.jpg");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image1 = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
R<float[]> featureResult1 = faceRecModel.extractTopFaceFeature(image1);
if(featureResult1.isSuccess()){
log.info("图片1人脸特征提取成功{}", JSONObject.toJSONString(featureResult1.getData()));
}else{
@@ -283,7 +338,8 @@ public class FaceRecDemo {
return;
}
//特征提取(提取分数最高人脸特征),适用于单人脸场景
R<float[]> featureResult2 = faceRecModel.extractTopFaceFeature("src/main/resources/iu_2.jpg");
Image image2 = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_2.jpg");
R<float[]> featureResult2 = faceRecModel.extractTopFaceFeature(image2);
if(featureResult2.isSuccess()){
log.info("图片2人脸特征提取成功{}", JSONObject.toJSONString(featureResult2.getData()));
}else{
@@ -293,6 +349,12 @@ public class FaceRecDemo {
//计算相似度
float similar = faceRecModel.calculSimilar(featureResult1.getData(), featureResult2.getData());
log.info("相似度:{}", similar);
//不同模型的相似度标准不同。当前阈值仅适用于 insight_face 模型,切换模型时请相应调整阈值,详情请参考文档。
if(similar >= 0.62f){
log.info("识别为同一人");
}else{
log.info("识别为不同人");
}
}
catch (Exception e){
e.printStackTrace();
@@ -318,8 +380,10 @@ public class FaceRecDemo {
Thread.sleep(100);
}
log.info("====================人脸注册==========================");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
//特征提取(提取分数最高人脸特征),适用于单人脸场景
R<float[]> featureResult = faceRecModel.extractTopFaceFeature("src/main/resources/iu_1.jpg");
R<float[]> featureResult = faceRecModel.extractTopFaceFeature(image);
if(featureResult.isSuccess()){
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(featureResult.getData()));
}else{
@@ -341,21 +405,23 @@ public class FaceRecDemo {
}else{
log.info("注册失败:{}", registerResult.getMessage());
}
/*log.info("====================人脸更新==========================");
log.info("====================人脸更新==========================");
//更新人脸 只支持自定义IDvectorDBConfig.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());
faceRecModel.upsertFace(updateInfo, "src/main/resources/iu_2.jpg");
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());
// Image image2 = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_2.jpg");
// faceRecModel.upsertFace(updateInfo, image2);
// log.info("更新人脸成功");
log.info("====================人脸查询==========================");
//特征提取(提取分数最高人脸特征),适用于单人脸场景
R<float[]> featureResult2 = faceRecModel.extractTopFaceFeature("src/main/resources/iu_3.jpg");
Image image3 = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_3.jpg");
R<float[]> featureResult2 = faceRecModel.extractTopFaceFeature(image3);
if(featureResult2.isSuccess()){
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(featureResult2.getData()));
}else{
@@ -364,8 +430,7 @@ public class FaceRecDemo {
}
FaceSearchParams faceSearchParams = new FaceSearchParams();
faceSearchParams.setTopK(1);
faceSearchParams.setThreshold(0.8f);
// faceSearchParams.setThreshold(0.62f);
List<FaceSearchResult> faceSearchResults = faceRecModel.search(featureResult2.getData(), faceSearchParams);
// R<DetectionResponse> faceSearchResults = faceModel.search("src/main/resources/face/iu_3.jpg", faceSearchParams);
log.info("人脸查询结果:{}", JSONArray.toJSONString(faceSearchResults));
@@ -397,7 +462,9 @@ public class FaceRecDemo {
}
log.info("====================人脸注册==========================");
//特征提取(提取分数最高人脸特征),适用于单人脸场景
R<float[]> featureResult = faceRecModel.extractTopFaceFeature("src/main/resources/iu_1.jpg");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
R<float[]> featureResult = faceRecModel.extractTopFaceFeature(image);
if(featureResult.isSuccess()){
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(featureResult.getData()));
}else{
@@ -429,11 +496,13 @@ public class FaceRecDemo {
updateInfo.setMetadata(metadataJsonUpdate.toJSONString());
//更新必须设置ID,只有
updateInfo.setId(registerResult.getData());
faceRecModel.upsertFace(updateInfo, "src/main/resources/iu_2.jpg");
Image image2 = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_2.jpg");
faceRecModel.upsertFace(updateInfo, image2);
log.info("更新人脸成功");
log.info("====================人脸查询==========================");
//特征提取(提取分数最高人脸特征),适用于单人脸场景
R<float[]> featureResult2 = faceRecModel.extractTopFaceFeature("src/main/resources/iu_3.jpg");
Image image3 = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_3.jpg");
R<float[]> featureResult2 = faceRecModel.extractTopFaceFeature(image3);
if(featureResult2.isSuccess()){
log.info("人脸特征提取成功:{}", JSONObject.toJSONString(featureResult2.getData()));
}else{
@@ -442,7 +511,7 @@ public class FaceRecDemo {
}
FaceSearchParams faceSearchParams = new FaceSearchParams();
faceSearchParams.setTopK(1);
faceSearchParams.setThreshold(0.8f);
//faceSearchParams.setThreshold(0.62f);
List<FaceSearchResult> faceSearchResults = faceRecModel.search(featureResult2.getData(), faceSearchParams);
log.info("人脸查询结果:{}", JSONArray.toJSONString(faceSearchResults));
log.info("====================人脸删除==========================");
@@ -454,6 +523,57 @@ public class FaceRecDemo {
}
}
/**
* 人脸查询及绘制
*
* @throws Exception
*/
@Test
public void searchFace3(){
try {
//高精度模型,速度慢, 追求速度请更换高速模型
FaceRecModel faceRecModel = getFaceRecModelWithSQLiteConfig();
//等待加载人脸库结束
while (!faceRecModel.isLoadFaceCompleted()){
Thread.sleep(100);
}
log.info("====================人脸注册==========================");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
//人脸注册信息
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 = faceRecModel.register(faceRegisterInfo, image);
if(registerResult.isSuccess()){
log.info("注册成功ID-{}", registerResult.getData());
}else{
log.info("注册失败:{}", registerResult.getMessage());
}
log.info("====================人脸查询==========================");
//特征提取(提取分数最高人脸特征),适用于单人脸场景
Image image3 = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_3.jpg");
FaceSearchParams faceSearchParams = new FaceSearchParams();
faceSearchParams.setTopK(1);
//faceSearchParams.setThreshold(0.62f);
//图片中只会显示Metadata信息中name的字段
Image drawSearchResult = faceRecModel.drawSearchResult(image3, faceSearchParams, "name");
ImageUtils.save(drawSearchResult, "output/search_result.jpg");
log.info("====================人脸删除==========================");
faceRecModel.removeRegister(registerResult.getData());
log.info("人脸删除成功");
}
catch (Exception e){
e.printStackTrace();
}
}
/**
* 获取人脸信息
@@ -486,7 +606,7 @@ public class FaceRecDemo {
public void listFaces(){
//使用ID获取人脸信息
try {
FaceRecModel faceRecModel = getFaceRecModelWithDbConfig();
FaceRecModel faceRecModel = getFaceRecModelWithSQLiteConfig();
//等待加载人脸库结束
while (!faceRecModel.isLoadFaceCompleted()){
Thread.sleep(100);

View File

@@ -4,6 +4,7 @@ import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import cn.hutool.core.lang.UUID;
import cn.smartjavaai.common.config.Config;
import cn.smartjavaai.common.cv.SmartImageFactory;
import cn.smartjavaai.common.entity.DetectionInfo;
import cn.smartjavaai.common.entity.DetectionRectangle;
import cn.smartjavaai.common.entity.DetectionResponse;
@@ -65,6 +66,8 @@ public class LivenessDetDemo {
@BeforeClass
public static void beforeAll() throws IOException {
//将图片处理的底层引擎切换为 OpenCV
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -104,9 +107,9 @@ public class LivenessDetDemo {
config.setModelEnum(LivenessModelEnum.MINI_VISION_MODEL);
config.setDevice(device);
//模型1路径需替换为实际模型存储路径
config.setModelPath("/Users/xxx/Documents/develop/model/live/2.7_80x80_MiniFASNetV2.onnx");
config.setModelPath("/Users/wenjie/Documents/develop/model/live/2.7_80x80_MiniFASNetV2.onnx");
//SE模型路径需替换为实际模型存储路径
config.putCustomParam("seModelPath", "/Users/xxx/Documents/develop/model/live/4_0_0_80x80_MiniFASNetV1SE.onnx");
config.putCustomParam("seModelPath", "/Users/wenjie/Documents/develop/model/live/4_0_0_80x80_MiniFASNetV1SE.onnx");
//人脸活体阈值,可选,超过阈值则认为是真人,低于阈值是非活体
config.setRealityThreshold(0.5f);
/*视频检测帧数可选默认10输出帧数超过这个number之后就可以输出识别结果。
@@ -132,7 +135,7 @@ public class LivenessDetDemo {
//人脸检测模型SmartJavaAI提供了多种模型选择(更多模型,请查看文档)切换模型需要同时修改modelEnum及modelPath
config.setModelEnum(FaceDetModelEnum.MTCNN);
//下载模型并替换本地路径下载地址https://pan.baidu.com/s/10l22x5fRz_gwLr8EAHa1Jg?pwd=1234 提取码: 1234
config.setModelPath("/Users/wenjie/Documents/develop/face_model");
config.setModelPath("/Users/wenjie/Documents/develop/model/face_model/mtcnn");
//只返回相似度大于该值的人脸,需要根据实际情况调整,分值越大越严格容易漏检,分值越小越宽松容易误识别
config.setConfidenceThreshold(0.5f);
//用于去除重复的人脸框,当两个框的重叠度超过该值时,只保留一个
@@ -149,10 +152,12 @@ public class LivenessDetDemo {
public void testLivenessDetect(){
try {
LivenessDetModel livenessDetModel = getLivenessDetModel();
R<DetectionResponse> response = livenessDetModel.detect("src/main/resources/liveness/1.jpg");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/liveness/1.jpg");
R<DetectionResponse> response = livenessDetModel.detect(image);
if(response.isSuccess()){
for (DetectionInfo detectionInfo : response.getData().getDetectionInfoList()){
log.info("活体检测结果:{}", JSONObject.toJSONString(detectionInfo.getFaceInfo().getLivenessStatus().getStatus().getDescription()));
log.info("活体检测结果:{}", JSONObject.toJSONString(detectionInfo));
}
}else{
log.info("活体检测失败:{}", response.getMessage());
@@ -169,18 +174,18 @@ public class LivenessDetDemo {
public void testLivenessDetectAndDraw(){
try {
LivenessDetModel livenessDetModel = getLivenessDetModel();
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/liveness/1.jpg").toAbsolutePath().toString()));
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/liveness/1.jpg");
R<DetectionResponse> response = livenessDetModel.detect(image);
if(response.isSuccess()){
for (DetectionInfo detectionInfo : response.getData().getDetectionInfoList()){
log.info("活体检测结果:{}", JSONObject.toJSONString(detectionInfo.getFaceInfo().getLivenessStatus().getStatus().getDescription()));
Color color = detectionInfo.getFaceInfo().getLivenessStatus().getStatus() == LivenessStatus.LIVE ? Color.GREEN : Color.RED;
ImageUtils.drawImageRectWithText(image, detectionInfo.getDetectionRectangle(), detectionInfo.getFaceInfo().getLivenessStatus().getStatus().getDescription(), color);
ImageUtils.drawRectAndText(image, detectionInfo.getDetectionRectangle(), detectionInfo.getFaceInfo().getLivenessStatus().getStatus().toString());
ImageUtils.save(image, "output/detect.jpg");
}
}else{
log.info("活体检测失败:{}", response.getMessage());
}
ImageUtils.saveImage(image, "output/detect.jpg");
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -194,10 +199,12 @@ public class LivenessDetDemo {
try {
LivenessDetModel livenessDetModel = getLivenessDetModel();
//指定文件夹路径
File dir = new File("face-example/src/main/resources/liveness");
File dir = new File("src/main/resources/liveness");
File[] files = dir.listFiles();
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
SmartImageFactory imageFactory = SmartImageFactory.getInstance();
for (File file : files) {
R<LivenessResult> response = livenessDetModel.detectTopFace(ImageIO.read(file));
R<LivenessResult> response = livenessDetModel.detectTopFace(imageFactory.fromFile(file));
if(response.isSuccess()){
log.info("{}活体检测结果:{},分数:{}", file.getName(), response.getData().getStatus().getDescription(), response.getData().getScore());
}else{
@@ -218,8 +225,8 @@ public class LivenessDetDemo {
try {
FaceDetModel faceDetectModel = getFaceDetModel();
LivenessDetModel livenessDetModel = getLivenessDetModel();
// 将图片路径转换为 BufferedImage
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/liveness/1.jpg").toAbsolutePath().toString()));
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/liveness/1.jpg");
//人脸检测
R<DetectionResponse> detectionResponse = faceDetectModel.detect(image);
if(detectionResponse.isSuccess()){
@@ -251,8 +258,8 @@ public class LivenessDetDemo {
try {
FaceDetModel faceDetModel = getFaceDetModel();
LivenessDetModel livenessDetModel = getMiniVisionLivenessDetModel();
// 将图片路径转换为 BufferedImage
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/liveness/1.jpg").toAbsolutePath().toString()));
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/liveness/1.jpg");
R<DetectionResponse> detResult = faceDetModel.detect(image);
if(detResult.isSuccess()){
for (DetectionInfo detectionInfo : detResult.getData().getDetectionInfoList()) {
@@ -281,7 +288,7 @@ public class LivenessDetDemo {
try {
LivenessDetModel livenessDetModel = getLivenessDetModel();
//视频路径
R<LivenessResult> livenessStatus = livenessDetModel.detectVideo("video.mp4");
R<LivenessResult> livenessStatus = livenessDetModel.detectVideo("/Users/wenjie/Documents/idea_workplace/SmartJavaAI-Demo/src/main/resources/girl.mp4");
if (livenessStatus.isSuccess()){
log.info("识别结果:{}", JSONObject.toJSONString(livenessStatus.getData()));
}else{
@@ -296,7 +303,7 @@ public class LivenessDetDemo {
* 摄像头活体检测
* 注意事项:如果视频比较卡,可以使用轻量的人脸检测模型
*/
@Test
// @Test
public void testLivenessDetectCamera(){
try {
LivenessDetModel livenessDetModel = getLivenessDetModel();
@@ -335,7 +342,7 @@ public class LivenessDetDemo {
JOptionPane.showConfirmDialog(null, "Failed to capture image from WebCam.");
}
ViewerFrame frame = new ViewerFrame(width, height);
ImageFactory factory = ImageFactory.getInstance();
SmartImageFactory factory = SmartImageFactory.getInstance();
Size size = new Size(width, height);
while (capture.isOpened()) {
@@ -344,9 +351,8 @@ public class LivenessDetDemo {
}
Mat resizeImage = new Mat();
Imgproc.resize(image, resizeImage, size);
Image img = factory.fromImage(resizeImage);
BufferedImage bufferedImage = OpenCVUtils.mat2Image(resizeImage);
R<DetectionResponse> detectedResult = livenessDetModel.detect(bufferedImage);
Image img = factory.fromMat(resizeImage);
R<DetectionResponse> detectedResult = livenessDetModel.detect(img);
if(!detectedResult.isSuccess()){
log.debug("识别失败:{}", detectedResult.getMessage());
continue;
@@ -355,11 +361,10 @@ public class LivenessDetDemo {
DetectionRectangle detectionRectangle = detectionInfo.getDetectionRectangle();
Color color = detectionInfo.getFaceInfo().getLivenessStatus().getStatus() == LivenessStatus.LIVE ? Color.GREEN : Color.RED;
String text = detectionInfo.getFaceInfo().getLivenessStatus().getStatus().getDescription() + ":" + detectionInfo.getFaceInfo().getLivenessStatus().getScore();
ImageUtils.drawImageRectWithText(bufferedImage, detectionRectangle, text, color);
ImageUtils.drawRectAndText(img, detectionRectangle, text);
}
frame.showImage(bufferedImage);
frame.showImage(ImageUtils.toBufferedImage(img));
}
capture.release();
System.exit(0);
} catch (Exception e) {

View File

@@ -1,6 +1,8 @@
package smartai.examples.face.quality;
import ai.djl.modality.cv.Image;
import cn.smartjavaai.common.config.Config;
import cn.smartjavaai.common.cv.SmartImageFactory;
import cn.smartjavaai.common.entity.DetectionInfo;
import cn.smartjavaai.common.entity.DetectionResponse;
import cn.smartjavaai.common.entity.R;
@@ -47,6 +49,8 @@ public class FaceQualityDetDemo {
@BeforeClass
public static void beforeAll() throws IOException {
//将图片处理的底层引擎切换为 OpenCV
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -62,7 +66,7 @@ public class FaceQualityDetDemo {
QualityConfig config = new QualityConfig();
config.setModelEnum(QualityModelEnum.SEETA_FACE6_MODEL);
//需替换为实际模型存储路径
config.setModelPath("C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models");
config.setModelPath("C:/Users/DengWenJie/Downloads/sf3.0_models/sf3.0_models");
config.setDevice(device);
return FaceQualityModelFactory.getInstance().getModel(config);
}
@@ -74,7 +78,7 @@ public class FaceQualityDetDemo {
*/
public FaceDetModel getFaceDetModel() {
//需替换为实际模型存储路径
String modelPath = "C:/Users/Administrator/Downloads/sf3.0_models/sf3.0_models";
String modelPath = "C:/Users/DengWenJie/Downloads/sf3.0_models/sf3.0_models";
FaceDetConfig faceDetectModelConfig = new FaceDetConfig();
faceDetectModelConfig.setModelEnum(FaceDetModelEnum.SEETA_FACE6_MODEL);
faceDetectModelConfig.setModelPath(modelPath);
@@ -91,8 +95,9 @@ public class FaceQualityDetDemo {
try {
FaceQualityModel faceQualityModel = getFaceQualityModel();
FaceDetModel faceDetModel = getFaceDetModel();
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
//人脸检测
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/iu_1.jpg").toAbsolutePath().toString()));
R<DetectionResponse> detectionResponse = faceDetModel.detect(image);
if(detectionResponse.isSuccess()){
log.info("人脸检测结果:{}", JSONObject.toJSONString(detectionResponse.getData()));
@@ -124,8 +129,9 @@ public class FaceQualityDetDemo {
try {
FaceQualityModel faceQualityModel = getFaceQualityModel();
FaceDetModel faceDetModel = getFaceDetModel();
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
//人脸检测
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/iu_1.jpg").toAbsolutePath().toString()));
R<DetectionResponse> detectionResponse = faceDetModel.detect(image);
if(detectionResponse.isSuccess()){
log.info("人脸检测结果:{}", JSONObject.toJSONString(detectionResponse.getData()));
@@ -157,8 +163,8 @@ public class FaceQualityDetDemo {
try {
FaceQualityModel faceQualityModel = getFaceQualityModel();
FaceDetModel faceDetModel = getFaceDetModel();
//人脸检测
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/iu_1.jpg").toAbsolutePath().toString()));
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
R<DetectionResponse> detectionResponse = faceDetModel.detect(image);
if(detectionResponse.isSuccess()){
log.info("人脸检测结果:{}", JSONObject.toJSONString(detectionResponse.getData()));
@@ -190,8 +196,9 @@ public class FaceQualityDetDemo {
try {
FaceQualityModel faceQualityModel = getFaceQualityModel();
FaceDetModel faceDetModel = getFaceDetModel();
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
//人脸检测
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/iu_1.jpg").toAbsolutePath().toString()));
R<DetectionResponse> detectionResponse = faceDetModel.detect(image);
if(detectionResponse.isSuccess()){
log.info("人脸检测结果:{}", JSONObject.toJSONString(detectionResponse.getData()));
@@ -224,8 +231,9 @@ public class FaceQualityDetDemo {
try {
FaceQualityModel faceQualityModel = getFaceQualityModel();
FaceDetModel faceDetModel = getFaceDetModel();
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
//人脸检测
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/iu_1.jpg").toAbsolutePath().toString()));
R<DetectionResponse> detectionResponse = faceDetModel.detect(image);
if(detectionResponse.isSuccess()){
log.info("人脸检测结果:{}", JSONObject.toJSONString(detectionResponse.getData()));
@@ -258,8 +266,9 @@ public class FaceQualityDetDemo {
try {
FaceQualityModel faceQualityModel = getFaceQualityModel();
FaceDetModel faceDetModel = getFaceDetModel();
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/iu_1.jpg");
//人脸检测
BufferedImage image = ImageIO.read(new File(Paths.get("src/main/resources/iu_1.jpg").toAbsolutePath().toString()));
R<DetectionResponse> detectionResponse = faceDetModel.detect(image);
if(detectionResponse.isSuccess()){
log.info("人脸检测结果:{}", JSONObject.toJSONString(detectionResponse.getData()));