diff --git a/README.md b/README.md
index ae0153e..5d11bca 100644
--- a/README.md
+++ b/README.md
@@ -228,7 +228,8 @@ SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的
语音识别
- - 支持100种语言
+ - 支持100种语言
+ - 支持实时语音识别
|
@@ -343,7 +344,7 @@ SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的
cn.smartjavaai
smartjavaai-all
- 1.0.23
+ 1.0.24
```
### 3、完整示例代码
@@ -592,15 +593,20 @@ SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的
## 献代码的步骤
1、在Gitee或者Github/Gitcode上fork项目到自己的repo
+
2、把fork过去的项目也就是你的项目clone到你的本地
+
3、修改代码(记得一定要修改dev分支)
+
4、commit后push到自己的库(dev分支)
+
5、登录Gitee或Github/Gitcode在你首页可以看到一个 pull request 按钮,点击它,填写一些说明信息,然后提交即可。
+
6、等待维护者合并
## 近期更新日志
-## [v1.0.23] - 2025-08-09
+## [v1.0.24] - 2025-08-09
- 新增 语音识别模块,集成 OpenAI 开源的 Whisper 和 Vosk
- 修复 质量评估模型的 Bug
- 修复 OCR 模块 recognizeAndDraw 方法的 Bug
diff --git a/smartjavaai-all/pom.xml b/all/pom.xml
similarity index 94%
rename from smartjavaai-all/pom.xml
rename to all/pom.xml
index 75bb859..0e06207 100644
--- a/smartjavaai-all/pom.xml
+++ b/all/pom.xml
@@ -6,11 +6,11 @@
cn.smartjavaai
smartjavaai-parent
- 1.0.23
+ 1.0.24
- smartjavaai-all
- 1.0.23
+ all
+ 1.0.24
${project.artifactId}
SmartJavaAI
https://github.com/geekwenjie/SmartJavaAI
@@ -33,31 +33,31 @@
cn.smartjavaai
- smartjavaai-face
+ face
${project.version}
cn.smartjavaai
- smartjavaai-objectdetection
+ vision
${project.version}
cn.smartjavaai
- smartjavaai-ocr
+ ocr
${project.version}
cn.smartjavaai
- smartjavaai-translate
+ translate
${project.version}
cn.smartjavaai
- smartjavaai-speech
+ speech
${project.version}
diff --git a/all/src/test/java/Test.java b/all/src/test/java/Test.java
new file mode 100644
index 0000000..245980a
--- /dev/null
+++ b/all/src/test/java/Test.java
@@ -0,0 +1,47 @@
+import ai.djl.Application;
+import ai.djl.Model;
+import ai.djl.repository.zoo.Criteria;
+import ai.djl.repository.zoo.ModelZoo;
+import cn.smartjavaai.ocr.config.OcrDetModelConfig;
+import cn.smartjavaai.ocr.entity.OcrBox;
+import cn.smartjavaai.ocr.enums.CommonDetModelEnum;
+import cn.smartjavaai.ocr.factory.OcrModelFactory;
+import cn.smartjavaai.ocr.model.common.detect.OcrCommonDetModel;
+import lombok.extern.slf4j.Slf4j;
+import org.bytedeco.javacv.FFmpegFrameGrabber;
+import org.bytedeco.javacv.Frame;
+import org.bytedeco.javacv.Java2DFrameUtils;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * @author dwj
+ * @date 2025/4/24
+ */
+@Slf4j
+public class Test {
+
+
+ public static String savePath = "/Users/wenjie/Downloads/";
+ //public static String image1Path = "/Users/wenjie/Documents/idea_workplace/SmartJavaAI-Demo/src/main/resources/5.jpg";
+ public static String image1Path = "/Users/wenjie/Documents/idea_workplace/SmartJavaAI-Demo/src/main/resources/MJ_20250226_172200.png";
+
+ public static String image2Path = "/Users/wenjie/Documents/idea_workplace/SmartJavaAI-Demo/src/main/resources/MJ_20250226_172222.png";
+
+ public static void main(String[] args) throws IOException {
+// // 加载模型
+// Model model = ModelZoo.loadModel(Criteria.builder()
+// .optApplication(Application.NLP.ANY)
+// .optEngine("PyTorch")
+// .optModelName("Llama 3")
+// .optTranslatorFactory(new Llama3TranslatorFactory())
+// .optTranslatorProvider(() -> new Llama3Translator())
+// .build());
+
+
+ }
+
+
+}
diff --git a/smartjavaai-bom/pom.xml b/bom/pom.xml
similarity index 92%
rename from smartjavaai-bom/pom.xml
rename to bom/pom.xml
index acf3279..c73693c 100644
--- a/smartjavaai-bom/pom.xml
+++ b/bom/pom.xml
@@ -6,12 +6,12 @@
cn.smartjavaai
smartjavaai-parent
- 1.0.23
+ 1.0.24
- 1.0.23
- smartjavaai-bom
- smartjavaai-bom
+ 1.0.24
+ bom
+ sbom
统一版本管理的 BOM 包,同时支持 import 和全量依赖
@@ -25,27 +25,27 @@
cn.smartjavaai
- smartjavaai-face
+ face
${project.parent.version}
cn.smartjavaai
- smartjavaai-objectdetection
+ vision
${project.parent.version}
cn.smartjavaai
- smartjavaai-ocr
+ ocr
${project.parent.version}
cn.smartjavaai
- smartjavaai-translate
+ translate
${project.parent.version}
cn.smartjavaai
- smartjavaai-speech
+ speech
${project.parent.version}
diff --git a/build/output/0.png b/build/output/0.png
new file mode 100644
index 0000000..7092e20
Binary files /dev/null and b/build/output/0.png differ
diff --git a/build/output/0crop.png b/build/output/0crop.png
new file mode 100644
index 0000000..b7e2cca
Binary files /dev/null and b/build/output/0crop.png differ
diff --git a/build/output/1.png b/build/output/1.png
new file mode 100644
index 0000000..7fc2031
Binary files /dev/null and b/build/output/1.png differ
diff --git a/build/output/10.png b/build/output/10.png
new file mode 100644
index 0000000..017c967
Binary files /dev/null and b/build/output/10.png differ
diff --git a/build/output/10crop.png b/build/output/10crop.png
new file mode 100644
index 0000000..5afe051
Binary files /dev/null and b/build/output/10crop.png differ
diff --git a/build/output/11.png b/build/output/11.png
new file mode 100644
index 0000000..2c1b426
Binary files /dev/null and b/build/output/11.png differ
diff --git a/build/output/11crop.png b/build/output/11crop.png
new file mode 100644
index 0000000..63b5afd
Binary files /dev/null and b/build/output/11crop.png differ
diff --git a/build/output/12.png b/build/output/12.png
new file mode 100644
index 0000000..1d429e8
Binary files /dev/null and b/build/output/12.png differ
diff --git a/build/output/12crop.png b/build/output/12crop.png
new file mode 100644
index 0000000..2ae7697
Binary files /dev/null and b/build/output/12crop.png differ
diff --git a/build/output/13.png b/build/output/13.png
new file mode 100644
index 0000000..f677beb
Binary files /dev/null and b/build/output/13.png differ
diff --git a/build/output/13crop.png b/build/output/13crop.png
new file mode 100644
index 0000000..5fd78d0
Binary files /dev/null and b/build/output/13crop.png differ
diff --git a/build/output/14.png b/build/output/14.png
new file mode 100644
index 0000000..e7b9346
Binary files /dev/null and b/build/output/14.png differ
diff --git a/build/output/14crop.png b/build/output/14crop.png
new file mode 100644
index 0000000..af9584b
Binary files /dev/null and b/build/output/14crop.png differ
diff --git a/build/output/15.png b/build/output/15.png
new file mode 100644
index 0000000..9ac9735
Binary files /dev/null and b/build/output/15.png differ
diff --git a/build/output/15crop.png b/build/output/15crop.png
new file mode 100644
index 0000000..03a69de
Binary files /dev/null and b/build/output/15crop.png differ
diff --git a/build/output/1crop.png b/build/output/1crop.png
new file mode 100644
index 0000000..32bb534
Binary files /dev/null and b/build/output/1crop.png differ
diff --git a/build/output/2.png b/build/output/2.png
new file mode 100644
index 0000000..9e32185
Binary files /dev/null and b/build/output/2.png differ
diff --git a/build/output/2crop.png b/build/output/2crop.png
new file mode 100644
index 0000000..b62e6a1
Binary files /dev/null and b/build/output/2crop.png differ
diff --git a/build/output/3.png b/build/output/3.png
new file mode 100644
index 0000000..b90bc03
Binary files /dev/null and b/build/output/3.png differ
diff --git a/build/output/3crop.png b/build/output/3crop.png
new file mode 100644
index 0000000..2584aaa
Binary files /dev/null and b/build/output/3crop.png differ
diff --git a/build/output/4.png b/build/output/4.png
new file mode 100644
index 0000000..62cb0ab
Binary files /dev/null and b/build/output/4.png differ
diff --git a/build/output/4crop.png b/build/output/4crop.png
new file mode 100644
index 0000000..22c5211
Binary files /dev/null and b/build/output/4crop.png differ
diff --git a/build/output/5.png b/build/output/5.png
new file mode 100644
index 0000000..768affd
Binary files /dev/null and b/build/output/5.png differ
diff --git a/build/output/5crop.png b/build/output/5crop.png
new file mode 100644
index 0000000..f9fba23
Binary files /dev/null and b/build/output/5crop.png differ
diff --git a/build/output/6.png b/build/output/6.png
new file mode 100644
index 0000000..e4602ba
Binary files /dev/null and b/build/output/6.png differ
diff --git a/build/output/6crop.png b/build/output/6crop.png
new file mode 100644
index 0000000..75f7bbc
Binary files /dev/null and b/build/output/6crop.png differ
diff --git a/build/output/7.png b/build/output/7.png
new file mode 100644
index 0000000..a56e06e
Binary files /dev/null and b/build/output/7.png differ
diff --git a/build/output/7crop.png b/build/output/7crop.png
new file mode 100644
index 0000000..7d45920
Binary files /dev/null and b/build/output/7crop.png differ
diff --git a/build/output/8.png b/build/output/8.png
new file mode 100644
index 0000000..b9d0fdf
Binary files /dev/null and b/build/output/8.png differ
diff --git a/build/output/8crop.png b/build/output/8crop.png
new file mode 100644
index 0000000..17b127e
Binary files /dev/null and b/build/output/8crop.png differ
diff --git a/build/output/9.png b/build/output/9.png
new file mode 100644
index 0000000..3e769d4
Binary files /dev/null and b/build/output/9.png differ
diff --git a/build/output/9crop.png b/build/output/9crop.png
new file mode 100644
index 0000000..5e1f927
Binary files /dev/null and b/build/output/9crop.png differ
diff --git a/build/output/9rotate.png b/build/output/9rotate.png
new file mode 100644
index 0000000..59812e1
Binary files /dev/null and b/build/output/9rotate.png differ
diff --git a/build/output/cn_layout_detect_result.png b/build/output/cn_layout_detect_result.png
new file mode 100644
index 0000000..793a3bc
Binary files /dev/null and b/build/output/cn_layout_detect_result.png differ
diff --git a/build/output/ocr_1_detected.jpg b/build/output/ocr_1_detected.jpg
new file mode 100644
index 0000000..f0e2c82
Binary files /dev/null and b/build/output/ocr_1_detected.jpg differ
diff --git a/build/output/table.jpg b/build/output/table.jpg
new file mode 100644
index 0000000..b1ba41f
Binary files /dev/null and b/build/output/table.jpg differ
diff --git a/build/output/yolo_detected.png b/build/output/yolo_detected.png
new file mode 100644
index 0000000..0f6494b
Binary files /dev/null and b/build/output/yolo_detected.png differ
diff --git a/smartjavaai-common/pom.xml b/common/pom.xml
similarity index 97%
rename from smartjavaai-common/pom.xml
rename to common/pom.xml
index 749bec1..24a57e4 100644
--- a/smartjavaai-common/pom.xml
+++ b/common/pom.xml
@@ -6,11 +6,11 @@
cn.smartjavaai
smartjavaai-parent
- 1.0.23
+ 1.0.24
- smartjavaai-common
- smartjavaai-common
+ common
+ common
SmartJavaAI
https://github.com/geekwenjie/SmartJavaAI
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/config/Config.java b/common/src/main/java/cn/smartjavaai/common/config/Config.java
similarity index 83%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/config/Config.java
rename to common/src/main/java/cn/smartjavaai/common/config/Config.java
index 9e1c9d9..cf6ad84 100644
--- a/smartjavaai-common/src/main/java/cn/smartjavaai/common/config/Config.java
+++ b/common/src/main/java/cn/smartjavaai/common/config/Config.java
@@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
+import java.nio.file.Paths;
/**
* 全局配置
@@ -68,16 +69,25 @@ public class Config {
String osName = SystemUtil.getOsInfo().getName();
log.info("当前操作系统:{}", osName);
if(osName.toLowerCase().contains("windows")){
- cachePath = SystemUtil.getUserInfo().getHomeDir() + CACHE_DIR;
+ cachePath = Paths.get(
+ SystemUtil.getUserInfo().getHomeDir(),
+ "smartjavaai_cache"
+ ).toString();
FileUtil.mkdir(cachePath);
}else if(osName.toLowerCase().contains("linux")){
cachePath = "/root/" + CACHE_DIR;
FileUtil.mkdir(cachePath);
}else if(osName.toLowerCase().contains("mac")){
- cachePath = SystemUtil.getUserInfo().getHomeDir() + CACHE_DIR;
+ cachePath = Paths.get(
+ SystemUtil.getUserInfo().getHomeDir(),
+ "smartjavaai_cache"
+ ).toString();
FileUtil.mkdir(cachePath);
}else{
- cachePath = SystemUtil.getUserInfo().getHomeDir() + CACHE_DIR;
+ cachePath = Paths.get(
+ SystemUtil.getUserInfo().getHomeDir(),
+ "smartjavaai_cache"
+ ).toString();
FileUtil.mkdir(cachePath);
}
}
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/config/ModelConfig.java b/common/src/main/java/cn/smartjavaai/common/config/ModelConfig.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/config/ModelConfig.java
rename to common/src/main/java/cn/smartjavaai/common/config/ModelConfig.java
diff --git a/common/src/main/java/cn/smartjavaai/common/cv/SmartImageFactory.java b/common/src/main/java/cn/smartjavaai/common/cv/SmartImageFactory.java
new file mode 100644
index 0000000..9f456a1
--- /dev/null
+++ b/common/src/main/java/cn/smartjavaai/common/cv/SmartImageFactory.java
@@ -0,0 +1,65 @@
+package cn.smartjavaai.common.cv;
+
+import ai.djl.modality.cv.BufferedImageFactory;
+import ai.djl.modality.cv.Image;
+import ai.djl.modality.cv.ImageFactory;
+import ai.djl.modality.cv.output.DetectedObjects;
+import ai.djl.modality.cv.util.NDImageUtils;
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.types.DataType;
+import ai.djl.ndarray.types.Shape;
+import ai.djl.opencv.OpenCVImageFactory;
+import ai.djl.util.Utils;
+import cn.smartjavaai.common.utils.Base64ImageUtils;
+import cn.smartjavaai.common.utils.OpenCVUtils;
+import nu.pattern.OpenCV;
+import org.opencv.core.CvType;
+import org.opencv.core.Mat;
+import org.opencv.core.MatOfByte;
+import org.opencv.imgcodecs.Imgcodecs;
+import org.opencv.imgproc.Imgproc;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.nio.file.Path;
+
+/**
+ * 图片处理工厂类
+ * @author dwj
+ */
+public class SmartImageFactory extends BufferedImageFactory {
+
+ private static volatile SmartImageFactory instance;
+
+ public static SmartImageFactory newInstance() {
+ if (instance == null) {
+ synchronized (SmartImageFactory.class) {
+ if (instance == null) {
+ instance = new SmartImageFactory();
+ }
+ }
+ }
+ return instance;
+ }
+
+ public static SmartImageFactory getInstance(){
+ return newInstance();
+ }
+
+ public Image fromBufferedImage(BufferedImage sourceImage){
+ return fromImage(OpenCVUtils.image2Mat(sourceImage));
+ }
+
+ public Image fromBase64(String base64Image) throws IOException {
+ return fromUrl(base64Image);
+ }
+
+ public Image fromBytes(byte[] imageData){
+ return fromImage(new ByteArrayInputStream(imageData));
+ }
+
+}
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/DetectionInfo.java b/common/src/main/java/cn/smartjavaai/common/entity/DetectionInfo.java
similarity index 86%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/DetectionInfo.java
rename to common/src/main/java/cn/smartjavaai/common/entity/DetectionInfo.java
index 4142637..247adca 100644
--- a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/DetectionInfo.java
+++ b/common/src/main/java/cn/smartjavaai/common/entity/DetectionInfo.java
@@ -32,6 +32,16 @@ public class DetectionInfo {
*/
private ObjectDetInfo objectDetInfo;
+ /**
+ * 目标分割信息
+ */
+ private InstanceSegInfo instanceSegInfo;
+
+ /**
+ * 旋转框信息
+ */
+ private ObbDetInfo obbDetInfo;
+
public DetectionInfo() {
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/DetectionRectangle.java b/common/src/main/java/cn/smartjavaai/common/entity/DetectionRectangle.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/DetectionRectangle.java
rename to common/src/main/java/cn/smartjavaai/common/entity/DetectionRectangle.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/DetectionResponse.java b/common/src/main/java/cn/smartjavaai/common/entity/DetectionResponse.java
similarity index 86%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/DetectionResponse.java
rename to common/src/main/java/cn/smartjavaai/common/entity/DetectionResponse.java
index 394f3ea..a0df61e 100644
--- a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/DetectionResponse.java
+++ b/common/src/main/java/cn/smartjavaai/common/entity/DetectionResponse.java
@@ -1,5 +1,6 @@
package cn.smartjavaai.common.entity;
+import ai.djl.modality.cv.Image;
import lombok.Data;
import java.util.List;
@@ -14,6 +15,8 @@ public class DetectionResponse {
private List detectionInfoList;
+ private Image drawnImage;
+
public DetectionResponse() {
}
diff --git a/common/src/main/java/cn/smartjavaai/common/entity/InstanceSegInfo.java b/common/src/main/java/cn/smartjavaai/common/entity/InstanceSegInfo.java
new file mode 100644
index 0000000..6d42298
--- /dev/null
+++ b/common/src/main/java/cn/smartjavaai/common/entity/InstanceSegInfo.java
@@ -0,0 +1,29 @@
+package cn.smartjavaai.common.entity;
+
+import lombok.Data;
+
+/**
+ * 目标分割信息
+ * @author dwj
+ */
+@Data
+public class InstanceSegInfo {
+
+ /**
+ * 类别名称
+ */
+ private String className;
+
+ /**
+ * 遮罩
+ */
+ private float[][] mask;
+
+ public InstanceSegInfo() {
+ }
+
+ public InstanceSegInfo(String className, float[][] mask) {
+ this.className = className;
+ this.mask = mask;
+ }
+}
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/Language.java b/common/src/main/java/cn/smartjavaai/common/entity/Language.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/Language.java
rename to common/src/main/java/cn/smartjavaai/common/entity/Language.java
diff --git a/common/src/main/java/cn/smartjavaai/common/entity/ObbDetInfo.java b/common/src/main/java/cn/smartjavaai/common/entity/ObbDetInfo.java
new file mode 100644
index 0000000..7490df3
--- /dev/null
+++ b/common/src/main/java/cn/smartjavaai/common/entity/ObbDetInfo.java
@@ -0,0 +1,29 @@
+package cn.smartjavaai.common.entity;
+
+import java.util.List;
+
+/**
+ * 定向边界框 检测结果
+ * @author dwj
+ */
+public class ObbDetInfo {
+
+ /**
+ * 类别名称
+ */
+ private String className;
+
+ /**
+ * 检测框坐标
+ */
+ private RotatedBox rotatedBox;
+
+ public ObbDetInfo() {
+ }
+
+
+ public ObbDetInfo(String className, RotatedBox rotatedBox) {
+ this.className = className;
+ this.rotatedBox = rotatedBox;
+ }
+}
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/ObjectDetInfo.java b/common/src/main/java/cn/smartjavaai/common/entity/ObjectDetInfo.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/ObjectDetInfo.java
rename to common/src/main/java/cn/smartjavaai/common/entity/ObjectDetInfo.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/Point.java b/common/src/main/java/cn/smartjavaai/common/entity/Point.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/Point.java
rename to common/src/main/java/cn/smartjavaai/common/entity/Point.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/R.java b/common/src/main/java/cn/smartjavaai/common/entity/R.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/R.java
rename to common/src/main/java/cn/smartjavaai/common/entity/R.java
diff --git a/common/src/main/java/cn/smartjavaai/common/entity/RotatedBox.java b/common/src/main/java/cn/smartjavaai/common/entity/RotatedBox.java
new file mode 100644
index 0000000..bf76541
--- /dev/null
+++ b/common/src/main/java/cn/smartjavaai/common/entity/RotatedBox.java
@@ -0,0 +1,38 @@
+package cn.smartjavaai.common.entity;
+
+/**
+ * 旋转框
+ * @author dwj
+ */
+public class RotatedBox {
+
+ /**
+ * 左上角
+ */
+ private Point topLeft;
+
+ /**
+ * 右上角
+ */
+ private Point topRight;
+
+ /**
+ * 右下角
+ */
+ private Point bottomRight;
+
+ /**
+ * 左下角
+ */
+ private Point bottomLeft;
+
+ public RotatedBox(Point topLeft, Point topRight, Point bottomRight, Point bottomLeft) {
+ this.topLeft = topLeft;
+ this.topRight = topRight;
+ this.bottomRight = bottomRight;
+ this.bottomLeft = bottomLeft;
+ }
+
+ public RotatedBox() {
+ }
+}
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/face/ExpressionResult.java b/common/src/main/java/cn/smartjavaai/common/entity/face/ExpressionResult.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/face/ExpressionResult.java
rename to common/src/main/java/cn/smartjavaai/common/entity/face/ExpressionResult.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/face/FaceAttribute.java b/common/src/main/java/cn/smartjavaai/common/entity/face/FaceAttribute.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/face/FaceAttribute.java
rename to common/src/main/java/cn/smartjavaai/common/entity/face/FaceAttribute.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/face/FaceInfo.java b/common/src/main/java/cn/smartjavaai/common/entity/face/FaceInfo.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/face/FaceInfo.java
rename to common/src/main/java/cn/smartjavaai/common/entity/face/FaceInfo.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/face/FaceSearchResult.java b/common/src/main/java/cn/smartjavaai/common/entity/face/FaceSearchResult.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/face/FaceSearchResult.java
rename to common/src/main/java/cn/smartjavaai/common/entity/face/FaceSearchResult.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/face/HeadPose.java b/common/src/main/java/cn/smartjavaai/common/entity/face/HeadPose.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/face/HeadPose.java
rename to common/src/main/java/cn/smartjavaai/common/entity/face/HeadPose.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/face/LivenessResult.java b/common/src/main/java/cn/smartjavaai/common/entity/face/LivenessResult.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/face/LivenessResult.java
rename to common/src/main/java/cn/smartjavaai/common/entity/face/LivenessResult.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/ocr/TableStructure.java b/common/src/main/java/cn/smartjavaai/common/entity/ocr/TableStructure.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/entity/ocr/TableStructure.java
rename to common/src/main/java/cn/smartjavaai/common/entity/ocr/TableStructure.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/enums/DeviceEnum.java b/common/src/main/java/cn/smartjavaai/common/enums/DeviceEnum.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/enums/DeviceEnum.java
rename to common/src/main/java/cn/smartjavaai/common/enums/DeviceEnum.java
diff --git a/common/src/main/java/cn/smartjavaai/common/enums/VideoSourceType.java b/common/src/main/java/cn/smartjavaai/common/enums/VideoSourceType.java
new file mode 100644
index 0000000..522c501
--- /dev/null
+++ b/common/src/main/java/cn/smartjavaai/common/enums/VideoSourceType.java
@@ -0,0 +1,12 @@
+package cn.smartjavaai.common.enums;
+
+/**
+ * 视频源类型枚举
+ * @author dwj
+ * @date 2025/8/27
+ */
+public enum VideoSourceType {
+ STREAM, // RTSP 或 HTTP 流
+ FILE, // 本地视频文件
+ CAMERA; // 本地摄像头
+}
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/enums/face/EyeStatus.java b/common/src/main/java/cn/smartjavaai/common/enums/face/EyeStatus.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/enums/face/EyeStatus.java
rename to common/src/main/java/cn/smartjavaai/common/enums/face/EyeStatus.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/enums/face/FacialExpression.java b/common/src/main/java/cn/smartjavaai/common/enums/face/FacialExpression.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/enums/face/FacialExpression.java
rename to common/src/main/java/cn/smartjavaai/common/enums/face/FacialExpression.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/enums/face/GenderType.java b/common/src/main/java/cn/smartjavaai/common/enums/face/GenderType.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/enums/face/GenderType.java
rename to common/src/main/java/cn/smartjavaai/common/enums/face/GenderType.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/enums/face/LivenessStatus.java b/common/src/main/java/cn/smartjavaai/common/enums/face/LivenessStatus.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/enums/face/LivenessStatus.java
rename to common/src/main/java/cn/smartjavaai/common/enums/face/LivenessStatus.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/pool/CommonPredictorFactory.java b/common/src/main/java/cn/smartjavaai/common/pool/CommonPredictorFactory.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/pool/CommonPredictorFactory.java
rename to common/src/main/java/cn/smartjavaai/common/pool/CommonPredictorFactory.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/pool/ModelPredictorPoolManager.java b/common/src/main/java/cn/smartjavaai/common/pool/ModelPredictorPoolManager.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/pool/ModelPredictorPoolManager.java
rename to common/src/main/java/cn/smartjavaai/common/pool/ModelPredictorPoolManager.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/pool/PredictorFactory.java b/common/src/main/java/cn/smartjavaai/common/pool/PredictorFactory.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/pool/PredictorFactory.java
rename to common/src/main/java/cn/smartjavaai/common/pool/PredictorFactory.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/preprocess/BufferedImagePreprocessor.java b/common/src/main/java/cn/smartjavaai/common/preprocess/BufferedImagePreprocessor.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/preprocess/BufferedImagePreprocessor.java
rename to common/src/main/java/cn/smartjavaai/common/preprocess/BufferedImagePreprocessor.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/ArrayUtils.java b/common/src/main/java/cn/smartjavaai/common/utils/ArrayUtils.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/ArrayUtils.java
rename to common/src/main/java/cn/smartjavaai/common/utils/ArrayUtils.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/Base64ImageUtils.java b/common/src/main/java/cn/smartjavaai/common/utils/Base64ImageUtils.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/Base64ImageUtils.java
rename to common/src/main/java/cn/smartjavaai/common/utils/Base64ImageUtils.java
diff --git a/common/src/main/java/cn/smartjavaai/common/utils/DJLCommonUtils.java b/common/src/main/java/cn/smartjavaai/common/utils/DJLCommonUtils.java
new file mode 100644
index 0000000..0f1ccb1
--- /dev/null
+++ b/common/src/main/java/cn/smartjavaai/common/utils/DJLCommonUtils.java
@@ -0,0 +1,32 @@
+package cn.smartjavaai.common.utils;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * @author dwj
+ */
+public class DJLCommonUtils {
+
+ /**
+ * 检查模型目录中是否存在 "serving.properties" 文件
+ *
+ * @param modelPath 模型目录路径
+ * @return true 表示存在,false 表示不存在
+ */
+ public static boolean isServingPropertiesExists(Path modelPath) {
+ if (modelPath == null || !Files.exists(modelPath)) {
+ return false;
+ }
+ // 确定目录路径
+ Path dirPath = Files.isDirectory(modelPath) ? modelPath : modelPath.getParent();
+ if (dirPath == null) {
+ return false; // 可能是根目录的文件
+ }
+
+ // 判断目录下的 serving.properties 是否存在
+ Path servingFile = dirPath.resolve("serving.properties");
+ return Files.exists(servingFile);
+ }
+
+}
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/FileUtils.java b/common/src/main/java/cn/smartjavaai/common/utils/FileUtils.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/FileUtils.java
rename to common/src/main/java/cn/smartjavaai/common/utils/FileUtils.java
diff --git a/common/src/main/java/cn/smartjavaai/common/utils/FrameConverterUtil.java b/common/src/main/java/cn/smartjavaai/common/utils/FrameConverterUtil.java
new file mode 100644
index 0000000..b2ac439
--- /dev/null
+++ b/common/src/main/java/cn/smartjavaai/common/utils/FrameConverterUtil.java
@@ -0,0 +1,66 @@
+package cn.smartjavaai.common.utils;
+
+import ai.djl.modality.cv.Image;
+import ai.djl.modality.cv.ImageFactory;
+import org.bytedeco.javacpp.BytePointer;
+import org.bytedeco.javacv.OpenCVFrameConverter;
+import org.bytedeco.opencv.opencv_core.CvMat;
+import org.bytedeco.opencv.opencv_core.Mat;
+import org.opencv.core.CvType;
+
+import java.awt.image.BufferedImage;
+
+/**
+ * @author dwj
+ * @date 2025/8/27
+ */
+public class FrameConverterUtil {
+
+ /**
+ * 将 Bytedeco Mat 转为 DJL Image
+ * 支持 1/3/4 通道
+ */
+ public static Image matToDJLImage(Mat cvMat) {
+ if (cvMat == null || cvMat.empty()) {
+ return null;
+ }
+
+ int width = cvMat.cols();
+ int height = cvMat.rows();
+ int channels = cvMat.channels();
+
+ int[] pixels = new int[width * height];
+
+ if (channels == 1) { // 灰度图
+ byte[] data = new byte[width * height];
+ cvMat.data().get(data);
+ for (int i = 0; i < width * height; i++) {
+ int gray = data[i] & 0xFF;
+ pixels[i] = (0xFF << 24) | (gray << 16) | (gray << 8) | gray;
+ }
+ } else if (channels == 3) { // BGR
+ byte[] data = new byte[width * height * 3];
+ cvMat.data().get(data);
+ for (int i = 0; i < width * height; i++) {
+ int b = data[i * 3] & 0xFF;
+ int g = data[i * 3 + 1] & 0xFF;
+ int r = data[i * 3 + 2] & 0xFF;
+ pixels[i] = (0xFF << 24) | (r << 16) | (g << 8) | b;
+ }
+ } else if (channels == 4) { // BGRA
+ byte[] data = new byte[width * height * 4];
+ cvMat.data().get(data);
+ for (int i = 0; i < width * height; i++) {
+ int b = data[i * 4] & 0xFF;
+ int g = data[i * 4 + 1] & 0xFF;
+ int r = data[i * 4 + 2] & 0xFF;
+ int a = data[i * 4 + 3] & 0xFF;
+ pixels[i] = (a << 24) | (r << 16) | (g << 8) | b;
+ }
+ } else {
+ throw new IllegalArgumentException("只支持 1/3/4 通道图像");
+ }
+
+ return ImageFactory.getInstance().fromPixels(pixels, width, height);
+ }
+}
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/ImageUtils.java b/common/src/main/java/cn/smartjavaai/common/utils/ImageUtils.java
similarity index 99%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/ImageUtils.java
rename to common/src/main/java/cn/smartjavaai/common/utils/ImageUtils.java
index e71e281..e0b6344 100644
--- a/smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/ImageUtils.java
+++ b/common/src/main/java/cn/smartjavaai/common/utils/ImageUtils.java
@@ -139,7 +139,7 @@ public class ImageUtils {
* @param width
* @param height
*/
- public static void drawImageRect(Image image, int x, int y, int width, int height) {
+ public static void drawBufferedImageRect(Image image, int x, int y, int width, int height) {
// 将绘制图像转换为Graphics2D
BufferedImage bufferedImage = (BufferedImage)image.getWrappedImage();
Graphics2D g = (Graphics2D) bufferedImage.getGraphics();
@@ -501,4 +501,7 @@ public class ImageUtils {
+
+
+
}
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/LetterBoxUtils.java b/common/src/main/java/cn/smartjavaai/common/utils/LetterBoxUtils.java
similarity index 80%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/LetterBoxUtils.java
rename to common/src/main/java/cn/smartjavaai/common/utils/LetterBoxUtils.java
index 678251b..c2eca79 100644
--- a/smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/LetterBoxUtils.java
+++ b/common/src/main/java/cn/smartjavaai/common/utils/LetterBoxUtils.java
@@ -1,5 +1,6 @@
package cn.smartjavaai.common.utils;
+import ai.djl.modality.cv.output.Rectangle;
import ai.djl.modality.cv.util.NDImageUtils;
import ai.djl.ndarray.NDArray;
import ai.djl.ndarray.NDManager;
@@ -121,4 +122,27 @@ public class LetterBoxUtils {
return boxes;
}
+ /**
+ * 恢复缩放后的 box(左上角坐标)
+ * @param rectangle
+ * @param scale
+ * @param origImageWidth
+ * @param origImageHeight
+ */
+ public static Rectangle restoreBox(Rectangle rectangle, float scale, int origImageWidth, int origImageHeight, int inputWidth, int inputHeight){
+ double paddingWidth = (inputWidth - origImageWidth * scale) / 2;
+ double paddingHeight = (inputHeight - origImageHeight * scale) / 2;
+
+ // 去掉 padding
+ double x_noPad = rectangle.getX() - paddingWidth;
+ double y_noPad = rectangle.getY() - paddingHeight;
+
+ //模型输出就是原图坐标
+ double x1 = x_noPad / scale / origImageWidth;
+ double y1 = y_noPad / scale / origImageHeight;
+ double boxW = rectangle.getWidth() / scale / origImageWidth ;
+ double boxH = rectangle.getHeight() / scale / origImageHeight;
+ return new Rectangle(x1, y1, boxW, boxH);
+ }
+
}
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/NMSUtils.java b/common/src/main/java/cn/smartjavaai/common/utils/NMSUtils.java
similarity index 53%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/NMSUtils.java
rename to common/src/main/java/cn/smartjavaai/common/utils/NMSUtils.java
index ef2799a..390f892 100644
--- a/smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/NMSUtils.java
+++ b/common/src/main/java/cn/smartjavaai/common/utils/NMSUtils.java
@@ -1,6 +1,10 @@
package cn.smartjavaai.common.utils;
import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDArrays;
+import ai.djl.ndarray.NDList;
+import ai.djl.ndarray.NDManager;
+import ai.djl.ndarray.types.DataType;
import java.util.ArrayList;
import java.util.List;
@@ -64,4 +68,43 @@ public class NMSUtils {
return keep.stream().mapToInt(i -> i).toArray();
}
+
+
+ /**
+ * 批量执行 NMS,输入 NDArray 形式的 boxes、scores 和 idxs,返回保留的索引列表
+ *
+ * @param boxes NDArray 形状为 (N, 4),格式为 [x1, y1, x2, y2]
+ * @param scores NDArray 形状为 (N,) 或 (N,1),每个 box 的置信度
+ * @param idxs NDArray 形状为 (N,),每个 box 对应的 batch id
+ * @param iouThreshold IOU 阈值,超过该阈值则认为有
+ * @return 批量保留框的索引列表
+ *
+ */
+ public static NDArray batchedNms(NDArray boxes, NDArray scores, NDArray idxs, float iouThreshold, NDManager manager) {
+ List keepList = new ArrayList<>();
+ // 获取唯一 batch id
+ NDArray uniqueIdxs = idxs.unique().get(0);
+ for (long batchId : uniqueIdxs.toLongArray()) {
+ // 找出当前 batch 的框
+ NDArray mask = idxs.eq(batchId);
+ NDArray batchBoxes = boxes.get(mask);
+ NDArray batchScores = scores.get(mask);
+ // 执行单 batch NMS
+ int[] keepIndices = nms(batchBoxes, batchScores, iouThreshold);
+ if (keepIndices.length > 0) {
+ // 将局部索引映射回全局索引
+ NDArray globalIndices = manager.arange(boxes.getShape().get(0))
+ .get(mask)
+ .toType(DataType.INT64, false)
+ .get(manager.create(keepIndices));
+
+ keepList.add(globalIndices);
+ }
+ }
+ if (keepList.isEmpty()) {
+ return manager.create(new long[0]);
+ }
+ return NDArrays.concat(new NDList(keepList));
+ }
+
}
diff --git a/common/src/main/java/cn/smartjavaai/common/utils/OpenCVUtils.java b/common/src/main/java/cn/smartjavaai/common/utils/OpenCVUtils.java
new file mode 100644
index 0000000..ea782d1
--- /dev/null
+++ b/common/src/main/java/cn/smartjavaai/common/utils/OpenCVUtils.java
@@ -0,0 +1,265 @@
+package cn.smartjavaai.common.utils;
+
+import ai.djl.modality.cv.Image;
+import ai.djl.modality.cv.ImageFactory;
+import ai.djl.ndarray.NDArray;
+import ai.djl.ndarray.NDManager;
+import ai.djl.util.RandomUtils;
+import cn.smartjavaai.common.entity.DetectionInfo;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.opencv.core.*;
+import org.opencv.core.Point;
+import org.opencv.imgproc.Imgproc;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferByte;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * OpenCV 工具类
+ */
+public class OpenCVUtils {
+ /**
+ * canny算法,边缘检测
+ *
+ * @param src
+ * @return
+ */
+ public static Mat canny(Mat src) {
+ Mat mat = src.clone();
+ Imgproc.Canny(src, mat, 100, 200);
+ return mat;
+ }
+
+ /**
+ * 画线
+ *
+ * @param mat
+ * @param point1
+ * @param point2
+ */
+ public static void line(Mat mat, Point point1, Point point2) {
+ Imgproc.line(mat, point1, point2, new Scalar(255, 255, 255), 1);
+ }
+
+ /**
+ * NDArray to opencv_core.Mat
+ *
+ * @param manager
+ * @param srcPoints
+ * @param dstPoints
+ * @return
+ */
+ public static Mat toOpenCVMat(NDManager manager, NDArray srcPoints, NDArray dstPoints) {
+ NDArray svdMat = SVDUtils.transformationFromPoints(manager, srcPoints, dstPoints);
+ double[] doubleArray = svdMat.toDoubleArray();
+ Mat newSvdMat = new Mat(2, 3, CvType.CV_64F);
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 3; j++) {
+ newSvdMat.put(i, j, doubleArray[i * 3 + j]);
+ }
+ }
+ return newSvdMat;
+ }
+
+ /**
+ * double[][] points array to Mat
+ * @param points
+ * @return
+ */
+ public static Mat toOpenCVMat(double[][] points) {
+ Mat mat = new Mat(5, 2, CvType.CV_64F);
+ for (int i = 0; i < 5; i++) {
+ for (int j = 0; j < 2; j++) {
+ mat.put(i, j, points[i * 5 + j]);
+ }
+ }
+ return mat;
+ }
+
+ /**
+ * 变换矩阵的逆矩阵
+ *
+ * @param src
+ * @return
+ */
+ public static Mat invertAffineTransform(Mat src) {
+ Mat dst = src.clone();
+ Imgproc.invertAffineTransform(src, dst);
+ return dst;
+ }
+
+ /**
+ * Mat to BufferedImage
+ *
+ * @param mat
+ * @return
+ */
+ public static BufferedImage mat2Image(Mat mat) {
+ int width = mat.width();
+ int height = mat.height();
+ byte[] data = new byte[width * height * (int) mat.elemSize()];
+ Imgproc.cvtColor(mat, mat, 4);
+ mat.get(0, 0, data);
+ BufferedImage ret = new BufferedImage(width, height, 5);
+ ret.getRaster().setDataElements(0, 0, width, height, data);
+ return ret;
+ }
+
+ /**
+ * BufferedImage to Mat
+ *
+ * @param img
+ * @return
+ */
+ public static Mat image2Mat(BufferedImage img) {
+ int width = img.getWidth();
+ int height = img.getHeight();
+
+ // 强制转换为 TYPE_3BYTE_BGR,自动去除透明通道
+ BufferedImage convertedImg = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR);
+ Graphics2D g2d = convertedImg.createGraphics();
+ g2d.drawImage(img, 0, 0, null);
+ g2d.dispose();
+
+ byte[] data = ((DataBufferByte) convertedImg.getRaster().getDataBuffer()).getData();
+ Mat mat = new Mat(height, width, CvType.CV_8UC3);
+ mat.put(0, 0, data);
+ return mat;
+ }
+
+ /**
+ * 透视变换
+ *
+ * @param src
+ * @param srcPoints
+ * @param dstPoints
+ * @return
+ */
+ public static Mat perspectiveTransform(Mat src, Mat srcPoints, Mat dstPoints) {
+ Mat dst = src.clone();
+ Mat warp_mat = Imgproc.getPerspectiveTransform(srcPoints, dstPoints);
+ Imgproc.warpPerspective(src, dst, warp_mat, dst.size());
+ warp_mat.release();
+ return dst;
+ }
+
+ /**
+ * 绘制矩形框和文字
+ *
+ * @param image
+ * @param detectionInfoList
+ */
+ public static void drawRectAndText(Image image, List detectionInfoList) {
+ if(CollectionUtils.isEmpty(detectionInfoList))
+ return;
+ for(DetectionInfo detectionInfo : detectionInfoList){
+ drawRectAndText(image, detectionInfo);
+ }
+ }
+
+
+ /**
+ * 绘制矩形框和文字
+ *
+ * @param image
+ * @param detectionInfo
+ */
+ public static void drawRectAndText(Image image, DetectionInfo detectionInfo) {
+
+
+ Mat mat = (Mat)image.getWrappedImage();
+ if (image == null) return;
+ int x = detectionInfo.getDetectionRectangle().getX();
+ int y = detectionInfo.getDetectionRectangle().getY();
+ int width = detectionInfo.getDetectionRectangle().getWidth();
+ int height = detectionInfo.getDetectionRectangle().getHeight();
+
+ Scalar rectangleColor = new Scalar((double)RandomUtils.nextInt(178), (double)RandomUtils.nextInt(178), (double)RandomUtils.nextInt(178));
+
+ // 绘制矩形框
+ Point pt1 = new Point(x, y);
+ Point pt2 = new Point(x + width, y + height);
+ Imgproc.rectangle(mat, pt1, pt2, rectangleColor, 2);
+
+ // 绘制文字
+ if (Objects.nonNull(detectionInfo.getObjectDetInfo()) && StringUtils.isNotBlank(detectionInfo.getObjectDetInfo().getClassName())) {
+ String className = detectionInfo.getObjectDetInfo().getClassName();
+ Size size = Imgproc.getTextSize(className, 1, 1.3, 1, (int[])null);
+ Point br = new Point((double)x + size.width + 4.0, (double)y + size.height + 4.0);
+ Imgproc.rectangle(mat, pt1, br, rectangleColor, -1);
+ Point point = new Point((double)x, (double)y + size.height + 2.0);
+ Scalar color = new Scalar(255.0, 255.0, 255.0);
+ Imgproc.putText(mat, className, point, 1, 1.3, color, 1);
+ }
+ image = ImageFactory.getInstance().fromImage(mat);
+ }
+
+ /**
+ * 在Mat上绘制矩形框和文字
+ *
+ * @param mat 待绘制的Mat
+ * @param x 矩形左上角X
+ * @param y 矩形左上角Y
+ * @param width 矩形宽度
+ * @param height 矩形高度
+ * @param color 框的颜色,例如 new Scalar(0, 255, 0) 绿色
+ * @param thickness 框线宽度
+ * @param text 需要绘制的文字,可以为null或空
+ * @param fontScale 文字缩放比例
+ * @param textColor 文字颜色
+ */
+ public static void drawRectAndText(Mat mat,
+ int x, int y, int width, int height,
+ Scalar color, int thickness,
+ String text, double fontScale, Scalar textColor) {
+
+ if (mat == null || mat.empty()) return;
+
+ // 绘制矩形框
+ Point pt1 = new Point(x, y);
+ Point pt2 = new Point(x + width, y + height);
+ Imgproc.rectangle(mat, pt1, pt2, color, thickness);
+
+ // 绘制文字
+ if (text != null && !text.isEmpty()) {
+ int baseline[] = new int[1];
+ Size textSize = Imgproc.getTextSize(text, Imgproc.FONT_HERSHEY_SIMPLEX, fontScale, thickness, baseline);
+ // 保证文字不超出矩形
+ Point textOrg = new Point(x, y - 5 < 0 ? y + textSize.height + 5 : y - 5);
+ Imgproc.putText(mat, text, textOrg, Imgproc.FONT_HERSHEY_SIMPLEX, fontScale, textColor, thickness);
+ }
+ }
+
+ /**
+ * 将 Bytedeco 的 Mat 转换为 OpenCV 官方的 Mat
+ * @param src Bytedeco Mat (BGR 或 BGRA)
+ * @return OpenCV Mat (BGR 或 BGRA)
+ */
+ public static org.opencv.core.Mat convertToOpenCVMat(org.bytedeco.opencv.opencv_core.Mat bMat) {
+
+
+ try {
+ int width = bMat.cols();
+ int height = bMat.rows();
+ int channels = bMat.channels();
+
+ // 创建 OpenCV Mat
+ org.opencv.core.Mat cvMat = new org.opencv.core.Mat(height, width, channels == 3 ? CvType.CV_8UC3 : CvType.CV_8UC1);
+
+ // 从 bytedeco Mat 获取像素数据
+ byte[] data = new byte[width * height * channels];
+ bMat.data().get(data);
+
+ // 填充到 OpenCV Mat
+ cvMat.put(0, 0, data);
+ return cvMat;
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/PointUtils.java b/common/src/main/java/cn/smartjavaai/common/utils/PointUtils.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/PointUtils.java
rename to common/src/main/java/cn/smartjavaai/common/utils/PointUtils.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/PoolUtils.java b/common/src/main/java/cn/smartjavaai/common/utils/PoolUtils.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/PoolUtils.java
rename to common/src/main/java/cn/smartjavaai/common/utils/PoolUtils.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/SVDUtils.java b/common/src/main/java/cn/smartjavaai/common/utils/SVDUtils.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/SVDUtils.java
rename to common/src/main/java/cn/smartjavaai/common/utils/SVDUtils.java
diff --git a/smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/VideoUtils.java b/common/src/main/java/cn/smartjavaai/common/utils/VideoUtils.java
similarity index 100%
rename from smartjavaai-common/src/main/java/cn/smartjavaai/common/utils/VideoUtils.java
rename to common/src/main/java/cn/smartjavaai/common/utils/VideoUtils.java
diff --git a/examples/face-example/pom.xml b/examples/face-example/pom.xml
index cd2e3c9..d10c33d 100644
--- a/examples/face-example/pom.xml
+++ b/examples/face-example/pom.xml
@@ -12,7 +12,7 @@
11
11
UTF-8
- 1.0.23
+ 1.0.24
smartai.examples.face.facedet.FaceDetDemo
@@ -255,6 +255,14 @@
runtime
+
+ ai.djl.pytorch
+ pytorch-native-cpu
+ linux-aarch64
+ runtime
+ 2.5.1
+
+
diff --git a/examples/face-example/src/main/java/smartai/examples/face/PythonTranslator.java b/examples/face-example/src/main/java/smartai/examples/face/PythonTranslator.java
new file mode 100644
index 0000000..542118c
--- /dev/null
+++ b/examples/face-example/src/main/java/smartai/examples/face/PythonTranslator.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
+ * with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
+ * OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions
+ * and limitations under the License.
+ */
+package smartai.examples.face;
+
+import ai.djl.ModelException;
+import ai.djl.inference.Predictor;
+import ai.djl.modality.Classifications;
+import ai.djl.modality.Input;
+import ai.djl.modality.Output;
+import ai.djl.modality.cv.Image;
+import ai.djl.ndarray.NDList;
+import ai.djl.repository.zoo.Criteria;
+import ai.djl.repository.zoo.ZooModel;
+import ai.djl.translate.NoBatchifyTranslator;
+import ai.djl.translate.TranslateException;
+import ai.djl.translate.TranslatorContext;
+import ai.djl.util.JsonUtils;
+import ai.djl.util.Utils;
+
+import com.google.gson.reflect.TypeToken;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Type;
+import java.net.URL;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class PythonTranslator implements NoBatchifyTranslator {
+
+ private ZooModel model;
+ private Predictor predictor;
+
+ @Override
+ public void prepare(TranslatorContext ctx) throws ModelException, IOException {
+ if (predictor == null) {
+ Criteria criteria =
+ Criteria.builder()
+ .setTypes(Input.class, Output.class)
+ .optModelPath(Paths.get("src/test/python"))
+ .optEngine("Python")
+ .build();
+ model = criteria.loadModel();
+ predictor = model.newPredictor();
+ }
+ }
+
+// @Override
+// public NDList processInput(TranslatorContext ctx, String url)
+// throws IOException, TranslateException {
+// Input input = new Input();
+// try (InputStream is = new URL(url).openStream()) {
+// input.add("data", Utils.toByteArray(is));
+// }
+// input.addProperty("Content-Type", "image/jpeg");
+// // calling preprocess() function in model.py
+// input.addProperty("handler", "preprocess");
+// Output output = predictor.predict(input);
+// if (output.getCode() != 200) {
+// throw new TranslateException("Python preprocess() failed: " + output.getMessage());
+// }
+//
+// return output.getDataAsNDList(ctx.getNDManager());
+// }
+
+ @Override
+ public NDList processInput(TranslatorContext ctx, byte[] image)
+ throws IOException, TranslateException {
+ Input input = new Input();
+ input.add("data", image);
+ input.addProperty("Content-Type", "image/jpeg");
+ // calling preprocess() function in model.py
+ input.addProperty("handler", "preprocess");
+ Output output = predictor.predict(input);
+ if (output.getCode() != 200) {
+ throw new TranslateException("Python preprocess() failed: " + output.getMessage());
+ }
+ return output.getDataAsNDList(ctx.getNDManager());
+ }
+
+ @Override
+ public Classifications processOutput(TranslatorContext ctx, NDList list)
+ throws TranslateException {
+ Input input = new Input();
+ input.add("data", list);
+ // calling postprocess() function in processing.py
+ input.addProperty("handler", "postprocess");
+ Output output = predictor.predict(input);
+ if (output.getCode() != 200) {
+ throw new TranslateException("Python postprocess() failed: " + output.getMessage());
+ }
+
+ String json = output.getData().getAsString();
+ System.out.println("json:" + json);
+ return null;
+ }
+
+ public void close() {
+ if (predictor != null) {
+ predictor.close();
+ model.close();
+ predictor = null;
+ model = null;
+ }
+ }
+}
diff --git a/examples/face-example/src/main/java/smartai/examples/face/Test.java b/examples/face-example/src/main/java/smartai/examples/face/Test.java
new file mode 100644
index 0000000..cbcbcd7
--- /dev/null
+++ b/examples/face-example/src/main/java/smartai/examples/face/Test.java
@@ -0,0 +1,99 @@
+package smartai.examples.face;
+
+import ai.djl.Application;
+import ai.djl.Device;
+import ai.djl.MalformedModelException;
+import ai.djl.inference.Predictor;
+import ai.djl.modality.Classifications;
+import ai.djl.modality.audio.Audio;
+import ai.djl.modality.audio.AudioFactory;
+import ai.djl.modality.audio.translator.SpeechRecognitionTranslatorFactory;
+import ai.djl.repository.Artifact;
+import ai.djl.repository.MRL;
+import ai.djl.repository.zoo.Criteria;
+import ai.djl.repository.zoo.ModelNotFoundException;
+import ai.djl.repository.zoo.ModelZoo;
+import ai.djl.repository.zoo.ZooModel;
+import ai.djl.translate.TranslateException;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author dwj
+ * @date 2025/7/29
+ */
+@Slf4j
+public class Test {
+
+ public static void main(String[] args) throws ModelNotFoundException, MalformedModelException, IOException, TranslateException {
+// PythonTranslator translator = new PythonTranslator();
+// Criteria criteria =
+// Criteria.builder()
+// .setTypes(byte[].class, Classifications.class)
+// .optModelPath(Paths.get("/Users/wenjie/Documents/develop/model/arcfaceresnet100-11-int8.onnx"))
+// .optEngine("OnnxRuntime")
+// .optTranslator(translator)
+// .build();
+// String path = "/Users/wenjie/Downloads/facetest/jsy.jpg";
+// try (ZooModel model = criteria.loadModel();
+// Predictor predictor = model.newPredictor()) {
+// byte[] data = Files.readAllBytes(Paths.get(path));
+// Classifications ret = predictor.predict(data);
+// System.out.println(ret);
+// }
+//
+// // unload python model
+// translator.close();
+
+
+ // Load model.
+ // Wav2Vec2 model is a speech model that accepts a float array corresponding to the raw
+ // waveform of the speech signal.
+
+// String url = "/Users/wenjie/Downloads/20210601_u2++_conformer_exp/final.pt";
+// Criteria |