1、OCR:新增表格识别模型

2、OCR:新增9个通用模型
3、OCR:支持批量检测识别
4、OCR:新增更多参数,使用更加灵活
5、人脸识别:支持ID查询及分页获取人脸信息
6、活体检测:视频检测支持设置最大帧数
This commit is contained in:
dengwenjie
2025-07-18 12:28:06 +08:00
parent 5d1f074de5
commit 6fbca62e5b
77 changed files with 3544 additions and 842 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.19</smartjavaai.version>
<smartjavaai.version>1.0.20</smartjavaai.version>
<!--如果打包运行需要替换成你的main-->
<exec.mainClass>smartai.examples.face.facedet.FaceDetDemo</exec.mainClass>

View File

@@ -20,6 +20,7 @@ import cn.smartjavaai.face.model.facerec.FaceRecModel;
import cn.smartjavaai.face.utils.SimilarityUtil;
import cn.smartjavaai.face.vector.config.MilvusConfig;
import cn.smartjavaai.face.vector.config.SQLiteConfig;
import cn.smartjavaai.face.vector.entity.FaceVector;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
@@ -360,6 +361,53 @@ public class FaceRecDemo {
}
/**
* 获取人脸信息
*/
@Test
public void getFaceInfo(){
//使用ID获取人脸信息
try (FaceRecModel faceRecModel = getFaceRecModelWithSQLiteConfig()){
//等待加载人脸库结束
while (!faceRecModel.isLoadFaceCompleted()){
Thread.sleep(100);
}
//ID需改为你需要查询的ID
R<FaceVector> faceInfoResult = faceRecModel.getFaceInfoById("9c4c316d53a74b1184195c1714c250c4");
if(faceInfoResult.isSuccess()){
log.info("人脸信息:{}", JSONObject.toJSONString(faceInfoResult.getData()));
}else{
log.info("获取人脸信息失败:{}", faceInfoResult.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取人脸信息
*/
@Test
public void listFaces(){
//使用ID获取人脸信息
try (FaceRecModel faceRecModel = getFaceRecModelWithDbConfig()){
//等待加载人脸库结束
while (!faceRecModel.isLoadFaceCompleted()){
Thread.sleep(100);
}
//ID需改为你需要查询的ID
R<List<FaceVector>> faceInfoResult = faceRecModel.listFaces(1, 10);
if(faceInfoResult.isSuccess()){
log.info("人脸信息:{}", JSONObject.toJSONString(faceInfoResult.getData()));
}else{
log.info("获取人脸信息失败:{}", faceInfoResult.getMessage());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -79,6 +79,8 @@ public class LivenessDetDemo {
这个数量相当于多帧识别结果融合的融合的帧数。当输入的帧数超过设定帧数的时候,会采用滑动窗口的方式,返回融合的最近输入的帧融合的识别结果。
一般来说在10以内帧数越多结果越稳定相对性能越好但是得到结果的延时越高。*/
config.setFrameCount(LivenessConstant.DEFAULT_FRAME_COUNT);
//视频最大检测帧数
config.setMaxVideoDetectFrames(LivenessConstant.DEFAULT_MAX_VIDEO_DETECT_FRAMES);
//指定人脸检测模型
config.setDetectModel(getFaceDetModel());
return LivenessModelFactory.getInstance().getModel(config);
@@ -103,6 +105,8 @@ public class LivenessDetDemo {
这个数量相当于多帧识别结果融合的融合的帧数。当输入的帧数超过设定帧数的时候,会采用滑动窗口的方式,返回融合的最近输入的帧融合的识别结果。
一般来说在10以内帧数越多结果越稳定相对性能越好但是得到结果的延时越高。*/
config.setFrameCount(LivenessConstant.DEFAULT_FRAME_COUNT);
//视频最大检测帧数
config.setMaxVideoDetectFrames(LivenessConstant.DEFAULT_MAX_VIDEO_DETECT_FRAMES);
//指定人脸检测模型
config.setDetectModel(getFaceDetModel());
return LivenessModelFactory.getInstance().getModel(config);

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.19</smartjavaai.version>
<smartjavaai.version>1.0.20</smartjavaai.version>
<!--如果打包运行需要替换成你的main-->
<exec.mainClass>smartai.examples.objectdetection.ObjectDetection</exec.mainClass>

View File

@@ -12,9 +12,9 @@
<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.19</smartjavaai.version>
<smartjavaai.version>1.0.20</smartjavaai.version>
<!--如果打包运行需要替换成你的main-->
<exec.mainClass>smartai.examples.ocr.OcrRecognizeDemo</exec.mainClass>
<exec.mainClass>smartai.examples.ocr.common.OcrRecognizeDemo</exec.mainClass>
<javacv.version>1.5.10</javacv.version>

View File

@@ -1,76 +0,0 @@
package smartai.examples.ocr;
import cn.smartjavaai.common.entity.DetectionResponse;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.ocr.config.OcrDetModelConfig;
import cn.smartjavaai.ocr.entity.OcrBox;
import cn.smartjavaai.ocr.enums.CommonDetModelEnum;
import cn.smartjavaai.ocr.factory.OcrModelFactory;
import cn.smartjavaai.ocr.model.common.detect.OcrCommonDetModel;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.file.Paths;
import java.util.List;
/**
* OCR 文本检测 示例
* 模型下载地址https://pan.baidu.com/s/15Noz2xHQzqMQSl1B19BobQ?pwd=1234 提取码: 1234
* @author dwj
*/
@Slf4j
public class OcrDetectionDemo {
//设备类型
public static DeviceEnum device = DeviceEnum.CPU;
/**
* 文本检测
* 检测图像中的文本区域,仅返回文本框位置,不识别文字内容
* 模型需要放在单独文件夹
*/
@Test
public void detect(){
OcrDetModelConfig config = new OcrDetModelConfig();
//指定检测模型
config.setModelEnum(CommonDetModelEnum.PADDLEOCR_V5_DET_MODEL);
//指定模型位置,需要更改为自己的模型路径(下载地址请查看文档)
config.setDetModelPath("/Users/xxx/Documents/develop/ocr模型/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
config.setDevice(device);
try (OcrCommonDetModel model = OcrModelFactory.getInstance().getDetModel(config)){
List<OcrBox> boxes = model.detect("src/main/resources/ocr_1.jpg");
log.info("OCR检测结果{}", JSONObject.toJSONString(boxes));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 文本检测并绘制结果
* 检测图像中的文本区域,仅检测文本框位置,不识别文字内容
* 模型需要放在单独文件夹
*/
@Test
public void detectAndDraw(){
OcrDetModelConfig config = new OcrDetModelConfig();
//指定检测模型
config.setModelEnum(CommonDetModelEnum.PADDLEOCR_V5_DET_MODEL);
//指定模型位置,需要更改为自己的模型路径(下载地址请查看文档)
config.setDetModelPath("/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
try (OcrCommonDetModel model = OcrModelFactory.getInstance().getDetModel(config)){
model.detectAndDraw("src/main/resources/ocr_1.jpg", "output/ocr_1_detected.jpg");
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -1,145 +0,0 @@
package smartai.examples.ocr;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.ocr.config.OcrDetModelConfig;
import cn.smartjavaai.ocr.config.OcrRecModelConfig;
import cn.smartjavaai.ocr.entity.OcrBox;
import cn.smartjavaai.ocr.entity.OcrInfo;
import cn.smartjavaai.ocr.enums.CommonDetModelEnum;
import cn.smartjavaai.ocr.enums.CommonRecModelEnum;
import cn.smartjavaai.ocr.enums.DirectionModelEnum;
import cn.smartjavaai.ocr.factory.OcrModelFactory;
import cn.smartjavaai.ocr.model.common.detect.OcrCommonDetModel;
import cn.smartjavaai.ocr.model.common.recognize.OcrCommonRecModel;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.File;
import java.util.List;
/**
* OCR 文本识别 示例
* 模型下载地址https://pan.baidu.com/s/1MLfd73Vjdpnuls9-oqc9uw?pwd=1234 提取码: 1234
* @author dwj
* @date 2025/5/25
*/
@Slf4j
public class OcrRecognizeDemo {
//设备类型
public static DeviceEnum device = DeviceEnum.CPU;
/**
* 获取通用识别模型(不带方向矫正)
* @return
*/
public OcrCommonRecModel getRecModel(){
OcrRecModelConfig recModelConfig = new OcrRecModelConfig();
//指定检测模型
recModelConfig.setDetModelEnum(CommonDetModelEnum.PADDLEOCR_V5_DET_MODEL);
//指定检测模型位置,需要更改为自己的模型路径(下载地址请查看文档)
recModelConfig.setDetModelPath("/Users/xxx/Documents/develop/ocr模型/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
//指定识别模型
recModelConfig.setRecModelEnum(CommonRecModelEnum.PADDLEOCR_V5_REC_MODEL);
//指定识别模型位置,需要更改为自己的模型路径(下载地址请查看文档)
recModelConfig.setRecModelPath("/Users/xxx/Documents/develop/ocr模型/PP-OCRv5_server_rec_infer/PP-OCRv5_server_rec.onnx");
recModelConfig.setDevice(device);
return OcrModelFactory.getInstance().getRecModel(recModelConfig);
}
/**
* 获取通用识别模型(带方向矫正)
* @return
*/
public OcrCommonRecModel getRecModelWithDirection() {
OcrRecModelConfig recModelConfig = new OcrRecModelConfig();
//指定检测模型
recModelConfig.setDetModelEnum(CommonDetModelEnum.PADDLEOCR_V5_DET_MODEL);
//指定检测模型位置,需要更改为自己的模型路径(下载地址请查看文档)
recModelConfig.setDetModelPath("/Users/xxx/Documents/develop/ocr模型/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
//指定识别模型
recModelConfig.setRecModelEnum(CommonRecModelEnum.PADDLEOCR_V5_REC_MODEL);
//指定识别模型位置,需要更改为自己的模型路径(下载地址请查看文档)
recModelConfig.setRecModelPath("/Users/xxx/Documents/develop/ocr模型/PP-OCRv5_server_rec_infer/PP-OCRv5_server_rec.onnx");
//指定方向检测模型
recModelConfig.setDirectionModelEnum(DirectionModelEnum.CH_PPOCR_MOBILE_V2_CLS);
//指定方向模型位置,需要更改为自己的模型路径(下载地址请查看文档)
recModelConfig.setDirectionModelPath("/Users/xxx/Documents/develop/ocr模型/ch_ppocr_mobile_v2.0_cls.onnx");
recModelConfig.setDevice(device);
return OcrModelFactory.getInstance().getRecModel(recModelConfig);
}
/**
* 文本识别
* 支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字
* 流程:文本检测 -> 文本识别
* 模型需要放在单独文件夹
*/
@Test
public void recognize(){
try (OcrCommonRecModel recModel = getRecModel()){
OcrInfo ocrInfo = recModel.recognize("src/main/resources/ocr_2.jpg");
log.info("OCR识别结果{}", JSONObject.toJSONString(ocrInfo));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 文本识别(手写字)
* 支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字
* 流程:文本检测 -> 文本识别
* 模型需要放在单独文件夹
*/
@Test
public void recognizeHandWriting(){
try (OcrCommonRecModel recModel = getRecModel()){
OcrInfo ocrInfo = recModel.recognize("src/main/resources/handwriting_1.jpg");
log.info("OCR识别结果{}", JSONObject.toJSONString(ocrInfo));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 文本识别(带方向矫正)
* 支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字
* 本方法支持多角度文字识别
* 流程:文本检测 -> 方向检测 -> 方向矫正 -> 文本识别
* 模型需要放在单独文件夹
*/
@Test
public void recognize2(){
try (OcrCommonRecModel recModel = getRecModelWithDirection()){
OcrInfo ocrInfo = recModel.recognize("src/main/resources/ocr_4.jpg");
log.info("OCR识别结果{}", JSONObject.toJSONString(ocrInfo));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 文本识别并绘制结果
* 支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字
* 流程:文本检测 -> 文本识别
* 模型需要放在单独文件夹
*/
@Test
public void recognizeAndDraw(){
try (OcrCommonRecModel recModel = getRecModelWithDirection()){
int fontSize = 25;
recModel.recognizeAndDraw("src/main/resources/ocr_4.jpg", "output/ocr_4_recognized.jpg", fontSize);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,113 @@
package smartai.examples.ocr.common;
import ai.djl.modality.cv.Image;
import cn.smartjavaai.common.entity.DetectionResponse;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.common.utils.ImageUtils;
import cn.smartjavaai.ocr.config.OcrDetModelConfig;
import cn.smartjavaai.ocr.config.OcrRecOptions;
import cn.smartjavaai.ocr.entity.OcrBox;
import cn.smartjavaai.ocr.entity.OcrInfo;
import cn.smartjavaai.ocr.enums.CommonDetModelEnum;
import cn.smartjavaai.ocr.factory.OcrModelFactory;
import cn.smartjavaai.ocr.model.common.detect.OcrCommonDetModel;
import cn.smartjavaai.ocr.opencv.OcrOpenCVUtils;
import cn.smartjavaai.ocr.utils.OcrUtils;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.opencv.core.Mat;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.file.Paths;
import java.util.List;
/**
* OCR 文本检测 示例
* 模型下载地址https://pan.baidu.com/s/15Noz2xHQzqMQSl1B19BobQ?pwd=1234 提取码: 1234
* @author dwj
*/
@Slf4j
public class OcrDetectionDemo {
//设备类型
public static DeviceEnum device = DeviceEnum.CPU;
/**
* 获取文本检测模型
* @return
*/
public OcrCommonDetModel getDetectionModel() {
OcrDetModelConfig config = new OcrDetModelConfig();
//指定检测模型
config.setModelEnum(CommonDetModelEnum.PP_OCR_V5_MOBILE_DET_MODEL);
//指定模型位置,需要更改为自己的模型路径(下载地址请查看文档)
config.setDetModelPath("/Users/xxx/Documents/develop/model/ocr/PP-OCRv5_mobile_det_infer/PP-OCRv5_mobile_det_infer.onnx");
config.setDevice(device);
return OcrModelFactory.getInstance().getDetModel(config);
}
/**
* 文本检测
* 检测图像中的文本区域,仅返回文本框位置,不识别文字内容
* 注意事项:
* 1、批量检测时模型应统一放在外层 try 中使用,避免重复加载,自动释放资源更安全。
* 2、模型文件需要放在单独文件夹
*/
@Test
public void detect(){
try (OcrCommonDetModel model = getDetectionModel()){
List<OcrBox> boxes = model.detect("src/main/resources/ocr_1.jpg");
log.info("OCR检测结果{}", JSONObject.toJSONString(boxes));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 文本检测并绘制结果
* 检测图像中的文本区域,仅检测文本框位置,不识别文字内容
* 注意事项:
* 1、批量检测时模型应统一放在外层 try 中使用,避免重复加载,自动释放资源更安全。
* 2、模型文件需要放在单独文件夹
*/
@Test
public void detectAndDraw(){
try (OcrCommonDetModel model = getDetectionModel()){
model.detectAndDraw("src/main/resources/ocr_1.jpg", "output/ocr_1_detected.jpg");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 批量文本检测:批量检测要求图片宽高一致
* 检测图像中的文本区域,仅返回文本框位置,不识别文字内容
* 注意事项:
* 1、批量检测时模型应统一放在外层 try 中使用,避免重复加载,自动释放资源更安全。
* 2、模型文件需要放在单独文件夹
*/
@Test
public void batchDetect(){
try (OcrCommonDetModel model = getDetectionModel()){
//批量检测要求图片宽高一致
String folderPath = "/Users/xxx/Downloads/testing33";
//读取文件夹中所有图片
List<Image> images = ImageUtils.readImagesFromFolder(folderPath);
List<List<OcrBox>> ocrResult = model.batchDetectDJLImage(images);
for(int i = 0; i < ocrResult.size(); i++){
log.info("图片" + i + "文本检测结果:{}", JSONObject.toJSONString(ocrResult.get(i)));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -1,4 +1,4 @@
package smartai.examples.ocr;
package smartai.examples.ocr.common;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.ocr.config.DirectionModelConfig;
@@ -17,7 +17,7 @@ import org.junit.Test;
import java.util.List;
/**
* OCR 文本方向检测 示例
* OCR 文本方向检测 示例
* 模型下载地址https://pan.baidu.com/s/1MLfd73Vjdpnuls9-oqc9uw?pwd=1234 提取码: 1234
* @author dwj
* @date 2025/5/25
@@ -34,18 +34,29 @@ public class OcrDirectionDetDemo {
*/
public OcrDirectionModel getDirectionModel(){
DirectionModelConfig directionModelConfig = new DirectionModelConfig();
//指定检测模型
directionModelConfig.setDetModelEnum(CommonDetModelEnum.PADDLEOCR_V5_DET_MODEL);
//指定检测模型位置需要更改为自己的模型路径下载地址请查看文档
directionModelConfig.setDetModelPath("/Users/xxx/Documents/develop/ocr模型/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
//指定文本方向检测模型
directionModelConfig.setModelEnum(DirectionModelEnum.CH_PPOCR_MOBILE_V2_CLS);
//指定文本方向检测模型路径需要更改为自己的模型路径下载地址请查看文档
directionModelConfig.setModelPath("/Users/xxx/Documents/develop/ocr模型/ch_ppocr_mobile_v2.0_cls.onnx");
//指定行文本方向检测模型
directionModelConfig.setModelEnum(DirectionModelEnum.PP_LCNET_X0_25);
//指定行文本方向检测模型路径需要更改为自己的模型路径下载地址请查看文档
directionModelConfig.setModelPath("/Users/xxx/Documents/develop/model/ocr/PP-LCNet_x0_25_textline_ori_infer/PP-LCNet_x0_25_textline_ori_infer.onnx");
directionModelConfig.setDevice(device);
directionModelConfig.setTextDetModel(getDetectionModel());
return OcrModelFactory.getInstance().getDirectionModel(directionModelConfig);
}
/**
* 获取文本检测模型
* @return
*/
public OcrCommonDetModel getDetectionModel() {
OcrDetModelConfig config = new OcrDetModelConfig();
//指定检测模型
config.setModelEnum(CommonDetModelEnum.PP_OCR_V5_MOBILE_DET_MODEL);
//指定模型位置需要更改为自己的模型路径下载地址请查看文档
config.setDetModelPath("/Users/xxx/Documents/develop/model/ocr/PP-OCRv5_mobile_det_infer/PP-OCRv5_mobile_det_infer.onnx");
config.setDevice(device);
return OcrModelFactory.getInstance().getDetModel(config);
}
/**
* 文本方向检测
@@ -57,8 +68,8 @@ public class OcrDirectionDetDemo {
@Test
public void detect(){
try (OcrDirectionModel directionModel = getDirectionModel()){
List<OcrItem> itemList = directionModel.detect("src/main/resources/ocr_3.jpg");
log.info("OCR方向检测结果{}", JSONObject.toJSONString(itemList));
List<OcrItem> itemList = directionModel.detect("src/main/resources/ocr_1.jpg");
log.info("OCR方向检测结果1{}", JSONObject.toJSONString(itemList));
} catch (Exception e) {
e.printStackTrace();
}

View File

@@ -0,0 +1,206 @@
package smartai.examples.ocr.common;
import ai.djl.modality.cv.Image;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.common.utils.ImageUtils;
import cn.smartjavaai.ocr.config.DirectionModelConfig;
import cn.smartjavaai.ocr.config.OcrDetModelConfig;
import cn.smartjavaai.ocr.config.OcrRecModelConfig;
import cn.smartjavaai.ocr.config.OcrRecOptions;
import cn.smartjavaai.ocr.entity.OcrBox;
import cn.smartjavaai.ocr.entity.OcrInfo;
import cn.smartjavaai.ocr.enums.CommonDetModelEnum;
import cn.smartjavaai.ocr.enums.CommonRecModelEnum;
import cn.smartjavaai.ocr.enums.DirectionModelEnum;
import cn.smartjavaai.ocr.factory.OcrModelFactory;
import cn.smartjavaai.ocr.model.common.detect.OcrCommonDetModel;
import cn.smartjavaai.ocr.model.common.direction.OcrDirectionModel;
import cn.smartjavaai.ocr.model.common.recognize.OcrCommonRecModel;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.io.File;
import java.util.List;
/**
* OCR 文本识别 示例
* 模型下载地址https://pan.baidu.com/s/1MLfd73Vjdpnuls9-oqc9uw?pwd=1234 提取码: 1234
* @author dwj
* @date 2025/5/25
*/
@Slf4j
public class OcrRecognizeDemo {
//设备类型
public static DeviceEnum device = DeviceEnum.CPU;
/**
* 获取通用识别模型(不带方向矫正)
* @return
*/
public OcrCommonRecModel getRecModel(){
OcrRecModelConfig recModelConfig = new OcrRecModelConfig();
//指定文本识别模型
recModelConfig.setRecModelEnum(CommonRecModelEnum.PP_OCR_V5_MOBILE_REC_MODEL);
//指定识别模型位置,需要更改为自己的模型路径(下载地址请查看文档)
recModelConfig.setRecModelPath("/Users/xxx/Documents/develop/model/ocr/PP-OCRv5_mobile_rec_infer/PP-OCRv5_mobile_rec_infer.onnx");
recModelConfig.setDevice(device);
recModelConfig.setTextDetModel(getDetectionModel());
return OcrModelFactory.getInstance().getRecModel(recModelConfig);
}
/**
* 获取文本检测模型
* @return
*/
public OcrCommonDetModel getDetectionModel() {
OcrDetModelConfig config = new OcrDetModelConfig();
//指定检测模型
config.setModelEnum(CommonDetModelEnum.PP_OCR_V5_MOBILE_DET_MODEL);
//指定模型位置,需要更改为自己的模型路径(下载地址请查看文档)
config.setDetModelPath("/Users/xxx/Documents/develop/model/ocr/PP-OCRv5_mobile_det_infer/PP-OCRv5_mobile_det_infer.onnx");
config.setDevice(device);
return OcrModelFactory.getInstance().getDetModel(config);
}
/**
* 获取方向检测模型
* @return
*/
public OcrDirectionModel getDirectionModel(){
DirectionModelConfig directionModelConfig = new DirectionModelConfig();
//指定行文本方向检测模型
directionModelConfig.setModelEnum(DirectionModelEnum.PP_LCNET_X0_25);
//指定行文本方向检测模型路径,需要更改为自己的模型路径(下载地址请查看文档)
directionModelConfig.setModelPath("/Users/xxx/Documents/develop/model/ocr/PP-LCNet_x0_25_textline_ori_infer/PP-LCNet_x0_25_textline_ori_infer.onnx");
directionModelConfig.setDevice(device);
return OcrModelFactory.getInstance().getDirectionModel(directionModelConfig);
}
/**
* 获取通用识别模型(带方向矫正)
* @return
*/
public OcrCommonRecModel getRecModelWithDirection() {
OcrRecModelConfig recModelConfig = new OcrRecModelConfig();
//指定文本识别模型
recModelConfig.setRecModelEnum(CommonRecModelEnum.PP_OCR_V5_MOBILE_REC_MODEL);
//指定识别模型位置,需要更改为自己的模型路径(下载地址请查看文档)
recModelConfig.setRecModelPath("/Users/xxx/Documents/develop/model/ocr/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);
}
/**
* 文本识别
* 支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字
* 流程:文本检测 -> 文本识别
* 注意事项:
* 1、批量检测时模型应统一放在外层 try 中使用,避免重复加载,自动释放资源更安全。
* 2、模型文件需要放在单独文件夹
*/
@Test
public void recognize(){
try (OcrCommonRecModel recModel = getRecModel()){
//不带方向矫正,分行返回文本
OcrRecOptions options = new OcrRecOptions(false, true);
OcrInfo ocrInfo = recModel.recognize("src/main/resources/ocr_2.jpg",options);
log.info("OCR识别结果{}", JSONObject.toJSONString(ocrInfo));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 文本识别(手写字)
* 支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字
* 流程:文本检测 -> 文本识别
* 注意事项:
* 1、批量检测时模型应统一放在外层 try 中使用,避免重复加载,自动释放资源更安全。
* 2、模型文件需要放在单独文件夹
*/
@Test
public void recognizeHandWriting(){
try (OcrCommonRecModel recModel = getRecModel()){
OcrInfo ocrInfo = recModel.recognize("src/main/resources/handwriting_1.jpg",new OcrRecOptions());
log.info("OCR识别结果{}", JSONObject.toJSONString(ocrInfo));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 文本识别(带方向矫正)
* 支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字
* 本方法支持多角度文字识别
* 流程:文本检测 -> 方向检测 -> 方向矫正 -> 文本识别
* 注意事项:
* 1、批量检测时模型应统一放在外层 try 中使用,避免重复加载,自动释放资源更安全。
* 2、模型文件需要放在单独文件夹
*/
@Test
public void recognize2(){
try (OcrCommonRecModel recModel = getRecModelWithDirection()){
//带方向矫正,分行返回文本
OcrRecOptions options = new OcrRecOptions(true, true);
OcrInfo ocrInfo = recModel.recognize("src/main/resources/ocr_3.jpg",options);
log.info("OCR识别结果{}", JSONObject.toJSONString(ocrInfo));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 文本识别并绘制结果
* 支持简体中文、繁体中文、英文、日文四种主要语言,以及手写、竖版、拼音、生僻字
* 流程:文本检测 -> 文本识别
* 注意事项:
* 1、批量检测时模型应统一放在外层 try 中使用,避免重复加载,自动释放资源更安全。
* 2、模型文件需要放在单独文件夹
*/
@Test
public void recognizeAndDraw(){
try (OcrCommonRecModel recModel = getRecModelWithDirection()){
int fontSize = 18;
recModel.recognizeAndDraw("src/main/resources/general_ocr_002.png", "output/ocr_4_recognized.jpg", fontSize, new OcrRecOptions());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 批量识别
* 注意事项:
* 1、批量检测时模型应统一放在外层 try 中使用,避免重复加载,自动释放资源更安全。
* 2、模型文件需要放在单独文件夹
*/
@Test
public void batchRecognize(){
try (OcrCommonRecModel recModel = getRecModelWithDirection()){
//批量检测要求图片宽高一致
String folderPath = "/Users/xxx/Downloads/testing33";
//读取文件夹中所有图片
List<Image> images = ImageUtils.readImagesFromFolder(folderPath);
//带方向矫正,分行返回文本
OcrRecOptions options = new OcrRecOptions(true, true);
List<OcrInfo> ocrResult = recModel.batchRecognizeDJLImage(images, options);
for(int i = 0; i < ocrResult.size(); i++){
log.info("图片" + i + "文本识别结果:{}", JSONObject.toJSONString(ocrResult.get(i)));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,144 @@
package smartai.examples.ocr.table;
import ai.djl.modality.cv.Image;
import cn.hutool.core.io.FileUtil;
import cn.smartjavaai.common.entity.R;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.common.utils.ImageUtils;
import cn.smartjavaai.ocr.config.*;
import cn.smartjavaai.ocr.entity.OcrInfo;
import cn.smartjavaai.ocr.entity.TableStructureResult;
import cn.smartjavaai.ocr.enums.CommonDetModelEnum;
import cn.smartjavaai.ocr.enums.CommonRecModelEnum;
import cn.smartjavaai.ocr.enums.DirectionModelEnum;
import cn.smartjavaai.ocr.enums.TableStructureModelEnum;
import cn.smartjavaai.ocr.factory.OcrModelFactory;
import cn.smartjavaai.ocr.factory.TableRecModelFactory;
import cn.smartjavaai.ocr.model.common.detect.OcrCommonDetModel;
import cn.smartjavaai.ocr.model.common.direction.OcrDirectionModel;
import cn.smartjavaai.ocr.model.common.recognize.OcrCommonRecModel;
import cn.smartjavaai.ocr.model.table.TableRecognizer;
import cn.smartjavaai.ocr.model.table.TableStructureModel;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
/**
* OCR 文本识别 示例
* 模型下载地址https://pan.baidu.com/s/1MLfd73Vjdpnuls9-oqc9uw?pwd=1234 提取码: 1234
* @author dwj
* @date 2025/5/25
*/
@Slf4j
public class TableRecDemo {
//设备类型
public static DeviceEnum device = DeviceEnum.CPU;
/**
* 获取通用识别模型(不带方向矫正)
* @return
*/
public OcrCommonRecModel getRecModel(){
OcrRecModelConfig recModelConfig = new OcrRecModelConfig();
//指定文本识别模型
recModelConfig.setRecModelEnum(CommonRecModelEnum.PP_OCR_V5_MOBILE_REC_MODEL);
//指定识别模型位置,需要更改为自己的模型路径(下载地址请查看文档)
recModelConfig.setRecModelPath("/Users/xxx/Documents/develop/model/ocr/PP-OCRv5_mobile_rec_infer/PP-OCRv5_mobile_rec_infer.onnx");
recModelConfig.setDevice(device);
recModelConfig.setTextDetModel(getDetectionModel());
return OcrModelFactory.getInstance().getRecModel(recModelConfig);
}
/**
* 获取文本检测模型
* @return
*/
public OcrCommonDetModel getDetectionModel() {
OcrDetModelConfig config = new OcrDetModelConfig();
//指定检测模型
config.setModelEnum(CommonDetModelEnum.PP_OCR_V5_MOBILE_DET_MODEL);
//指定模型位置,需要更改为自己的模型路径(下载地址请查看文档)
config.setDetModelPath("/Users/xxx/Documents/develop/model/ocr/PP-OCRv5_mobile_det_infer/PP-OCRv5_mobile_det_infer.onnx");
// config.setDetModelPath("/Users/xxx/Documents/develop/model/ocr/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
config.setDevice(device);
return OcrModelFactory.getInstance().getDetModel(config);
}
/**
* 获取方向检测模型
* @return
*/
public OcrDirectionModel getDirectionModel(){
DirectionModelConfig directionModelConfig = new DirectionModelConfig();
//指定行文本方向检测模型
directionModelConfig.setModelEnum(DirectionModelEnum.PP_LCNET_X0_25);
//指定行文本方向检测模型路径,需要更改为自己的模型路径(下载地址请查看文档)
directionModelConfig.setModelPath("/Users/xxx/Documents/develop/model/ocr/PP-LCNet_x0_25_textline_ori_infer/PP-LCNet_x0_25_textline_ori_infer.onnx");
directionModelConfig.setDevice(device);
return OcrModelFactory.getInstance().getDirectionModel(directionModelConfig);
}
/**
* 创建表格结构识别模型
* @return
*/
public TableStructureModel getTableStructureModel(){
TableStructureConfig config = new TableStructureConfig();
//指定行文本方向检测模型
config.setModelEnum(TableStructureModelEnum.SLANET_PLUS);
//指定行文本方向检测模型路径,需要更改为自己的模型路径(下载地址请查看文档)
config.setModelPath("/Users/xxx/Documents/develop/model/ocr/slanet-plus/slanet-plus.onnx");
// config.setModelPath("/Users/xxx/Documents/develop/model/ocr/SLANet_infer/SLANet.onnx");
config.setDevice(device);
return TableRecModelFactory.getInstance().getTableStructureModel(config);
}
/**
* 表格识别
* 仅支持简单表格
* 流程:表格结构识别 -> 文本检测 -> 文本识别 -> 合成html table
* 注意事项:
* 1、批量检测时模型应统一放在外层 try 中使用,避免重复加载,自动释放资源更安全。
* 2、模型文件需要放在单独文件夹
*/
@Test
public void recognize(){
try (TableStructureModel tableStructureModel = getTableStructureModel();
OcrCommonDetModel detModel = getDetectionModel();
OcrCommonRecModel recModel = getRecModel();
OcrDirectionModel directionModel = getDirectionModel()){
//创建表格识别器
TableRecognizer tableRecognizer = TableRecognizer.builder()
.withStructureModel(tableStructureModel)
.withTextDetModel(detModel)
// .withDirectionModel(getDirectionModel()) //如果表格中存在旋转的文字,可以使用方向分类模型
.withTextRecModel(recModel).build();
String imagePath = "src/main/resources/table/table_ch1.png";
BufferedImage image = ImageIO.read(new File(Paths.get(imagePath).toAbsolutePath().toString()));
R<TableStructureResult> result = tableRecognizer.recognize(image);
if(result.isSuccess()){
log.info("result: {}", result.getData().getHtml());
//导出html内容到文件
Path outputPath = Paths.get("output/table_ch2_result.html");
FileUtil.writeUtf8String(result.getData().getHtml(), outputPath.toAbsolutePath().toString());
//绘制表格结构
tableRecognizer.drawTable(result.getData(), image, "output/table_ch2_result.jpg");
//导出excel如果导出失败可能是因为表格结果识别的结果是错乱的
tableRecognizer.exportExcel(result.getData().getHtml(), "output/table_ch2_result.xls");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 241 KiB

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.19</smartjavaai.version>
<smartjavaai.version>1.0.20</smartjavaai.version>
<!--如果打包运行需要替换成你的main-->
<exec.mainClass>smartai.examples.nlp.translation.TranslationDemo</exec.mainClass>