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

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

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

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

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

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

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

View File

@@ -12,7 +12,7 @@
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<smartjavaai.version>1.0.24</smartjavaai.version>
<smartjavaai.version>1.0.25</smartjavaai.version>
<!--如果打包运行需要替换成你的main-->
<exec.mainClass>smartai.examples.vision.ObjectDetectionDemo</exec.mainClass>
@@ -272,36 +272,6 @@
</dependency>
<!-- linux aarch64 平台 (保留对应平台的配置,可以减小包大小)-->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>${javacv.version}</version>
<classifier>${javacv.platform.linux-arm64}</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>ffmpeg</artifactId>
<version>6.1.1-1.5.10</version>
<classifier>${javacv.platform.linux-arm64}</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>openblas</artifactId>
<version>0.3.26-1.5.10</version>
<classifier>${javacv.platform.linux-arm64}</classifier>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>opencv</artifactId>
<version>4.9.0-1.5.10</version>
<classifier>${javacv.platform.linux-arm64}</classifier>
</dependency>
</dependencies>

View File

@@ -32,6 +32,8 @@ public class ActionRecognizeDemo {
@BeforeClass
public static void beforeAll() throws IOException {
//将图片处理的底层引擎切换为 OpenCV
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}

View File

@@ -41,6 +41,8 @@ public class InstanceSegDemo {
@BeforeClass
public static void beforeAll() throws IOException {
//将图片处理的底层引擎切换为 OpenCV
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -119,7 +121,7 @@ public class InstanceSegDemo {
if(result.isSuccess()){
log.info("实例分割结果:{}", JSONObject.toJSONString(result.getData()));
//保存图片
ImageUtils.saveImage(result.getData().getDrawnImage(), "dog_bike_car_detected.png", "output");
ImageUtils.save(result.getData().getDrawnImage(), "dog_bike_car_detected2.png", "output");
}else{
log.info("实例分割失败:{}", result.getMessage());
}

View File

@@ -36,6 +36,8 @@ public class ObbDetDemo {
@BeforeClass
public static void beforeAll() throws IOException {
//将图片处理的底层引擎切换为 OpenCV
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -115,7 +117,7 @@ public class ObbDetDemo {
if(result.isSuccess()){
log.info("旋转框检测结果:{}", JSONObject.toJSONString(result.getData()));
//保存图片
ImageUtils.saveImage(result.getData().getDrawnImage(), "boats_obb_detected.png", "output");
ImageUtils.save(result.getData().getDrawnImage(), "output/boats_obb_detected2.png");
}else{
log.info("旋转框检测失败:{}", result.getMessage());
}

View File

@@ -5,6 +5,7 @@ import ai.djl.modality.cv.ImageFactory;
import ai.djl.util.JsonUtils;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.UUID;
import cn.smartjavaai.common.cv.SmartImageFactory;
import cn.smartjavaai.common.entity.DetectionInfo;
import cn.smartjavaai.common.entity.DetectionRectangle;
import cn.smartjavaai.common.entity.DetectionResponse;
@@ -56,6 +57,8 @@ public class ObjectDetectionDemo {
@BeforeClass
public static void beforeAll() throws IOException {
//将图片处理的底层引擎切换为 OpenCV
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -90,7 +93,9 @@ public class ObjectDetectionDemo {
public void objectDetection(){
try {
DetectorModel detectorModel = getModel();
DetectionResponse detectionResponse = detectorModel.detect("src/main/resources/object_detection.jpg");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/object_detection.jpg");
DetectionResponse detectionResponse = detectorModel.detect(image);
log.info("目标检测结果:{}", JSONObject.toJSONString(detectionResponse));
} catch (Exception e) {
e.printStackTrace();
@@ -118,10 +123,14 @@ public class ObjectDetectionDemo {
try {
DetectorModel detectorModel = getModel();
String imagePath = "src/main/resources/object_detection.jpg";
BufferedImage image = ImageIO.read(new File(Paths.get(imagePath).toAbsolutePath().toString()));
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile(imagePath);
//可以根据后续业务场景使用detectedImage
BufferedImage detectedImage = detectorModel.detectAndDraw(image);
Assert.assertNotNull("detectedImage null", detectedImage);
DetectionResponse detectionResponse = detectorModel.detectAndDraw(image);
log.info("目标检测结果:{}", JSONObject.toJSONString(detectionResponse));
if(detectionResponse != null && detectionResponse.getDrawnImage() != null){
ImageUtils.save(detectionResponse.getDrawnImage(), "output/object_detection_detected2.png");
}
} catch (Exception e) {
e.printStackTrace();
}
@@ -181,9 +190,9 @@ public class ObjectDetectionDemo {
config.setTopK(100);
config.setDevice(device);
DetectorModel detectorModel = ObjectDetectionModelFactory.getInstance().getModel(config);
DetectionResponse detectionResponse = detectorModel.detect("src/main/resources/dog_bike_car.jpg");
//检测并保存绘制结果
detectorModel.detectAndDraw("src/main/resources/dog_bike_car.jpg", "output/dog_bike_car_detect.jpg");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/dog_bike_car.jpg");
DetectionResponse detectionResponse = detectorModel.detect(image);
log.info("目标检测结果:{}", JSONObject.toJSONString(detectionResponse));
} catch (Exception e) {
e.printStackTrace();
@@ -218,11 +227,11 @@ public class ObjectDetectionDemo {
log.info("时间:" + LocalDateTimeUtil.now().toString());
log.info("检测结果:{}", JsonUtils.toJson(detectionInfoList));
//绘制检测结果
OpenCVUtils.drawRectAndText(image, detectionInfoList);
ImageUtils.drawRectAndText(image, detectionInfoList);
//保存图片
ImageUtils.saveImage(image, "test"+ UUID.fastUUID().toString() +".png","/Users/wenjie/Downloads");
ImageUtils.save(image, "test"+ UUID.fastUUID().toString() +".png","/Users/wenjie/Downloads");
if (image != null){
((Mat)image.getWrappedImage()).release();
ImageUtils.releaseOpenCVMat(image);
}
}
@@ -268,9 +277,12 @@ public class ObjectDetectionDemo {
log.info("时间:" + LocalDateTimeUtil.now().toString());
log.info("检测结果:{}", JsonUtils.toJson(detectionInfoList));
//绘制检测结果
OpenCVUtils.drawRectAndText(image, detectionInfoList);
ImageUtils.drawRectAndText(image, detectionInfoList);
//保存图片
ImageUtils.saveImage(image, "test"+ UUID.fastUUID().toString() +".png","/Users/wenjie/Downloads");
ImageUtils.save(image, "test"+ UUID.fastUUID().toString() +".png","/Users/wenjie/Downloads");
if (image != null){
ImageUtils.releaseOpenCVMat(image);
}
}
@Override
@@ -316,9 +328,12 @@ public class ObjectDetectionDemo {
log.info("时间:" + LocalDateTimeUtil.now().toString());
log.info("检测结果:{}", JsonUtils.toJson(detectionInfoList));
//绘制检测结果
OpenCVUtils.drawRectAndText(image, detectionInfoList);
ImageUtils.drawRectAndText(image, detectionInfoList);
//保存图片
ImageUtils.saveImage(image, "test"+ UUID.fastUUID().toString() +".png","/Users/wenjie/Downloads");
ImageUtils.save(image, "test"+ UUID.fastUUID().toString() +".png","/Users/wenjie/Downloads");
if (image != null){
ImageUtils.releaseOpenCVMat(image);
}
}
@Override
@@ -385,7 +400,7 @@ public class ObjectDetectionDemo {
JOptionPane.showConfirmDialog(null, "Failed to capture image from WebCam.");
}
ViewerFrame frame = new ViewerFrame(width, height);
ImageFactory factory = ImageFactory.getInstance();
SmartImageFactory factory = SmartImageFactory.getInstance();
Size size = new Size(width, height);
while (capture.isOpened()) {
@@ -394,9 +409,8 @@ public class ObjectDetectionDemo {
}
Mat resizeImage = new Mat();
Imgproc.resize(image, resizeImage, size);
Image img = factory.fromImage(resizeImage);
BufferedImage bufferedImage = OpenCVUtils.mat2Image(resizeImage);
DetectionResponse detectedResult = detectorModel.detect(bufferedImage);
Image img = factory.fromMat(resizeImage);
DetectionResponse detectedResult = detectorModel.detect(img);
if (Objects.isNull(detectedResult) || Objects.isNull(detectedResult.getDetectionInfoList()) || detectedResult.getDetectionInfoList().size() == 0){
log.debug("未检测到物体");
continue;
@@ -404,11 +418,10 @@ public class ObjectDetectionDemo {
for(DetectionInfo detectionInfo : detectedResult.getDetectionInfoList()){
DetectionRectangle detectionRectangle = detectionInfo.getDetectionRectangle();
String text = detectionInfo.getObjectDetInfo().getClassName();
ImageUtils.drawImageRectWithText(bufferedImage, detectionRectangle, text, Color.RED);
ImageUtils.drawRectAndText(img, detectionRectangle, text);
}
frame.showImage(bufferedImage);
frame.showImage(ImageUtils.toBufferedImage(img));
}
capture.release();
System.exit(0);
} catch (Exception e) {

View File

@@ -32,6 +32,8 @@ public class PersonDetectDemo {
@BeforeClass
public static void beforeAll() throws IOException {
//将图片处理的底层引擎切换为 OpenCV
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -108,7 +110,7 @@ public class PersonDetectDemo {
if(result.isSuccess()){
log.info("行人检测结果:{}", JSONObject.toJSONString(result.getData()));
//保存图片
ImageUtils.saveImage(result.getData().getDrawnImage(), "person_result.png", "output");
ImageUtils.save(result.getData().getDrawnImage(), "person_result.png", "output");
}else{
log.info("行人检测失败:{}", result.getMessage());
}

View File

@@ -33,6 +33,8 @@ public class PoseDetDemo {
@BeforeClass
public static void beforeAll() throws IOException {
//将图片处理的底层引擎切换为 OpenCV
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -105,7 +107,7 @@ public class PoseDetDemo {
//可以根据后续业务场景使用detectedImage
Image drawImage = detectorModel.detectAndDraw(image);
//保存图片
ImageUtils.saveImage(drawImage, "pose_detected.png", "output");
ImageUtils.save(drawImage, "pose_detected2.png", "output");
} catch (Exception e) {
e.printStackTrace();
}

View File

@@ -36,6 +36,8 @@ public class SemSegDemo {
@BeforeClass
public static void beforeAll() throws IOException {
//将图片处理的底层引擎切换为 OpenCV
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -109,7 +111,7 @@ public class SemSegDemo {
//可以根据后续业务场景使用detectedImage
Image dretectedImage = detectorModel.detectAndDraw(image);
//保存
ImageUtils.saveImage(dretectedImage, "dog_bike_car_detected.png", "output");
ImageUtils.save(dretectedImage, "dog_bike_car_detected2.png", "output");
} catch (Exception e) {
e.printStackTrace();
}