package com.xindao.ocr.swingui.service;
|
|
import cn.smartjavaai.common.enums.DeviceEnum;
|
import com.alibaba.fastjson.JSONObject;
|
import com.xindao.ocr.smartjavaai.config.DirectionModelConfig;
|
import com.xindao.ocr.smartjavaai.config.OcrDetModelConfig;
|
import com.xindao.ocr.smartjavaai.config.OcrRecModelConfig;
|
import com.xindao.ocr.smartjavaai.config.OcrRecOptions;
|
import com.xindao.ocr.smartjavaai.entity.OcrInfo;
|
import com.xindao.ocr.smartjavaai.enums.CommonDetModelEnum;
|
import com.xindao.ocr.smartjavaai.enums.CommonRecModelEnum;
|
import com.xindao.ocr.smartjavaai.enums.DirectionModelEnum;
|
import com.xindao.ocr.smartjavaai.factory.OcrModelFactory;
|
import com.xindao.ocr.smartjavaai.model.common.detect.OcrCommonDetModel;
|
import com.xindao.ocr.smartjavaai.model.common.direction.OcrDirectionModel;
|
import com.xindao.ocr.smartjavaai.model.common.recognize.OcrCommonRecModel;
|
import com.xindao.ocr.swingui.constant.OcrSwingConstants;
|
import lombok.RequiredArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.core.io.ClassPathResource;
|
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
import org.springframework.stereotype.Service;
|
|
import javax.annotation.PostConstruct;
|
import java.io.File;
|
import java.io.IOException;
|
import java.nio.file.Files;
|
import java.nio.file.StandardCopyOption;
|
|
@Slf4j
|
@Service
|
@RequiredArgsConstructor
|
public class OcrService {
|
|
public static DeviceEnum device = DeviceEnum.CPU;
|
|
private final static String MAIN_PP_DIR = "PP_OCRv5";
|
|
private OcrCommonRecModel recModel;
|
|
/**
|
* 初始化加载ocr模型
|
*/
|
@PostConstruct
|
private void init() {
|
log.info("复制ocr文件到本地用户缓存...");
|
// 复制PP_OCRv5目录到本地缓存
|
copyPaddleCppToCache();
|
try {
|
recModel = getRecModel();
|
} catch (IOException e) {
|
log.error("加载OCR模型失败: {}", e.getMessage());
|
e.printStackTrace();
|
}
|
}
|
|
/**
|
* 复制resources中的Paddle_CPP目录到本地缓存
|
*/
|
private void copyPaddleCppToCache() {
|
try {
|
// 创建缓存目录 - 使用用户主目录避免权限问题
|
File cacheDir = OcrSwingConstants.ocrDir;
|
if (!cacheDir.exists()) {
|
cacheDir.mkdirs();
|
}
|
|
// 获取resources中的Paddle_CPP目录资源
|
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
Resource[] resources = resolver.getResources("classpath:"+MAIN_PP_DIR+"/**");
|
|
// 复制所有资源到缓存目录,保持目录结构
|
for (Resource resource : resources) {
|
String resourcePath = resource.getURL().getPath();
|
// 获取相对于Paddle_CPP的路径
|
int startIndex = resourcePath.indexOf(MAIN_PP_DIR) + MAIN_PP_DIR.length();
|
String relativePath = resourcePath.substring(startIndex);
|
// 处理Windows路径分隔符
|
relativePath = relativePath.replace('/', File.separatorChar);
|
// 创建目标文件
|
File destFile = new File(cacheDir, relativePath);
|
// 如果是目录,创建目录
|
if (resource.isReadable() && resource.contentLength() == 0 && relativePath.endsWith(File.separator)) {
|
if (!destFile.exists()) {
|
destFile.mkdirs();
|
log.info("创建目录: {}", destFile.getAbsolutePath());
|
}
|
} else if (resource.isReadable()) {
|
// 确保父目录存在
|
File parentDir = destFile.getParentFile();
|
if (parentDir != null && !parentDir.exists()) {
|
parentDir.mkdirs();
|
}
|
// 复制文件
|
Files.copy(resource.getInputStream(), destFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
log.info("复制资源: {} 到 {}", relativePath, destFile.getAbsolutePath());
|
}
|
}
|
|
} catch (IOException e) {
|
log.error("复制PP_OCRv5目录到缓存失败: {}", e.getMessage());
|
e.printStackTrace();
|
}
|
}
|
|
|
/**
|
* 获取 resources 下模型文件的绝对路径
|
*
|
* @param relativePath 相对于 resources 的路径
|
*/
|
private String getModelPath(String relativePath) throws IOException {
|
String localPath = null;
|
try{
|
new ClassPathResource(relativePath).getFile().getAbsolutePath();
|
}catch (IOException e){
|
// 如果找不到文件,则尝试从本地缓存目录获取
|
localPath = getLocalPath(relativePath);
|
File modelFile = new File(localPath);
|
if (!modelFile.exists()) {
|
throw new IOException("模型文件不存在: " + localPath);
|
}
|
} finally {
|
log.info("OCR模型文件路径: {}", localPath);
|
}
|
return localPath;
|
}
|
|
/**
|
* 获取 resources 下模型文件的用户本地路径
|
*
|
* @param relativePath 相对于 resources 的路径
|
*/
|
private String getLocalPath(String relativePath) {
|
return new File(OcrSwingConstants.ocrDir,File.separator + relativePath).getAbsolutePath();
|
}
|
|
public OcrCommonRecModel getRecModel() throws IOException {
|
OcrRecModelConfig recModelConfig = new OcrRecModelConfig();
|
recModelConfig.setRecModelEnum(CommonRecModelEnum.PP_OCR_V5_MOBILE_REC_MODEL);
|
recModelConfig.setRecModelPath(
|
getModelPath("PP-OCRv5_server_rec_infer/PP-OCRv5_server_rec.onnx")
|
);
|
recModelConfig.setDevice(device);
|
recModelConfig.setTextDetModel(getDetectionModel());
|
return OcrModelFactory.getInstance().getRecModel(recModelConfig);
|
}
|
|
public OcrCommonDetModel getDetectionModel() throws IOException {
|
OcrDetModelConfig config = new OcrDetModelConfig();
|
config.setModelEnum(CommonDetModelEnum.PP_OCR_V5_MOBILE_DET_MODEL);
|
config.setDetModelPath(
|
getModelPath("PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx")
|
);
|
config.setDevice(device);
|
return OcrModelFactory.getInstance().getDetModel(config);
|
}
|
|
public OcrDirectionModel getDirectionModel() throws IOException {
|
DirectionModelConfig directionModelConfig = new DirectionModelConfig();
|
directionModelConfig.setModelEnum(DirectionModelEnum.PP_LCNET_X0_25);
|
directionModelConfig.setModelPath(
|
getModelPath("PP-LCNet_x0_25_textline_ori_infer/PP-LCNet_x0_25_textline_ori_infer.onnx")
|
);
|
directionModelConfig.setDevice(device);
|
return OcrModelFactory.getInstance().getDirectionModel(directionModelConfig);
|
}
|
|
public OcrCommonRecModel getRecModelWithDirection() throws IOException {
|
OcrRecModelConfig recModelConfig = new OcrRecModelConfig();
|
recModelConfig.setRecModelEnum(CommonRecModelEnum.PP_OCR_V5_MOBILE_REC_MODEL);
|
recModelConfig.setRecModelPath(
|
getModelPath("PP-OCRv5_mobile_rec_infer/PP-OCRv5_mobile_rec_infer.onnx")
|
);
|
recModelConfig.setDevice(device);
|
recModelConfig.setTextDetModel(getDetectionModel());
|
recModelConfig.setDirectionModel(getDirectionModel());
|
return OcrModelFactory.getInstance().getRecModel(recModelConfig);
|
}
|
|
public String ocr(String url) {
|
String fullText = null;
|
try {
|
OcrRecOptions options = new OcrRecOptions(false, true);
|
OcrInfo ocrInfo = recModel.recognize(url, options);
|
log.info("OCR识别结果:{}", JSONObject.toJSONString(ocrInfo));
|
fullText = ocrInfo.getFullText();
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
return fullText;
|
}
|
|
}
|