mirror of
https://github.com/geekwenjie/SmartJavaAI.git
synced 2026-09-20 01:29:18 +00:00
- 【人脸检测】新增6个模型(MTCNN、YOLOV5、RetinaFace小尺寸版),大幅提升性能
- 【人脸识别】新增Seetaface6轻量模型 - 【目标检测】支持视频流目标检测(rtsp、视频文件等) - 【目标检测】支持tensorflow2目标检测模型 - 【目标检测】新增行人检测模型(yolo-person) - 【通用视觉】新增4个动作识别模型 - 【通用视觉】新增语义分割模型 - 【通用视觉】新增5个实例分割模型(含yolov8-seg、yolov11-seg) - 【通用视觉】新增yolo-obb11旋转框检测(含yolov11-obb) - 【通用视觉】新增5个姿态估计模型(含yolov8-pose、yolov11-pose)
This commit is contained in:
@@ -6,23 +6,32 @@ import ai.djl.inference.Predictor;
|
||||
import ai.djl.modality.cv.Image;
|
||||
import ai.djl.modality.cv.ImageFactory;
|
||||
import ai.djl.modality.cv.output.CategoryMask;
|
||||
import ai.djl.modality.cv.output.DetectedObjects;
|
||||
import ai.djl.repository.zoo.Criteria;
|
||||
import ai.djl.repository.zoo.ModelNotFoundException;
|
||||
import ai.djl.repository.zoo.ZooModel;
|
||||
import cn.smartjavaai.common.cv.SmartImageFactory;
|
||||
import cn.smartjavaai.common.entity.DetectionResponse;
|
||||
import cn.smartjavaai.common.entity.R;
|
||||
import cn.smartjavaai.common.pool.PredictorFactory;
|
||||
import cn.smartjavaai.common.utils.Base64ImageUtils;
|
||||
import cn.smartjavaai.common.utils.ImageUtils;
|
||||
import cn.smartjavaai.instanceseg.exception.InstanceSegException;
|
||||
import cn.smartjavaai.objectdetection.exception.DetectionException;
|
||||
import cn.smartjavaai.semseg.config.SemSegModelConfig;
|
||||
import cn.smartjavaai.semseg.criteria.SemSegCriteriaFactory;
|
||||
import cn.smartjavaai.vision.utils.CategoryMaskFilter;
|
||||
import cn.smartjavaai.vision.utils.DetectorUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -63,26 +72,12 @@ public class CommonSemSegModel implements SemSegModel {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<CategoryMask> detectBase64(String base64Image) {
|
||||
if(StringUtils.isBlank(base64Image)){
|
||||
return R.fail(R.Status.INVALID_IMAGE);
|
||||
}
|
||||
try {
|
||||
byte[] imageData = Base64ImageUtils.base64ToImage(base64Image);
|
||||
Image image = ImageFactory.getInstance().fromInputStream(new ByteArrayInputStream(imageData));
|
||||
return detect(image);
|
||||
} catch (IOException e) {
|
||||
throw new DetectionException("读取图片异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<CategoryMask> detect(Image image) {
|
||||
CategoryMask categoryMask = detectCore(image);
|
||||
// 过滤
|
||||
if(CollectionUtils.isNotEmpty(config.getAllowedClasses())
|
||||
&& Objects.nonNull(categoryMask) && !categoryMask.getClasses().isEmpty()){
|
||||
&& Objects.nonNull(categoryMask) && CollectionUtils.isNotEmpty(categoryMask.getClasses())){
|
||||
categoryMask = new CategoryMaskFilter(config.getAllowedClasses()).filter(categoryMask);
|
||||
}
|
||||
return R.ok(categoryMask);
|
||||
@@ -117,6 +112,33 @@ public class CommonSemSegModel implements SemSegModel {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public R<CategoryMask> detectAndDraw(String imagePath, String outputPath) {
|
||||
try {
|
||||
Image img = SmartImageFactory.getInstance().fromFile(Paths.get(imagePath));
|
||||
CategoryMask categoryMask = detectCore(img);
|
||||
if(Objects.isNull(categoryMask) || CollectionUtils.isEmpty(categoryMask.getClasses())){
|
||||
throw new InstanceSegException("未检测到实例");
|
||||
}
|
||||
ImageUtils.drawMask(categoryMask, img, 180, 0);
|
||||
img.save(Files.newOutputStream(Paths.get(outputPath)), "png");
|
||||
return R.ok(categoryMask);
|
||||
} catch (IOException e) {
|
||||
throw new InstanceSegException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Image detectAndDraw(Image image) {
|
||||
CategoryMask categoryMask = detectCore(image);
|
||||
if(Objects.isNull(categoryMask) || CollectionUtils.isEmpty(categoryMask.getClasses())){
|
||||
throw new InstanceSegException("未检测到实例");
|
||||
}
|
||||
Image drawnImage = ImageUtils.copy(image);
|
||||
ImageUtils.drawMask(categoryMask, drawnImage, 180, 0);
|
||||
return drawnImage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
try {
|
||||
|
||||
@@ -20,15 +20,6 @@ public interface SemSegModel extends AutoCloseable{
|
||||
*/
|
||||
void loadModel(SemSegModelConfig config);
|
||||
|
||||
/**
|
||||
* 语义分割
|
||||
* @param base64Image
|
||||
* @return
|
||||
*/
|
||||
default R<CategoryMask> detectBase64(String base64Image){
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
|
||||
/**
|
||||
* 语义分割
|
||||
* @param image
|
||||
@@ -38,5 +29,14 @@ public interface SemSegModel extends AutoCloseable{
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
|
||||
default R<CategoryMask> detectAndDraw(String imagePath, String outputPath){
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
|
||||
default Image detectAndDraw(Image image){
|
||||
throw new UnsupportedOperationException("默认不支持该功能");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package cn.smartjavaai.semseg.model;
|
||||
|
||||
import cn.smartjavaai.common.config.Config;
|
||||
import cn.smartjavaai.objectdetection.exception.DetectionException;
|
||||
import cn.smartjavaai.semseg.config.SemSegModelConfig;
|
||||
import cn.smartjavaai.semseg.enums.SemSegModelEnum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 语义分割 模型工厂
|
||||
* @author dwj
|
||||
*/
|
||||
@Slf4j
|
||||
public class SemSegModelFactory {
|
||||
|
||||
// 使用 volatile 和双重检查锁定来确保线程安全的单例模式
|
||||
private static volatile SemSegModelFactory instance;
|
||||
|
||||
private static final ConcurrentHashMap<SemSegModelEnum, SemSegModel> modelMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 模型注册表
|
||||
*/
|
||||
private static final Map<SemSegModelEnum, Class<? extends SemSegModel>> registry =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
// 私有构造函数,防止外部创建实例
|
||||
private SemSegModelFactory() {}
|
||||
|
||||
// 双重检查锁定的单例方法
|
||||
public static SemSegModelFactory getInstance() {
|
||||
if (instance == null) {
|
||||
synchronized (SemSegModelFactory.class) {
|
||||
if (instance == null) {
|
||||
instance = new SemSegModelFactory();
|
||||
}
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模型(通过配置)
|
||||
* @param config
|
||||
* @return
|
||||
*/
|
||||
public SemSegModel getModel(SemSegModelConfig config) {
|
||||
if(Objects.isNull(config) || Objects.isNull(config.getModelEnum())){
|
||||
throw new DetectionException("未配置模型");
|
||||
}
|
||||
return modelMap.computeIfAbsent(config.getModelEnum(), k -> {
|
||||
return createFaceDetModel(config);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用ModelConfig创建模型
|
||||
* @param config
|
||||
* @return
|
||||
*/
|
||||
private SemSegModel createFaceDetModel(SemSegModelConfig config) {
|
||||
Class<?> clazz = registry.get(config.getModelEnum());
|
||||
if(clazz == null){
|
||||
throw new DetectionException("Unsupported model");
|
||||
}
|
||||
SemSegModel model = null;
|
||||
try {
|
||||
model = (SemSegModel) clazz.newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException e) {
|
||||
throw new DetectionException(e);
|
||||
}
|
||||
model.loadModel(config);
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 注册模型
|
||||
* @param modelEnum
|
||||
* @param clazz
|
||||
*/
|
||||
private static void registerAlgorithm(SemSegModelEnum modelEnum, Class<? extends SemSegModel> clazz) {
|
||||
registry.put(modelEnum, clazz);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 移除缓存的模型
|
||||
* @param modelEnum
|
||||
*/
|
||||
public static void removeFromCache(SemSegModelEnum modelEnum) {
|
||||
modelMap.remove(modelEnum);
|
||||
}
|
||||
|
||||
|
||||
// 初始化默认算法
|
||||
static {
|
||||
registerAlgorithm(SemSegModelEnum.DEEPLABV3, CommonSemSegModel.class);
|
||||
log.debug("缓存目录:{}", Config.getCachePath());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user