1、新增图片与视频活体检测

2、新增人脸属性识别(性别、年龄、口罩、姿态、眼睛状态)
3、优化检测返回与包结构
4、新增 dependencyManagement 统一依赖版本管理
This commit is contained in:
dengwenjie
2025-05-09 20:10:04 +08:00
parent 42d2943a94
commit bef574cb91
63 changed files with 3266 additions and 382 deletions

View File

@@ -0,0 +1,37 @@
package cn.smartjavaai.ocr.recognition;
import cn.smartjavaai.common.entity.DetectionResponse;
/**
* OCR模型
* @author dwj
*/
public interface OcrRecModel {
/**
* 加载模型
* @param config
*/
void loadModel(OcrRecModelConfig config); // 加载模型
/**
* 人脸检测
* @param imagePath 图片路径
* @return
*/
default DetectionResponse detect(String imagePath) {
throw new UnsupportedOperationException("默认不支持该功能");
}
/**
* 检测并绘制结果
* @param imagePath 图片输入路径(包含文件名称)
* @param outputPath 图片输出路径(包含文件名称)
*/
default void detectAndDraw(String imagePath, String outputPath) {
throw new UnsupportedOperationException("默认不支持该功能");
}
}

View File

@@ -0,0 +1,28 @@
package cn.smartjavaai.ocr.recognition;
import cn.smartjavaai.common.enums.DeviceEnum;
import lombok.Data;
/**
* @author dwj
* @date 2025/4/22
*/
@Data
public class OcrRecModelConfig {
/**
* 模型名称
*/
private OcrRecModelEnum modelEnum;
/**
* 设备类型
*/
private DeviceEnum device;
/**
* 模型路径
*/
private String modelPath;
}

View File

@@ -0,0 +1,27 @@
package cn.smartjavaai.ocr.recognition;
/**
* OCR识别模型枚举
* @author dwj
* @date 2025/4/4
*/
public enum OcrRecModelEnum {
PADDLEOCR_V4_REC_MODEL;
/**
* 根据名称获取枚举 (忽略大小写和下划线变体)
*/
public static OcrRecModelEnum fromName(String name) {
String formatted = name.trim().toUpperCase().replaceAll("[-_]", "");
for (OcrRecModelEnum model : values()) {
if (model.name().replaceAll("_", "").equals(formatted)) {
return model;
}
}
throw new IllegalArgumentException("未知模型名称: " + name);
}
}

View File

@@ -0,0 +1,95 @@
package cn.smartjavaai.ocr.recognition;
import cn.smartjavaai.common.config.Config;
import cn.smartjavaai.ocr.exception.OcrException;
import cn.smartjavaai.ocr.ppv4.model.PaddleOCRV4DetModel;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* OCR模型工厂
* @author dwj
*/
@Slf4j
public class OcrRecModelFactory {
// 使用 volatile 和双重检查锁定来确保线程安全的单例模式
private static volatile OcrRecModelFactory instance;
private static final ConcurrentHashMap<String, OcrRecModel> modelMap = new ConcurrentHashMap<>();
/**
* 算法注册表
*/
private static final Map<String, Class<? extends OcrRecModel>> registry =
new ConcurrentHashMap<>();
public static OcrRecModelFactory getInstance() {
if (instance == null) {
synchronized (OcrRecModelFactory.class) {
if (instance == null) {
instance = new OcrRecModelFactory();
}
}
}
return instance;
}
/**
* 注册算法
* @param name
* @param clazz
*/
private static void registerModel(String name, Class<? extends OcrRecModel> clazz) {
registry.put(name.toLowerCase(), clazz);
}
/**
* 获取模型(通过配置)
* @param config
* @return
*/
public OcrRecModel getModel(OcrRecModelConfig config) {
if(Objects.isNull(config) || Objects.isNull(config.getModelEnum())){
throw new OcrException("未配置OCR模型");
}
return modelMap.computeIfAbsent(config.getModelEnum().name(), k -> {
return createFaceModel(config);
});
}
/**
* 使用ModelConfig创建算法
* @param config
* @return
*/
private OcrRecModel createFaceModel(OcrRecModelConfig config) {
Class<?> clazz = registry.get(config.getModelEnum().name().toLowerCase());
if(clazz == null){
throw new OcrException("Unsupported model");
}
OcrRecModel algorithm = null;
try {
algorithm = (OcrRecModel) clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new OcrException(e);
}
algorithm.loadModel(config);
return algorithm;
}
// 初始化默认算法
static {
//registerModel("PADDLEOCR_V4_REC_MODEL", PaddleOCRV4DetModel.class);
log.info("缓存目录:{}", Config.getCachePath());
}
}