Merge pull request #26 from geekwenjie/master

合并
This commit is contained in:
geekwenjie
2025-12-31 11:37:17 +08:00
committed by GitHub
29 changed files with 451 additions and 73 deletions

View File

@@ -39,6 +39,22 @@
SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的 JAVA AI算法工具包致力于帮助JAVA开发者零门槛使用各种AI算法模型开发者无需深入了解底层实现即可轻松在 Java 代码中调用人脸识别、目标检测、OCR 等功能。底层支持包括基于 DJL (Deep Java Library) 封装的深度学习模型,以及通过 JNI 接入的 C++/Python 算法,兼容多种主流深度学习框架如 PyTorch、TensorFlow、ONNX、Paddle 等,屏蔽复杂的模型部署与调用细节,开发者无需了解 AI 底层实现即可直接在 Java 项目中集成使用,后续将持续扩展更多算法,目标是构建一个“像 Hutool 一样简单易用”的 JAVA AI 通用工具箱
## 📱 SmartJavaAI Android 商业版
**SmartJavaAI 现已支持 Android 移动端!**
如果您有移动端离线人脸识别的需求,我们推出了基于 SmartJavaAI 的 Android SDK 及演示 APP。
* 🚀 **核心能力**:毫秒级离线人脸检测、比对、注册与 1:N 搜索。
* 📦 **开箱即用**:提供标准 SDK 接口与完整 Demo APK。
* 💼 **商业授权**Android 版本为商业授权版本。
👉 **[点击查看 Android 版演示截图、APK 下载及获取方式](./android.md)**
## 🚀 能力展示
<div align="center">
@@ -498,7 +514,7 @@ SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的
<dependency>
<groupId>cn.smartjavaai</groupId>
<artifactId>all</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
</dependency>
```

View File

@@ -6,11 +6,11 @@
<parent>
<groupId>cn.smartjavaai</groupId>
<artifactId>smartjavaai-parent</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
</parent>
<artifactId>all</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
<name>${project.artifactId}</name>
<description>SmartJavaAI</description>
<url>https://github.com/geekwenjie/SmartJavaAI</url>

68
android.md Normal file
View File

@@ -0,0 +1,68 @@
# SmartJavaAI Android 商业版 (SDK & App)
欢迎关注 SmartJavaAI Android 版本。这是专为移动设备打造的高性能、离线人脸识别解决方案。
## ✨ 核心功能
Android 版本包含以下四大核心模块,支持完全**离线运行**,无需联网:
1. **人脸检测 (Face Detection)**
2. **人脸注册 (Face Registration)**
3. **人脸比对 (Face Comparison 1:1)**
4. **人脸查询 (Face Search 1:N)**
---
## 📸 效果演示
所见即所得,以下是 Demo App 在真机上的运行实拍:
| **人脸检测** | **人脸比对** |
|:----------------------------------------------------------------------------------------------------------------:|:------------------------------------------------------------------------------------------------:|
| <img src="https://cdn.jsdelivr.net/gh/geekwenjie/SmartJavaAI-Site/images/android/android1.jpg"/> | <img src="https://cdn.jsdelivr.net/gh/geekwenjie/SmartJavaAI-Site/images/android/android2.jpg"/> |
---
## 🚀 免费试用申请 (Free Trial)
我们为开发者提供 **3天全功能免费试用 License**,以便您充分评估 SDK 的性能与效果。请按照以下步骤获取试用:
### 第一步:下载演示 APK
* **文件名**SmartJavaAI_Face_Demo_v1.0.apk
* **下载地址**[点击这里下载 APK](https://pan.baidu.com/s/1cJhY9q6HcRiLX7orv6CoXQ?pwd=1234)
### 第二步:邮件申请 License
请发送邮件至 **775747758@qq.com** 申请试用授权License。
* **邮件标题**SmartJavaAI Android 试用申请
* **邮件内容**
* **申请类型**:企业 / 个人
* **公司名称/个人姓名**
* **联系电话**(选填)
* **用途简述**(例如:门禁项目测试)
> 💡 **小贴士**:您可以直接复制上方内容。收到邮件后,我们通常会在 24 小时内将 License 文件回复给您。
### 第三步:激活使用
下载 APK 并安装后,将邮件附件中的 `秘钥` 粘贴到 App中即可开启 3 天免费试用。
---
## 🤝 正式商业授权与咨询
试用满意后,如需购买正式商业授权,请联系我们:
* **SDK 形式**:提供标准 AAR/Jar 包,方便集成。
* **源码支持**:提供完整的 Demo 工程源码。
---
**咨询微信 (WeChat)[deng775747758]**
*(添加时请备注android)*
---
[🔙 返回项目主页](./README.md)

View File

@@ -6,10 +6,10 @@
<parent>
<groupId>cn.smartjavaai</groupId>
<artifactId>smartjavaai-parent</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
</parent>
<version>1.1.0</version>
<version>1.1.1</version>
<artifactId>bom</artifactId>
<name>bom</name>
<description>统一版本管理的 BOM 包,同时支持 import 和全量依赖</description>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>cn.smartjavaai</groupId>
<artifactId>smartjavaai-parent</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
</parent>
<name>common</name>

View File

@@ -24,6 +24,7 @@ import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.file.Path;
@@ -147,6 +148,19 @@ public class SmartImageFactory {
return ImageFactory.getInstance().fromInputStream(inputStream);
}
public Image fromUrl(URL url) throws IOException {
if (url == null) {
throw new IllegalArgumentException("URL 不能为空");
}
try (InputStream inputStream = url.openStream()) {
return ImageFactory.getInstance().fromInputStream(inputStream);
}
}
public Image fromUrl(String urlString) throws IOException {
return this.fromUrl(new URL(urlString));
}
}

View File

@@ -0,0 +1,35 @@
# 使用官方 Ubuntu 22.04 作为基础
FROM ubuntu:22.04
# 设置工作目录(可选,但推荐)
WORKDIR /app
# 更新 apt 仓库并安装 OpenJDK 11
RUN apt-get update && \
apt-get install -y --no-install-recommends openjdk-11-jdk && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# (可选) 验证 Java 安装 (可以选择添加你的应用程序,并编译运行,或者只是执行 java -version)
RUN java -version
# 设置默认的模型路径环境变量
ENV SMART_MODEL_PATH=/app/models
# 创建该目录
RUN mkdir -p /app/models
# 挂载
VOLUME ["/app/models"]
# UTF-8
ENV LANG=zh_CN.UTF-8
ENV LC_ALL=zh_CN.UTF-8
# 声明服务运行在8080端口
EXPOSE 8080
# 指定docker容器启动时运行jar包
ENTRYPOINT ["java", "-Dfile.encoding=UTF-8", "-jar", "app.jar"]

View File

@@ -12,9 +12,9 @@
<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.1.0</smartjavaai.version>
<smartjavaai.version>1.1.1</smartjavaai.version>
<!--如果打包运行需要替换成你的main-->
<exec.mainClass>smartai.examples.face.facedet.FaceDetDemo</exec.mainClass>
<exec.mainClass>smartai.examples.face.FaceDemo</exec.mainClass>
<javacv.version>1.5.10</javacv.version>
@@ -86,8 +86,22 @@
<dependency>
<groupId>cn.smartjavaai</groupId>
<artifactId>face</artifactId>
<exclusions>
<exclusion>
<groupId>com.microsoft.onnxruntime</groupId>
<artifactId>onnxruntime</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.microsoft.onnxruntime</groupId>
<artifactId>onnxruntime</artifactId>
<version>1.20.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>ai.djl.pytorch</groupId>
<artifactId>pytorch-jni</artifactId>

View File

@@ -0,0 +1,73 @@
package smartai.examples.face;
import ai.djl.modality.cv.Image;
import cn.smartjavaai.common.config.Config;
import cn.smartjavaai.common.cv.SmartImageFactory;
import cn.smartjavaai.common.entity.DetectionInfo;
import cn.smartjavaai.common.entity.DetectionResponse;
import cn.smartjavaai.common.entity.R;
import cn.smartjavaai.common.utils.ImageUtils;
import cn.smartjavaai.face.config.FaceDetConfig;
import cn.smartjavaai.face.constant.FaceDetectConstant;
import cn.smartjavaai.face.enums.FaceDetModelEnum;
import cn.smartjavaai.face.factory.FaceDetModelFactory;
import cn.smartjavaai.face.model.facedect.FaceDetModel;
import cn.smartjavaai.face.utils.FaceUtils;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import java.io.InputStream;
/**
* @author dwj
* @date 2025/12/23
*/
@Slf4j
public class FaceDemo {
public static String MODEL_PATH = "";
/**
* 获取人脸检测模型
* 注意事项:极速模型,识别准确度低,速度快
* @return
*/
public static FaceDetModel getFaceDetModel(){
FaceDetConfig config = new FaceDetConfig();
//人脸检测模型SmartJavaAI提供了多种模型选择(更多模型,请查看文档)切换模型需要同时修改modelEnum及modelPath
config.setModelEnum(FaceDetModelEnum.YOLOV5_FACE_320);
//下载模型并替换本地路径下载地址https://pan.baidu.com/s/10l22x5fRz_gwLr8EAHa1Jg?pwd=1234 提取码: 1234
config.setModelPath(MODEL_PATH + "/face_model/yolo-face/yolov5face-n-0.5-320x320.onnx");
//只返回相似度大于该值的人脸,需要根据实际情况调整,分值越大越严格容易漏检,分值越小越宽松容易误识别
config.setConfidenceThreshold(0.5f);
//用于去除重复的人脸框,当两个框的重叠度超过该值时,只保留一个
config.setNmsThresh(FaceDetectConstant.NMS_THRESHOLD);
return FaceDetModelFactory.getInstance().getModel(config);
}
public static void main(String[] args) {
try {
MODEL_PATH = System.getenv("SMART_MODEL_PATH");
log.info("MODEL_PATH:" + MODEL_PATH);
Config.setCachePath("/app/smartjavaai_cache");
FaceDetModel faceModel = getFaceDetModel();
InputStream is = FaceDemo.class
.getClassLoader()
.getResourceAsStream("iu_1.jpg");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromInputStream(is);
R<DetectionResponse> detectedResult = faceModel.detect(image);
if(detectedResult.isSuccess()){
log.info("人脸检测结果:{}", JSONObject.toJSONString(detectedResult.getData()));
}else{
log.info("人脸检测失败:{}", detectedResult.getMessage());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -31,9 +31,6 @@ import cn.smartjavaai.face.utils.FaceUtils;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import nu.pattern.OpenCV;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameUtils;
import org.junit.BeforeClass;
import org.junit.Test;
import org.opencv.core.Mat;

View File

@@ -0,0 +1,35 @@
# 使用官方 Ubuntu 22.04 作为基础
FROM ubuntu:22.04
# 设置工作目录(可选,但推荐)
WORKDIR /app
# 更新 apt 仓库并安装 OpenJDK 11
RUN apt-get update && \
apt-get install -y --no-install-recommends openjdk-11-jdk && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# (可选) 验证 Java 安装 (可以选择添加你的应用程序,并编译运行,或者只是执行 java -version)
RUN java -version
# 设置默认的模型路径环境变量
ENV SMART_MODEL_PATH=/app/models
# 创建该目录
RUN mkdir -p /app/models
# 挂载
VOLUME ["/app/models"]
# UTF-8
ENV LANG=zh_CN.UTF-8
ENV LC_ALL=zh_CN.UTF-8
# 声明服务运行在8080端口
EXPOSE 8080
# 指定docker容器启动时运行jar包
ENTRYPOINT ["java", "-Dfile.encoding=UTF-8", "-jar", "app.jar"]

View File

@@ -12,7 +12,7 @@
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<smartjavaai.version>1.1.0</smartjavaai.version>
<smartjavaai.version>1.1.1</smartjavaai.version>
<!--如果打包运行需要替换成你的main-->
<exec.mainClass>smartai.examples.ocr.common.OcrRecognizeDemo</exec.mainClass>
@@ -89,6 +89,19 @@
<dependency>
<groupId>cn.smartjavaai</groupId>
<artifactId>ocr</artifactId>
<exclusions>
<exclusion>
<groupId>com.microsoft.onnxruntime</groupId>
<artifactId>onnxruntime</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.microsoft.onnxruntime</groupId>
<artifactId>onnxruntime</artifactId>
<version>1.20.0</version>
<scope>runtime</scope>
</dependency>

View File

@@ -0,0 +1,35 @@
# 使用官方 Ubuntu 22.04 作为基础
FROM ubuntu:22.04
# 设置工作目录(可选,但推荐)
WORKDIR /app
# 更新 apt 仓库并安装 OpenJDK 11
RUN apt-get update && \
apt-get install -y --no-install-recommends openjdk-11-jdk && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# (可选) 验证 Java 安装 (可以选择添加你的应用程序,并编译运行,或者只是执行 java -version)
RUN java -version
# 设置默认的模型路径环境变量
ENV SMART_MODEL_PATH=/app/models
# 创建该目录
RUN mkdir -p /app/models
# 挂载
VOLUME ["/app/models"]
# UTF-8
ENV LANG=zh_CN.UTF-8
ENV LC_ALL=zh_CN.UTF-8
# 声明服务运行在8080端口
EXPOSE 8080
# 指定docker容器启动时运行jar包
ENTRYPOINT ["java", "-Dfile.encoding=UTF-8", "-jar", "app.jar"]

View File

@@ -12,7 +12,7 @@
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<smartjavaai.version>1.1.0</smartjavaai.version>
<smartjavaai.version>1.1.1</smartjavaai.version>
<!--如果打包运行需要替换成你的main-->
<exec.mainClass>smartai.examples.speech.asr.common.OcrRecognizeDemo</exec.mainClass>

View File

@@ -234,6 +234,8 @@ public class SpeechRecognizeDemo {
@Test
public void testVosk() {
try {
//解决中文乱码问题
System.setProperty("jna.encoding","utf-8");
SpeechRecognizer recognizer = geVoskRecognizer();
//建议上传 WAV 格式音频。其他格式将自动转换为 WAV可能影响处理速度
R<AsrResult> result = recognizer.recognize("src/main/resources/lff_zh.mp3");
@@ -289,6 +291,8 @@ public class SpeechRecognizeDemo {
@Test
public void testVoskAdvanced() {
try {
//解决中文乱码问题
System.setProperty("jna.encoding","utf-8");
VoskRecognizer recognizer = (VoskRecognizer)geVoskRecognizer();
//使用vosk内部接口需要指定识别音频的采样率
Recognizer voskRecognizer = recognizer.createAdvancedRecognizer(16000);
@@ -318,6 +322,8 @@ public class SpeechRecognizeDemo {
@Test
public void testVoskRealTime() {
try {
//解决中文乱码问题
System.setProperty("jna.encoding","utf-8");
VoskRecognizer recognizer = (VoskRecognizer)geVoskRecognizer();
//使用vosk内部接口需要指定识别音频的采样率
Recognizer voskRecognizer = recognizer.createAdvancedRecognizer(16000);

View File

@@ -0,0 +1,35 @@
# 使用官方 Ubuntu 22.04 作为基础
FROM ubuntu:22.04
# 设置工作目录(可选,但推荐)
WORKDIR /app
# 更新 apt 仓库并安装 OpenJDK 11
RUN apt-get update && \
apt-get install -y --no-install-recommends openjdk-11-jdk && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# (可选) 验证 Java 安装 (可以选择添加你的应用程序,并编译运行,或者只是执行 java -version)
RUN java -version
# 设置默认的模型路径环境变量
ENV SMART_MODEL_PATH=/app/models
# 创建该目录
RUN mkdir -p /app/models
# 挂载
VOLUME ["/app/models"]
# UTF-8
ENV LANG=zh_CN.UTF-8
ENV LC_ALL=zh_CN.UTF-8
# 声明服务运行在8080端口
EXPOSE 8080
# 指定docker容器启动时运行jar包
ENTRYPOINT ["java", "-Dfile.encoding=UTF-8", "-jar", "app.jar"]

View File

@@ -12,7 +12,7 @@
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<smartjavaai.version>1.1.0</smartjavaai.version>
<smartjavaai.version>1.1.1</smartjavaai.version>
<!--如果打包运行需要替换成你的main-->
<exec.mainClass>smartai.examples.nlp.translation.TranslationDemo</exec.mainClass>

View File

@@ -0,0 +1,35 @@
# 使用官方 Ubuntu 22.04 作为基础
FROM ubuntu:22.04
# 设置工作目录(可选,但推荐)
WORKDIR /app
# 更新 apt 仓库并安装 OpenJDK 11
RUN apt-get update && \
apt-get install -y --no-install-recommends openjdk-11-jdk && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# (可选) 验证 Java 安装 (可以选择添加你的应用程序,并编译运行,或者只是执行 java -version)
RUN java -version
# 设置默认的模型路径环境变量
ENV SMART_MODEL_PATH=/app/models
# 创建该目录
RUN mkdir -p /app/models
# 挂载
VOLUME ["/app/models"]
# UTF-8
ENV LANG=zh_CN.UTF-8
ENV LC_ALL=zh_CN.UTF-8
# 声明服务运行在8080端口
EXPOSE 8080
# 指定docker容器启动时运行jar包
ENTRYPOINT ["java", "-Dfile.encoding=UTF-8", "-jar", "app.jar"]

View File

@@ -12,7 +12,7 @@
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<smartjavaai.version>1.1.0</smartjavaai.version>
<smartjavaai.version>1.1.1</smartjavaai.version>
<!--如果打包运行需要替换成你的main-->
<exec.mainClass>smartai.examples.vision.ObjectDetectionDemo</exec.mainClass>
@@ -86,6 +86,19 @@
<dependency>
<groupId>cn.smartjavaai</groupId>
<artifactId>vision</artifactId>
<exclusions>
<exclusion>
<groupId>com.microsoft.onnxruntime</groupId>
<artifactId>onnxruntime</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.microsoft.onnxruntime</groupId>
<artifactId>onnxruntime</artifactId>
<version>1.20.0</version>
<scope>runtime</scope>
</dependency>
@@ -241,17 +254,10 @@
<dependency>
<groupId>ai.djl.tensorflow</groupId>
<artifactId>tensorflow-native-cpu</artifactId>
<classifier>${javacv.platform.linux-arm64}</classifier>
<classifier>${djl.platform.linux-aarch64}</classifier>
<scope>runtime</scope>
<version>2.16.1</version>
</dependency>
<dependency>
<groupId>ai.djl.mxnet</groupId>
<artifactId>mxnet-native-mkl</artifactId>
<classifier>${javacv.platform.linux-arm64}</classifier>
<scope>runtime</scope>
<version>1.9.1</version>
</dependency>
<!-- macOS M系列 平台 (保留对应平台的配置,可以减小包大小)-->

View File

@@ -205,13 +205,16 @@ public class ObjectDetectionDemo {
*/
@Test
public void testStream(){
StreamDetector detector = new StreamDetector.Builder()
//视频源类型:支持视频流、本地摄像头、视频文件
.sourceType(VideoSourceType.STREAM)
//视频流地址支持rtsp、rtmp、http等常见视频流
.streamUrl("rtsp://username:password@ip:port/Streaming/Channels/101")
.streamUrl("rtsp://127.0.0.1:8554/stream")
//每隔多少帧检测一次(需要根据模型检测速度决定)
.frameDetectionInterval(10)
//是否打印调试日志
.enableDebugLog(false)
//目标检测模型
.detectorModel(getModel())
//回调函数检测到指定目标时触发getModel中可指定模型检测的物体
@@ -246,6 +249,7 @@ public class ObjectDetectionDemo {
}
}).build();
detector.startDetection();
//阻塞主线程
CountDownLatch latch = new CountDownLatch(1);
try {
@@ -319,8 +323,6 @@ public class ObjectDetectionDemo {
.frameDetectionInterval(5)
//目标检测模型
.detectorModel(getModel())
//同物体重复检测时间间隔单位s
.repeatGap(5)
//回调函数检测到指定目标时触发getModel中可指定模型检测的物体
.listener(new StreamDetectionListener() {
@Override

View File

@@ -6,11 +6,11 @@
<parent>
<groupId>cn.smartjavaai</groupId>
<artifactId>smartjavaai-parent</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
</parent>
<artifactId>face</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
<name>face</name>
<description>SmartJavaAI</description>
<url>https://github.com/geekwenjie/SmartJavaAI</url>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>cn.smartjavaai</groupId>
<artifactId>smartjavaai-parent</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
</parent>
<artifactId>ocr</artifactId>
@@ -42,7 +42,7 @@
</dependency>
</dependencies>
<version>1.1.0</version>
<version>1.1.1</version>
<name>ocr</name>
<description>SmartJavaAI</description>
<url>https://github.com/geekwenjie/SmartJavaAI</url>

View File

@@ -7,7 +7,7 @@
<name>SmartJavaAI</name>
<groupId>cn.smartjavaai</groupId>
<artifactId>smartjavaai-parent</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
<packaging>pom</packaging>
<description>SmartJavaAI</description>
<modules>
@@ -109,7 +109,7 @@
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<version>1.18.34</version>
</dependency>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>cn.smartjavaai</groupId>
<artifactId>smartjavaai-parent</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
</parent>
<artifactId>speech</artifactId>
@@ -57,7 +57,7 @@
</dependencies>
<version>1.1.0</version>
<version>1.1.1</version>
<name>speech</name>
<description>SmartJavaAI</description>
<url>https://github.com/geekwenjie/SmartJavaAI</url>

View File

@@ -56,6 +56,8 @@ public class VoskRecognizer implements SpeechRecognizer{
@Override
public void loadModel(AsrModelConfig config) {
this.config = config;
//防止中文乱码
System.setProperty("jna.encoding","utf-8");
if(StringUtils.isBlank(config.getModelPath())){
throw new AsrException("modelPath is null");
}

View File

@@ -25,7 +25,7 @@
</dependency>
</dependencies>
<version>1.1.0</version>
<version>1.1.1</version>
<name>translate</name>
<description>SmartJavaAI</description>
<url>https://github.com/geekwenjie/SmartJavaAI</url>

View File

@@ -6,11 +6,11 @@
<parent>
<groupId>cn.smartjavaai</groupId>
<artifactId>smartjavaai-parent</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
</parent>
<artifactId>vision</artifactId>
<version>1.1.0</version>
<version>1.1.1</version>
<name>vision</name>
<description>SmartJavaAI</description>
<url>https://github.com/geekwenjie/SmartJavaAI</url>

View File

@@ -29,10 +29,14 @@ public class CriteriaBuilderFactory {
switch (config.getModelEnum()) {
case YOLOV8_OFFICIAL_ONNX:
return new YoloCriteriaBuilder().buildCriteria(config);
case YOLOV11_OFFICIAL_ONNX:
return new YoloCriteriaBuilder().buildCriteria(config);
case YOLOV12_OFFICIAL_ONNX:
return new YoloCriteriaBuilder().buildCriteria(config);
case YOLOV8_CUSTOM_ONNX:
return new YoloCriteriaBuilder().buildCriteria(config);
case YOLOV11_CUSTOM_ONNX:
return new YoloCriteriaBuilder().buildCriteria(config);
case YOLOV12_CUSTOM_ONNX:
return new YoloCriteriaBuilder().buildCriteria(config);
case TENSORFLOW2_OFFICIAL:

View File

@@ -49,7 +49,6 @@ public class StreamDetector implements AutoCloseable{
//回调线程池
ExecutorService callbackExecutor;
private int frameDetectionInterval = 1;
private long repeatGap = 5; // 秒
private volatile boolean isRunning;
private FrameGrabber grabber;
private StreamDetectionListener listener;
@@ -57,6 +56,8 @@ public class StreamDetector implements AutoCloseable{
private VideoSourceType sourceType = VideoSourceType.STREAM; // 默认流
private int cameraIndex = 0; // 默认第一个摄像头
private boolean enableDebugLog; //是否开启debug log
private Map<String, Long> lastDetectTime = new ConcurrentHashMap<>();
private BlockingQueue<Frame> frameQueue = new LinkedBlockingQueue<>(100);
@@ -84,7 +85,8 @@ public class StreamDetector implements AutoCloseable{
this.listener = builder.listener;
this.sourceType = builder.sourceType;
this.cameraIndex = builder.cameraIndex;
this.repeatGap = builder.repeatGap;
// this.repeatGap = builder.repeatGap;
this.enableDebugLog = builder.enableDebugLog;
this.converterToMat = new OpenCVFrameConverter.ToOrgOpenCvCoreMat();
}
@@ -160,7 +162,7 @@ public class StreamDetector implements AutoCloseable{
* 负责抓取视频帧到队列
*/
private void processFrames() {
long frameCount = 0;
long detectCounter = 0;
while (!grabberFinished && isRunning) {
try {
Frame frame = grabber.grabFrame();
@@ -192,11 +194,16 @@ public class StreamDetector implements AutoCloseable{
continue;
}
}
frameCount++;
if (frameCount % frameDetectionInterval != 0) continue;
detectCounter++;
if (detectCounter < frameDetectionInterval) {
continue;
}
detectCounter = 0;
Frame currentFrame = frame.clone();
frameQueue.offer(currentFrame);
// log.debug("正在抓取第{}帧,当前帧数:{}", frameCount, frameQueue.size());
if (enableDebugLog){
log.debug("当前未处理帧数:{}", frameQueue.size());
}
} catch (Exception e) {
log.error("抓取视频帧异常", e);
}
@@ -242,16 +249,15 @@ public class StreamDetector implements AutoCloseable{
Image image = SmartImageFactory.getInstance().fromMat(mat);
DetectedObjects detectedObjects = predictor.predict(image);
// log.info("内部检测结果:{}", detectedObjects.toString());
if (enableDebugLog){
log.debug("帧检测结果:{}", detectedObjects.toString());
}
DetectionResponse detectionResponse = DetectorUtils.convertToDetectionResponse(detectedObjects, image);
if(Objects.isNull(detectionResponse)){
return;
}
List<DetectionInfo> filtered = filterRepeatedObjects(detectionResponse);
if (!filtered.isEmpty() && listener != null) {
Image copyImage = image.duplicate();
callbackExecutor.submit(() -> listener.onObjectDetected(filtered, copyImage));
}
Image copyImage = image.duplicate();
callbackExecutor.submit(() -> listener.onObjectDetected(detectionResponse.getDetectionInfoList(), copyImage));
} catch (Throwable e) {
e.printStackTrace();
log.error("单帧处理异常", e);
@@ -260,21 +266,6 @@ public class StreamDetector implements AutoCloseable{
}
}
private List<DetectionInfo> filterRepeatedObjects(DetectionResponse response) {
List<DetectionInfo> result = new ArrayList<>();
long now = System.currentTimeMillis();
for (DetectionInfo info : response.getDetectionInfoList()) {
String name = info.getObjectDetInfo().getClassName();
Long last = lastDetectTime.get(name);
if (last == null || (now - last) > repeatGap * 1000) {
lastDetectTime.put(name, now);
result.add(info);
}
}
return result;
}
/**
* 开始检测下一个视频文件
*/
@@ -322,10 +313,6 @@ public class StreamDetector implements AutoCloseable{
@Override
public void close() {
// if(isRunning){
// System.out.println("--isRunning" + isRunning);
// stopDetection();
// }
if (grabberExecutor != null){
grabberExecutor.shutdownNow();
}
@@ -345,15 +332,11 @@ public class StreamDetector implements AutoCloseable{
private VideoSourceType sourceType = VideoSourceType.STREAM; // 默认流
private int cameraIndex = 0; // 默认第一个摄像头
private long repeatGap = 5;//同物体重复检测间隔
private boolean enableDebugLog; //是否开启debug log
public Builder detectorModel(DetectorModel m) { this.detectorModel = m; return this; }
public Builder streamUrl(String url) { this.streamUrl = url; return this; }
public Builder listener(StreamDetectionListener listener) { this.listener = listener; return this; }
public Builder repeatGap(long repeatGap) {
this.repeatGap = repeatGap;
return this;
}
public Builder sourceType(VideoSourceType sourceType) {
this.sourceType = sourceType;
return this;
@@ -368,6 +351,11 @@ public class StreamDetector implements AutoCloseable{
return this;
}
public Builder enableDebugLog(boolean enableDebugLog) {
this.enableDebugLog = enableDebugLog;
return this;
}
public StreamDetector build() {
if (detectorModel == null) {
throw new DetectionException("detectorModel 不能为空");