Skip to content

Commit dfa8cf9

Browse files
committed
【人脸识别】 新增多种人脸识别模型
【底层优化】 支持自由选择 OpenCV 或 BufferedImage 作为图像引擎 【通用图像】 全部模型启用 Image 输入,支持各类图片格式与 Image 的互转 【模型管理】 优化模型生命周期,关闭后可重新创建 【人脸识别】 支持在人脸查询结果中绘制姓名标注 【人脸检测】 新增人脸裁剪功能 【修复】 修复若干已知问题,提升系统稳定性
1 parent 1b50e2b commit dfa8cf9

File tree

133 files changed

+6569
-3466
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

133 files changed

+6569
-3466
lines changed

README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的
426426
### 2、Maven
427427

428428
在项目的 `pom.xml``dependencies` 中可以一次性引入全部功能(如下所示)。
429+
429430
⚠️ **注意:不推荐直接引入全部依赖**,更推荐根据实际需求,按功能模块单独引入,避免引入不必要的包。
430431

431432
详细引入方式请查看 [文档](http://doc.smartjavaai.cn/install.html)、或查看[示例代码](https://gitee.com/dengwenjie/SmartJavaAI/tree/master/examples)
@@ -434,7 +435,7 @@ SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的
434435
<dependency>
435436
<groupId>cn.smartjavaai</groupId>
436437
<artifactId>smartjavaai-all</artifactId>
437-
<version>1.0.24</version>
438+
<version>1.0.25</version>
438439
</dependency>
439440
```
440441

@@ -577,6 +578,7 @@ SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的
577578
| YOLOV8-SEG | OnnxRuntime | Ultralytics在COCO 数据集 上训练的模型 | [Github](https://docs.ultralytics.com/zh/tasks/segment/) |
578579
| YOLOV11-SEG | OnnxRuntime | Ultralytics在COCO 数据集 上训练的模型 | [Github](https://docs.ultralytics.com/zh/tasks/segment/) |
579580
| Mask R-CNN | MXNet | Mask R-CNN 是一种在目标检测基础上,同时为每个物体生成像素级分割区域的深度学习模型 ||
581+
580582
---
581583

582584
#### OBB旋转框目标检测模型
@@ -733,6 +735,18 @@ SmartJavaAI是专为JAVA 开发者打造的一个功能丰富、开箱即用的
733735

734736
## 近期更新日志
735737

738+
## [v1.0.25] - 2025-10-02
739+
- 【人脸检测】新增6个模型(MTCNN、YOLOV5、RetinaFace小尺寸版),大幅提升性能
740+
- 【人脸识别】新增Seetaface6轻量模型
741+
- 【目标检测】支持视频流目标检测(rtsp、视频文件等)
742+
- 【目标检测】支持tensorflow2目标检测模型
743+
- 【目标检测】新增行人检测模型(yolo-person)
744+
- 【通用视觉】新增4个动作识别模型
745+
- 【通用视觉】新增语义分割模型
746+
- 【通用视觉】新增5个实例分割模型(含yolov8-seg、yolov11-seg)
747+
- 【通用视觉】新增yolo-obb11旋转框检测(含yolov11-obb)
748+
- 【通用视觉】新增5个姿态估计模型(含yolov8-pose、yolov11-pose)
749+
736750
## [v1.0.24] - 2025-09-07
737751
- 【人脸检测】新增6个模型(MTCNN、YOLOV5、RetinaFace小尺寸版),大幅提升性能
738752
- 【人脸识别】新增Seetaface6轻量模型

all/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
<parent>
77
<groupId>cn.smartjavaai</groupId>
88
<artifactId>smartjavaai-parent</artifactId>
9-
<version>1.0.24</version>
9+
<version>1.0.25</version>
1010
</parent>
1111

1212
<artifactId>all</artifactId>
13-
<version>1.0.24</version>
13+
<version>1.0.25</version>
1414
<name>${project.artifactId}</name>
1515
<description>SmartJavaAI</description>
1616
<url>https://github.com/geekwenjie/SmartJavaAI</url>

bom/pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
<parent>
77
<groupId>cn.smartjavaai</groupId>
88
<artifactId>smartjavaai-parent</artifactId>
9-
<version>1.0.24</version>
9+
<version>1.0.25</version>
1010
</parent>
1111

12-
<version>1.0.24</version>
12+
<version>1.0.25</version>
1313
<artifactId>bom</artifactId>
14-
<name>sbom</name>
14+
<name>bom</name>
1515
<description>统一版本管理的 BOM 包,同时支持 import 和全量依赖</description>
1616

1717
<properties>

common/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<parent>
77
<groupId>cn.smartjavaai</groupId>
88
<artifactId>smartjavaai-parent</artifactId>
9-
<version>1.0.24</version>
9+
<version>1.0.25</version>
1010
</parent>
1111

1212
<name>common</name>

common/src/main/java/cn/smartjavaai/common/cv/SmartImageFactory.java

Lines changed: 100 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,45 +21,132 @@
2121

2222
import java.awt.image.BufferedImage;
2323
import java.io.ByteArrayInputStream;
24+
import java.io.File;
2425
import java.io.IOException;
2526
import java.io.InputStream;
2627
import java.nio.ByteBuffer;
2728
import java.nio.IntBuffer;
2829
import java.nio.file.Path;
30+
import java.nio.file.Paths;
2931

3032
/**
3133
* 图片处理工厂类
3234
* @author dwj
3335
*/
34-
public class SmartImageFactory extends BufferedImageFactory {
36+
public class SmartImageFactory {
3537

38+
public enum Engine {
39+
BUFFEREDIMAGE,
40+
OPENCV
41+
}
42+
43+
private static volatile Engine currentEngine = Engine.BUFFEREDIMAGE;
3644
private static volatile SmartImageFactory instance;
3745

38-
public static SmartImageFactory newInstance() {
46+
public static synchronized void setEngine(Engine engine) {
47+
if (engine == null || engine == currentEngine) {
48+
return;
49+
}
50+
currentEngine = engine;
51+
// 只在切换时注册全局
52+
switch (currentEngine) {
53+
case OPENCV:
54+
ImageFactory.setImageFactory(new OpenCVImageFactory());
55+
break;
56+
case BUFFEREDIMAGE:
57+
default:
58+
ImageFactory.setImageFactory(new BufferedImageFactory());
59+
}
60+
}
61+
62+
public static synchronized SmartImageFactory getInstance() {
3963
if (instance == null) {
40-
synchronized (SmartImageFactory.class) {
41-
if (instance == null) {
42-
instance = new SmartImageFactory();
43-
}
64+
instance = new SmartImageFactory();
65+
// 初始化全局 Engine
66+
switch (currentEngine) {
67+
case OPENCV:
68+
ImageFactory.setImageFactory(new OpenCVImageFactory());
69+
break;
70+
case BUFFEREDIMAGE:
71+
default:
72+
ImageFactory.setImageFactory(new BufferedImageFactory());
4473
}
4574
}
4675
return instance;
4776
}
4877

49-
public static SmartImageFactory getInstance(){
50-
return newInstance();
51-
}
5278

5379
public Image fromBufferedImage(BufferedImage sourceImage){
54-
return fromImage(OpenCVUtils.image2Mat(sourceImage));
80+
if (sourceImage == null) {
81+
throw new IllegalArgumentException("BufferedImage 不能为空");
82+
}
83+
Image image = null;
84+
switch (currentEngine) {
85+
case BUFFEREDIMAGE:
86+
image = ImageFactory.getInstance().fromImage(sourceImage);
87+
break;
88+
case OPENCV:
89+
// 先转 Mat
90+
Mat mat = OpenCVUtils.image2Mat(sourceImage);
91+
image = ImageFactory.getInstance().fromImage(mat);
92+
break;
93+
default:
94+
throw new IllegalStateException("未知 Engine: " + currentEngine);
95+
}
96+
return image;
97+
}
98+
99+
public Image fromMat(Mat mat){
100+
if (mat == null) {
101+
throw new IllegalArgumentException("mat 不能为空");
102+
}
103+
Image image = null;
104+
switch (currentEngine) {
105+
case OPENCV:
106+
image = ImageFactory.getInstance().fromImage(mat);
107+
break;
108+
case BUFFEREDIMAGE:
109+
// 先转 Mat
110+
BufferedImage sourceImage = OpenCVUtils.mat2Image(mat);
111+
image = ImageFactory.getInstance().fromImage(sourceImage);
112+
break;
113+
default:
114+
throw new IllegalStateException("未知 Engine: " + currentEngine);
115+
}
116+
return image;
55117
}
56118

57119
public Image fromBase64(String base64Image) throws IOException {
58-
return fromUrl(base64Image);
120+
return ImageFactory.getInstance().fromUrl(base64Image);
59121
}
60122

61-
public Image fromBytes(byte[] imageData){
62-
return fromImage(new ByteArrayInputStream(imageData));
123+
public Image fromBytes(byte[] imageData) throws IOException {
124+
return ImageFactory.getInstance().fromInputStream(new ByteArrayInputStream(imageData));
63125
}
64126

127+
public Image fromFile(File file) throws IOException {
128+
return ImageFactory.getInstance().fromFile(file.toPath());
129+
}
130+
131+
public Image fromFile(Path path) throws IOException {
132+
return ImageFactory.getInstance().fromFile(path);
133+
}
134+
135+
public Image fromFile(String filePath) throws IOException {
136+
if (filePath == null || filePath.trim().isEmpty()) {
137+
throw new IllegalArgumentException("filePath 不能为空");
138+
}
139+
return fromFile(Paths.get(filePath));
140+
}
141+
142+
public Image fromPixels(int[] pixels, int width, int height){
143+
return ImageFactory.getInstance().fromPixels(pixels, width, height);
144+
}
145+
146+
public Image fromInputStream(InputStream inputStream) throws IOException {
147+
return ImageFactory.getInstance().fromInputStream(inputStream);
148+
}
149+
150+
151+
65152
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package cn.smartjavaai.common.entity;
2+
3+
import lombok.Data;
4+
5+
import java.util.List;
6+
7+
/**
8+
* 多边形
9+
* @author dwj
10+
*/
11+
@Data
12+
public class PolygonLabel {
13+
14+
private List<Point> points;
15+
private String text;
16+
17+
public PolygonLabel(List<Point> points, String text) {
18+
this.points = points;
19+
this.text = text;
20+
}
21+
22+
public PolygonLabel() {
23+
}
24+
25+
public PolygonLabel(List<Point> points) {
26+
this.points = points;
27+
}
28+
}

common/src/main/java/cn/smartjavaai/common/preprocess/BufferedImagePreprocessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* @author dwj
1111
* @date 2025/6/27
1212
*/
13-
public class BufferedImagePreprocessor {
13+
public class BufferedImagePreprocessor implements ImagePreprocessor<BufferedImage>{
1414

1515
private BufferedImage image;
1616
private DetectionRectangle rect;
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package cn.smartjavaai.common.preprocess;
2+
3+
import ai.djl.modality.cv.Image;
4+
import cn.smartjavaai.common.cv.SmartImageFactory;
5+
import cn.smartjavaai.common.entity.DetectionRectangle;
6+
import org.opencv.core.Mat;
7+
8+
import java.awt.*;
9+
import java.awt.image.BufferedImage;
10+
11+
/**
12+
* @author dwj
13+
*/
14+
public class DJLImagePreprocessor implements ImagePreprocessor<Image>{
15+
16+
17+
private final ImagePreprocessor<?> delegate;
18+
private Image input = null;
19+
20+
public DJLImagePreprocessor(Image image, DetectionRectangle rect) {
21+
this.input = image;
22+
if (input.getWrappedImage() instanceof BufferedImage) {
23+
this.delegate = new BufferedImagePreprocessor((BufferedImage) input.getWrappedImage(), rect);
24+
} else if (input.getWrappedImage() instanceof Mat) {
25+
this.delegate = new OpenCVPreprocessor((Mat) input.getWrappedImage(), rect);
26+
} else {
27+
throw new IllegalArgumentException("Unsupported input type");
28+
}
29+
}
30+
31+
@Override
32+
public DJLImagePreprocessor setExtendRatio(float ratio) {
33+
delegate.setExtendRatio(ratio);
34+
return this;
35+
}
36+
37+
@Override
38+
public DJLImagePreprocessor setTargetSize(int size) {
39+
delegate.setTargetSize(size);
40+
return this;
41+
}
42+
43+
@Override
44+
public DJLImagePreprocessor setCenterCropSize(int size) {
45+
delegate.setCenterCropSize(size);
46+
return this;
47+
}
48+
49+
@Override
50+
public DJLImagePreprocessor enableSquarePadding(boolean enable) {
51+
delegate.enableSquarePadding(enable);
52+
return this;
53+
}
54+
55+
@Override
56+
public DJLImagePreprocessor enableScaling(boolean enable) {
57+
delegate.enableScaling(enable);
58+
return this;
59+
}
60+
61+
@Override
62+
public DJLImagePreprocessor enableCenterCrop(boolean enable) {
63+
delegate.enableCenterCrop(enable);
64+
return this;
65+
}
66+
67+
@Override
68+
public ImagePreprocessor setPaddingColor(Color color) {
69+
return delegate.setPaddingColor(color);
70+
}
71+
72+
73+
@Override
74+
public Image process() {
75+
Object result = delegate.process();
76+
if (result instanceof BufferedImage) {
77+
return SmartImageFactory.getInstance().fromBufferedImage((BufferedImage) result);
78+
} else if (result instanceof Mat) {
79+
return SmartImageFactory.getInstance().fromMat((Mat) result);
80+
}
81+
throw new IllegalStateException("Unsupported process result: " + result.getClass());
82+
}
83+
84+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package cn.smartjavaai.common.preprocess;
2+
3+
import java.awt.*;
4+
5+
/**
6+
* 图片预处理
7+
* @author dwj
8+
*/
9+
public interface ImagePreprocessor<T> {
10+
11+
12+
ImagePreprocessor<T> setExtendRatio(float ratio);
13+
14+
ImagePreprocessor<T> setTargetSize(int size);
15+
16+
ImagePreprocessor<T> setCenterCropSize(int size);
17+
18+
ImagePreprocessor<T> enableSquarePadding(boolean enable);
19+
20+
ImagePreprocessor<T> enableScaling(boolean enable);
21+
22+
ImagePreprocessor<T> enableCenterCrop(boolean enable);
23+
24+
ImagePreprocessor<T> setPaddingColor(Color color);
25+
26+
T process();
27+
28+
}

0 commit comments

Comments
 (0)