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

【底层优化】 支持自由选择 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 682 KiB

After

Width:  |  Height:  |  Size: 674 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 KiB

After

Width:  |  Height:  |  Size: 273 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.24</smartjavaai.version>
<smartjavaai.version>1.0.25</smartjavaai.version>
<!--如果打包运行需要替换成你的main-->
<exec.mainClass>smartai.examples.ocr.common.OcrRecognizeDemo</exec.mainClass>
@@ -219,39 +219,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>
<build>

View File

@@ -2,6 +2,7 @@ package smartai.examples.ocr.common;
import ai.djl.modality.cv.Image;
import cn.smartjavaai.common.config.Config;
import cn.smartjavaai.common.cv.SmartImageFactory;
import cn.smartjavaai.common.entity.DetectionResponse;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.common.utils.ImageUtils;
@@ -43,6 +44,7 @@ public class OcrDetectionDemo {
@BeforeClass
public static void beforeAll() throws IOException {
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -56,7 +58,7 @@ public class OcrDetectionDemo {
//指定检测模型切换模型需要同时修改modelEnum及modelPath
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/wenjie/Documents/develop/model/ocr/PP-OCRv5_mobile_det_infer/PP-OCRv5_mobile_det_infer.onnx");
config.setDevice(device);
return OcrModelFactory.getInstance().getDetModel(config);
}
@@ -73,7 +75,9 @@ public class OcrDetectionDemo {
public void detect(){
try {
OcrCommonDetModel model = getDetectionModel();
List<OcrBox> boxes = model.detect("src/main/resources/ocr_1.jpg");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/ocr_1.jpg");
List<OcrBox> boxes = model.detect(image);
log.info("OCR检测结果{}", JSONObject.toJSONString(boxes));
} catch (Exception e) {
e.printStackTrace();
@@ -97,6 +101,26 @@ public class OcrDetectionDemo {
}
}
/**
* 文本检测并绘制结果
* 检测图像中的文本区域,仅检测文本框位置,不识别文字内容
* 注意事项:
* 1、批量检测时模型应统一放在外层 try 中使用,避免重复加载,自动释放资源更安全。
* 2、模型文件需要放在单独文件夹
*/
@Test
public void detectAndDraw2(){
try {
OcrCommonDetModel model = getDetectionModel();
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/ocr_1.jpg");
Image resultImage = model.detectAndDraw(image);
ImageUtils.save(resultImage, "output/ocr_1_detected2.jpg");
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 批量文本检测:批量检测要求图片宽高一致
@@ -110,7 +134,7 @@ public class OcrDetectionDemo {
try {
OcrCommonDetModel model = getDetectionModel();
//批量检测要求图片宽高一致
String folderPath = "/Users/xxx/Downloads/testing33";
String folderPath = "/Users/wenjie/Downloads/testing33";
//读取文件夹中所有图片
List<Image> images = ImageUtils.readImagesFromFolder(folderPath);
List<List<OcrBox>> ocrResult = model.batchDetectDJLImage(images);

View File

@@ -1,7 +1,10 @@
package smartai.examples.ocr.common;
import ai.djl.modality.cv.Image;
import cn.smartjavaai.common.config.Config;
import cn.smartjavaai.common.cv.SmartImageFactory;
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.entity.OcrBox;
@@ -46,7 +49,7 @@ public class OcrDirectionDetDemo {
//指定行文本方向检测模型切换模型需要同时修改modelEnum及modelPath
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.setModelPath("/Users/wenjie/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);
@@ -61,7 +64,7 @@ public class OcrDirectionDetDemo {
//指定检测模型切换模型需要同时修改modelEnum及modelPath
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/wenjie/Documents/develop/model/ocr/PP-OCRv5_mobile_det_infer/PP-OCRv5_mobile_det_infer.onnx");
config.setDevice(device);
return OcrModelFactory.getInstance().getDetModel(config);
}
@@ -78,7 +81,9 @@ public class OcrDirectionDetDemo {
public void detect(){
try {
OcrDirectionModel directionModel = getDirectionModel();
List<OcrItem> itemList = directionModel.detect("src/main/resources/ocr_1.jpg");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/ocr_1.jpg");
List<OcrItem> itemList = directionModel.detect(image);
log.info("OCR方向检测结果1{}", JSONObject.toJSONString(itemList));
} catch (Exception e) {
e.printStackTrace();
@@ -102,6 +107,25 @@ public class OcrDirectionDetDemo {
}
}
/**
* 文本检测并绘制结果
* 流程:文本检测 -> 方向分类
* 检测图像中的文本区域,仅检测文本框位置,不识别文字内容
* 模型需要放在单独文件夹
*/
@Test
public void detectAndDraw2(){
try {
OcrDirectionModel directionModel = getDirectionModel();
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/ocr_1.jpg");
Image resultImage = directionModel.detectAndDraw(image);
ImageUtils.save(resultImage, "output/ocr_1_detected4.jpg");
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@@ -5,7 +5,9 @@ import ai.djl.util.JsonUtils;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileUtil;
import cn.smartjavaai.common.config.Config;
import cn.smartjavaai.common.cv.SmartImageFactory;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.common.utils.BufferedImageUtils;
import cn.smartjavaai.common.utils.ImageUtils;
import cn.smartjavaai.ocr.config.DirectionModelConfig;
import cn.smartjavaai.ocr.config.OcrDetModelConfig;
@@ -48,34 +50,70 @@ public class OcrRecognizeDemo {
@BeforeClass
public static void beforeAll() throws IOException {
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
//Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
/**
* 获取通用识别模型(不带方向矫正
* 获取通用识别模型(高精确度模型
* 注意事项:高精度模型,识别准确度高,速度慢
* @return
*/
public OcrCommonRecModel getRecModel(){
public OcrCommonRecModel getProRecModel(){
OcrRecModelConfig recModelConfig = new OcrRecModelConfig();
//指定文本识别模型切换模型需要同时修改modelEnum及modelPath
recModelConfig.setRecModelEnum(CommonRecModelEnum.PP_OCR_V5_MOBILE_REC_MODEL);
recModelConfig.setRecModelEnum(CommonRecModelEnum.PP_OCR_V5_SERVER_REC_MODEL);
//指定识别模型位置,需要更改为自己的模型路径(下载地址请查看文档)
recModelConfig.setRecModelPath("/Users/wenjie/Documents/develop/model/ocr/PP-OCRv5_server_rec_infer/PP-OCRv5_server_rec.onnx");
recModelConfig.setDevice(device);
recModelConfig.setTextDetModel(getDetectionModel());
recModelConfig.setTextDetModel(getProDetectionModel());
recModelConfig.setDirectionModel(getDirectionModel());
return OcrModelFactory.getInstance().getRecModel(recModelConfig);
}
/**
* 获取文本检测模型
* 获取通用识别模型(极速模型)
* 注意事项:极速模型,识别准确度低,速度快
* @return
*/
public OcrCommonDetModel getDetectionModel() {
public OcrCommonRecModel getFastRecModel(){
OcrRecModelConfig recModelConfig = new OcrRecModelConfig();
//指定文本识别模型切换模型需要同时修改modelEnum及modelPath
recModelConfig.setRecModelEnum(CommonRecModelEnum.PP_OCR_V5_MOBILE_REC_MODEL);
//指定识别模型位置,需要更改为自己的模型路径(下载地址请查看文档)
recModelConfig.setRecModelPath("/Users/wenjie/Documents/develop/model/ocr/PP-OCRv5_mobile_rec_infer/PP-OCRv5_mobile_rec_infer.onnx");
recModelConfig.setDevice(device);
recModelConfig.setTextDetModel(getFastDetectionModel());
return OcrModelFactory.getInstance().getRecModel(recModelConfig);
}
/**
* 获取文本检测模型(极速模型)
* 注意事项:极速模型,识别准确度低,速度快
* @return
*/
public OcrCommonDetModel getFastDetectionModel() {
OcrDetModelConfig config = new OcrDetModelConfig();
//指定检测模型切换模型需要同时修改modelEnum及modelPath
config.setModelEnum(CommonDetModelEnum.PP_OCR_V5_MOBILE_DET_MODEL);
//指定模型位置,需要更改为自己的模型路径(下载地址请查看文档)
config.setDetModelPath("/Users/wenjie/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 OcrCommonDetModel getProDetectionModel() {
OcrDetModelConfig config = new OcrDetModelConfig();
//指定检测模型切换模型需要同时修改modelEnum及modelPath
config.setModelEnum(CommonDetModelEnum.PP_OCR_V5_SERVER_DET_MODEL);
//指定模型位置,需要更改为自己的模型路径(下载地址请查看文档)
config.setDetModelPath("/Users/wenjie/Documents/develop/model/ocr/PP-OCRv5_server_det_infer/PP-OCRv5_server_det.onnx");
config.setDevice(device);
return OcrModelFactory.getInstance().getDetModel(config);
@@ -90,28 +128,12 @@ public class OcrRecognizeDemo {
//指定行文本方向检测模型切换模型需要同时修改modelEnum及modelPath
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.setModelPath("/Users/wenjie/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();
//指定文本识别模型切换模型需要同时修改modelEnum及modelPath
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);
}
/**
* 文本识别
@@ -124,10 +146,12 @@ public class OcrRecognizeDemo {
@Test
public void recognize(){
try {
OcrCommonRecModel recModel = getRecModel();
OcrCommonRecModel recModel = getFastRecModel();
//不带方向矫正,分行返回文本
OcrRecOptions options = new OcrRecOptions(false, true);
OcrInfo ocrInfo = recModel.recognize("/Users/wenjie/Downloads/49421755855753_.pic_hd.jpg",options);
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/ocr_1.jpg");
OcrInfo ocrInfo = recModel.recognize(image, options);
log.info("OCR识别结果{}", JSONObject.toJSONString(ocrInfo));
} catch (Exception e) {
e.printStackTrace();
@@ -146,8 +170,10 @@ public class OcrRecognizeDemo {
@Test
public void recognizeHandWriting(){
try {
OcrCommonRecModel recModel = getRecModel();
OcrInfo ocrInfo = recModel.recognize("src/main/resources/handwriting_1.jpg",new OcrRecOptions());
OcrCommonRecModel recModel = getFastRecModel();
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/handwriting_1.jpg");
OcrInfo ocrInfo = recModel.recognize(image, new OcrRecOptions());
log.info("OCR识别结果{}", JSONObject.toJSONString(ocrInfo));
} catch (Exception e) {
e.printStackTrace();
@@ -166,10 +192,12 @@ public class OcrRecognizeDemo {
@Test
public void recognize2(){
try {
OcrCommonRecModel recModel = getRecModelWithDirection();
OcrCommonRecModel recModel = getFastRecModel();
//带方向矫正,分行返回文本
OcrRecOptions options = new OcrRecOptions(true, true);
OcrInfo ocrInfo = recModel.recognize("src/main/resources/ocr_3.jpg",options);
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/ocr_3.jpg");
OcrInfo ocrInfo = recModel.recognize(image, options);
log.info("OCR识别结果{}", JSONObject.toJSONString(ocrInfo));
} catch (Exception e) {
e.printStackTrace();
@@ -189,7 +217,7 @@ public class OcrRecognizeDemo {
@Test
public void recognizeAndDraw(){
try {
OcrCommonRecModel recModel = getRecModelWithDirection();
OcrCommonRecModel recModel = getFastRecModel();
int fontSize = 18;
recModel.recognizeAndDraw("src/main/resources/general_ocr_002.png", "output/ocr_4_recognized.jpg", fontSize, new OcrRecOptions());
} catch (Exception e) {
@@ -200,55 +228,24 @@ public class OcrRecognizeDemo {
@Test
public void recognizeAndDraw2(){
try {
OcrCommonRecModel recModel = getRecModel();
OcrCommonRecModel recModel = getFastRecModel();
int fontSize = 18;
//创建保存路径
Path inputImagePath = Paths.get("src/main/resources/general_ocr_002.png");
Path imageOutputPath = Paths.get("output/ocr_4_recognized.jpg");
BufferedImage image = null;
image = ImageIO.read(new File(inputImagePath.toAbsolutePath().toString()));
BufferedImage resultImage = recModel.recognizeAndDraw(image, fontSize, new OcrRecOptions());
ImageUtils.saveImage(resultImage, imageOutputPath.toAbsolutePath().toString());
Path imageOutputPath = Paths.get("output/ocr_5_recognized.jpg");
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile(inputImagePath);
OcrInfo ocrInfo = recModel.recognizeAndDraw(image, fontSize, new OcrRecOptions());
log.info("OCR识别结果{}", JSONObject.toJSONString(ocrInfo));
//保存绘制结果
if(ocrInfo != null && ocrInfo.getDrawnImage() != null){
ImageUtils.save(ocrInfo.getDrawnImage(), imageOutputPath.toAbsolutePath().toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 文本识别并绘制结果返回base64
*/
@Test
public void recognizeAndDrawToBase64(){
try {
OcrCommonRecModel recModel = getRecModel();
int fontSize = 18;
//创建保存路径
Path inputImagePath = Paths.get("src/main/resources/general_ocr_002.png");
byte[] imageBytes = FileUtil.readBytes(inputImagePath);
String base64 = recModel.recognizeAndDrawToBase64(imageBytes, fontSize, new OcrRecOptions());
log.info("base64:{}", base64);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 文本识别并绘制结果返回OcrInfo,OcrInfo中包含base64
*/
@Test
public void recognizeAndDraw3(){
try {
OcrCommonRecModel recModel = getRecModel();
int fontSize = 18;
//创建保存路径
Path inputImagePath = Paths.get("src/main/resources/general_ocr_002.png");
byte[] imageBytes = FileUtil.readBytes(inputImagePath);
OcrInfo ocrInfo = recModel.recognizeAndDraw(imageBytes, fontSize, new OcrRecOptions());
log.info("ocrInfo:{}", JsonUtils.toJson(ocrInfo));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 批量识别
@@ -259,7 +256,7 @@ public class OcrRecognizeDemo {
@Test
public void batchRecognize(){
try {
OcrCommonRecModel recModel = getRecModelWithDirection();
OcrCommonRecModel recModel = getFastRecModel();
//批量检测要求图片宽高一致
String folderPath = "/Users/xxx/Downloads/testing33";
//读取文件夹中所有图片

View File

@@ -1,7 +1,9 @@
package smartai.examples.ocr.plate;
import ai.djl.modality.cv.Image;
import ai.djl.util.JsonUtils;
import cn.smartjavaai.common.config.Config;
import cn.smartjavaai.common.cv.SmartImageFactory;
import cn.smartjavaai.common.entity.R;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.common.utils.ImageUtils;
@@ -38,6 +40,7 @@ public class PlateRecDemo {
@BeforeClass
public static void beforeAll() throws IOException {
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -68,6 +71,7 @@ public class PlateRecDemo {
recModelConfig.setModelPath("/Users/wenjie/Documents/develop/model/plate/plate_rec_color.onnx");
//指定车牌检测模型
recModelConfig.setPlateDetModel(getPlateDetModel());
recModelConfig.setDevice(device);
return PlateModelFactory.getInstance().getRecModel(recModelConfig);
}
@@ -75,10 +79,12 @@ public class PlateRecDemo {
* 车牌识别
*/
@Test
public void testDetect() {
public void testDetect() throws IOException {
PlateRecModel plateRecModel = getPlateRecModel();
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile("src/main/resources/plate/Quicker_20220930_180856.png");
//识别车号
R<List<PlateInfo>> result = plateRecModel.recognize("src/main/resources/plate/Quicker_20220930_180856.png");
R<List<PlateInfo>> result = plateRecModel.recognize(image);
if(result.isSuccess()){
log.info("车牌识别结果:{}", JsonUtils.toJson(result.getData()));
}else{
@@ -109,14 +115,14 @@ public class PlateRecDemo {
public void recognizeAndDraw2() {
try {
PlateRecModel plateRecModel = getPlateRecModel();
BufferedImage image = null;
String imagePath = "src/main/resources/plate/Quicker_20220930_180856.png";
image = ImageIO.read(new File(Paths.get(imagePath).toAbsolutePath().toString()));
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile(imagePath);
//可以根据后续业务场景使用detectedImage
R<BufferedImage> detectedImage = plateRecModel.recognizeAndDraw(image);
R<Image> detectedImage = plateRecModel.recognizeAndDraw(image);
if(detectedImage.isSuccess()){
log.info("车牌识别成功");
ImageUtils.saveImage(detectedImage.getData(), "output/plate_recognized2.jpg");
ImageUtils.save(detectedImage.getData(), "output/plate_recognized3.jpg");
}else{
log.error("车牌识别失败:{}", detectedImage.getMessage());
}

View File

@@ -3,6 +3,7 @@ package smartai.examples.ocr.table;
import ai.djl.modality.cv.Image;
import cn.hutool.core.io.FileUtil;
import cn.smartjavaai.common.config.Config;
import cn.smartjavaai.common.cv.SmartImageFactory;
import cn.smartjavaai.common.entity.R;
import cn.smartjavaai.common.enums.DeviceEnum;
import cn.smartjavaai.common.utils.ImageUtils;
@@ -47,6 +48,7 @@ public class TableRecDemo {
@BeforeClass
public static void beforeAll() throws IOException {
SmartImageFactory.setEngine(SmartImageFactory.Engine.OPENCV);
//修改缓存路径
// Config.setCachePath("/Users/xxx/smartjavaai_cache");
}
@@ -79,7 +81,6 @@ public class TableRecDemo {
config.setModelEnum(CommonDetModelEnum.PP_OCR_V5_MOBILE_DET_MODEL);
//指定模型位置,需要更改为自己的模型路径(下载地址请查看文档)
config.setDetModelPath("/Users/wenjie/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);
}
@@ -115,45 +116,6 @@ public class TableRecDemo {
/**
* 表格识别
* 仅支持简单表格
* 流程:表格结构识别 -> 文本检测 -> 文本识别 -> 合成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();
}
}
/**
* 表格识别
@@ -177,7 +139,8 @@ public class TableRecDemo {
// .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()));
//创建Image对象可以从文件、url、InputStream创建、BufferedImage、Base64创建具体使用方法可以查看文档
Image image = SmartImageFactory.getInstance().fromFile(imagePath);
R<TableStructureResult> result = tableRecognizer.recognize(image);
if(result.isSuccess()){
log.info("result: {}", result.getData().getHtml());
@@ -185,8 +148,8 @@ public class TableRecDemo {
Path outputPath = Paths.get("output/table_ch2_result.html");
FileUtil.writeUtf8String(result.getData().getHtml(), outputPath.toAbsolutePath().toString());
//绘制表格结构
BufferedImage resultImage = tableRecognizer.drawTable(result.getData(), image);
ImageUtils.saveImage(resultImage, "output/table_ch2_result.jpg");
Image resultImage = tableRecognizer.drawTable(result.getData(), image);
ImageUtils.save(resultImage, "output/table_ch2_result.jpg");
//导出excel如果导出失败可能是因为表格结果识别的结果是错乱的
try (OutputStream out = Files.newOutputStream(Paths.get("output/table_ch2_result2.xls"))) {
tableRecognizer.exportExcel(result.getData().getHtml(), out);