mirror of
https://github.com/geekwenjie/SmartJavaAI.git
synced 2026-09-09 19:18:52 +00:00
1、目标检测:支持自己训练的模型推理
2、目标检测:支持yolo12模型 3、支持JDK8使用 4、引入离线依赖库,支持完全离线使用 5、优化FaceNet人脸比对速度 6、支持4通道图片检测
This commit is contained in:
19
README.md
19
README.md
@@ -13,7 +13,7 @@
|
||||
<img src="https://img.shields.io/:license-MulanPSL2-blue.svg" />
|
||||
</a>
|
||||
<a target="_blank" href="https://www.oracle.com/java/technologies/javase/javase-jdk11-downloads.html">
|
||||
<img src="https://img.shields.io/badge/JDK-11+-green.svg" />
|
||||
<img src="https://img.shields.io/badge/JDK-8+-green.svg" />
|
||||
</a>
|
||||
<a target="_blank" href='https://gitee.com/dengwenjie/SmartJavaAI/stargazers'>
|
||||
<img src='https://gitee.com/dengwenjie/SmartJavaAI/badge/star.svg?theme=gvp' alt='star'/>
|
||||
@@ -230,7 +230,7 @@ SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的
|
||||
|
||||
### 1、环境要求
|
||||
|
||||
- Java 版本:**JDK 11或更高版本**
|
||||
- Java 版本:**JDK 8或更高版本**
|
||||
- 操作系统:不同模型支持的系统不一样,具体请查看文档
|
||||
|
||||
### 2、Maven
|
||||
@@ -240,7 +240,7 @@ SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的
|
||||
<dependency>
|
||||
<groupId>cn.smartjavaai</groupId>
|
||||
<artifactId>smartjavaai-all</artifactId>
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
</dependency>
|
||||
```
|
||||
### 3、完整示例代码
|
||||
@@ -273,7 +273,15 @@ SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的
|
||||
🚀 **如果这个项目对你有帮助,别忘了点个 Star ⭐!你的支持是我持续优化升级的动力!** ❤️
|
||||
|
||||
|
||||
## 更新日志
|
||||
## 近期更新日志
|
||||
|
||||
## [v1.0.13] - 2025-05-17
|
||||
- 支持 JDK8 环境运行
|
||||
- 引入离线依赖,支持完全离线使用
|
||||
- 优化 FaceNet 人脸比对性能,提升比对速度
|
||||
- 支持带 Alpha 通道的 4 通道图片检测
|
||||
- 目标检测:新增 YOLOv12 官方模型支持
|
||||
- 目标检测:支持加载自训练模型进行推理
|
||||
|
||||
## [v1.0.12] - 2025-05-09
|
||||
- 新增图片与视频活体检测
|
||||
@@ -297,9 +305,6 @@ SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的
|
||||
- 修复若干已知问题
|
||||
- 支持自定义选择使用 GPU 或 CPU 运算
|
||||
- 人脸识别模块新增多种接口,功能更加完善
|
||||
## [v1.0.6] - 2025-04-01
|
||||
- 修复人脸识别算法facenet-pytorch实现方式
|
||||
- 优化Seetaface6算法,兼容jdk高版本
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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.12</smartjavaai.version>
|
||||
<smartjavaai.version>1.0.13</smartjavaai.version>
|
||||
<!--如果打包运行,需要替换成你的main-->
|
||||
<exec.mainClass>smartai.examples.face.facerec.RetinaFaceDemo</exec.mainClass>
|
||||
|
||||
@@ -104,6 +104,14 @@
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>ai.djl.pytorch</groupId>
|
||||
<artifactId>pytorch-jni</artifactId>
|
||||
<version>2.5.1-0.32.0</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- windows平台 (保留对应平台的配置,可以减小包大小)-->
|
||||
<dependency>
|
||||
<groupId>org.bytedeco</groupId>
|
||||
@@ -132,6 +140,15 @@
|
||||
<classifier>${javacv.platform.windows-x86_64}</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ai.djl.pytorch</groupId>
|
||||
<artifactId>pytorch-native-cpu</artifactId>
|
||||
<classifier>${djl.platform.windows-x86_64}</classifier>
|
||||
<version>2.5.1</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- linux x86 平台 (保留对应平台的配置,可以减小包大小)-->
|
||||
<dependency>
|
||||
@@ -161,6 +178,14 @@
|
||||
<classifier>${javacv.platform.linux-x86_64}</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ai.djl.pytorch</groupId>
|
||||
<artifactId>pytorch-native-cpu</artifactId>
|
||||
<classifier>${djl.platform.linux-x86_64}</classifier>
|
||||
<version>2.5.1</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- macOS M系列 平台 (保留对应平台的配置,可以减小包大小)-->
|
||||
<dependency>
|
||||
@@ -190,6 +215,14 @@
|
||||
<classifier>${javacv.platform.macosx-arm64}</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ai.djl.pytorch</groupId>
|
||||
<artifactId>pytorch-native-cpu</artifactId>
|
||||
<classifier>${djl.platform.osx-aarch64}</classifier>
|
||||
<version>2.5.1</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- linux aarch64 平台 (保留对应平台的配置,可以减小包大小)-->
|
||||
<dependency>
|
||||
@@ -220,8 +253,13 @@
|
||||
<classifier>${javacv.platform.linux-arm64}</classifier>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>ai.djl.pytorch</groupId>
|
||||
<artifactId>pytorch-native-cpu-precxx11</artifactId>
|
||||
<classifier>${djl.platform.linux-aarch64}</classifier>
|
||||
<version>2.5.1</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -54,14 +54,17 @@ public class FaceNetDemo {
|
||||
@Test
|
||||
public void testExtractFeaturesWithCustomConfig(){
|
||||
try {
|
||||
//人脸特征提取模型
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(
|
||||
new FaceModelConfig(FaceModelEnum.FACENET_FEATURE_EXTRACTION));
|
||||
//人脸模型参数
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.FACENET_FEATURE_EXTRACTION);
|
||||
//人脸特征提取参数
|
||||
FaceExtractConfig extractConfig = new FaceExtractConfig();
|
||||
//人脸检测模型配置
|
||||
extractConfig.setDetectModelConfig(new FaceModelConfig(FaceModelEnum.ULTRA_LIGHT_FAST_GENERIC_FACE));
|
||||
List<float[]> faceResult = faceModel.extractFeatures("src/main/resources/kana1.jpg",extractConfig);
|
||||
extractConfig.setDetectModel(FaceModelFactory.getInstance().getModel(new FaceModelConfig(FaceModelEnum.ULTRA_LIGHT_FAST_GENERIC_FACE)));
|
||||
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();
|
||||
@@ -94,13 +97,16 @@ public class FaceNetDemo {
|
||||
@Test
|
||||
public void testExtractTopFaceFeatureWithCustomConfig(){
|
||||
try {
|
||||
//人脸特征提取模型
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(
|
||||
new FaceModelConfig(FaceModelEnum.FACENET_FEATURE_EXTRACTION));
|
||||
//人脸模型参数
|
||||
FaceModelConfig config = new FaceModelConfig();
|
||||
config.setModelEnum(FaceModelEnum.FACENET_FEATURE_EXTRACTION);
|
||||
//人脸特征提取参数
|
||||
FaceExtractConfig extractConfig = new FaceExtractConfig();
|
||||
//人脸检测模型配置
|
||||
extractConfig.setDetectModelConfig(new FaceModelConfig(FaceModelEnum.ULTRA_LIGHT_FAST_GENERIC_FACE));
|
||||
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));
|
||||
}catch (Exception e){
|
||||
|
||||
@@ -13,8 +13,8 @@ import ai.djl.repository.zoo.ZooModel;
|
||||
import ai.djl.training.util.ProgressBar;
|
||||
import cn.smartjavaai.common.entity.DetectionResponse;
|
||||
import cn.smartjavaai.common.enums.DeviceEnum;
|
||||
import cn.smartjavaai.objectdetection.DetectorModelConfig;
|
||||
import cn.smartjavaai.objectdetection.DetectorModelEnum;
|
||||
import cn.smartjavaai.objectdetection.config.DetectorModelConfig;
|
||||
import cn.smartjavaai.objectdetection.enums.DetectorModelEnum;
|
||||
import cn.smartjavaai.objectdetection.exception.DetectionException;
|
||||
import cn.smartjavaai.objectdetection.model.DetectorModel;
|
||||
import cn.smartjavaai.objectdetection.model.ObjectDetectionModelFactory;
|
||||
@@ -62,7 +62,7 @@ public class ObjectDetection {
|
||||
@Test
|
||||
public void objectDetection2(){
|
||||
DetectorModelConfig config = new DetectorModelConfig();
|
||||
config.setModelEnum(DetectorModelEnum.SSD_300_RESNET50);//检测模型,目前支持19种模型
|
||||
config.setModelEnum(DetectorModelEnum.SSD_300_RESNET50);//检测模型,目前支持19种预置模型
|
||||
DetectorModel detectorModel = ObjectDetectionModelFactory.getInstance().getModel(config);
|
||||
DetectionResponse detectionResponse = detectorModel.detect("src/main/resources/dog_bike_car.jpg");
|
||||
log.info("目标检测结果:{}", JSONObject.toJSONString(detectionResponse));
|
||||
@@ -110,5 +110,35 @@ public class ObjectDetection {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 使用yolo官方模型检测
|
||||
*/
|
||||
@Test
|
||||
public void objectDetectionWithOfficialModel(){
|
||||
DetectorModelConfig config = new DetectorModelConfig();
|
||||
//也支持YoloV8:YOLOV8_OFFICIAL 模型可以从文档中提供的地址下载
|
||||
config.setModelEnum(DetectorModelEnum.YOLOV12_OFFICIAL);//检测模型,目前支持19种模型
|
||||
// 指定模型路径,需要更改为自己的模型路径
|
||||
config.setModelPath("/Users/xxx/Documents/develop/face_model/yolov12n.onnx");
|
||||
DetectorModel detectorModel = ObjectDetectionModelFactory.getInstance().getModel(config);
|
||||
//一定要将yolo官方的类别文件:synset.txt(文档中下载)放在模型同目录下,否则报错
|
||||
detectorModel.detectAndDraw("src/main/resources/object_detection.jpg","output/object_detection_detected.png");
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用自己训练的模型检测
|
||||
*/
|
||||
@Test
|
||||
public void objectDetectionWithCustomModel(){
|
||||
DetectorModelConfig config = new DetectorModelConfig();
|
||||
//也支持YoloV8:YOLOV8_CUSTOM 模型需要自己训练,训练教程可以查看文档
|
||||
config.setModelEnum(DetectorModelEnum.YOLOV12_CUSTOM);//自定义YOLOV12模型
|
||||
// 指定模型路径,需要更改为自己的模型路径
|
||||
config.setModelPath("/Users/xxx/Documents/develop/fire_model/best.onnx");
|
||||
DetectorModel detectorModel = ObjectDetectionModelFactory.getInstance().getModel(config);
|
||||
//一定要将类别文件:synset.txt 放在模型同目录下,否则报错(具体请参看文档)
|
||||
detectorModel.detectAndDraw("/Users/xxx/Downloads/test.jpg","output/test_detected.jpg");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
14
pom.xml
14
pom.xml
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>cn.smartjavaai</groupId>
|
||||
<artifactId>smartjavaai-parent</artifactId>
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
<packaging>pom</packaging>
|
||||
<description>SmartJavaAI</description>
|
||||
<modules>
|
||||
@@ -19,8 +19,8 @@
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<djl.version>0.32.0</djl.version>
|
||||
|
||||
@@ -39,13 +39,13 @@
|
||||
<dependency>
|
||||
<groupId>cn.smartjavaai</groupId>
|
||||
<artifactId>smartjavaai-common</artifactId>
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.smartjavaai</groupId>
|
||||
<artifactId>smartjavaai-face</artifactId>
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
<dependency>
|
||||
<groupId>org.testng</groupId>
|
||||
<artifactId>testng</artifactId>
|
||||
<version>7.10.2</version>
|
||||
<version>7.4.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
@@ -260,7 +260,7 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
|
||||
<!-- <javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>-->
|
||||
<doclint>none</doclint>
|
||||
<additionalJOptions>
|
||||
<additionalJOption>-Xdoclint:none</additionalJOption>
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<parent>
|
||||
<groupId>cn.smartjavaai</groupId>
|
||||
<artifactId>smartjavaai-parent</artifactId>
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>smartjavaai-all</artifactId>
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
<name>${project.artifactId}</name>
|
||||
<description>SmartJavaAI</description>
|
||||
<url>https://github.com/geekwenjie/SmartJavaAI</url>
|
||||
@@ -23,8 +23,8 @@
|
||||
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<!-- <maven.compiler.source>11</maven.compiler.source>-->
|
||||
<!-- <maven.compiler.target>11</maven.compiler.target>-->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.test.skip>true</maven.test.skip>
|
||||
</properties>
|
||||
@@ -111,7 +111,7 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
|
||||
<!-- <javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>-->
|
||||
<doclint>none</doclint>
|
||||
<additionalJOptions>
|
||||
<additionalJOption>-Xdoclint:none</additionalJOption>
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
<parent>
|
||||
<groupId>cn.smartjavaai</groupId>
|
||||
<artifactId>smartjavaai-parent</artifactId>
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
</parent>
|
||||
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
<artifactId>smartjavaai-bom</artifactId>
|
||||
<name>smartjavaai-bom</name>
|
||||
<description>统一版本管理的 BOM 包,同时支持 import 和全量依赖</description>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<!-- <maven.compiler.source>11</maven.compiler.source>-->
|
||||
<!-- <maven.compiler.target>11</maven.compiler.target>-->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
|
||||
<!-- <javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>-->
|
||||
<doclint>none</doclint>
|
||||
<additionalJOptions>
|
||||
<additionalJOption>-Xdoclint:none</additionalJOption>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>cn.smartjavaai</groupId>
|
||||
<artifactId>smartjavaai-parent</artifactId>
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>smartjavaai-common</artifactId>
|
||||
@@ -58,7 +58,7 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
|
||||
<!-- <javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>-->
|
||||
<doclint>none</doclint>
|
||||
<additionalJOptions>
|
||||
<additionalJOption>-Xdoclint:none</additionalJOption>
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<parent>
|
||||
<groupId>cn.smartjavaai</groupId>
|
||||
<artifactId>smartjavaai-parent</artifactId>
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>smartjavaai-face</artifactId>
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
<name>smartjavaai-face</name>
|
||||
<description>SmartJavaAI</description>
|
||||
<url>https://github.com/geekwenjie/SmartJavaAI</url>
|
||||
@@ -22,8 +22,8 @@
|
||||
</licenses>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<!-- <maven.compiler.source>11</maven.compiler.source>-->
|
||||
<!-- <maven.compiler.target>11</maven.compiler.target>-->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.test.skip>true</maven.test.skip>
|
||||
<javacv.version>1.5.8</javacv.version>
|
||||
@@ -87,7 +87,7 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
|
||||
<!-- <javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>-->
|
||||
<doclint>none</doclint>
|
||||
<additionalJOptions>
|
||||
<additionalJOption>-Xdoclint:none</additionalJOption>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.smartjavaai.face.config;
|
||||
|
||||
import cn.smartjavaai.face.model.facerec.FaceModel;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
@@ -21,17 +22,17 @@ public class FaceExtractConfig {
|
||||
private boolean align = true;
|
||||
|
||||
/**
|
||||
* 人脸检测模型配置
|
||||
* 人脸检测模型
|
||||
*/
|
||||
private FaceModelConfig detectModelConfig;
|
||||
private FaceModel detectModel;
|
||||
|
||||
public FaceExtractConfig() {
|
||||
}
|
||||
|
||||
public FaceExtractConfig(boolean cropFace, boolean align, FaceModelConfig detectModelConfig) {
|
||||
public FaceExtractConfig(boolean cropFace, boolean align, FaceModel detectModel) {
|
||||
this.cropFace = cropFace;
|
||||
this.align = align;
|
||||
this.detectModelConfig = detectModelConfig;
|
||||
this.detectModel = detectModel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -52,6 +52,11 @@ public class FaceModelConfig {
|
||||
*/
|
||||
private int gpuId = 0;
|
||||
|
||||
/**
|
||||
* 人脸特征提取配置
|
||||
*/
|
||||
private FaceExtractConfig extractConfig;
|
||||
|
||||
public FaceModelConfig() {
|
||||
}
|
||||
|
||||
|
||||
@@ -140,21 +140,6 @@ public abstract class AbstractFaceModel implements FaceModel {
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<float[]> extractFeatures(BufferedImage image, FaceExtractConfig config) {
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<float[]> extractFeatures(String imagePath, FaceExtractConfig config) {
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<float[]> extractFeatures(byte[] imageData, FaceExtractConfig config) {
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] extractTopFaceFeature(BufferedImage image) {
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
@@ -170,18 +155,5 @@ public abstract class AbstractFaceModel implements FaceModel {
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] extractTopFaceFeature(BufferedImage image, FaceExtractConfig config) {
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] extractTopFaceFeature(String imagePath, FaceExtractConfig config) {
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] extractTopFaceFeature(byte[] imageData, FaceExtractConfig config) {
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,30 +199,6 @@ public interface FaceModel {
|
||||
*/
|
||||
List<float[]> extractFeatures(BufferedImage image);
|
||||
|
||||
/**
|
||||
* 特征提取(使用自定义配置)
|
||||
* 强制裁剪操作
|
||||
* @param image BufferedImage
|
||||
* @param config
|
||||
* @return
|
||||
*/
|
||||
List<float[]> extractFeatures(BufferedImage image, FaceExtractConfig config);
|
||||
|
||||
/**
|
||||
* 特征提取(使用自定义配置)
|
||||
* @param imagePath 图片路径
|
||||
* @param config
|
||||
* @return
|
||||
*/
|
||||
List<float[]> extractFeatures(String imagePath, FaceExtractConfig config);
|
||||
|
||||
/**
|
||||
* 特征提取(使用自定义配置)
|
||||
* @param imageData 图片字节流
|
||||
* @param config
|
||||
* @return
|
||||
*/
|
||||
List<float[]> extractFeatures(byte[] imageData, FaceExtractConfig config);
|
||||
|
||||
/**
|
||||
* 提取分数最高人脸特征(使用默认配置)
|
||||
@@ -245,27 +221,6 @@ public interface FaceModel {
|
||||
*/
|
||||
float[] extractTopFaceFeature(byte[] imageData);
|
||||
|
||||
/**
|
||||
* 提取分数最高人脸特征(使用自定义配置)
|
||||
* @param image BufferedImage
|
||||
* @return
|
||||
*/
|
||||
float[] extractTopFaceFeature(BufferedImage image, FaceExtractConfig config);
|
||||
|
||||
/**
|
||||
* 提取分数最高人脸特征(使用自定义配置)
|
||||
* @param imagePath 图片路径
|
||||
* @param config
|
||||
* @return
|
||||
*/
|
||||
float[] extractTopFaceFeature(String imagePath, FaceExtractConfig config);
|
||||
|
||||
/**
|
||||
* 提取分数最高人脸特征(使用自定义配置)
|
||||
* @param imageData 图片字节流
|
||||
* @param config
|
||||
* @return
|
||||
*/
|
||||
float[] extractTopFaceFeature(byte[] imageData, FaceExtractConfig config);
|
||||
|
||||
}
|
||||
|
||||
@@ -59,6 +59,8 @@ public class FeatureExtractionModel extends AbstractFaceModel implements AutoClo
|
||||
|
||||
private ZooModel<Image, float[]> model;
|
||||
|
||||
private FaceModelConfig config;
|
||||
|
||||
public static final List<Float> mean =
|
||||
Arrays.asList(
|
||||
127.5f / 255.0f,
|
||||
@@ -75,10 +77,21 @@ public class FeatureExtractionModel extends AbstractFaceModel implements AutoClo
|
||||
*/
|
||||
@Override
|
||||
public void loadModel(FaceModelConfig config) {
|
||||
if(Objects.isNull(config)){
|
||||
throw new FaceException("config为null");
|
||||
}
|
||||
if(Objects.isNull(config.getExtractConfig())){
|
||||
config.setExtractConfig(getDefaultConfig());
|
||||
}else{
|
||||
if(Objects.isNull(config.getExtractConfig().getDetectModel())){
|
||||
throw new FaceException("请设置人脸检测模型");
|
||||
}
|
||||
}
|
||||
Device device = null;
|
||||
if(!Objects.isNull(config.getDevice())){
|
||||
device = config.getDevice() == DeviceEnum.CPU ? Device.cpu() : Device.gpu();
|
||||
}
|
||||
this.config = config;
|
||||
String normalize = mean.stream().map(Object::toString).collect(Collectors.joining(","));
|
||||
Criteria<Image, float[]> faceFeatureCriteria =
|
||||
Criteria.builder()
|
||||
@@ -162,7 +175,8 @@ public class FeatureExtractionModel extends AbstractFaceModel implements AutoClo
|
||||
}
|
||||
float[] feature1 = extractTopFaceFeature(imagePath1);
|
||||
float[] feature2 = extractTopFaceFeature(imagePath2);
|
||||
return calculSimilar(feature1, feature2);
|
||||
float ret = calculSimilar(feature1, feature2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -194,37 +208,18 @@ public class FeatureExtractionModel extends AbstractFaceModel implements AutoClo
|
||||
FaceExtractConfig config = new FaceExtractConfig();
|
||||
FaceModelConfig detectModelConfig = new FaceModelConfig();
|
||||
detectModelConfig.setModelEnum(FaceModelEnum.ULTRA_LIGHT_FAST_GENERIC_FACE);
|
||||
config.setDetectModelConfig(detectModelConfig);
|
||||
log.debug("创建默认检测模型:ULTRA_LIGHT_FAST_GENERIC_FACE");
|
||||
FaceModel detectModel = FaceModelFactory.getInstance().getModel(detectModelConfig);
|
||||
log.debug("创建检测模型完毕");
|
||||
config.setDetectModel(detectModel);
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<float[]> extractFeatures(String imagePath) {
|
||||
return extractFeatures(imagePath, getDefaultConfig());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<float[]> extractFeatures(byte[] imageData) {
|
||||
return extractFeatures(imageData, getDefaultConfig());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<float[]> extractFeatures(BufferedImage image) {
|
||||
return extractFeatures(image, getDefaultConfig());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<float[]> extractFeatures(BufferedImage image, FaceExtractConfig config) {
|
||||
if(Objects.isNull(config)){
|
||||
throw new FaceException("config为null");
|
||||
}
|
||||
List<float[]> featureList = new ArrayList<float[]>();
|
||||
if(Objects.isNull(config.getDetectModelConfig())){
|
||||
throw new FaceException("config.detectModelConfig为null");
|
||||
}
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config.getDetectModelConfig());
|
||||
DetectionResponse detectedResult = faceModel.detect(image);
|
||||
DetectionResponse detectedResult = config.getExtractConfig().getDetectModel().detect(image);
|
||||
if(Objects.isNull(detectedResult) || Objects.isNull(detectedResult.getDetectionInfoList()) || detectedResult.getDetectionInfoList().isEmpty()){
|
||||
throw new FaceException("未检测到人脸");
|
||||
}
|
||||
@@ -237,7 +232,7 @@ public class FeatureExtractionModel extends AbstractFaceModel implements AutoClo
|
||||
//裁剪人脸
|
||||
Image subImage = djlImage.getSubImage(rectangle.getX(), rectangle.getY() , rectangle.getWidth() , rectangle.getHeight());
|
||||
//人脸对齐
|
||||
if(config.isAlign()){
|
||||
if(config.getExtractConfig().isAlign()){
|
||||
//获取子图中人脸关键点坐标
|
||||
double[][] pointsArray = FaceUtils.facePoints(detectionInfo.getFaceInfo().getKeyPoints());
|
||||
NDArray srcPoints = manager.create(pointsArray);
|
||||
@@ -263,8 +258,21 @@ public class FeatureExtractionModel extends AbstractFaceModel implements AutoClo
|
||||
return featureList;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<float[]> extractFeatures(String imagePath, FaceExtractConfig config) {
|
||||
public List<float[]> extractFeatures(byte[] imageData) {
|
||||
if(Objects.isNull(imageData)){
|
||||
throw new FaceException("图像无效");
|
||||
}
|
||||
try {
|
||||
return extractFeatures(ImageIO.read(new ByteArrayInputStream(imageData)));
|
||||
} catch (IOException e) {
|
||||
throw new FaceException("错误的图像", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<float[]> extractFeatures(String imagePath) {
|
||||
if(!FileUtils.isFileExists(imagePath)){
|
||||
throw new FaceException("图像文件不存在");
|
||||
}
|
||||
@@ -275,49 +283,15 @@ public class FeatureExtractionModel extends AbstractFaceModel implements AutoClo
|
||||
} catch (IOException e) {
|
||||
throw new FaceException("无效图片路径", e);
|
||||
}
|
||||
return extractFeatures(image, config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<float[]> extractFeatures(byte[] imageData, FaceExtractConfig config) {
|
||||
if(Objects.isNull(imageData)){
|
||||
throw new FaceException("图像无效");
|
||||
}
|
||||
try {
|
||||
return extractFeatures(ImageIO.read(new ByteArrayInputStream(imageData)), config);
|
||||
} catch (IOException e) {
|
||||
throw new FaceException("错误的图像", e);
|
||||
}
|
||||
return extractFeatures(image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] extractTopFaceFeature(BufferedImage image) {
|
||||
return extractTopFaceFeature(image, getDefaultConfig());
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] extractTopFaceFeature(String imagePath) {
|
||||
return extractTopFaceFeature(imagePath, getDefaultConfig());
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] extractTopFaceFeature(byte[] imageData) {
|
||||
return extractTopFaceFeature(imageData, getDefaultConfig());
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] extractTopFaceFeature(BufferedImage image, FaceExtractConfig config) {
|
||||
if(Objects.isNull(config)){
|
||||
throw new FaceException("config为null");
|
||||
}
|
||||
if(Objects.isNull(config.getDetectModelConfig())){
|
||||
throw new FaceException("config.detectModelConfig为null");
|
||||
}
|
||||
Image djlImage = ImageFactory.getInstance().fromImage(OpenCVUtils.image2Mat(image));
|
||||
float[] features = null;
|
||||
if(config.isCropFace()){
|
||||
FaceModel faceModel = FaceModelFactory.getInstance().getModel(config.getDetectModelConfig());
|
||||
DetectionResponse detectedResult = faceModel.detect(image);
|
||||
if(config.getExtractConfig().isCropFace()){
|
||||
DetectionResponse detectedResult = config.getExtractConfig().getDetectModel().detect(image);
|
||||
if(Objects.isNull(detectedResult) || Objects.isNull(detectedResult.getDetectionInfoList()) || detectedResult.getDetectionInfoList().isEmpty()){
|
||||
throw new FaceException("未检测到人脸");
|
||||
}
|
||||
@@ -327,7 +301,7 @@ public class FeatureExtractionModel extends AbstractFaceModel implements AutoClo
|
||||
//裁剪人脸
|
||||
Image subImage = djlImage.getSubImage(rectangle.getX(), rectangle.getY() , rectangle.getWidth() , rectangle.getHeight());
|
||||
//人脸对齐
|
||||
if(config.isAlign()){
|
||||
if(config.getExtractConfig().isAlign()){
|
||||
NDManager manager = NDManager.newBaseManager();
|
||||
//获取子图中人脸关键点坐标
|
||||
double[][] pointsArray = FaceUtils.facePoints(detectionInfo.getFaceInfo().getKeyPoints());
|
||||
@@ -355,7 +329,7 @@ public class FeatureExtractionModel extends AbstractFaceModel implements AutoClo
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] extractTopFaceFeature(String imagePath, FaceExtractConfig config) {
|
||||
public float[] extractTopFaceFeature(String imagePath) {
|
||||
if(!FileUtils.isFileExists(imagePath)){
|
||||
throw new FaceException("图像文件不存在");
|
||||
}
|
||||
@@ -366,16 +340,16 @@ public class FeatureExtractionModel extends AbstractFaceModel implements AutoClo
|
||||
} catch (IOException e) {
|
||||
throw new FaceException("无效图片路径", e);
|
||||
}
|
||||
return extractTopFaceFeature(image, config);
|
||||
return extractTopFaceFeature(image);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float[] extractTopFaceFeature(byte[] imageData, FaceExtractConfig config) {
|
||||
public float[] extractTopFaceFeature(byte[] imageData) {
|
||||
if(Objects.isNull(imageData)){
|
||||
throw new FaceException("图像无效");
|
||||
}
|
||||
try {
|
||||
return extractTopFaceFeature(ImageIO.read(new ByteArrayInputStream(imageData)), config);
|
||||
return extractTopFaceFeature(ImageIO.read(new ByteArrayInputStream(imageData)));
|
||||
} catch (IOException e) {
|
||||
throw new FaceException("错误的图像", e);
|
||||
}
|
||||
|
||||
@@ -629,6 +629,7 @@ public class SeetaFace6Model extends AbstractFaceModel {
|
||||
|
||||
@Override
|
||||
public FaceResult search(BufferedImage image) {
|
||||
long time1 = System.currentTimeMillis();
|
||||
if(!ImageUtils.isImageValid(image)){
|
||||
throw new FaceException("图像无效");
|
||||
}
|
||||
@@ -648,7 +649,12 @@ public class SeetaFace6Model extends AbstractFaceModel {
|
||||
if(similarity[0] < config.getSimilarityThreshold()){
|
||||
return null;
|
||||
}
|
||||
return searchFaceDb(index[0], similarity[0]);
|
||||
long time2 = System.currentTimeMillis();
|
||||
System.out.println("总耗时1:" + (time2 - time1) + " ms");
|
||||
FaceResult faceResult = searchFaceDb(index[0], similarity[0]);
|
||||
long time3 = System.currentTimeMillis();
|
||||
System.out.println("总耗时2:" + (time3 - time2) + " ms");
|
||||
return faceResult;
|
||||
} catch (FaceException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -111,8 +111,26 @@ public class OpenCVUtils {
|
||||
public static Mat image2Mat(BufferedImage img) {
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
int channels;
|
||||
|
||||
// 获取图像类型
|
||||
int imageType = img.getType();
|
||||
|
||||
// 判断是3通道还是4通道
|
||||
if (imageType == BufferedImage.TYPE_3BYTE_BGR) {
|
||||
channels = 3;
|
||||
} else if (imageType == BufferedImage.TYPE_4BYTE_ABGR || imageType == BufferedImage.TYPE_4BYTE_ABGR_PRE) {
|
||||
channels = 4;
|
||||
} else {
|
||||
// 如果不是已知格式,强制转换为 3 通道 BGR
|
||||
BufferedImage convertedImg = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
|
||||
convertedImg.getGraphics().drawImage(img, 0, 0, null);
|
||||
img = convertedImg;
|
||||
channels = 3;
|
||||
}
|
||||
|
||||
byte[] data = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
|
||||
Mat mat = new Mat(height, width, CvType.CV_8UC3);
|
||||
Mat mat = new Mat(height, width, CvType.CV_8UC(channels));
|
||||
mat.put(0, 0, data);
|
||||
return mat;
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<parent>
|
||||
<groupId>cn.smartjavaai</groupId>
|
||||
<artifactId>smartjavaai-parent</artifactId>
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>smartjavaai-objectdetection</artifactId>
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
<name>smartjavaai-objectdetection</name>
|
||||
<description>SmartJavaAI</description>
|
||||
<url>https://github.com/geekwenjie/SmartJavaAI</url>
|
||||
@@ -23,8 +23,8 @@
|
||||
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<!-- <maven.compiler.source>11</maven.compiler.source>-->
|
||||
<!-- <maven.compiler.target>11</maven.compiler.target>-->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.test.skip>true</maven.test.skip>
|
||||
</properties>
|
||||
@@ -72,7 +72,7 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
|
||||
<!-- <javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>-->
|
||||
<doclint>none</doclint>
|
||||
<additionalJOptions>
|
||||
<additionalJOption>-Xdoclint:none</additionalJOption>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package cn.smartjavaai.objectdetection;
|
||||
package cn.smartjavaai.objectdetection.config;
|
||||
|
||||
import cn.smartjavaai.common.enums.DeviceEnum;
|
||||
import cn.smartjavaai.objectdetection.constant.DetectorConstant;
|
||||
import cn.smartjavaai.objectdetection.enums.DetectorModelEnum;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
@@ -20,13 +22,25 @@ public class DetectorModelConfig {
|
||||
/**
|
||||
* 置信度阈值
|
||||
*/
|
||||
private float threshold = DetectorConfig.DEFAULT_THRESHOLD;
|
||||
private float threshold = DetectorConstant.DEFAULT_THRESHOLD;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
*/
|
||||
private DeviceEnum device;
|
||||
|
||||
/**
|
||||
* 模型路径
|
||||
*/
|
||||
private String modelPath;
|
||||
|
||||
/**
|
||||
* 候选框数量:默认为8400. 应设置0到8400之间的整数
|
||||
* 用于性能优化的关键参数,它通过限制模型后处理阶段需要处理的候选框(bounding boxes)数量来提高推理速度
|
||||
* 建议不低于1000
|
||||
*/
|
||||
private int maxBox;
|
||||
|
||||
public DetectorModelConfig() {
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package cn.smartjavaai.objectdetection;
|
||||
package cn.smartjavaai.objectdetection.constant;
|
||||
|
||||
/**
|
||||
* @author dwj
|
||||
* @date 2025/4/7
|
||||
*/
|
||||
public class DetectorConfig {
|
||||
public class DetectorConstant {
|
||||
|
||||
/**
|
||||
* 置信度阈值
|
||||
*/
|
||||
public static final float DEFAULT_THRESHOLD = 0.5F;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package cn.smartjavaai.objectdetection.criteria;
|
||||
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.repository.zoo.Criteria;
|
||||
import cn.smartjavaai.objectdetection.config.DetectorModelConfig;
|
||||
import cn.smartjavaai.objectdetection.enums.DetectorModelEnum;
|
||||
import cn.smartjavaai.objectdetection.exception.DetectionException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* Criteria构建工厂
|
||||
* @author dwj
|
||||
* @date 2025/5/14
|
||||
*/
|
||||
public class CriteriaBuilderFactory {
|
||||
|
||||
public static Criteria<Image, DetectedObjects> createCriteria(DetectorModelConfig config) {
|
||||
//以下模型modelPath不允许为空
|
||||
if(config.getModelEnum() == DetectorModelEnum.YOLOV8_OFFICIAL ||
|
||||
config.getModelEnum() == DetectorModelEnum.YOLOV12_OFFICIAL ||
|
||||
config.getModelEnum() == DetectorModelEnum.YOLOV8_CUSTOM ||
|
||||
config.getModelEnum() == DetectorModelEnum.YOLOV12_CUSTOM){
|
||||
if(StringUtils.isBlank(config.getModelPath())){
|
||||
throw new DetectionException("modelPath is null");
|
||||
}
|
||||
}
|
||||
switch (config.getModelEnum()) {
|
||||
case YOLOV8_OFFICIAL:
|
||||
return new YoloCriteriaBuilder().buildCriteria(config);
|
||||
case YOLOV12_OFFICIAL:
|
||||
return new YoloCriteriaBuilder().buildCriteria(config);
|
||||
case YOLOV8_CUSTOM:
|
||||
return new YoloCriteriaBuilder().buildCriteria(config);
|
||||
case YOLOV12_CUSTOM:
|
||||
return new YoloCriteriaBuilder().buildCriteria(config);
|
||||
// 其他类型
|
||||
default:
|
||||
return new DJLModelCriteriaBuilder().buildCriteria(config);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.smartjavaai.objectdetection.criteria;
|
||||
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.repository.zoo.Criteria;
|
||||
import cn.smartjavaai.objectdetection.config.DetectorModelConfig;
|
||||
|
||||
/**
|
||||
* 模型加载策略接口,用于根据不同模型类型构建对应的 DJL Criteria 实例
|
||||
* @author dwj
|
||||
* @date 2025/5/14
|
||||
*/
|
||||
public interface CriteriaBuilderStrategy {
|
||||
|
||||
/**
|
||||
* 根据模型类型构建对应的 DJL Criteria 实例
|
||||
* @param config
|
||||
* @return
|
||||
*/
|
||||
Criteria<Image, DetectedObjects> buildCriteria(DetectorModelConfig config);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package cn.smartjavaai.objectdetection.criteria;
|
||||
|
||||
import ai.djl.Application;
|
||||
import ai.djl.Device;
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.repository.zoo.Criteria;
|
||||
import ai.djl.training.util.ProgressBar;
|
||||
import cn.smartjavaai.common.enums.DeviceEnum;
|
||||
import cn.smartjavaai.objectdetection.config.DetectorModelConfig;
|
||||
import cn.smartjavaai.objectdetection.constant.DetectorConstant;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* DJL提供的Criteria 构建器
|
||||
* @author dwj
|
||||
* @date 2025/5/14
|
||||
*/
|
||||
public class DJLModelCriteriaBuilder implements CriteriaBuilderStrategy {
|
||||
|
||||
private static final String DJL_MODEL_PREFIX = "djl://";
|
||||
|
||||
@Override
|
||||
public Criteria<Image, DetectedObjects> buildCriteria(DetectorModelConfig config) {
|
||||
Device device = null;
|
||||
if(!Objects.isNull(config.getDevice())){
|
||||
device = config.getDevice() == DeviceEnum.CPU ? Device.cpu() : Device.gpu();
|
||||
}
|
||||
Criteria<Image, DetectedObjects> criteria = Criteria.builder()
|
||||
.optApplication(Application.CV.OBJECT_DETECTION)
|
||||
.setTypes(Image.class, DetectedObjects.class)
|
||||
.optArgument("threshold", config.getThreshold() > 0 ? config.getThreshold() : DetectorConstant.DEFAULT_THRESHOLD)
|
||||
.optModelUrls(DJL_MODEL_PREFIX + config.getModelEnum().getModelUri())
|
||||
.optDevice(device)
|
||||
.optProgress(new ProgressBar())
|
||||
.build();
|
||||
return criteria;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package cn.smartjavaai.objectdetection.criteria;
|
||||
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.modality.cv.translator.YoloV8TranslatorFactory;
|
||||
import ai.djl.repository.zoo.Criteria;
|
||||
import ai.djl.training.util.ProgressBar;
|
||||
import cn.smartjavaai.objectdetection.constant.DetectorConstant;
|
||||
import cn.smartjavaai.objectdetection.config.DetectorModelConfig;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* YOLO模型Criteria 构建器
|
||||
* @author dwj
|
||||
* @date 2025/5/14
|
||||
*/
|
||||
public class YoloCriteriaBuilder implements CriteriaBuilderStrategy {
|
||||
@Override
|
||||
public Criteria<Image, DetectedObjects> buildCriteria(DetectorModelConfig config) {
|
||||
Criteria.Builder criteriaBuilder = Criteria.builder()
|
||||
.setTypes(Image.class, DetectedObjects.class)
|
||||
//.optModelUrls("/Users/wenjie/Documents/develop/face_model/yolo")
|
||||
.optModelPath(Paths.get(config.getModelPath()))
|
||||
.optEngine("OnnxRuntime")
|
||||
.optArgument("width", 640) //将输入图像的宽度缩放为 640 像素
|
||||
.optArgument("height", 640)
|
||||
.optArgument("resize", true)
|
||||
.optArgument("toTensor", true)
|
||||
.optArgument("applyRatio", true)
|
||||
.optTranslatorFactory(new YoloV8TranslatorFactory())
|
||||
.optProgress(new ProgressBar())
|
||||
.optArgument("threshold", config.getThreshold() > 0 ? config.getThreshold() : DetectorConstant.DEFAULT_THRESHOLD);
|
||||
if(config.getMaxBox() > 0){
|
||||
criteriaBuilder.optArgument("maxBox", config.getMaxBox());
|
||||
}
|
||||
Criteria<Image, DetectedObjects> criteria = criteriaBuilder.build();
|
||||
return criteria;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.smartjavaai.objectdetection;
|
||||
package cn.smartjavaai.objectdetection.enums;
|
||||
|
||||
/**
|
||||
* 目标检测模型枚举
|
||||
@@ -34,7 +34,14 @@ public enum DetectorModelEnum {
|
||||
YOLO3_DARKNET_COCO_608("ai.djl.mxnet/yolo/0.0.1/yolo3_darknet_coco_608"),
|
||||
YOLO3_MOBILENET_COCO_320("ai.djl.mxnet/yolo/0.0.1/yolo3_mobilenet_coco_320"),
|
||||
YOLO3_MOBILENET_COCO_416("ai.djl.mxnet/yolo/0.0.1/yolo3_mobilenet_coco_416"),
|
||||
YOLO3_MOBILENET_COCO_608("ai.djl.mxnet/yolo/0.0.1/yolo3_mobilenet_coco_608");
|
||||
YOLO3_MOBILENET_COCO_608("ai.djl.mxnet/yolo/0.0.1/yolo3_mobilenet_coco_608"),
|
||||
|
||||
YOLOV12_OFFICIAL(""),
|
||||
YOLOV8_OFFICIAL(""),
|
||||
|
||||
YOLOV8_CUSTOM(""),
|
||||
|
||||
YOLOV12_CUSTOM("");
|
||||
|
||||
/**
|
||||
* 根据名称获取枚举 (忽略大小写和下划线变体)
|
||||
@@ -1,41 +1,34 @@
|
||||
package cn.smartjavaai.objectdetection.model;
|
||||
|
||||
import ai.djl.Application;
|
||||
import ai.djl.Device;
|
||||
import ai.djl.MalformedModelException;
|
||||
import ai.djl.inference.Predictor;
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.ImageFactory;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.opencv.OpenCVImageFactory;
|
||||
import ai.djl.modality.cv.translator.YoloV8TranslatorFactory;
|
||||
import ai.djl.repository.zoo.Criteria;
|
||||
import ai.djl.repository.zoo.ModelNotFoundException;
|
||||
import ai.djl.repository.zoo.ZooModel;
|
||||
import ai.djl.training.util.ProgressBar;
|
||||
import ai.djl.translate.TranslateException;
|
||||
import cn.smartjavaai.common.entity.DetectionResponse;
|
||||
import cn.smartjavaai.common.enums.DeviceEnum;
|
||||
import cn.smartjavaai.common.pool.ModelPredictorPoolManager;
|
||||
import cn.smartjavaai.common.pool.PredictorFactory;
|
||||
import cn.smartjavaai.common.utils.FileUtils;
|
||||
import cn.smartjavaai.common.utils.ImageUtils;
|
||||
import cn.smartjavaai.common.utils.OpenCVUtils;
|
||||
import cn.smartjavaai.objectdetection.DetectorConfig;
|
||||
import cn.smartjavaai.objectdetection.DetectorModelConfig;
|
||||
import cn.smartjavaai.objectdetection.config.DetectorModelConfig;
|
||||
import cn.smartjavaai.objectdetection.constant.DetectorConstant;
|
||||
import cn.smartjavaai.objectdetection.criteria.CriteriaBuilderFactory;
|
||||
import cn.smartjavaai.objectdetection.exception.DetectionException;
|
||||
import cn.smartjavaai.objectdetection.utils.DetectorUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.pool2.ObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -50,23 +43,16 @@ public class DetectorModel implements AutoCloseable{
|
||||
|
||||
//private Predictor<Image, DetectedObjects> predictor;
|
||||
|
||||
private static final String DJL_MODEL_PREFIX = "djl://";
|
||||
|
||||
|
||||
private ObjectPool<Predictor<Image, DetectedObjects>> predictorPool;
|
||||
|
||||
public void loadModel(DetectorModelConfig config){
|
||||
Device device = null;
|
||||
if(!Objects.isNull(config.getDevice())){
|
||||
device = config.getDevice() == DeviceEnum.CPU ? Device.cpu() : Device.gpu();
|
||||
if(Objects.isNull(config.getModelEnum())){
|
||||
throw new DetectionException("未配置模型枚举");
|
||||
}
|
||||
Criteria<Image, DetectedObjects> criteria = Criteria.builder()
|
||||
.optApplication(Application.CV.OBJECT_DETECTION)
|
||||
.setTypes(Image.class, DetectedObjects.class)
|
||||
.optArgument("threshold", config.getThreshold() > 0 ? config.getThreshold() : DetectorConfig.DEFAULT_THRESHOLD)
|
||||
.optModelUrls(DJL_MODEL_PREFIX + config.getModelEnum().getModelUri())
|
||||
.optDevice(device)
|
||||
.optProgress(new ProgressBar())
|
||||
.build();
|
||||
Criteria<Image, DetectedObjects> criteria = CriteriaBuilderFactory.createCriteria(config);
|
||||
|
||||
try {
|
||||
model = criteria.loadModel();
|
||||
// 创建池子:每个线程独享 Predictor
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package cn.smartjavaai.objectdetection.model;
|
||||
|
||||
import cn.smartjavaai.common.config.Config;
|
||||
import cn.smartjavaai.objectdetection.DetectorModelConfig;
|
||||
import cn.smartjavaai.objectdetection.DetectorModelEnum;
|
||||
import cn.smartjavaai.objectdetection.config.DetectorModelConfig;
|
||||
import cn.smartjavaai.objectdetection.enums.DetectorModelEnum;
|
||||
import cn.smartjavaai.objectdetection.exception.DetectionException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
<parent>
|
||||
<groupId>cn.smartjavaai</groupId>
|
||||
<artifactId>smartjavaai-parent</artifactId>
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>smartjavaai-ocr</artifactId>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
<!-- <maven.compiler.source>11</maven.compiler.source>-->
|
||||
<!-- <maven.compiler.target>11</maven.compiler.target>-->
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<javacv.version>1.5.8</javacv.version>
|
||||
<javacv.ffmpeg.version>5.1.2-1.5.8</javacv.ffmpeg.version>
|
||||
@@ -41,7 +41,7 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<version>1.0.12</version>
|
||||
<version>1.0.13</version>
|
||||
<name>smartjavaai-ocr</name>
|
||||
<description>SmartJavaAI</description>
|
||||
<url>https://github.com/geekwenjie/SmartJavaAI</url>
|
||||
@@ -84,7 +84,7 @@
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>
|
||||
<!-- <javadocExecutable>${java.home}/bin/javadoc</javadocExecutable>-->
|
||||
<doclint>none</doclint>
|
||||
<additionalJOptions>
|
||||
<additionalJOption>-Xdoclint:none</additionalJOption>
|
||||
|
||||
Reference in New Issue
Block a user